uneeq-js 3.13.0 → 3.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/3.index.js +1 -1
- package/dist/3.index.js.map +1 -1
- package/dist/363.index.js +1 -1
- package/dist/363.index.js.map +1 -1
- package/dist/deepgram-flux-stt.d.ts +10 -1
- package/dist/deepgram-stt.d.ts +9 -1
- package/dist/esm/chunks/chunk-557JQDB4.js +1 -0
- package/dist/esm/chunks/chunk-V5GQSIWD.js +2 -0
- package/dist/esm/chunks/deepgram-flux-stt-MHRGSAVD.js +27 -0
- package/dist/esm/chunks/deepgram-stt-WX4KHFSO.js +1 -0
- package/dist/esm/chunks/google-stt-P7QLHE5H.js +2486 -0
- package/dist/esm/index.js +10 -10
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/UneeqMessages.d.ts +15 -0
- package/package.json +1 -1
package/dist/363.index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"363.index.js","mappings":"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","sources":["webpack://Uneeq/./src/deepgram-flux-stt.ts"],"sourcesContent":["import { type Subject } from 'rxjs'\nimport Logger from './lib/logger'\nimport {\n UserStartedSpeakingMessage,\n UserStoppedSpeakingMessage,\n SpeechTranscriptionMessage,\n EnableMicrophoneUpdatedMessage,\n SessionErrorMessage,\n DeviceErrorMessage,\n AvatarInterruptedMessage,\n type UneeqMessage,\n UneeqMessageType,\n type PromptResultMessage,\n type AvatarAnswerMessage,\n type CustomMetadataUpdated,\n} from './types/UneeqMessages'\nimport { type SpeechTranscriptionResult } from './types/SpeechTranscriptionResult'\nimport { type DataChannelMessage } from './webrtc-data-channel/DataChannelMessage'\nimport { UserSpeaking, UserSpeakingState } from './webrtc-data-channel/messages/UserSpeaking'\nimport { ChatPrompt } from './webrtc-data-channel/messages/ChatPrompt'\nimport { StopSpeaking } from './webrtc-data-channel/messages/StopSpeaking'\nimport { type PromptMetadata } from './types/PromptMetadata'\nimport { DeepgramClient } from '@deepgram/sdk'\nimport { type SpeechRecognitionInterface } from './types/SpeechRecognitionInterface'\n\n// Local interface for the Deepgram v2 connection — duck-typed to avoid coupling to SDK type names\ninterface DeepgramV2Connection {\n on(event: string, handler: (...args: unknown[]) => void): void\n sendMedia(data: ArrayBuffer): void\n sendListenV2Configure(config: Record<string, unknown>): void\n sendCloseStream(message: { type: string }): void\n connect(): void\n waitForOpen(): Promise<unknown>\n close(): void\n}\n\n// Constants\nconst LOG_PREFIX = '[Deepgram Flux STT]'\nconst CONNECTION_TIMEOUT_MS = 10000\n// PCM audio configuration — v2 API requires explicit encoding (no container auto-detection)\nconst PCM_SAMPLE_RATE = 16000\n// Deepgram recommends 80ms audio chunks for optimal Flux latency.\n// At 16kHz mono, 80ms = 1280 samples = 2560 bytes of int16.\n// AudioWorklet processes 128 samples per render quantum, so we accumulate 10 quanta.\nconst PCM_CHUNK_SAMPLES = 1280\n\n// AudioWorklet processor source — runs off the main thread.\n// Inlined as a Blob URL to avoid needing a separate bundled file.\nconst WORKLET_PROCESSOR_SOURCE = `\nclass PcmCaptureProcessor extends AudioWorkletProcessor {\n constructor() {\n super()\n this._buffer = new Float32Array(${PCM_CHUNK_SAMPLES})\n this._offset = 0\n }\n process(inputs, outputs, parameters) {\n const input = inputs[0]?.[0]\n if (!input) return true\n for (let i = 0; i < input.length; i++) {\n this._buffer[this._offset++] = input[i]\n if (this._offset >= this._buffer.length) {\n const int16 = new Int16Array(this._buffer.length)\n for (let j = 0; j < this._buffer.length; j++) {\n const s = Math.max(-1, Math.min(1, this._buffer[j]))\n int16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF\n }\n this.port.postMessage(int16.buffer, [int16.buffer])\n this._offset = 0\n }\n }\n return true\n }\n}\nregisterProcessor('pcm-capture-processor', PcmCaptureProcessor)\n`\n\n// Safety net: if no TurnInfo events arrive while the user is in a speaking state,\n// reset speaking indicators to prevent the UI getting stuck.\nconst SAFETY_NET_TIMEOUT_MS = 2000\n\n// Reconnection constants\nconst INITIAL_RECONNECT_DELAY_MS = 1000\nconst MAX_RECONNECT_DELAY_MS = 30000\nconst RECONNECT_BACKOFF_MULTIPLIER = 2\nconst MAX_RECONNECT_ATTEMPTS = 5\n\n// STT Engine States\nenum STTState {\n Idle = 'Idle',\n Connecting = 'Connecting',\n Connected = 'Connected',\n Paused = 'Paused',\n Disconnected = 'Disconnected'\n}\n\n/**\n * Flux v2 TurnInfo message from unified 'message' event.\n * The v2 API delivers turn lifecycle events via data.type === 'TurnInfo'.\n * Note: all fields are at the top level — there is no nested turn_info property.\n */\ninterface TurnInfoMessage {\n type: 'TurnInfo'\n event: 'StartOfTurn' | 'Update' | 'EagerEndOfTurn' | 'TurnResumed' | 'EndOfTurn'\n transcript: string\n turn_index: number\n end_of_turn_confidence?: number\n words?: Array<{\n word: string\n confidence: number\n }>\n}\n\n/**\n * Flux v2 Error message indicating an unrecoverable error.\n * Note: SDK type is \"Error\" (not \"FatalError\") per ListenV2FatalError.\n */\ninterface FatalErrorMessage {\n type: 'Error'\n code: string\n description: string\n}\n\ninterface DeepgramTokenResponse {\n token: string\n api_url: string\n sdk_version: string\n expires_at: string\n}\n\nexport interface DeepgramFluxSTTOptions {\n // Backend configuration\n connectionUrl: string\n jwtToken: string\n\n // Session information\n sessionId: string\n\n // Deepgram Flux configuration\n model?: string\n language?: string\n\n /** End-of-turn confidence threshold (0.5-0.9). @default 0.7 */\n eotThreshold?: number\n /** Eager end-of-turn threshold (0.3-0.9). */\n eagerEotThreshold?: number\n /** End-of-turn timeout in ms. */\n eotTimeoutMs?: number\n /** Send ChatPrompt on EagerEndOfTurn (lower latency, risk of incomplete). @default true */\n useEagerEndOfTurn?: boolean\n\n /**\n * Safety net timeout in milliseconds. Resets speaking indicators if no TurnInfo\n * events arrive for this duration while in a speaking state. @default 2000\n */\n safetyNetTimeoutMs?: number\n\n /**\n * Keyterms to boost in transcription results.\n */\n keyterms?: string[]\n\n // Microphone configuration\n echoCancellation?: boolean\n noiseSuppression?: boolean\n autoGainControl?: boolean\n microphoneDeviceId?: string\n\n // Metadata and callbacks\n promptMetadata: PromptMetadata\n messages: Subject<UneeqMessage>\n sendMessage: (msg: DataChannelMessage) => void\n}\n\nexport class DeepgramFluxSTT implements SpeechRecognitionInterface {\n private connection: DeepgramV2Connection | null = null\n private state: STTState = STTState.Idle\n private shouldReconnect: boolean = true\n private stream: MediaStream | null = null\n private audioContext: AudioContext | null = null\n private workletNode: AudioWorkletNode | null = null\n\n // Reconnection state\n private reconnectAttempts: number = 0\n private reconnectDelay: number = INITIAL_RECONNECT_DELAY_MS\n private reconnectTimeoutId: NodeJS.Timeout | null = null\n\n // Digital human speaking state\n private digitalHumanSpeaking: boolean = false\n\n // User speaking state (for data channel messages to Renny)\n private isUserCurrentlySpeaking: boolean = false\n\n // UI speaking state (for UI indicator)\n private isUiShowingSpeaking: boolean = false\n\n // Track whether an eager prompt was already sent for the current turn\n private eagerPromptSentForTurn: boolean = false\n\n // Safety net: reset speaking state if Deepgram stalls mid-turn\n private safetyNetTimeoutId: NodeJS.Timeout | null = null\n\n // Debug: track audio chunks sent\n private audioChunksSent: number = 0\n\n constructor(private readonly options: DeepgramFluxSTTOptions) {\n // Apply defaults\n this.options.model = this.options.model || 'flux-general-en'\n this.options.language = this.options.language || 'en'\n this.options.eotThreshold = this.options.eotThreshold ?? 0.7\n this.options.useEagerEndOfTurn = this.options.useEagerEndOfTurn ?? true\n this.options.safetyNetTimeoutMs = this.options.safetyNetTimeoutMs ?? SAFETY_NET_TIMEOUT_MS\n\n this.options.echoCancellation = this.options.echoCancellation ?? true\n this.options.noiseSuppression = this.options.noiseSuppression ?? true\n this.options.autoGainControl = this.options.autoGainControl ?? true\n\n this.handleAppMessages()\n }\n\n // Main lifecycle methods\n public async startRecognition(): Promise<void> {\n Logger.info(`${LOG_PREFIX} Starting speech recognition`)\n this.shouldReconnect = true\n this.resetReconnectionState()\n await this.connect()\n }\n\n public async stopRecognition(): Promise<void> {\n Logger.info(`${LOG_PREFIX} Stopping speech recognition`)\n this.shouldReconnect = false\n this.clearReconnectTimeout()\n await this.disconnect()\n }\n\n public async pause(): Promise<boolean> {\n Logger.info(`${LOG_PREFIX} Pausing speech recognition`)\n this.state = STTState.Paused\n\n // Reset speaking states\n this.clearSafetyNet()\n this.resetSpeakingStates()\n this.eagerPromptSentForTurn = false\n\n // Disable audio tracks to stop sending audio, but keep microphone and connection alive\n if (this.stream) {\n this.stream.getTracks().forEach((track) => { track.enabled = false })\n Logger.debug(`${LOG_PREFIX} Audio tracks disabled`)\n }\n\n return true\n }\n\n public async resume(): Promise<boolean> {\n Logger.info(`${LOG_PREFIX} Resuming speech recognition`)\n\n if (this.state === STTState.Paused) {\n if (this.stream) {\n // Re-enable existing audio tracks (resume from normal pause)\n this.state = STTState.Connected\n this.stream.getTracks().forEach((track) => { track.enabled = true })\n Logger.debug(`${LOG_PREFIX} Audio tracks re-enabled`)\n return true\n }\n // Connection exists but no stream (paused during connect) — start microphone\n if (this.connection) {\n this.state = STTState.Connected\n await this.startMicrophone()\n return true\n }\n // No connection and no stream — reset state so connect() doesn't bail out\n this.state = STTState.Disconnected\n }\n\n // No connection — need full connect\n Logger.debug(`${LOG_PREFIX} Initiating connection`)\n await this.connect()\n return true\n }\n\n // Metadata management\n public setChatMetadata(chatMetadata: PromptMetadata): void {\n this.options.promptMetadata = chatMetadata\n }\n\n // Private methods\n private async connect(): Promise<void> {\n if (this.state === STTState.Connected) {\n Logger.warn(`${LOG_PREFIX} Already connected`)\n return\n }\n\n if (this.state === STTState.Connecting) {\n Logger.warn(`${LOG_PREFIX} Connection already in progress`)\n return\n }\n\n this.state = STTState.Connecting\n\n try {\n const tokenData = await this.getToken()\n Logger.info(`${LOG_PREFIX} Connecting to Deepgram Flux v2 — api_url=\"${tokenData.api_url}\", sdk_version=\"${tokenData.sdk_version}\", token_length=${tokenData.token?.length ?? 0}`)\n\n // CRITICAL: Must use { accessToken: token } format for temporary tokens\n const deepgram = new DeepgramClient({\n accessToken: tokenData.token,\n baseUrl: tokenData.api_url\n })\n\n // Build v2 connection options\n // Note: v2 API does NOT accept 'language' — for Flux, language is embedded in model name (e.g. flux-general-en)\n // Audio format: raw linear16 PCM with explicit encoding+sample_rate (per Flux quickstart docs)\n // Container formats (WebM/Opus) should auto-detect but don't produce TurnInfo events in practice\n const connectionOptions: Record<string, unknown> = {\n model: this.options.model,\n encoding: 'linear16',\n sample_rate: String(PCM_SAMPLE_RATE),\n // Always opt out of Deepgram's Model Improvement Program\n mip_opt_out: 'true',\n // Flux-specific v2 options\n ...(this.options.eotThreshold !== undefined && { eot_threshold: this.options.eotThreshold }),\n ...(this.options.eagerEotThreshold !== undefined && { eager_eot_threshold: this.options.eagerEotThreshold }),\n ...(this.options.eotTimeoutMs !== undefined && { eot_timeout_ms: this.options.eotTimeoutMs }),\n ...(this.options.keyterms && this.options.keyterms.length > 0 && { keyterm: this.options.keyterms }),\n }\n\n // v5 SDK: listen.v2.connect() returns a V2Socket wrapping a WebSocket.\n // Cast because the v5 SDK's TypeScript types don't expose .v2 directly.\n interface DeepgramV2API { connect(options: Record<string, unknown>): Promise<DeepgramV2Connection> }\n this.connection = await (deepgram.listen as unknown as { v2: DeepgramV2API }).v2.connect(connectionOptions)\n\n // Initiate the WebSocket and wait for it to open (with timeout).\n this.connection.connect()\n await Promise.race([\n this.connection.waitForOpen(),\n new Promise<void>((_, reject) =>\n setTimeout(() => reject(new Error('Connection timeout')), CONNECTION_TIMEOUT_MS)\n )\n ])\n\n // Don't overwrite Paused state (user may have paused during async connection)\n if ((this.state as STTState) !== STTState.Paused) {\n this.state = STTState.Connected\n }\n Logger.info(`${LOG_PREFIX} Connection opened`)\n\n // Now set up the persistent event handlers\n this.setupEventHandlers()\n\n // If user paused during async connection, stay paused — don't start microphone\n if ((this.state as STTState) === STTState.Paused) {\n Logger.info(`${LOG_PREFIX} Pause requested during connection — staying paused`)\n this.resetReconnectionState()\n return\n }\n\n // Start the microphone\n await this.startMicrophone()\n\n Logger.info(`${LOG_PREFIX} Connected successfully`)\n\n // Reset reconnection state on successful connection\n this.resetReconnectionState()\n } catch (error) {\n this.state = STTState.Disconnected\n Logger.error(`${LOG_PREFIX} Connection error`, Logger.serialiseError(error))\n this.handleError(error)\n\n // Attempt reconnection with exponential backoff\n if (this.shouldReconnect) {\n this.scheduleReconnect()\n }\n }\n }\n\n private async disconnect(): Promise<void> {\n if (this.state === STTState.Idle || (this.state === STTState.Disconnected && !this.connection)) {\n return\n }\n\n Logger.info(`${LOG_PREFIX} Disconnecting`)\n\n try {\n this.stopMicrophone()\n\n if (this.connection) {\n // Send CloseStream to let Deepgram flush any in-flight transcription\n try { this.connection.sendCloseStream({ type: 'CloseStream' }) } catch { /* best effort */ }\n this.connection.close()\n this.connection = null\n }\n } catch (error) {\n Logger.error(`${LOG_PREFIX} Disconnect error`, Logger.serialiseError(error))\n }\n\n // Reset speaking states\n this.clearSafetyNet()\n this.resetSpeakingStates()\n this.eagerPromptSentForTurn = false\n\n this.state = STTState.Disconnected\n this.clientMsgSend(new EnableMicrophoneUpdatedMessage(false))\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n Logger.error(`${LOG_PREFIX} Max reconnection attempts (${MAX_RECONNECT_ATTEMPTS}) reached`)\n this.clientMsgSend(new SessionErrorMessage(\n `Unable to connect to speech recognition service after ${MAX_RECONNECT_ATTEMPTS} attempts`\n ))\n return\n }\n\n this.reconnectAttempts++\n Logger.info(\n `${LOG_PREFIX} Scheduling reconnection attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS} ` +\n `in ${this.reconnectDelay}ms`\n )\n\n this.reconnectTimeoutId = setTimeout(() => {\n void this.connect()\n }, this.reconnectDelay)\n\n // Exponential backoff\n this.reconnectDelay = Math.min(\n this.reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER,\n MAX_RECONNECT_DELAY_MS\n )\n }\n\n private resetReconnectionState(): void {\n this.reconnectAttempts = 0\n this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS\n this.clearReconnectTimeout()\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeoutId) {\n clearTimeout(this.reconnectTimeoutId)\n this.reconnectTimeoutId = null\n }\n }\n\n private async getToken(): Promise<DeepgramTokenResponse> {\n const model = this.options.model || 'flux-general-en'\n const tokenEndpoint = `${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(model)}`\n\n const response = await fetch(tokenEndpoint, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${this.options.jwtToken}`,\n 'Content-Type': 'application/json'\n }\n })\n\n if (!response.ok) {\n throw new Error(`Token fetch failed: ${response.status} ${response.statusText}`)\n }\n\n return await response.json()\n }\n\n private async startMicrophone(): Promise<void> {\n try {\n Logger.info(`${LOG_PREFIX} Starting microphone`)\n\n // Stop any existing microphone/stream first to prevent orphaned resources\n this.stopMicrophone()\n\n // Get user media\n this.stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n deviceId: this.options.microphoneDeviceId ? { exact: this.options.microphoneDeviceId } : undefined,\n echoCancellation: this.options.echoCancellation,\n noiseSuppression: this.options.noiseSuppression,\n autoGainControl: this.options.autoGainControl\n }\n })\n\n // Check if user paused during the getUserMedia await\n if ((this.state as STTState) === STTState.Paused) {\n Logger.info(`${LOG_PREFIX} Paused during getUserMedia — keeping stream but disabling tracks`)\n this.stream.getTracks().forEach((track) => { track.enabled = false })\n return\n }\n\n // AudioWorklet captures raw linear16 PCM off the main thread.\n // The processor is inlined as a Blob URL to avoid a separate bundled file.\n this.audioContext = new AudioContext({ sampleRate: PCM_SAMPLE_RATE })\n const source = this.audioContext.createMediaStreamSource(this.stream)\n\n const blob = new Blob([WORKLET_PROCESSOR_SOURCE], { type: 'application/javascript' })\n const processorUrl = URL.createObjectURL(blob)\n await this.audioContext.audioWorklet.addModule(processorUrl)\n URL.revokeObjectURL(processorUrl)\n\n this.workletNode = new AudioWorkletNode(this.audioContext, 'pcm-capture-processor')\n this.audioChunksSent = 0\n\n this.workletNode.port.onmessage = (event: MessageEvent) => {\n if (!this.connection || this.state !== STTState.Connected) {\n return\n }\n this.connection.sendMedia(event.data as ArrayBuffer)\n this.audioChunksSent++\n if (this.audioChunksSent % 50 === 1) {\n Logger.info(`${LOG_PREFIX} Audio chunks sent: ${this.audioChunksSent}, size: ${(event.data as ArrayBuffer).byteLength} bytes`)\n }\n }\n\n source.connect(this.workletNode)\n this.workletNode.connect(this.audioContext.destination)\n\n Logger.info(`${LOG_PREFIX} Microphone started (linear16 PCM @ ${PCM_SAMPLE_RATE}Hz)`)\n\n // Notify that microphone is enabled\n this.clientMsgSend(new EnableMicrophoneUpdatedMessage(true))\n } catch (error) {\n Logger.error(`${LOG_PREFIX} Microphone error`, Logger.serialiseError(error))\n this.clientMsgSend(new DeviceErrorMessage(new Error(JSON.stringify(error))))\n }\n }\n\n private stopMicrophone(): void {\n if (this.workletNode) {\n this.workletNode.port.close()\n this.workletNode.disconnect()\n this.workletNode = null\n }\n\n if (this.audioContext) {\n void this.audioContext.close().catch(() => {})\n this.audioContext = null\n }\n\n if (this.stream) {\n this.stream.getTracks().forEach((track) => {\n track.stop()\n })\n this.stream = null\n }\n\n Logger.info(`${LOG_PREFIX} Microphone stopped`)\n }\n\n private setupEventHandlers(): void {\n if (!this.connection) {\n return\n }\n\n this.connection.on('open', () => {\n this.handleConnectionOpen()\n })\n\n // v2: all messages are unified under a single 'message' event,\n // discriminated by data.type ('TurnInfo', 'Connected', 'FatalError', etc.)\n this.connection.on('message', (data: unknown) => {\n if (data !== null && typeof data === 'object' && 'type' in data) {\n const typed = data as { type: string }\n if (typed.type === 'TurnInfo') {\n this.handleTurnInfo(data as unknown as TurnInfoMessage)\n } else if (typed.type === 'Connected') {\n Logger.info(`${LOG_PREFIX} v2 connection confirmed`)\n } else if (typed.type === 'Error') {\n this.handleFatalError(data as unknown as FatalErrorMessage)\n } else {\n Logger.debug(`${LOG_PREFIX} Unhandled v2 message type: ${typed.type}`)\n }\n }\n })\n\n this.connection.on('close', (event: unknown) => {\n this.handleConnectionClose(event)\n })\n\n this.connection.on('error', (error: unknown) => {\n this.handleError(error)\n })\n }\n\n /**\n * Primary handler for Flux v2 TurnInfo events.\n * Routes to specific handlers based on the turn event type.\n */\n private handleTurnInfo(data: TurnInfoMessage): void {\n try {\n Logger.debug(`${LOG_PREFIX} TurnInfo event: ${data.event}, ` +\n `transcript=\"${(data.transcript || '').substring(0, 50)}${(data.transcript || '').length > 50 ? '...' : ''}\", ` +\n `turn_index=${data.turn_index}, eot_confidence=${data.end_of_turn_confidence ?? 'n/a'}`)\n\n switch (data.event) {\n case 'StartOfTurn':\n this.handleStartOfTurn(data)\n break\n case 'Update':\n this.handleUpdate(data)\n break\n case 'EagerEndOfTurn':\n this.handleEagerEndOfTurn(data)\n break\n case 'TurnResumed':\n this.handleTurnResumed(data)\n break\n case 'EndOfTurn':\n this.handleEndOfTurn(data)\n break\n default:\n Logger.debug(`${LOG_PREFIX} Unknown TurnInfo event: ${(data as { event?: string }).event}`)\n }\n\n } catch (error) {\n Logger.error(`${LOG_PREFIX} Error processing TurnInfo`, Logger.serialiseError(error))\n } finally {\n // Always rearm the safety net — even if a handler threw.\n // Without this, an exception prevents rearming and the mic gets stuck.\n this.resetSafetyNet()\n }\n }\n\n /**\n * StartOfTurn: User has begun speaking.\n * Emit UserStartedSpeaking and send UserSpeaking(Start) to data channel.\n */\n private handleStartOfTurn(turnInfo: TurnInfoMessage): void {\n Logger.debug(`${LOG_PREFIX} StartOfTurn: turn_index=${turnInfo.turn_index}`)\n\n this.eagerPromptSentForTurn = false\n\n // Don't send speaking signals yet — wait for first Update with actual transcript.\n // This prevents background noise from interrupting the digital human.\n }\n\n /**\n * Update: Interim transcript during the current turn.\n *\n * This is also the interruption trigger: the first Update with real transcript\n * while the avatar is speaking sends StopSpeaking immediately. No word thresholds —\n * Flux's own turn detection is the source of truth.\n */\n private handleUpdate(turnInfo: TurnInfoMessage): void {\n const transcript = turnInfo.transcript || ''\n if (transcript === '') {\n return\n }\n\n // First non-empty transcript in this turn — now signal that user is speaking.\n // Deferred from StartOfTurn so background noise doesn't interrupt the digital human.\n if (!this.isUiShowingSpeaking) {\n this.isUiShowingSpeaking = true\n this.clientMsgSend(new UserStartedSpeakingMessage())\n }\n\n if (!this.isUserCurrentlySpeaking) {\n this.isUserCurrentlySpeaking = true\n this.dataChannelMsgSend(new UserSpeaking(UserSpeakingState.Start))\n }\n\n // If the avatar is speaking, interrupt immediately.\n // Flux always allows interruption — it's a conversational model.\n // We only interrupt here — EagerEndOfTurn/EndOfTurn just check the resulting state.\n if (this.digitalHumanSpeaking) {\n Logger.info(`${LOG_PREFIX} User speech detected during avatar speaking — interrupting`)\n this.dataChannelMsgSend(new StopSpeaking())\n this.clientMsgSend(new AvatarInterruptedMessage())\n this.digitalHumanSpeaking = false\n }\n\n // Emit interim transcription for closed captions\n const result: SpeechTranscriptionResult = {\n transcript,\n final: false,\n confidence: this.calculateWordConfidence(turnInfo.words),\n language_code: this.options.language || ''\n }\n this.clientMsgSend(new SpeechTranscriptionMessage(result))\n }\n\n /**\n * EagerEndOfTurn: Model predicts the user might be done speaking.\n * If useEagerEndOfTurn is enabled, send ChatPrompt immediately for lower latency.\n *\n * If the avatar is still speaking (interruption disabled or Update hasn't fired yet),\n * the prompt is discarded — we can't send competing prompts while the avatar talks.\n */\n private handleEagerEndOfTurn(turnInfo: TurnInfoMessage): void {\n const transcript = turnInfo.transcript || ''\n Logger.debug(`${LOG_PREFIX} EagerEndOfTurn: confidence=${turnInfo.end_of_turn_confidence}, transcript=\"${transcript}\"`)\n\n if (!this.options.useEagerEndOfTurn) {\n Logger.debug(`${LOG_PREFIX} EagerEndOfTurn ignored (useEagerEndOfTurn is disabled)`)\n return\n }\n\n if (transcript.trim() === '') {\n return\n }\n\n if (this.digitalHumanSpeaking) {\n Logger.debug(`${LOG_PREFIX} EagerEndOfTurn ignored — avatar is speaking`)\n return\n }\n\n Logger.info(`${LOG_PREFIX} EagerEndOfTurn: sending prompt early: \"${transcript}\"`)\n this.eagerPromptSentForTurn = true\n this.sendChatPrompt(transcript)\n }\n\n /**\n * TurnResumed: Model detects the user continued speaking after an EagerEndOfTurn.\n * If an eager prompt was already sent, log a warning (can't unsend).\n */\n private handleTurnResumed(turnInfo: TurnInfoMessage): void {\n Logger.debug(`${LOG_PREFIX} TurnResumed: turn_index=${turnInfo.turn_index}`)\n\n if (this.eagerPromptSentForTurn) {\n Logger.warn(`${LOG_PREFIX} TurnResumed after eager prompt was already sent — cancelling via StopSpeaking`)\n this.dataChannelMsgSend(new StopSpeaking())\n }\n\n this.eagerPromptSentForTurn = false\n }\n\n /**\n * EndOfTurn: Model has determined the user has finished speaking.\n *\n * If the avatar is still speaking (interruption disabled), the prompt is discarded.\n * Otherwise, cancel any in-flight eager prompt and send the definitive transcript.\n */\n private handleEndOfTurn(turnInfo: TurnInfoMessage): void {\n const transcript = turnInfo.transcript || ''\n Logger.info(`${LOG_PREFIX} EndOfTurn: \"${transcript}\", confidence=${turnInfo.end_of_turn_confidence}`)\n\n if (transcript.trim() !== '') {\n // Emit final transcription for closed captions (always, even if prompt is discarded)\n const result: SpeechTranscriptionResult = {\n transcript,\n final: true,\n confidence: this.calculateWordConfidence(turnInfo.words),\n language_code: this.options.language || ''\n }\n this.clientMsgSend(new SpeechTranscriptionMessage(result))\n\n if (this.digitalHumanSpeaking) {\n Logger.warn(`${LOG_PREFIX} EndOfTurn: discarding prompt — avatar is still speaking (no Update interrupted)`)\n } else {\n // Normal flow: cancel any in-flight eager prompt, send definitive transcript.\n // StopSpeaking is idempotent — safe to send even if nothing is in-flight.\n if (this.eagerPromptSentForTurn) {\n Logger.debug(`${LOG_PREFIX} EndOfTurn: cancelling in-flight eager prompt`)\n }\n this.dataChannelMsgSend(new StopSpeaking())\n this.sendChatPrompt(transcript)\n }\n }\n\n // Reset turn state\n this.eagerPromptSentForTurn = false\n this.resetSpeakingStates()\n }\n\n /**\n * Handle FatalError from v2 API.\n */\n private handleFatalError(data: FatalErrorMessage): void {\n Logger.error(`${LOG_PREFIX} Fatal error from Deepgram: ${data.code} — ${data.description}`)\n this.clientMsgSend(new SessionErrorMessage(`Deepgram error: ${data.code} — ${data.description}`))\n }\n\n /**\n * Calculate average confidence from word-level data, or return a default.\n */\n private calculateWordConfidence(words?: Array<{ confidence: number }>): number {\n if (!words || words.length === 0) {\n return 1.0\n }\n const sum = words.reduce((acc, w) => acc + w.confidence, 0)\n return sum / words.length\n }\n\n private handleAppMessages(): void {\n this.options.messages.subscribe((msg) => {\n switch (msg.uneeqMessageType) {\n case UneeqMessageType.AvatarStartedSpeaking:\n this.digitalHumanSpeaking = true\n break\n\n case UneeqMessageType.PromptResult: {\n const promptResultMessage = msg as PromptResultMessage\n if (!promptResultMessage.promptResult.success) {\n this.handleSpeakingEnd()\n }\n break\n }\n\n case UneeqMessageType.AvatarAnswer: {\n const answer = msg as AvatarAnswerMessage\n if (answer.answerSpeech.replace(/<[^>]*>/g, '') === '') {\n this.handleSpeakingEnd()\n }\n break\n }\n\n case UneeqMessageType.AvatarStoppedSpeaking: {\n this.handleSpeakingEnd()\n break\n }\n\n case UneeqMessageType.SessionEnded: {\n this.shouldReconnect = false\n void this.stopRecognition()\n break\n }\n\n case UneeqMessageType.SessionReconnecting: {\n this.handleSpeakingEnd()\n this.shouldReconnect = false\n void this.stopRecognition()\n break\n }\n\n case UneeqMessageType.CustomMetadataUpdated: {\n this.options.promptMetadata = (msg as CustomMetadataUpdated).chatMetadata\n break\n }\n\n case UneeqMessageType.SessionBackendError: {\n this.handleSpeakingEnd()\n break\n }\n\n default:\n }\n })\n }\n\n private handleConnectionOpen(): void {\n if (this.state !== STTState.Paused) {\n this.state = STTState.Connected\n }\n }\n\n private handleConnectionClose(event?: unknown): void {\n const code = (event as { code?: number })?.code ?? 'unknown'\n const reason = (event as { reason?: string })?.reason ?? ''\n Logger.info(`${LOG_PREFIX} Connection closed — code=${code}, reason=\"${reason}\"`)\n\n if (this.state === STTState.Paused) {\n Logger.info(`${LOG_PREFIX} Connection closed while paused — will reconnect on resume`)\n this.connection = null\n this.stopMicrophone()\n this.clearSafetyNet()\n this.resetSpeakingStates()\n return\n }\n\n this.state = STTState.Disconnected\n this.clearSafetyNet()\n this.resetSpeakingStates()\n this.eagerPromptSentForTurn = false\n this.clientMsgSend(new EnableMicrophoneUpdatedMessage(false))\n\n if (this.shouldReconnect) {\n Logger.info(`${LOG_PREFIX} Unexpected disconnect, attempting reconnection...`)\n this.scheduleReconnect()\n }\n }\n\n private handleError(error: unknown): void {\n // Extract useful info from WebSocket error events (which are opaque by design)\n const detail: Record<string, unknown> = {}\n if (error instanceof Event) {\n detail['type'] = error.type\n detail['target'] = (error.target as { url?: string; readyState?: number } | null)?.url\n ?? (error.target as { url?: string; readyState?: number } | null)?.readyState\n ?? 'unknown'\n }\n Logger.error(`${LOG_PREFIX} Error occurred`, error, detail)\n\n const errorMessage = error instanceof Error\n ? error.message\n : String(error)\n\n if (errorMessage.includes('microphone') || errorMessage.includes('permission') || errorMessage.includes('getUserMedia')) {\n this.clientMsgSend(new DeviceErrorMessage(new Error(errorMessage)))\n } else {\n this.clientMsgSend(new SessionErrorMessage(errorMessage))\n }\n }\n\n private sendChatPrompt(transcript: string): void {\n if (transcript && transcript.trim() !== '') {\n if (this.options.language) {\n this.options.promptMetadata.userSpokenLocale = this.options.language\n }\n\n this.dataChannelMsgSend(new ChatPrompt(transcript, this.options.promptMetadata))\n }\n }\n\n private handleSpeakingEnd(): void {\n this.digitalHumanSpeaking = false\n }\n\n /**\n * Reset the safety net timer. Called on every TurnInfo event.\n * If the user is in a speaking state and no events arrive for SAFETY_NET_TIMEOUT_MS,\n * the speaking indicators are reset to prevent the UI getting stuck.\n */\n private resetSafetyNet(): void {\n this.clearSafetyNet()\n\n if (this.isUiShowingSpeaking || this.isUserCurrentlySpeaking) {\n this.safetyNetTimeoutId = setTimeout(() => {\n Logger.warn(`${LOG_PREFIX} Safety net: no TurnInfo events for ${this.options.safetyNetTimeoutMs}ms while speaking — resetting`)\n this.resetSpeakingStates()\n }, this.options.safetyNetTimeoutMs)\n }\n }\n\n private clearSafetyNet(): void {\n if (this.safetyNetTimeoutId) {\n clearTimeout(this.safetyNetTimeoutId)\n this.safetyNetTimeoutId = null\n }\n }\n\n /**\n * Reset speaking states and send appropriate stop messages.\n */\n private resetSpeakingStates(): void {\n if (this.isUserCurrentlySpeaking) {\n this.isUserCurrentlySpeaking = false\n this.dataChannelMsgSend(new UserSpeaking(UserSpeakingState.Stop))\n }\n\n if (this.isUiShowingSpeaking) {\n this.isUiShowingSpeaking = false\n this.clientMsgSend(new UserStoppedSpeakingMessage())\n }\n }\n\n // Send a message on the data channel to renderer\n private dataChannelMsgSend(msg: DataChannelMessage): void {\n this.options.sendMessage(msg)\n }\n\n // Send a message to the client implementation, i.e. hosted experience\n private clientMsgSend(msg: UneeqMessage): void {\n this.options.messages.next(msg)\n }\n}\n"],"names":["LOG_PREFIX","STTState","DeepgramFluxSTT","options","connection","state","Idle","shouldReconnect","stream","audioContext","workletNode","reconnectAttempts","reconnectDelay","reconnectTimeoutId","digitalHumanSpeaking","isUserCurrentlySpeaking","isUiShowingSpeaking","eagerPromptSentForTurn","safetyNetTimeoutId","audioChunksSent","constructor","this","model","language","eotThreshold","useEagerEndOfTurn","safetyNetTimeoutMs","echoCancellation","noiseSuppression","autoGainControl","handleAppMessages","startRecognition","info","resetReconnectionState","connect","stopRecognition","clearReconnectTimeout","disconnect","pause","Paused","clearSafetyNet","resetSpeakingStates","getTracks","forEach","track","enabled","debug","resume","Connected","startMicrophone","Disconnected","setChatMetadata","chatMetadata","promptMetadata","Connecting","tokenData","getToken","api_url","sdk_version","token","length","deepgram","accessToken","baseUrl","connectionOptions","encoding","sample_rate","String","mip_opt_out","undefined","eot_threshold","eagerEotThreshold","eager_eot_threshold","eotTimeoutMs","eot_timeout_ms","keyterms","keyterm","listen","v2","Promise","race","waitForOpen","_","reject","setTimeout","Error","setupEventHandlers","error","serialiseError","handleError","scheduleReconnect","warn","stopMicrophone","sendCloseStream","type","close","clientMsgSend","Math","min","clearTimeout","tokenEndpoint","connectionUrl","encodeURIComponent","response","fetch","method","headers","Authorization","jwtToken","ok","status","statusText","json","navigator","mediaDevices","getUserMedia","audio","deviceId","microphoneDeviceId","exact","AudioContext","sampleRate","source","createMediaStreamSource","blob","Blob","processorUrl","URL","createObjectURL","audioWorklet","addModule","revokeObjectURL","AudioWorkletNode","port","onmessage","event","sendMedia","data","byteLength","destination","JSON","stringify","catch","stop","on","handleConnectionOpen","typed","handleTurnInfo","handleFatalError","handleConnectionClose","transcript","substring","turn_index","end_of_turn_confidence","handleStartOfTurn","handleUpdate","handleEagerEndOfTurn","handleTurnResumed","handleEndOfTurn","resetSafetyNet","turnInfo","dataChannelMsgSend","Start","result","final","confidence","calculateWordConfidence","words","language_code","trim","sendChatPrompt","code","description","reduce","acc","w","messages","subscribe","msg","uneeqMessageType","AvatarStartedSpeaking","PromptResult","promptResult","success","handleSpeakingEnd","AvatarAnswer","answerSpeech","replace","AvatarStoppedSpeaking","SessionEnded","SessionReconnecting","CustomMetadataUpdated","SessionBackendError","reason","detail","Event","target","url","readyState","errorMessage","message","includes","userSpokenLocale","Stop","sendMessage","next"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"363.index.js","mappings":"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","sources":["webpack://Uneeq/./src/deepgram-flux-stt.ts"],"sourcesContent":["import { type Subject } from 'rxjs'\nimport Logger from './lib/logger'\nimport {\n UserStartedSpeakingMessage,\n UserStoppedSpeakingMessage,\n SpeechTranscriptionMessage,\n EnableMicrophoneUpdatedMessage,\n SessionErrorMessage,\n SpeechRecognitionTransientErrorMessage,\n DeviceErrorMessage,\n AvatarInterruptedMessage,\n type UneeqMessage,\n UneeqMessageType,\n type PromptResultMessage,\n type AvatarAnswerMessage,\n type CustomMetadataUpdated,\n} from './types/UneeqMessages'\nimport { type SpeechTranscriptionResult } from './types/SpeechTranscriptionResult'\nimport { type DataChannelMessage } from './webrtc-data-channel/DataChannelMessage'\nimport { UserSpeaking, UserSpeakingState } from './webrtc-data-channel/messages/UserSpeaking'\nimport { ChatPrompt } from './webrtc-data-channel/messages/ChatPrompt'\nimport { StopSpeaking } from './webrtc-data-channel/messages/StopSpeaking'\nimport { type PromptMetadata } from './types/PromptMetadata'\nimport { DeepgramClient } from '@deepgram/sdk'\nimport { type SpeechRecognitionInterface } from './types/SpeechRecognitionInterface'\n\n// Local interface for the Deepgram v2 connection — duck-typed to avoid coupling to SDK type names\ninterface DeepgramV2Connection {\n on(event: string, handler: (...args: unknown[]) => void): void\n sendMedia(data: ArrayBuffer): void\n sendListenV2Configure(config: Record<string, unknown>): void\n sendCloseStream(message: { type: string }): void\n connect(): void\n waitForOpen(): Promise<unknown>\n close(): void\n}\n\n// Constants\nconst LOG_PREFIX = '[Deepgram Flux STT]'\nconst CONNECTION_TIMEOUT_MS = 10000\n// PCM audio configuration — v2 API requires explicit encoding (no container auto-detection)\nconst PCM_SAMPLE_RATE = 16000\n// Deepgram recommends 80ms audio chunks for optimal Flux latency.\n// At 16kHz mono, 80ms = 1280 samples = 2560 bytes of int16.\n// AudioWorklet processes 128 samples per render quantum, so we accumulate 10 quanta.\nconst PCM_CHUNK_SAMPLES = 1280\n\n// AudioWorklet processor source — runs off the main thread.\n// Inlined as a Blob URL to avoid needing a separate bundled file.\nconst WORKLET_PROCESSOR_SOURCE = `\nclass PcmCaptureProcessor extends AudioWorkletProcessor {\n constructor() {\n super()\n this._buffer = new Float32Array(${PCM_CHUNK_SAMPLES})\n this._offset = 0\n }\n process(inputs, outputs, parameters) {\n const input = inputs[0]?.[0]\n if (!input) return true\n for (let i = 0; i < input.length; i++) {\n this._buffer[this._offset++] = input[i]\n if (this._offset >= this._buffer.length) {\n const int16 = new Int16Array(this._buffer.length)\n for (let j = 0; j < this._buffer.length; j++) {\n const s = Math.max(-1, Math.min(1, this._buffer[j]))\n int16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF\n }\n this.port.postMessage(int16.buffer, [int16.buffer])\n this._offset = 0\n }\n }\n return true\n }\n}\nregisterProcessor('pcm-capture-processor', PcmCaptureProcessor)\n`\n\n// Safety net: if no TurnInfo events arrive while the user is in a speaking state,\n// reset speaking indicators to prevent the UI getting stuck.\nconst SAFETY_NET_TIMEOUT_MS = 2000\n\n// Reconnection constants\nconst INITIAL_RECONNECT_DELAY_MS = 1000\nconst MAX_RECONNECT_DELAY_MS = 30000\nconst RECONNECT_BACKOFF_MULTIPLIER = 2\nconst MAX_RECONNECT_ATTEMPTS = 5\n\n// STT Engine States\nenum STTState {\n Idle = 'Idle',\n Connecting = 'Connecting',\n Connected = 'Connected',\n Paused = 'Paused',\n Disconnected = 'Disconnected'\n}\n\n/**\n * Flux v2 TurnInfo message from unified 'message' event.\n * The v2 API delivers turn lifecycle events via data.type === 'TurnInfo'.\n * Note: all fields are at the top level — there is no nested turn_info property.\n */\ninterface TurnInfoMessage {\n type: 'TurnInfo'\n event: 'StartOfTurn' | 'Update' | 'EagerEndOfTurn' | 'TurnResumed' | 'EndOfTurn'\n transcript: string\n turn_index: number\n end_of_turn_confidence?: number\n words?: Array<{\n word: string\n confidence: number\n }>\n}\n\n/**\n * Flux v2 Error message indicating an unrecoverable error.\n * Note: SDK type is \"Error\" (not \"FatalError\") per ListenV2FatalError.\n */\ninterface FatalErrorMessage {\n type: 'Error'\n code: string\n description: string\n}\n\ninterface DeepgramTokenResponse {\n token: string\n api_url: string\n sdk_version: string\n expires_at: string\n}\n\nexport interface DeepgramFluxSTTOptions {\n // Backend configuration\n connectionUrl: string\n jwtToken: string\n\n // Session information\n sessionId: string\n\n // Deepgram Flux configuration\n model?: string\n language?: string\n\n /** End-of-turn confidence threshold (0.5-0.9). @default 0.7 */\n eotThreshold?: number\n /** Eager end-of-turn threshold (0.3-0.9). */\n eagerEotThreshold?: number\n /** End-of-turn timeout in ms. */\n eotTimeoutMs?: number\n /** Send ChatPrompt on EagerEndOfTurn (lower latency, risk of incomplete). @default true */\n useEagerEndOfTurn?: boolean\n\n /**\n * Safety net timeout in milliseconds. Resets speaking indicators if no TurnInfo\n * events arrive for this duration while in a speaking state. @default 2000\n */\n safetyNetTimeoutMs?: number\n\n /**\n * Keyterms to boost in transcription results.\n */\n keyterms?: string[]\n\n // Microphone configuration\n echoCancellation?: boolean\n noiseSuppression?: boolean\n autoGainControl?: boolean\n microphoneDeviceId?: string\n\n // Metadata and callbacks\n promptMetadata: PromptMetadata\n messages: Subject<UneeqMessage>\n sendMessage: (msg: DataChannelMessage) => void\n}\n\nexport class DeepgramFluxSTT implements SpeechRecognitionInterface {\n private connection: DeepgramV2Connection | null = null\n private state: STTState = STTState.Idle\n private shouldReconnect: boolean = true\n private stream: MediaStream | null = null\n private audioContext: AudioContext | null = null\n private workletNode: AudioWorkletNode | null = null\n\n // Reconnection state\n private reconnectAttempts: number = 0\n private reconnectDelay: number = INITIAL_RECONNECT_DELAY_MS\n private reconnectTimeoutId: NodeJS.Timeout | null = null\n\n // Digital human speaking state\n private digitalHumanSpeaking: boolean = false\n\n // User speaking state (for data channel messages to Renny)\n private isUserCurrentlySpeaking: boolean = false\n\n // UI speaking state (for UI indicator)\n private isUiShowingSpeaking: boolean = false\n\n // Track whether an eager prompt was already sent for the current turn\n private eagerPromptSentForTurn: boolean = false\n\n // Safety net: reset speaking state if Deepgram stalls mid-turn\n private safetyNetTimeoutId: NodeJS.Timeout | null = null\n\n // Debug: track audio chunks sent\n private audioChunksSent: number = 0\n\n constructor(private readonly options: DeepgramFluxSTTOptions) {\n // Apply defaults\n this.options.model = this.options.model || 'flux-general-en'\n this.options.language = this.options.language || 'en'\n this.options.eotThreshold = this.options.eotThreshold ?? 0.7\n this.options.useEagerEndOfTurn = this.options.useEagerEndOfTurn ?? true\n this.options.safetyNetTimeoutMs = this.options.safetyNetTimeoutMs ?? SAFETY_NET_TIMEOUT_MS\n\n this.options.echoCancellation = this.options.echoCancellation ?? true\n this.options.noiseSuppression = this.options.noiseSuppression ?? true\n this.options.autoGainControl = this.options.autoGainControl ?? true\n\n this.handleAppMessages()\n }\n\n // Main lifecycle methods\n public async startRecognition(): Promise<void> {\n Logger.info(`${LOG_PREFIX} Starting speech recognition`)\n this.shouldReconnect = true\n this.resetReconnectionState()\n await this.connect()\n }\n\n public async stopRecognition(): Promise<void> {\n Logger.info(`${LOG_PREFIX} Stopping speech recognition`)\n this.shouldReconnect = false\n this.clearReconnectTimeout()\n await this.disconnect()\n }\n\n public async pause(): Promise<boolean> {\n Logger.info(`${LOG_PREFIX} Pausing speech recognition`)\n this.state = STTState.Paused\n\n // Reset speaking states\n this.clearSafetyNet()\n this.resetSpeakingStates()\n this.eagerPromptSentForTurn = false\n\n // Disable audio tracks to stop sending audio, but keep microphone and connection alive\n if (this.stream) {\n this.stream.getTracks().forEach((track) => { track.enabled = false })\n Logger.debug(`${LOG_PREFIX} Audio tracks disabled`)\n }\n\n return true\n }\n\n public async resume(): Promise<boolean> {\n Logger.info(`${LOG_PREFIX} Resuming speech recognition`)\n\n if (this.state === STTState.Paused) {\n if (this.stream) {\n // Re-enable existing audio tracks (resume from normal pause)\n this.state = STTState.Connected\n this.stream.getTracks().forEach((track) => { track.enabled = true })\n Logger.debug(`${LOG_PREFIX} Audio tracks re-enabled`)\n return true\n }\n // Connection exists but no stream (paused during connect) — start microphone\n if (this.connection) {\n this.state = STTState.Connected\n await this.startMicrophone()\n return true\n }\n // No connection and no stream — reset state so connect() doesn't bail out\n this.state = STTState.Disconnected\n }\n\n // No connection — need full connect\n Logger.debug(`${LOG_PREFIX} Initiating connection`)\n await this.connect()\n return true\n }\n\n // Metadata management\n public setChatMetadata(chatMetadata: PromptMetadata): void {\n this.options.promptMetadata = chatMetadata\n }\n\n // Private methods\n private async connect(): Promise<void> {\n if (this.state === STTState.Connected) {\n Logger.warn(`${LOG_PREFIX} Already connected`)\n return\n }\n\n if (this.state === STTState.Connecting) {\n Logger.warn(`${LOG_PREFIX} Connection already in progress`)\n return\n }\n\n this.state = STTState.Connecting\n\n try {\n const tokenData = await this.getToken()\n Logger.info(`${LOG_PREFIX} Connecting to Deepgram Flux v2 — api_url=\"${tokenData.api_url}\", sdk_version=\"${tokenData.sdk_version}\", token_length=${tokenData.token?.length ?? 0}`)\n\n // CRITICAL: Must use { accessToken: token } format for temporary tokens\n const deepgram = new DeepgramClient({\n accessToken: tokenData.token,\n baseUrl: tokenData.api_url\n })\n\n // Build v2 connection options\n // Note: v2 API does NOT accept 'language' — for Flux, language is embedded in model name (e.g. flux-general-en)\n // Audio format: raw linear16 PCM with explicit encoding+sample_rate (per Flux quickstart docs)\n // Container formats (WebM/Opus) should auto-detect but don't produce TurnInfo events in practice\n const connectionOptions: Record<string, unknown> = {\n model: this.options.model,\n encoding: 'linear16',\n sample_rate: String(PCM_SAMPLE_RATE),\n // Always opt out of Deepgram's Model Improvement Program\n mip_opt_out: 'true',\n // Flux-specific v2 options\n ...(this.options.eotThreshold !== undefined && { eot_threshold: this.options.eotThreshold }),\n ...(this.options.eagerEotThreshold !== undefined && { eager_eot_threshold: this.options.eagerEotThreshold }),\n ...(this.options.eotTimeoutMs !== undefined && { eot_timeout_ms: this.options.eotTimeoutMs }),\n ...(this.options.keyterms && this.options.keyterms.length > 0 && { keyterm: this.options.keyterms }),\n }\n\n // v5 SDK: listen.v2.connect() returns a V2Socket wrapping a WebSocket.\n // Cast because the v5 SDK's TypeScript types don't expose .v2 directly.\n interface DeepgramV2API { connect(options: Record<string, unknown>): Promise<DeepgramV2Connection> }\n this.connection = await (deepgram.listen as unknown as { v2: DeepgramV2API }).v2.connect(connectionOptions)\n\n // Initiate the WebSocket and wait for it to open (with timeout).\n this.connection.connect()\n await Promise.race([\n this.connection.waitForOpen(),\n new Promise<void>((_, reject) =>\n setTimeout(() => reject(new Error('Connection timeout')), CONNECTION_TIMEOUT_MS)\n )\n ])\n\n // Don't overwrite Paused state (user may have paused during async connection)\n if ((this.state as STTState) !== STTState.Paused) {\n this.state = STTState.Connected\n }\n Logger.info(`${LOG_PREFIX} Connection opened`)\n\n // Now set up the persistent event handlers\n this.setupEventHandlers()\n\n // If user paused during async connection, stay paused — don't start microphone\n if ((this.state as STTState) === STTState.Paused) {\n Logger.info(`${LOG_PREFIX} Pause requested during connection — staying paused`)\n this.resetReconnectionState()\n return\n }\n\n // Start the microphone\n await this.startMicrophone()\n\n Logger.info(`${LOG_PREFIX} Connected successfully`)\n\n // Reset reconnection state on successful connection\n this.resetReconnectionState()\n } catch (error) {\n this.state = STTState.Disconnected\n Logger.error(`${LOG_PREFIX} Connection error`, Logger.serialiseError(error))\n\n // Emit a non-fatal transient error so the host can surface a \"reconnecting\"\n // indicator if it wants to. \n if (this.shouldReconnect) {\n this.emitTransientError(error)\n this.scheduleReconnect()\n }\n }\n }\n\n private async disconnect(): Promise<void> {\n if (this.state === STTState.Idle || (this.state === STTState.Disconnected && !this.connection)) {\n return\n }\n\n Logger.info(`${LOG_PREFIX} Disconnecting`)\n\n try {\n this.stopMicrophone()\n\n if (this.connection) {\n // Send CloseStream to let Deepgram flush any in-flight transcription\n try { this.connection.sendCloseStream({ type: 'CloseStream' }) } catch { /* best effort */ }\n this.connection.close()\n this.connection = null\n }\n } catch (error) {\n Logger.error(`${LOG_PREFIX} Disconnect error`, Logger.serialiseError(error))\n }\n\n // Reset speaking states\n this.clearSafetyNet()\n this.resetSpeakingStates()\n this.eagerPromptSentForTurn = false\n\n this.state = STTState.Disconnected\n this.clientMsgSend(new EnableMicrophoneUpdatedMessage(false))\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n Logger.error(`${LOG_PREFIX} Max reconnection attempts (${MAX_RECONNECT_ATTEMPTS}) reached`)\n this.clientMsgSend(new SessionErrorMessage(\n `Unable to connect to speech recognition service after ${MAX_RECONNECT_ATTEMPTS} attempts`\n ))\n return\n }\n\n this.reconnectAttempts++\n Logger.info(\n `${LOG_PREFIX} Scheduling reconnection attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS} ` +\n `in ${this.reconnectDelay}ms`\n )\n\n this.reconnectTimeoutId = setTimeout(() => {\n void this.connect()\n }, this.reconnectDelay)\n\n // Exponential backoff\n this.reconnectDelay = Math.min(\n this.reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER,\n MAX_RECONNECT_DELAY_MS\n )\n }\n\n private resetReconnectionState(): void {\n this.reconnectAttempts = 0\n this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS\n this.clearReconnectTimeout()\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeoutId) {\n clearTimeout(this.reconnectTimeoutId)\n this.reconnectTimeoutId = null\n }\n }\n\n private async getToken(): Promise<DeepgramTokenResponse> {\n const model = this.options.model || 'flux-general-en'\n const tokenEndpoint = `${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(model)}`\n\n const response = await fetch(tokenEndpoint, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${this.options.jwtToken}`,\n 'Content-Type': 'application/json'\n }\n })\n\n if (!response.ok) {\n throw new Error(`Token fetch failed: ${response.status} ${response.statusText}`)\n }\n\n return await response.json()\n }\n\n private async startMicrophone(): Promise<void> {\n try {\n Logger.info(`${LOG_PREFIX} Starting microphone`)\n\n // Stop any existing microphone/stream first to prevent orphaned resources\n this.stopMicrophone()\n\n // Get user media\n this.stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n deviceId: this.options.microphoneDeviceId ? { exact: this.options.microphoneDeviceId } : undefined,\n echoCancellation: this.options.echoCancellation,\n noiseSuppression: this.options.noiseSuppression,\n autoGainControl: this.options.autoGainControl\n }\n })\n\n // Check if user paused during the getUserMedia await\n if ((this.state as STTState) === STTState.Paused) {\n Logger.info(`${LOG_PREFIX} Paused during getUserMedia — keeping stream but disabling tracks`)\n this.stream.getTracks().forEach((track) => { track.enabled = false })\n return\n }\n\n // AudioWorklet captures raw linear16 PCM off the main thread.\n // The processor is inlined as a Blob URL to avoid a separate bundled file.\n this.audioContext = new AudioContext({ sampleRate: PCM_SAMPLE_RATE })\n const source = this.audioContext.createMediaStreamSource(this.stream)\n\n const blob = new Blob([WORKLET_PROCESSOR_SOURCE], { type: 'application/javascript' })\n const processorUrl = URL.createObjectURL(blob)\n await this.audioContext.audioWorklet.addModule(processorUrl)\n URL.revokeObjectURL(processorUrl)\n\n this.workletNode = new AudioWorkletNode(this.audioContext, 'pcm-capture-processor')\n this.audioChunksSent = 0\n\n this.workletNode.port.onmessage = (event: MessageEvent) => {\n if (!this.connection || this.state !== STTState.Connected) {\n return\n }\n this.connection.sendMedia(event.data as ArrayBuffer)\n this.audioChunksSent++\n if (this.audioChunksSent % 50 === 1) {\n Logger.info(`${LOG_PREFIX} Audio chunks sent: ${this.audioChunksSent}, size: ${(event.data as ArrayBuffer).byteLength} bytes`)\n }\n }\n\n source.connect(this.workletNode)\n this.workletNode.connect(this.audioContext.destination)\n\n Logger.info(`${LOG_PREFIX} Microphone started (linear16 PCM @ ${PCM_SAMPLE_RATE}Hz)`)\n\n // Notify that microphone is enabled\n this.clientMsgSend(new EnableMicrophoneUpdatedMessage(true))\n } catch (error) {\n Logger.error(`${LOG_PREFIX} Microphone error`, Logger.serialiseError(error))\n this.clientMsgSend(new DeviceErrorMessage(new Error(JSON.stringify(error))))\n }\n }\n\n private stopMicrophone(): void {\n if (this.workletNode) {\n this.workletNode.port.close()\n this.workletNode.disconnect()\n this.workletNode = null\n }\n\n if (this.audioContext) {\n void this.audioContext.close().catch(() => {})\n this.audioContext = null\n }\n\n if (this.stream) {\n this.stream.getTracks().forEach((track) => {\n track.stop()\n })\n this.stream = null\n }\n\n Logger.info(`${LOG_PREFIX} Microphone stopped`)\n }\n\n private setupEventHandlers(): void {\n if (!this.connection) {\n return\n }\n\n this.connection.on('open', () => {\n this.handleConnectionOpen()\n })\n\n // v2: all messages are unified under a single 'message' event,\n // discriminated by data.type ('TurnInfo', 'Connected', 'FatalError', etc.)\n this.connection.on('message', (data: unknown) => {\n if (data !== null && typeof data === 'object' && 'type' in data) {\n const typed = data as { type: string }\n if (typed.type === 'TurnInfo') {\n this.handleTurnInfo(data as unknown as TurnInfoMessage)\n } else if (typed.type === 'Connected') {\n Logger.info(`${LOG_PREFIX} v2 connection confirmed`)\n } else if (typed.type === 'Error') {\n this.handleFatalError(data as unknown as FatalErrorMessage)\n } else {\n Logger.debug(`${LOG_PREFIX} Unhandled v2 message type: ${typed.type}`)\n }\n }\n })\n\n this.connection.on('close', (event: unknown) => {\n this.handleConnectionClose(event)\n })\n\n this.connection.on('error', (error: unknown) => {\n // Emit a non-fatal transient error. A 'close' event will follow and drive\n // the reconnect machinery via handleConnectionClose() → scheduleReconnect().\n // SessionErrorMessage would be fatal in hosted-experience and is reserved\n // for MAX_RECONNECT_ATTEMPTS exhaustion. WebSocket error events are opaque\n // by design — extract what we can for logging.\n const detail: Record<string, unknown> = {}\n if (error instanceof Event) {\n detail['type'] = error.type\n detail['target'] = (error.target as { url?: string; readyState?: number } | null)?.url\n ?? (error.target as { url?: string; readyState?: number } | null)?.readyState\n ?? 'unknown'\n }\n Logger.error(`${LOG_PREFIX} WebSocket error event`, error, detail)\n this.emitTransientError(error)\n })\n }\n\n /**\n * Primary handler for Flux v2 TurnInfo events.\n * Routes to specific handlers based on the turn event type.\n */\n private handleTurnInfo(data: TurnInfoMessage): void {\n try {\n Logger.debug(`${LOG_PREFIX} TurnInfo event: ${data.event}, ` +\n `transcript=\"${(data.transcript || '').substring(0, 50)}${(data.transcript || '').length > 50 ? '...' : ''}\", ` +\n `turn_index=${data.turn_index}, eot_confidence=${data.end_of_turn_confidence ?? 'n/a'}`)\n\n switch (data.event) {\n case 'StartOfTurn':\n this.handleStartOfTurn(data)\n break\n case 'Update':\n this.handleUpdate(data)\n break\n case 'EagerEndOfTurn':\n this.handleEagerEndOfTurn(data)\n break\n case 'TurnResumed':\n this.handleTurnResumed(data)\n break\n case 'EndOfTurn':\n this.handleEndOfTurn(data)\n break\n default:\n Logger.debug(`${LOG_PREFIX} Unknown TurnInfo event: ${(data as { event?: string }).event}`)\n }\n\n } catch (error) {\n Logger.error(`${LOG_PREFIX} Error processing TurnInfo`, Logger.serialiseError(error))\n } finally {\n // Always rearm the safety net — even if a handler threw.\n // Without this, an exception prevents rearming and the mic gets stuck.\n this.resetSafetyNet()\n }\n }\n\n /**\n * StartOfTurn: User has begun speaking.\n * Emit UserStartedSpeaking and send UserSpeaking(Start) to data channel.\n */\n private handleStartOfTurn(turnInfo: TurnInfoMessage): void {\n Logger.debug(`${LOG_PREFIX} StartOfTurn: turn_index=${turnInfo.turn_index}`)\n\n this.eagerPromptSentForTurn = false\n\n // Don't send speaking signals yet — wait for first Update with actual transcript.\n // This prevents background noise from interrupting the digital human.\n }\n\n /**\n * Update: Interim transcript during the current turn.\n *\n * This is also the interruption trigger: the first Update with real transcript\n * while the avatar is speaking sends StopSpeaking immediately. No word thresholds —\n * Flux's own turn detection is the source of truth.\n */\n private handleUpdate(turnInfo: TurnInfoMessage): void {\n const transcript = turnInfo.transcript || ''\n if (transcript === '') {\n return\n }\n\n // First non-empty transcript in this turn — now signal that user is speaking.\n // Deferred from StartOfTurn so background noise doesn't interrupt the digital human.\n if (!this.isUiShowingSpeaking) {\n this.isUiShowingSpeaking = true\n this.clientMsgSend(new UserStartedSpeakingMessage())\n }\n\n if (!this.isUserCurrentlySpeaking) {\n this.isUserCurrentlySpeaking = true\n this.dataChannelMsgSend(new UserSpeaking(UserSpeakingState.Start))\n }\n\n // If the avatar is speaking, interrupt immediately.\n // Flux always allows interruption — it's a conversational model.\n // We only interrupt here — EagerEndOfTurn/EndOfTurn just check the resulting state.\n if (this.digitalHumanSpeaking) {\n Logger.info(`${LOG_PREFIX} User speech detected during avatar speaking — interrupting`)\n this.dataChannelMsgSend(new StopSpeaking())\n this.clientMsgSend(new AvatarInterruptedMessage())\n this.digitalHumanSpeaking = false\n }\n\n // Emit interim transcription for closed captions\n const result: SpeechTranscriptionResult = {\n transcript,\n final: false,\n confidence: this.calculateWordConfidence(turnInfo.words),\n language_code: this.options.language || ''\n }\n this.clientMsgSend(new SpeechTranscriptionMessage(result))\n }\n\n /**\n * EagerEndOfTurn: Model predicts the user might be done speaking.\n * If useEagerEndOfTurn is enabled, send ChatPrompt immediately for lower latency.\n *\n * If the avatar is still speaking (interruption disabled or Update hasn't fired yet),\n * the prompt is discarded — we can't send competing prompts while the avatar talks.\n */\n private handleEagerEndOfTurn(turnInfo: TurnInfoMessage): void {\n const transcript = turnInfo.transcript || ''\n Logger.debug(`${LOG_PREFIX} EagerEndOfTurn: confidence=${turnInfo.end_of_turn_confidence}, transcript=\"${transcript}\"`)\n\n if (!this.options.useEagerEndOfTurn) {\n Logger.debug(`${LOG_PREFIX} EagerEndOfTurn ignored (useEagerEndOfTurn is disabled)`)\n return\n }\n\n if (transcript.trim() === '') {\n return\n }\n\n if (this.digitalHumanSpeaking) {\n Logger.debug(`${LOG_PREFIX} EagerEndOfTurn ignored — avatar is speaking`)\n return\n }\n\n Logger.info(`${LOG_PREFIX} EagerEndOfTurn: sending prompt early: \"${transcript}\"`)\n this.eagerPromptSentForTurn = true\n this.sendChatPrompt(transcript)\n }\n\n /**\n * TurnResumed: Model detects the user continued speaking after an EagerEndOfTurn.\n * If an eager prompt was already sent, log a warning (can't unsend).\n */\n private handleTurnResumed(turnInfo: TurnInfoMessage): void {\n Logger.debug(`${LOG_PREFIX} TurnResumed: turn_index=${turnInfo.turn_index}`)\n\n if (this.eagerPromptSentForTurn) {\n Logger.warn(`${LOG_PREFIX} TurnResumed after eager prompt was already sent — cancelling via StopSpeaking`)\n this.dataChannelMsgSend(new StopSpeaking())\n }\n\n this.eagerPromptSentForTurn = false\n }\n\n /**\n * EndOfTurn: Model has determined the user has finished speaking.\n *\n * If the avatar is still speaking (interruption disabled), the prompt is discarded.\n * Otherwise, cancel any in-flight eager prompt and send the definitive transcript.\n */\n private handleEndOfTurn(turnInfo: TurnInfoMessage): void {\n const transcript = turnInfo.transcript || ''\n Logger.info(`${LOG_PREFIX} EndOfTurn: \"${transcript}\", confidence=${turnInfo.end_of_turn_confidence}`)\n\n if (transcript.trim() !== '') {\n // Emit final transcription for closed captions (always, even if prompt is discarded)\n const result: SpeechTranscriptionResult = {\n transcript,\n final: true,\n confidence: this.calculateWordConfidence(turnInfo.words),\n language_code: this.options.language || ''\n }\n this.clientMsgSend(new SpeechTranscriptionMessage(result))\n\n if (this.digitalHumanSpeaking) {\n Logger.warn(`${LOG_PREFIX} EndOfTurn: discarding prompt — avatar is still speaking (no Update interrupted)`)\n } else {\n // Normal flow: cancel any in-flight eager prompt, send definitive transcript.\n // StopSpeaking is idempotent — safe to send even if nothing is in-flight.\n if (this.eagerPromptSentForTurn) {\n Logger.debug(`${LOG_PREFIX} EndOfTurn: cancelling in-flight eager prompt`)\n }\n this.dataChannelMsgSend(new StopSpeaking())\n this.sendChatPrompt(transcript)\n }\n }\n\n // Reset turn state\n this.eagerPromptSentForTurn = false\n this.resetSpeakingStates()\n }\n\n /**\n * Handle FatalError from v2 API.\n */\n private handleFatalError(data: FatalErrorMessage): void {\n Logger.error(`${LOG_PREFIX} Fatal error from Deepgram: ${data.code} — ${data.description}`)\n this.clientMsgSend(new SessionErrorMessage(`Deepgram error: ${data.code} — ${data.description}`))\n }\n\n /**\n * Calculate average confidence from word-level data, or return a default.\n */\n private calculateWordConfidence(words?: Array<{ confidence: number }>): number {\n if (!words || words.length === 0) {\n return 1.0\n }\n const sum = words.reduce((acc, w) => acc + w.confidence, 0)\n return sum / words.length\n }\n\n private handleAppMessages(): void {\n this.options.messages.subscribe((msg) => {\n switch (msg.uneeqMessageType) {\n case UneeqMessageType.AvatarStartedSpeaking:\n this.digitalHumanSpeaking = true\n break\n\n case UneeqMessageType.PromptResult: {\n const promptResultMessage = msg as PromptResultMessage\n if (!promptResultMessage.promptResult.success) {\n this.handleSpeakingEnd()\n }\n break\n }\n\n case UneeqMessageType.AvatarAnswer: {\n const answer = msg as AvatarAnswerMessage\n if (answer.answerSpeech.replace(/<[^>]*>/g, '') === '') {\n this.handleSpeakingEnd()\n }\n break\n }\n\n case UneeqMessageType.AvatarStoppedSpeaking: {\n this.handleSpeakingEnd()\n break\n }\n\n case UneeqMessageType.SessionEnded: {\n this.shouldReconnect = false\n void this.stopRecognition()\n break\n }\n\n case UneeqMessageType.SessionReconnecting: {\n this.handleSpeakingEnd()\n this.shouldReconnect = false\n void this.stopRecognition()\n break\n }\n\n case UneeqMessageType.CustomMetadataUpdated: {\n this.options.promptMetadata = (msg as CustomMetadataUpdated).chatMetadata\n break\n }\n\n case UneeqMessageType.SessionBackendError: {\n this.handleSpeakingEnd()\n break\n }\n\n default:\n }\n })\n }\n\n private handleConnectionOpen(): void {\n if (this.state !== STTState.Paused) {\n this.state = STTState.Connected\n }\n }\n\n private handleConnectionClose(event?: unknown): void {\n const code = (event as { code?: number })?.code ?? 'unknown'\n const reason = (event as { reason?: string })?.reason ?? ''\n Logger.info(`${LOG_PREFIX} Connection closed — code=${code}, reason=\"${reason}\"`)\n\n if (this.state === STTState.Paused) {\n Logger.info(`${LOG_PREFIX} Connection closed while paused — will reconnect on resume`)\n this.connection = null\n this.stopMicrophone()\n this.clearSafetyNet()\n this.resetSpeakingStates()\n return\n }\n\n this.state = STTState.Disconnected\n this.clearSafetyNet()\n this.resetSpeakingStates()\n this.eagerPromptSentForTurn = false\n this.clientMsgSend(new EnableMicrophoneUpdatedMessage(false))\n\n if (this.shouldReconnect) {\n Logger.info(`${LOG_PREFIX} Unexpected disconnect, attempting reconnection...`)\n this.scheduleReconnect()\n }\n }\n\n /**\n * Emit a non-fatal transient error to the host. Used when a single\n * connect/reconnect attempt fails or a recoverable WebSocket error fires.\n * The reconnect machinery (scheduleReconnect) will continue retrying; the\n * host receives this as an informational signal, not a fatal one.\n * Compare with the fatal `SessionErrorMessage` emitted from\n * scheduleReconnect() only when MAX_RECONNECT_ATTEMPTS is exhausted, and\n * with `handleFatalError` for Deepgram-protocol-level Error messages.\n */\n private emitTransientError(error: unknown): void {\n const message = error instanceof Error ? error.message : String(error)\n this.clientMsgSend(new SpeechRecognitionTransientErrorMessage(message))\n }\n\n private sendChatPrompt(transcript: string): void {\n if (transcript && transcript.trim() !== '') {\n if (this.options.language) {\n this.options.promptMetadata.userSpokenLocale = this.options.language\n }\n\n this.dataChannelMsgSend(new ChatPrompt(transcript, this.options.promptMetadata))\n }\n }\n\n private handleSpeakingEnd(): void {\n this.digitalHumanSpeaking = false\n }\n\n /**\n * Reset the safety net timer. Called on every TurnInfo event.\n * If the user is in a speaking state and no events arrive for SAFETY_NET_TIMEOUT_MS,\n * the speaking indicators are reset to prevent the UI getting stuck.\n */\n private resetSafetyNet(): void {\n this.clearSafetyNet()\n\n if (this.isUiShowingSpeaking || this.isUserCurrentlySpeaking) {\n this.safetyNetTimeoutId = setTimeout(() => {\n Logger.warn(`${LOG_PREFIX} Safety net: no TurnInfo events for ${this.options.safetyNetTimeoutMs}ms while speaking — resetting`)\n this.resetSpeakingStates()\n }, this.options.safetyNetTimeoutMs)\n }\n }\n\n private clearSafetyNet(): void {\n if (this.safetyNetTimeoutId) {\n clearTimeout(this.safetyNetTimeoutId)\n this.safetyNetTimeoutId = null\n }\n }\n\n /**\n * Reset speaking states and send appropriate stop messages.\n */\n private resetSpeakingStates(): void {\n if (this.isUserCurrentlySpeaking) {\n this.isUserCurrentlySpeaking = false\n this.dataChannelMsgSend(new UserSpeaking(UserSpeakingState.Stop))\n }\n\n if (this.isUiShowingSpeaking) {\n this.isUiShowingSpeaking = false\n this.clientMsgSend(new UserStoppedSpeakingMessage())\n }\n }\n\n // Send a message on the data channel to renderer\n private dataChannelMsgSend(msg: DataChannelMessage): void {\n this.options.sendMessage(msg)\n }\n\n // Send a message to the client implementation, i.e. hosted experience\n private clientMsgSend(msg: UneeqMessage): void {\n this.options.messages.next(msg)\n }\n}\n"],"names":["LOG_PREFIX","STTState","DeepgramFluxSTT","options","connection","state","Idle","shouldReconnect","stream","audioContext","workletNode","reconnectAttempts","reconnectDelay","reconnectTimeoutId","digitalHumanSpeaking","isUserCurrentlySpeaking","isUiShowingSpeaking","eagerPromptSentForTurn","safetyNetTimeoutId","audioChunksSent","constructor","this","model","language","eotThreshold","useEagerEndOfTurn","safetyNetTimeoutMs","echoCancellation","noiseSuppression","autoGainControl","handleAppMessages","startRecognition","info","resetReconnectionState","connect","stopRecognition","clearReconnectTimeout","disconnect","pause","Paused","clearSafetyNet","resetSpeakingStates","getTracks","forEach","track","enabled","debug","resume","Connected","startMicrophone","Disconnected","setChatMetadata","chatMetadata","promptMetadata","Connecting","tokenData","getToken","api_url","sdk_version","token","length","deepgram","accessToken","baseUrl","connectionOptions","encoding","sample_rate","String","mip_opt_out","undefined","eot_threshold","eagerEotThreshold","eager_eot_threshold","eotTimeoutMs","eot_timeout_ms","keyterms","keyterm","listen","v2","Promise","race","waitForOpen","_","reject","setTimeout","Error","setupEventHandlers","error","serialiseError","emitTransientError","scheduleReconnect","warn","stopMicrophone","sendCloseStream","type","close","clientMsgSend","Math","min","clearTimeout","tokenEndpoint","connectionUrl","encodeURIComponent","response","fetch","method","headers","Authorization","jwtToken","ok","status","statusText","json","navigator","mediaDevices","getUserMedia","audio","deviceId","microphoneDeviceId","exact","AudioContext","sampleRate","source","createMediaStreamSource","blob","Blob","processorUrl","URL","createObjectURL","audioWorklet","addModule","revokeObjectURL","AudioWorkletNode","port","onmessage","event","sendMedia","data","byteLength","destination","JSON","stringify","catch","stop","on","handleConnectionOpen","typed","handleTurnInfo","handleFatalError","handleConnectionClose","detail","Event","target","url","readyState","transcript","substring","turn_index","end_of_turn_confidence","handleStartOfTurn","handleUpdate","handleEagerEndOfTurn","handleTurnResumed","handleEndOfTurn","resetSafetyNet","turnInfo","dataChannelMsgSend","Start","result","final","confidence","calculateWordConfidence","words","language_code","trim","sendChatPrompt","code","description","reduce","acc","w","messages","subscribe","msg","uneeqMessageType","AvatarStartedSpeaking","PromptResult","promptResult","success","handleSpeakingEnd","AvatarAnswer","answerSpeech","replace","AvatarStoppedSpeaking","SessionEnded","SessionReconnecting","CustomMetadataUpdated","SessionBackendError","reason","message","userSpokenLocale","Stop","sendMessage","next"],"sourceRoot":""}
|
|
@@ -115,7 +115,16 @@ export declare class DeepgramFluxSTT implements SpeechRecognitionInterface {
|
|
|
115
115
|
private handleAppMessages;
|
|
116
116
|
private handleConnectionOpen;
|
|
117
117
|
private handleConnectionClose;
|
|
118
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Emit a non-fatal transient error to the host. Used when a single
|
|
120
|
+
* connect/reconnect attempt fails or a recoverable WebSocket error fires.
|
|
121
|
+
* The reconnect machinery (scheduleReconnect) will continue retrying; the
|
|
122
|
+
* host receives this as an informational signal, not a fatal one.
|
|
123
|
+
* Compare with the fatal `SessionErrorMessage` emitted from
|
|
124
|
+
* scheduleReconnect() only when MAX_RECONNECT_ATTEMPTS is exhausted, and
|
|
125
|
+
* with `handleFatalError` for Deepgram-protocol-level Error messages.
|
|
126
|
+
*/
|
|
127
|
+
private emitTransientError;
|
|
119
128
|
private sendChatPrompt;
|
|
120
129
|
private handleSpeakingEnd;
|
|
121
130
|
/**
|
package/dist/deepgram-stt.d.ts
CHANGED
|
@@ -145,9 +145,17 @@ export declare class DeepgramSTT implements SpeechRecognitionInterface {
|
|
|
145
145
|
private resetSpeakingStates;
|
|
146
146
|
private handleConnectionOpen;
|
|
147
147
|
private handleConnectionClose;
|
|
148
|
-
private handleError;
|
|
149
148
|
private sendChatPrompt;
|
|
150
149
|
private handleSpeakingEnd;
|
|
150
|
+
/**
|
|
151
|
+
* Emit a non-fatal transient error to the host. Used when a single
|
|
152
|
+
* connect/reconnect attempt fails or a recoverable WebSocket error fires.
|
|
153
|
+
* The reconnect machinery (scheduleReconnect) will continue retrying; the
|
|
154
|
+
* host receives this as an informational signal, not a fatal one.
|
|
155
|
+
* Compare with the fatal `SessionErrorMessage` emitted from
|
|
156
|
+
* scheduleReconnect() only when MAX_RECONNECT_ATTEMPTS is exhausted.
|
|
157
|
+
*/
|
|
158
|
+
private emitTransientError;
|
|
151
159
|
private dataChannelMsgSend;
|
|
152
160
|
private clientMsgSend;
|
|
153
161
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var $=Object.create;var p=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var ee=Object.getOwnPropertyNames;var te=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty;var ae=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,s)=>(typeof require<"u"?require:t)[s]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var oe=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),ie=(e,t)=>{for(var s in t)p(e,s,{get:t[s],enumerable:!0})},se=(e,t,s,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ee(t))!ne.call(e,r)&&r!==s&&p(e,r,{get:()=>t[r],enumerable:!(i=_(t,r))||i.enumerable});return e};var pe=(e,t,s)=>(s=e!=null?$(te(e)):{},se(t||!e||!e.__esModule?p(s,"default",{value:e,enumerable:!0}):s,e));var c=(a=>(a.Fatal="fatal",a.Error="error",a.Warn="warn",a.Info="info",a.Debug="debug",a.Trace="trace",a))(c||{});var u="UneeQ SDK: ",m={fatal:0,error:1,warn:2,info:3,debug:4,trace:5},l=class e{static currentLevel="info";static shouldLog(t){return m[t]<=m[e.currentLevel]}static formatLogMessage(t,s){return s.length===0?u+t:u+t+" | "+JSON.stringify(s)}static fatal(t,...s){e.shouldLog("fatal")&&console.error(e.formatLogMessage(t,s))}static error(t,...s){e.shouldLog("error")&&console.error(e.formatLogMessage(t,s))}static warn(t,...s){e.shouldLog("warn")&&console.warn(e.formatLogMessage(t,s))}static info(t,...s){e.shouldLog("info")&&console.info(e.formatLogMessage(t,s))}static debug(t,...s){e.shouldLog("debug")&&console.debug(e.formatLogMessage(t,s))}static trace(t,...s){e.shouldLog("trace")&&console.debug(e.formatLogMessage(t,s))}static setLevel(t){Object.values(c).includes(t)?e.currentLevel=t:e.currentLevel="info"}static serialiseError(t){return JSON.stringify(t,Object.getOwnPropertyNames(t))}};var re=(n=>(n.AvatarAnswer="AvatarAnswer",n.AvatarInterrupted="AvatarInterrupted",n.AvatarStartedSpeaking="AvatarStartedSpeaking",n.AvatarStoppedSpeaking="AvatarStoppedSpeaking",n.CallToActionDismissed="CallToActionDismissed",n.CustomerConcurrencyLimitReached="CustomerConcurrencyLimitReached",n.CustomMetadataUpdated="CustomMetadataUpdated",n.DataProcessingWarning="DataProcessingWarning",n.DeviceError="DeviceError",n.DigitalHumanMuted="DigitalHumanMuted",n.DigitalHumanPlayedInMutedModeSuccess="DigitalHumanPlayedInMutedModeSuccess",n.DigitalHumanUnmuted="DigitalHumanUnmuted",n.EnableMicrophoneUpdated="EnableMicrophoneUpdated",n.FrameReady="FrameReady",n.FrameResize="FrameResize",n.MicPermissionDenied="MicPermissionDenied",n.NetworkQuality="NetworkQuality",n.Notification="Notification",n.PromptRequest="PromptRequest",n.PromptResult="PromptResult",n.ReadyToStart="ReadyToStart",n.RendererError="RendererError",n.SceneReady="SceneReady",n.SessionBackendError="SessionBackendError",n.SessionConnecting="SessionConnecting",n.SessionDisconnected="SessionDisconnected",n.SessionEnded="SessionEnded",n.SessionError="SessionError",n.SessionLive="SessionLive",n.SessionReconnecting="SessionReconnecting",n.SessionReconnectingFinished="SessionReconnectingFinished",n.SessionStateUpdate="SessionStateUpdate",n.SoftSwitchFinished="SoftSwitchFinished",n.SoftSwitchStarting="SoftSwitchStarting",n.SpeechEvent="SpeechEvent",n.SpeechRecognitionTransientError="SpeechRecognitionTransientError",n.SpeechTranscription="SpeechTranscription",n.UnhandledMessage="UnhandledMessage",n.UserStartedSpeaking="UserStartedSpeaking",n.UserStoppedSpeaking="UserStoppedSpeaking",n.VadInterruptionAllowed="VadInterruptionAllowed",n.VideoLayoutConfiguring="VideoLayoutConfiguring",n.WaitingInQueue="WaitingInQueue",n.WebRtcConnected="webRtcConnected",n.WebRtcStats="WebRtcStats",n))(re||{}),g=class{constructor(t){this.error=t}error;uneeqMessageType="DeviceError"},d=class{constructor(t,s,i,r){this.answer=t;this.answerAvatar=s;this.answerSpeech=i;this.transcriptId=r}answer;answerAvatar;answerSpeech;transcriptId;uneeqMessageType="AvatarAnswer"},y=class{constructor(t){this.speechTranscription=t}speechTranscription;uneeqMessageType="SpeechTranscription"},q=class{constructor(t){this.interruptionAllowed=t}interruptionAllowed;uneeqMessageType="VadInterruptionAllowed"},M=class{uneeqMessageType="UserStartedSpeaking"},b=class{uneeqMessageType="UserStoppedSpeaking"},U=class{uneeqMessageType="AvatarStartedSpeaking"},x=class{uneeqMessageType="AvatarStoppedSpeaking"},T=class{constructor(t){this.transcriptId=t}transcriptId;uneeqMessageType="AvatarInterrupted"},S=class{constructor(t){this.sessionId=t}sessionId;uneeqMessageType="SessionLive"},f=class{constructor(t){this.position=t}position;uneeqMessageType="WaitingInQueue"},h=class{constructor(t){this.stats=t}stats;uneeqMessageType="WebRtcStats"},D=class{constructor(t){this.error=t}error;uneeqMessageType="SessionError"},v=class{constructor(t){this.error=t}error;uneeqMessageType="SpeechRecognitionTransientError"},R=class{constructor(t){this.error=t}error;uneeqMessageType="SessionBackendError"},I=class{constructor(t){this.speechEvent=t}speechEvent;uneeqMessageType="SpeechEvent"},w=class{constructor(t){this.reason=t}reason;uneeqMessageType="SessionEnded"},C=class{uneeqMessageType="DigitalHumanPlayedInMutedModeSuccess";msg="Digital Human was successfully played in muted mode. After the user interacts with the page you will need to call unmuteDigitalHuman() to unmute the video."},A=class{uneeqMessageType="DigitalHumanUnmuted"},E=class{uneeqMessageType="DigitalHumanMuted"},k=class{constructor(t){this.enabled=t}enabled;uneeqMessageType="EnableMicrophoneUpdated"},L=class{constructor(t){this.chatMetadata=t}chatMetadata;uneeqMessageType="CustomMetadataUpdated"},P=class{constructor(t){this.promptRequest=t}promptRequest;uneeqMessageType="PromptRequest"},F=class{constructor(t){this.promptResult=t}promptResult;uneeqMessageType="PromptResult"},N=class{uneeqMessageType="SceneReady"},O=class{constructor(t){this.rendererId=t}rendererId;uneeqMessageType="SessionConnecting"},W=class{uneeqMessageType="SessionDisconnected"},H=class{uneeqMessageType="SessionReconnecting"},Q=class{uneeqMessageType="SessionReconnectingFinished"},J=class{uneeqMessageType="SoftSwitchStarting"},V=class{uneeqMessageType="SoftSwitchFinished"},B=class{uneeqMessageType="VideoLayoutConfiguring"},j=class{uneeqMessageType="webRtcConnected"},z=class{uneeqMessageType="CustomerConcurrencyLimitReached"},G=class{constructor(t){this.metrics=t}metrics;uneeqMessageType="NetworkQuality"},K=class{constructor(t,s){this.code=t;this.error=s}code;error;uneeqMessageType="RendererError"};function o(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}var X=class{constructor(t,s,i=o()){this.prompt=t;this.metadata=s;this.requestId=i}prompt;metadata;requestId;toJSON(){return{action:"chat_prompt",data:{requestId:this.requestId,prompt:this.prompt,metadata:this.metadata}}}};var Y=class{constructor(t,s=o()){this.state=t;this.requestId=s}state;requestId;toJSON(){return{action:"user_speaking",data:{requestId:this.requestId,event:this.state}}}};var Z=class{constructor(t=o()){this.requestId=t}requestId;toJSON(){return{action:"stop_speaking",data:{requestId:this.requestId}}}};export{ae as a,oe as b,ie as c,pe as d,c as e,l as f,re as g,g as h,d as i,y as j,q as k,M as l,b as m,U as n,x as o,T as p,S as q,f as r,h as s,D as t,v as u,R as v,I as w,w as x,C as y,A as z,E as A,k as B,L as C,P as D,F as E,N as F,O as G,W as H,H as I,Q as J,J as K,V as L,B as M,j as N,z as O,G as P,K as Q,o as R,X as S,Y as T,Z as U};
|