@ai-sdk/openai
Advanced tools
+11
-2
| import * as _ai_sdk_provider from '@ai-sdk/provider'; | ||
| import { JSONValue, ProviderV4, LanguageModelV4, EmbeddingModelV4, ImageModelV4, TranscriptionModelV4, SpeechModelV4, Experimental_RealtimeFactoryV4, FilesV4, SkillsV4, Experimental_RealtimeModelV4, Experimental_RealtimeModelV4ClientSecretOptions, Experimental_RealtimeModelV4ClientSecretResult, Experimental_RealtimeModelV4ServerEvent, Experimental_RealtimeModelV4ClientEvent, Experimental_RealtimeModelV4SessionConfig } from '@ai-sdk/provider'; | ||
| import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils'; | ||
| import { InferSchema, FetchFunction } from '@ai-sdk/provider-utils'; | ||
| import { InferSchema, FetchFunction, WebSocketConstructor } from '@ai-sdk/provider-utils'; | ||
@@ -1106,3 +1106,3 @@ type OpenAIChatModelId = 'o1' | 'o1-2024-12-17' | 'o3-mini' | 'o3-mini-2025-01-31' | 'o3' | 'o3-2025-04-16' | 'o4-mini' | 'o4-mini-2025-04-16' | 'gpt-4.1' | 'gpt-4.1-2025-04-14' | 'gpt-4.1-mini' | 'gpt-4.1-mini-2025-04-14' | 'gpt-4.1-nano' | 'gpt-4.1-nano-2025-04-14' | 'gpt-4o' | 'gpt-4o-2024-05-13' | 'gpt-4o-2024-08-06' | 'gpt-4o-2024-11-20' | 'gpt-4o-audio-preview' | 'gpt-4o-audio-preview-2024-12-17' | 'gpt-4o-audio-preview-2025-06-03' | 'gpt-4o-mini' | 'gpt-4o-mini-2024-07-18' | 'gpt-4o-mini-audio-preview' | 'gpt-4o-mini-audio-preview-2024-12-17' | 'gpt-4o-search-preview' | 'gpt-4o-search-preview-2025-03-11' | 'gpt-4o-mini-search-preview' | 'gpt-4o-mini-search-preview-2025-03-11' | 'gpt-3.5-turbo-0125' | 'gpt-3.5-turbo' | 'gpt-3.5-turbo-1106' | 'gpt-3.5-turbo-16k' | 'gpt-5' | 'gpt-5-2025-08-07' | 'gpt-5-mini' | 'gpt-5-mini-2025-08-07' | 'gpt-5-nano' | 'gpt-5-nano-2025-08-07' | 'gpt-5-chat-latest' | 'gpt-5.1' | 'gpt-5.1-2025-11-13' | 'gpt-5.1-chat-latest' | 'gpt-5.2' | 'gpt-5.2-2025-12-11' | 'gpt-5.2-chat-latest' | 'gpt-5.2-pro' | 'gpt-5.2-pro-2025-12-11' | 'gpt-5.3-chat-latest' | 'gpt-5.4' | 'gpt-5.4-2026-03-05' | 'gpt-5.4-mini' | 'gpt-5.4-mini-2026-03-17' | 'gpt-5.4-nano' | 'gpt-5.4-nano-2026-03-17' | 'gpt-5.4-pro' | 'gpt-5.4-pro-2026-03-05' | 'gpt-5.5' | 'gpt-5.5-2026-04-23' | (string & {}); | ||
| type OpenAITranscriptionModelId = 'whisper-1' | 'gpt-4o-mini-transcribe' | 'gpt-4o-mini-transcribe-2025-03-20' | 'gpt-4o-mini-transcribe-2025-12-15' | 'gpt-4o-transcribe' | 'gpt-4o-transcribe-diarize' | (string & {}); | ||
| type OpenAITranscriptionModelId = 'whisper-1' | 'gpt-4o-mini-transcribe' | 'gpt-4o-mini-transcribe-2025-03-20' | 'gpt-4o-mini-transcribe-2025-12-15' | 'gpt-4o-transcribe' | 'gpt-4o-transcribe-diarize' | 'gpt-realtime-whisper' | (string & {}); | ||
| declare const openAITranscriptionModelOptions: _ai_sdk_provider_utils.LazySchema<{ | ||
@@ -1114,2 +1114,6 @@ include?: string[] | undefined; | ||
| timestampGranularities?: ("word" | "segment")[] | undefined; | ||
| streaming?: { | ||
| delay?: "minimal" | "low" | "medium" | "high" | "xhigh" | undefined; | ||
| include?: string[] | undefined; | ||
| } | undefined; | ||
| }>; | ||
@@ -1216,2 +1220,7 @@ type OpenAITranscriptionModelOptions = InferSchema<typeof openAITranscriptionModelOptions>; | ||
| fetch?: FetchFunction; | ||
| /** | ||
| * Custom WebSocket implementation. This is useful for testing or for | ||
| * runtimes that need a WebSocket constructor with header support. | ||
| */ | ||
| webSocket?: WebSocketConstructor; | ||
| } | ||
@@ -1218,0 +1227,0 @@ /** |
| import * as _ai_sdk_provider from '@ai-sdk/provider'; | ||
| import { LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4GenerateResult, LanguageModelV4StreamResult, EmbeddingModelV4, ImageModelV4, TranscriptionModelV4CallOptions, TranscriptionModelV4, SpeechModelV4, JSONValue } from '@ai-sdk/provider'; | ||
| import { LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4GenerateResult, LanguageModelV4StreamResult, EmbeddingModelV4, ImageModelV4, TranscriptionModelV4CallOptions, TranscriptionModelV4, Experimental_TranscriptionModelV4StreamOptions, SpeechModelV4, JSONValue } from '@ai-sdk/provider'; | ||
| import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils'; | ||
| import { InferSchema, WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE, FetchFunction } from '@ai-sdk/provider-utils'; | ||
| import { InferSchema, WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE, FetchFunction, WebSocketConstructor } from '@ai-sdk/provider-utils'; | ||
@@ -107,2 +107,3 @@ type OpenAIChatModelId = 'o1' | 'o1-2024-12-17' | 'o3-mini' | 'o3-mini-2025-01-31' | 'o3' | 'o3-2025-04-16' | 'o4-mini' | 'o4-mini-2025-04-16' | 'gpt-4.1' | 'gpt-4.1-2025-04-14' | 'gpt-4.1-mini' | 'gpt-4.1-mini-2025-04-14' | 'gpt-4.1-nano' | 'gpt-4.1-nano-2025-04-14' | 'gpt-4o' | 'gpt-4o-2024-05-13' | 'gpt-4o-2024-08-06' | 'gpt-4o-2024-11-20' | 'gpt-4o-audio-preview' | 'gpt-4o-audio-preview-2024-12-17' | 'gpt-4o-audio-preview-2025-06-03' | 'gpt-4o-mini' | 'gpt-4o-mini-2024-07-18' | 'gpt-4o-mini-audio-preview' | 'gpt-4o-mini-audio-preview-2024-12-17' | 'gpt-4o-search-preview' | 'gpt-4o-search-preview-2025-03-11' | 'gpt-4o-mini-search-preview' | 'gpt-4o-mini-search-preview-2025-03-11' | 'gpt-3.5-turbo-0125' | 'gpt-3.5-turbo' | 'gpt-3.5-turbo-1106' | 'gpt-3.5-turbo-16k' | 'gpt-5' | 'gpt-5-2025-08-07' | 'gpt-5-mini' | 'gpt-5-mini-2025-08-07' | 'gpt-5-nano' | 'gpt-5-nano-2025-08-07' | 'gpt-5-chat-latest' | 'gpt-5.1' | 'gpt-5.1-2025-11-13' | 'gpt-5.1-chat-latest' | 'gpt-5.2' | 'gpt-5.2-2025-12-11' | 'gpt-5.2-chat-latest' | 'gpt-5.2-pro' | 'gpt-5.2-pro-2025-12-11' | 'gpt-5.3-chat-latest' | 'gpt-5.4' | 'gpt-5.4-2026-03-05' | 'gpt-5.4-mini' | 'gpt-5.4-mini-2026-03-17' | 'gpt-5.4-nano' | 'gpt-5.4-nano-2026-03-17' | 'gpt-5.4-pro' | 'gpt-5.4-pro-2026-03-05' | 'gpt-5.5' | 'gpt-5.5-2026-04-23' | (string & {}); | ||
| fetch?: FetchFunction; | ||
| webSocket?: WebSocketConstructor; | ||
| generateId?: () => string; | ||
@@ -200,3 +201,3 @@ /** | ||
| type OpenAITranscriptionModelId = 'whisper-1' | 'gpt-4o-mini-transcribe' | 'gpt-4o-mini-transcribe-2025-03-20' | 'gpt-4o-mini-transcribe-2025-12-15' | 'gpt-4o-transcribe' | 'gpt-4o-transcribe-diarize' | (string & {}); | ||
| type OpenAITranscriptionModelId = 'whisper-1' | 'gpt-4o-mini-transcribe' | 'gpt-4o-mini-transcribe-2025-03-20' | 'gpt-4o-mini-transcribe-2025-12-15' | 'gpt-4o-transcribe' | 'gpt-4o-transcribe-diarize' | 'gpt-realtime-whisper' | (string & {}); | ||
| declare const openAITranscriptionModelOptions: _ai_sdk_provider_utils.LazySchema<{ | ||
@@ -208,2 +209,6 @@ include?: string[] | undefined; | ||
| timestampGranularities?: ("word" | "segment")[] | undefined; | ||
| streaming?: { | ||
| delay?: "minimal" | "low" | "medium" | "high" | "xhigh" | undefined; | ||
| include?: string[] | undefined; | ||
| } | undefined; | ||
| }>; | ||
@@ -217,2 +222,7 @@ type OpenAITranscriptionModelOptions = InferSchema<typeof openAITranscriptionModelOptions>; | ||
| }; | ||
| type OpenAITranscriptionStreamOptions = Omit<Experimental_TranscriptionModelV4StreamOptions, 'providerOptions'> & { | ||
| providerOptions?: { | ||
| openai?: OpenAITranscriptionModelOptions; | ||
| }; | ||
| }; | ||
| interface OpenAITranscriptionModelConfig extends OpenAIConfig { | ||
@@ -239,2 +249,3 @@ _internal?: { | ||
| doGenerate(options: OpenAITranscriptionCallOptions): Promise<Awaited<ReturnType<TranscriptionModelV4['doGenerate']>>>; | ||
| doStream(options: OpenAITranscriptionStreamOptions): Promise<Awaited<ReturnType<NonNullable<TranscriptionModelV4['doStream']>>>>; | ||
| } | ||
@@ -1502,2 +1513,2 @@ | ||
| export { type ApplyPatchOperation, OpenAIChatLanguageModel, type OpenAIChatModelId, OpenAICompletionLanguageModel, type OpenAICompletionModelId, OpenAIEmbeddingModel, type OpenAIEmbeddingModelId, type OpenAIEmbeddingModelOptions, OpenAIImageModel, type OpenAIImageModelEditOptions, type OpenAIImageModelGenerationOptions, type OpenAIImageModelId, type OpenAIImageModelOptions, type OpenAILanguageModelChatOptions, type OpenAILanguageModelCompletionOptions, OpenAIResponsesLanguageModel, OpenAISpeechModel, type OpenAISpeechModelId, type OpenAISpeechModelOptions, type OpenAITranscriptionCallOptions, OpenAITranscriptionModel, type OpenAITranscriptionModelId, type OpenAITranscriptionModelOptions, type OpenaiResponsesCompactionProviderMetadata, type OpenaiResponsesProviderMetadata, type OpenaiResponsesReasoningProviderMetadata, type OpenaiResponsesSourceDocumentProviderMetadata, type OpenaiResponsesTextProviderMetadata, type ResponsesCompactionProviderMetadata, type ResponsesProviderMetadata, type ResponsesReasoningProviderMetadata, type ResponsesSourceDocumentProviderMetadata, type ResponsesTextProviderMetadata, applyPatch, applyPatchArgsSchema, applyPatchInputSchema, applyPatchOutputSchema, applyPatchToolFactory, codeInterpreter, codeInterpreterArgsSchema, codeInterpreterInputSchema, codeInterpreterOutputSchema, codeInterpreterToolFactory, fileSearch, fileSearchArgsSchema, fileSearchOutputSchema, hasDefaultResponseFormat, imageGeneration, imageGenerationArgsSchema, imageGenerationOutputSchema, modelMaxImagesPerCall, openAITranscriptionModelOptions, openaiEmbeddingModelOptions, openaiImageModelEditOptions, openaiImageModelGenerationOptions, openaiImageModelOptions, openaiLanguageModelChatOptions, openaiLanguageModelCompletionOptions, openaiSpeechModelOptionsSchema, webSearch, webSearchArgsSchema, webSearchOutputSchema, webSearchPreview, webSearchPreviewArgsSchema, webSearchPreviewInputSchema, webSearchToolFactory }; | ||
| export { type ApplyPatchOperation, OpenAIChatLanguageModel, type OpenAIChatModelId, OpenAICompletionLanguageModel, type OpenAICompletionModelId, OpenAIEmbeddingModel, type OpenAIEmbeddingModelId, type OpenAIEmbeddingModelOptions, OpenAIImageModel, type OpenAIImageModelEditOptions, type OpenAIImageModelGenerationOptions, type OpenAIImageModelId, type OpenAIImageModelOptions, type OpenAILanguageModelChatOptions, type OpenAILanguageModelCompletionOptions, OpenAIResponsesLanguageModel, OpenAISpeechModel, type OpenAISpeechModelId, type OpenAISpeechModelOptions, type OpenAITranscriptionCallOptions, OpenAITranscriptionModel, type OpenAITranscriptionModelId, type OpenAITranscriptionModelOptions, type OpenAITranscriptionStreamOptions, type OpenaiResponsesCompactionProviderMetadata, type OpenaiResponsesProviderMetadata, type OpenaiResponsesReasoningProviderMetadata, type OpenaiResponsesSourceDocumentProviderMetadata, type OpenaiResponsesTextProviderMetadata, type ResponsesCompactionProviderMetadata, type ResponsesProviderMetadata, type ResponsesReasoningProviderMetadata, type ResponsesSourceDocumentProviderMetadata, type ResponsesTextProviderMetadata, applyPatch, applyPatchArgsSchema, applyPatchInputSchema, applyPatchOutputSchema, applyPatchToolFactory, codeInterpreter, codeInterpreterArgsSchema, codeInterpreterInputSchema, codeInterpreterOutputSchema, codeInterpreterToolFactory, fileSearch, fileSearchArgsSchema, fileSearchOutputSchema, hasDefaultResponseFormat, imageGeneration, imageGenerationArgsSchema, imageGenerationOutputSchema, modelMaxImagesPerCall, openAITranscriptionModelOptions, openaiEmbeddingModelOptions, openaiImageModelEditOptions, openaiImageModelGenerationOptions, openaiImageModelOptions, openaiLanguageModelChatOptions, openaiLanguageModelCompletionOptions, openaiSpeechModelOptionsSchema, webSearch, webSearchArgsSchema, webSearchOutputSchema, webSearchPreview, webSearchPreviewArgsSchema, webSearchPreviewInputSchema, webSearchToolFactory }; |
+3
-3
| { | ||
| "name": "@ai-sdk/openai", | ||
| "version": "4.0.6", | ||
| "version": "4.0.7", | ||
| "type": "module", | ||
@@ -38,4 +38,4 @@ "license": "Apache-2.0", | ||
| "dependencies": { | ||
| "@ai-sdk/provider-utils": "5.0.4", | ||
| "@ai-sdk/provider": "4.0.1" | ||
| "@ai-sdk/provider": "4.0.2", | ||
| "@ai-sdk/provider-utils": "5.0.5" | ||
| }, | ||
@@ -42,0 +42,0 @@ "devDependencies": { |
@@ -1,2 +0,5 @@ | ||
| import type { FetchFunction } from '@ai-sdk/provider-utils'; | ||
| import type { | ||
| FetchFunction, | ||
| WebSocketConstructor, | ||
| } from '@ai-sdk/provider-utils'; | ||
@@ -8,2 +11,3 @@ export type OpenAIConfig = { | ||
| fetch?: FetchFunction; | ||
| webSocket?: WebSocketConstructor; | ||
| generateId?: () => string; | ||
@@ -10,0 +14,0 @@ /** |
@@ -19,2 +19,3 @@ import type { | ||
| type FetchFunction, | ||
| type WebSocketConstructor, | ||
| } from '@ai-sdk/provider-utils'; | ||
@@ -162,2 +163,8 @@ import { OpenAIChatLanguageModel } from './chat/openai-chat-language-model'; | ||
| fetch?: FetchFunction; | ||
| /** | ||
| * Custom WebSocket implementation. This is useful for testing or for | ||
| * runtimes that need a WebSocket constructor with header support. | ||
| */ | ||
| webSocket?: WebSocketConstructor; | ||
| } | ||
@@ -234,2 +241,3 @@ | ||
| fetch: options.fetch, | ||
| webSocket: options.webSocket, | ||
| }); | ||
@@ -236,0 +244,0 @@ |
@@ -15,2 +15,3 @@ import { | ||
| | 'gpt-4o-transcribe-diarize' | ||
| | 'gpt-realtime-whisper' | ||
| | (string & {}); | ||
@@ -52,2 +53,21 @@ | ||
| .optional(), | ||
| /** | ||
| * Options for streaming transcription models such as `gpt-realtime-whisper`. | ||
| */ | ||
| streaming: z | ||
| .object({ | ||
| /** | ||
| * Latency/accuracy tradeoff for realtime transcription. | ||
| */ | ||
| delay: z | ||
| .enum(['minimal', 'low', 'medium', 'high', 'xhigh']) | ||
| .optional(), | ||
| /** | ||
| * Additional fields to include in realtime transcription events. | ||
| */ | ||
| include: z.array(z.string()).optional(), | ||
| }) | ||
| .optional(), | ||
| }), | ||
@@ -54,0 +74,0 @@ ), |
@@ -1,5 +0,7 @@ | ||
| import type { | ||
| TranscriptionModelV4, | ||
| TranscriptionModelV4CallOptions, | ||
| SharedV4Warning, | ||
| import { | ||
| UnsupportedFunctionalityError, | ||
| type Experimental_TranscriptionModelV4StreamOptions as TranscriptionModelV4StreamOptions, | ||
| type SharedV4Warning, | ||
| type TranscriptionModelV4, | ||
| type TranscriptionModelV4CallOptions, | ||
| } from '@ai-sdk/provider'; | ||
@@ -9,7 +11,12 @@ import { | ||
| convertBase64ToUint8Array, | ||
| convertToBase64, | ||
| createJsonResponseHandler, | ||
| getWebSocketConstructor, | ||
| mediaTypeToExtension, | ||
| parseProviderOptions, | ||
| postFormDataToApi, | ||
| readWebSocketMessageText, | ||
| safeParseJSON, | ||
| serializeModelOptions, | ||
| toWebSocketUrl, | ||
| WORKFLOW_DESERIALIZE, | ||
@@ -35,2 +42,31 @@ WORKFLOW_SERIALIZE, | ||
| export type OpenAITranscriptionStreamOptions = Omit< | ||
| TranscriptionModelV4StreamOptions, | ||
| 'providerOptions' | ||
| > & { | ||
| providerOptions?: { | ||
| openai?: OpenAITranscriptionModelOptions; | ||
| }; | ||
| }; | ||
| type OpenAIRealtimeTranscriptionEvent = { | ||
| type?: string; | ||
| item_id?: string; | ||
| delta?: string; | ||
| transcript?: string; | ||
| error?: { message?: string }; | ||
| }; | ||
| /** | ||
| * Realtime transcription model IDs stream over the realtime WebSocket | ||
| * and do not support the REST transcription endpoint. Prefix matching | ||
| * keeps dated snapshots (e.g. `gpt-realtime-whisper-2026-01-01`) working. | ||
| */ | ||
| function isRealtimeTranscriptionModelId(modelId: string): boolean { | ||
| return ( | ||
| modelId === 'gpt-realtime-whisper' || | ||
| modelId.startsWith('gpt-realtime-whisper-') | ||
| ); | ||
| } | ||
| interface OpenAITranscriptionModelConfig extends OpenAIConfig { | ||
@@ -204,2 +240,8 @@ _internal?: { | ||
| ): Promise<Awaited<ReturnType<TranscriptionModelV4['doGenerate']>>> { | ||
| if (isRealtimeTranscriptionModelId(this.modelId)) { | ||
| throw new UnsupportedFunctionalityError({ | ||
| functionality: `non-streaming transcription with ${this.modelId}`, | ||
| }); | ||
| } | ||
| const currentDate = this.config._internal?.currentDate?.() ?? new Date(); | ||
@@ -257,2 +299,284 @@ const { formData, warnings } = await this.getArgs(options); | ||
| } | ||
| async doStream( | ||
| options: OpenAITranscriptionStreamOptions, | ||
| ): Promise< | ||
| Awaited<ReturnType<NonNullable<TranscriptionModelV4['doStream']>>> | ||
| > { | ||
| if (!isRealtimeTranscriptionModelId(this.modelId)) { | ||
| throw new UnsupportedFunctionalityError({ | ||
| functionality: `streaming transcription with ${this.modelId}`, | ||
| }); | ||
| } | ||
| const currentDate = this.config._internal?.currentDate?.() ?? new Date(); | ||
| const openAIOptions = await parseProviderOptions({ | ||
| provider: 'openai', | ||
| providerOptions: options.providerOptions, | ||
| schema: openAITranscriptionModelOptions, | ||
| }); | ||
| const warnings: SharedV4Warning[] = []; | ||
| // options that only apply to the REST transcription endpoint | ||
| // (checked on the raw options because some have schema defaults): | ||
| const rawOpenAIOptions = options.providerOptions?.openai ?? {}; | ||
| for (const option of [ | ||
| 'include', | ||
| 'prompt', | ||
| 'temperature', | ||
| 'timestampGranularities', | ||
| ]) { | ||
| if (rawOpenAIOptions[option as keyof typeof rawOpenAIOptions] != null) { | ||
| warnings.push({ | ||
| type: 'unsupported', | ||
| feature: `providerOptions.openai.${option}`, | ||
| details: `OpenAI streaming transcription does not support ${option}.`, | ||
| }); | ||
| } | ||
| } | ||
| const headers = combineHeaders(this.config.headers?.(), options.headers); | ||
| const sessionUpdate = buildOpenAIRealtimeTranscriptionSession({ | ||
| modelId: this.modelId, | ||
| inputAudioFormat: options.inputAudioFormat, | ||
| providerOptions: openAIOptions, | ||
| }); | ||
| return { | ||
| request: { body: sessionUpdate }, | ||
| response: { | ||
| timestamp: currentDate, | ||
| modelId: this.modelId, | ||
| }, | ||
| stream: createOpenAIRealtimeTranscriptionStream({ | ||
| webSocket: this.config.webSocket, | ||
| url: toWebSocketUrl( | ||
| this.config.url({ | ||
| path: '/realtime?intent=transcription', | ||
| modelId: this.modelId, | ||
| }), | ||
| ), | ||
| headers, | ||
| sessionUpdate, | ||
| language: openAIOptions?.language, | ||
| warnings, | ||
| audio: options.audio, | ||
| abortSignal: options.abortSignal, | ||
| includeRawChunks: options.includeRawChunks, | ||
| }), | ||
| }; | ||
| } | ||
| } | ||
| function createOpenAIRealtimeTranscriptionStream({ | ||
| webSocket, | ||
| url, | ||
| headers, | ||
| sessionUpdate, | ||
| language, | ||
| warnings, | ||
| audio, | ||
| abortSignal, | ||
| includeRawChunks, | ||
| }: { | ||
| webSocket: OpenAIConfig['webSocket']; | ||
| url: URL; | ||
| headers: Record<string, string | undefined>; | ||
| sessionUpdate: unknown; | ||
| language: string | undefined; | ||
| warnings: SharedV4Warning[]; | ||
| audio: ReadableStream<Uint8Array | string>; | ||
| abortSignal: AbortSignal | undefined; | ||
| includeRawChunks: boolean | undefined; | ||
| }) { | ||
| let finished = false; | ||
| let cleanup: (closeCode?: number) => void = () => {}; | ||
| return new ReadableStream({ | ||
| start: controller => { | ||
| const WebSocketConstructor = getWebSocketConstructor(webSocket); | ||
| const ws = new WebSocketConstructor( | ||
| url, | ||
| getOpenAIRealtimeProtocols(headers), | ||
| { headers }, | ||
| ); | ||
| let audioReader: | ||
| | ReadableStreamDefaultReader<Uint8Array | string> | ||
| | undefined; | ||
| cleanup = (closeCode?: number) => { | ||
| abortSignal?.removeEventListener('abort', abort); | ||
| void audioReader?.cancel().catch(() => {}); | ||
| try { | ||
| ws.close(closeCode); | ||
| } catch {} | ||
| }; | ||
| const finishWithError = (error: unknown) => { | ||
| if (finished) return; | ||
| finished = true; | ||
| cleanup(); | ||
| controller.error(error); | ||
| }; | ||
| const finish = (text: string, id?: string) => { | ||
| if (finished) return; | ||
| finished = true; | ||
| if (id != null) { | ||
| controller.enqueue({ type: 'transcript-final', id, text }); | ||
| } | ||
| controller.enqueue({ | ||
| type: 'finish', | ||
| text, | ||
| segments: [], | ||
| language, | ||
| }); | ||
| controller.close(); | ||
| cleanup(1000); | ||
| }; | ||
| const abort = () => { | ||
| finishWithError(abortSignal?.reason ?? new Error('Aborted')); | ||
| }; | ||
| if (abortSignal?.aborted) { | ||
| abort(); | ||
| return; | ||
| } | ||
| abortSignal?.addEventListener('abort', abort, { once: true }); | ||
| const sendAudio = async () => { | ||
| audioReader = audio.getReader(); | ||
| try { | ||
| while (true) { | ||
| const { done, value } = await audioReader.read(); | ||
| if (done || finished) break; | ||
| ws.send( | ||
| JSON.stringify({ | ||
| type: 'input_audio_buffer.append', | ||
| audio: convertToBase64(value), | ||
| }), | ||
| ); | ||
| } | ||
| } finally { | ||
| audioReader.releaseLock(); | ||
| } | ||
| if (!finished) { | ||
| ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' })); | ||
| } | ||
| }; | ||
| ws.onopen = () => { | ||
| controller.enqueue({ type: 'stream-start', warnings }); | ||
| ws.send(JSON.stringify(sessionUpdate)); | ||
| void sendAudio().catch(finishWithError); | ||
| }; | ||
| ws.onmessage = event => { | ||
| void readWebSocketMessageText(event.data) | ||
| .then(async text => { | ||
| const parsed = await safeParseJSON({ text }); | ||
| if (!parsed.success) return; | ||
| const raw = parsed.value as OpenAIRealtimeTranscriptionEvent; | ||
| if (includeRawChunks) { | ||
| controller.enqueue({ type: 'raw', rawValue: raw }); | ||
| } | ||
| switch (raw.type) { | ||
| case 'conversation.item.input_audio_transcription.delta': { | ||
| controller.enqueue({ | ||
| type: 'transcript-delta', | ||
| id: raw.item_id, | ||
| delta: raw.delta ?? '', | ||
| }); | ||
| break; | ||
| } | ||
| case 'conversation.item.input_audio_transcription.completed': { | ||
| finish(raw.transcript ?? '', raw.item_id); | ||
| break; | ||
| } | ||
| case 'error': { | ||
| finishWithError( | ||
| new Error(raw.error?.message ?? 'OpenAI realtime error'), | ||
| ); | ||
| break; | ||
| } | ||
| } | ||
| }) | ||
| .catch(finishWithError); | ||
| }; | ||
| ws.onerror = () => { | ||
| finishWithError(new Error('OpenAI realtime transcription error')); | ||
| }; | ||
| ws.onclose = () => { | ||
| if (finished) return; | ||
| finished = true; | ||
| cleanup(); | ||
| controller.close(); | ||
| }; | ||
| }, | ||
| cancel: () => { | ||
| if (finished) return; | ||
| finished = true; | ||
| cleanup(); | ||
| }, | ||
| }); | ||
| } | ||
| function buildOpenAIRealtimeTranscriptionSession({ | ||
| modelId, | ||
| inputAudioFormat, | ||
| providerOptions, | ||
| }: { | ||
| modelId: string; | ||
| inputAudioFormat: TranscriptionModelV4StreamOptions['inputAudioFormat']; | ||
| providerOptions: OpenAITranscriptionModelOptions | undefined; | ||
| }) { | ||
| return { | ||
| type: 'session.update', | ||
| session: { | ||
| type: 'transcription', | ||
| audio: { | ||
| input: { | ||
| format: { | ||
| type: inputAudioFormat.type, | ||
| ...(inputAudioFormat.rate != null | ||
| ? { rate: inputAudioFormat.rate } | ||
| : {}), | ||
| }, | ||
| transcription: { | ||
| model: modelId, | ||
| ...(providerOptions?.language != null | ||
| ? { language: providerOptions.language } | ||
| : {}), | ||
| ...(providerOptions?.streaming?.delay != null | ||
| ? { delay: providerOptions.streaming.delay } | ||
| : {}), | ||
| }, | ||
| turn_detection: null, | ||
| }, | ||
| }, | ||
| ...(providerOptions?.streaming?.include != null | ||
| ? { include: providerOptions.streaming.include } | ||
| : {}), | ||
| }, | ||
| }; | ||
| } | ||
| function getOpenAIRealtimeProtocols( | ||
| headers: Record<string, string | undefined>, | ||
| ): string[] { | ||
| const authorization = headers.Authorization ?? headers.authorization; | ||
| const token = authorization?.startsWith('Bearer ') | ||
| ? authorization.slice('Bearer '.length) | ||
| : undefined; | ||
| return token == null | ||
| ? ['realtime'] | ||
| : ['realtime', `openai-insecure-api-key.${token}`]; | ||
| } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
2402979
2.56%30348
2.92%3
50%+ Added
+ Added
- Removed
- Removed
Updated
Updated