uneeq-js 3.22.1 → 3.22.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.
@@ -1,27 +0,0 @@
1
- import{a as E}from"./chunk-KD2RTEWK.js";import{D as a,F as y,V as p,W as g,f as t,g as S,h as T,j as k,l as h,n as M,o as C,r as v,v as l,w as b}from"./chunk-HXVOCQLA.js";var i="[Deepgram Flux STT]",R=1e4,f=16e3,P=1280,_=`
2
- class PcmCaptureProcessor extends AudioWorkletProcessor {
3
- constructor() {
4
- super()
5
- this._buffer = new Float32Array(${P})
6
- this._offset = 0
7
- }
8
- process(inputs, outputs, parameters) {
9
- const input = inputs[0]?.[0]
10
- if (!input) return true
11
- for (let i = 0; i < input.length; i++) {
12
- this._buffer[this._offset++] = input[i]
13
- if (this._offset >= this._buffer.length) {
14
- const int16 = new Int16Array(this._buffer.length)
15
- for (let j = 0; j < this._buffer.length; j++) {
16
- const s = Math.max(-1, Math.min(1, this._buffer[j]))
17
- int16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF
18
- }
19
- this.port.postMessage(int16.buffer, [int16.buffer])
20
- this._offset = 0
21
- }
22
- }
23
- return true
24
- }
25
- }
26
- registerProcessor('pcm-capture-processor', PcmCaptureProcessor)
27
- `,I=2e3,$=1e3,D=3e4,x=2,c=5,m=3;var w=class d{constructor(e){this.options=e;this.options.model=this.options.model||"flux-general-en",this.options.language=this.options.language||"en",this.options.eotThreshold=this.options.eotThreshold??.9,this.options.eagerEotThreshold=this.options.eagerEotThreshold??.5,this.options.eotTimeoutMs=this.options.eotTimeoutMs??3e3,this.options.eagerMaxTurnDurationMs=this.options.eagerMaxTurnDurationMs??5e3,this.options.safetyNetTimeoutMs=this.options.safetyNetTimeoutMs??I,this.options.echoCancellation=this.options.echoCancellation??!0,this.options.noiseSuppression=this.options.noiseSuppression??!0,this.options.autoGainControl=this.options.autoGainControl??!0;let n=this.options.eagerEotThreshold===0?"disabled":`${this.options.eagerEotThreshold}`,s=this.options.eagerMaxTurnDurationMs===0?"disabled":`${this.options.eagerMaxTurnDurationMs}ms`;t.debug(`${i} init \u2014 features: pure-flux-event-flow, eot_threshold=${this.options.eotThreshold}, eager_eot_threshold=${n}, eot_timeout_ms=${this.options.eotTimeoutMs}, eager_max_turn_duration_ms=${s}`),this.handleAppMessages()}options;connection=null;state="Idle";shouldReconnect=!0;stream=null;audioContext=null;workletNode=null;reconnectAttempts=0;reconnectDelay=$;reconnectTimeoutId=null;digitalHumanSpeaking=!1;pendingPromptRequest=null;isUserCurrentlySpeaking=!1;isUiShowingSpeaking=!1;eagerPromptSentForTurn=!1;cancelledEagerRequestId=void 0;pendingConfigRollback=null;turnStartedAt=null;safetyNetTimeoutId=null;audioChunksSent=0;async startRecognition(){t.info(`${i} Starting speech recognition`),this.shouldReconnect=!0,this.resetReconnectionState(),await this.connect()}async stopRecognition(){t.info(`${i} Stopping speech recognition`),this.shouldReconnect=!1,this.clearReconnectTimeout(),await this.disconnect()}async pause(){return t.info(`${i} Pausing speech recognition`),this.state="Paused",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.stream&&(this.stream.getTracks().forEach(e=>{e.enabled=!1}),t.debug(`${i} Audio tracks disabled`)),!0}async resume(){if(t.info(`${i} Resuming speech recognition`),this.state==="Paused"){if(this.stream)return this.state="Connected",this.stream.getTracks().forEach(e=>{e.enabled=!0}),t.debug(`${i} Audio tracks re-enabled`),!0;if(this.connection)return this.state="Connected",await this.startMicrophone(),!0;this.state="Disconnected"}return t.debug(`${i} Initiating connection`),await this.connect(),!0}setChatMetadata(e){this.options.promptMetadata=e}updateConfig(e){let n=d.pickDefined(e);if(Object.keys(n).length===0)return t.info(`${i} updateConfig: no fields supplied, nothing to update`),!0;let s={eotThreshold:this.options.eotThreshold,eagerEotThreshold:this.options.eagerEotThreshold,eotTimeoutMs:this.options.eotTimeoutMs,keyterms:this.options.keyterms};Object.assign(this.options,n);let o=d.pickDefined({eot_threshold:n.eotThreshold,eager_eot_threshold:(n.eagerEotThreshold??0)>0?n.eagerEotThreshold:void 0,eot_timeout_ms:n.eotTimeoutMs}),r={type:"Configure",...d.pickDefined({thresholds:Object.keys(o).length>0?o:void 0,keyterms:n.keyterms})};if(!this.connection||this.state!=="Connected")return t.info(`${i} updateConfig: stored for next connection, not sent now (state=${this.state})`),!0;if(r.thresholds===void 0&&r.keyterms===void 0)return t.info(`${i} updateConfig: no sendable params (eager can't be disabled mid-stream); stored for next connection`),!0;try{return this.pendingConfigRollback=s,this.connection.sendConfigure(r),t.info(`${i} updateConfig: sent Configure ${JSON.stringify(r)}`),!0}catch(u){return this.rollbackPendingConfig(),t.error(`${i} updateConfig: failed to send Configure`,t.serialiseError(u)),!1}}rollbackPendingConfig(){this.pendingConfigRollback&&(Object.assign(this.options,this.pendingConfigRollback),this.pendingConfigRollback=null)}static pickDefined(e){let n={};for(let s of Object.keys(e))e[s]!==void 0&&(n[s]=e[s]);return n}async connect(){if(this.state==="Connected"){t.warn(`${i} Already connected`);return}if(this.state==="Connecting"){t.warn(`${i} Connection already in progress`);return}this.state="Connecting";try{let e=await this.getToken();t.info(`${i} Connecting to Deepgram Flux v2 \u2014 api_url="${e.api_url}", sdk_version="${e.sdk_version}", token_length=${e.token?.length??0}`);let n=new E({accessToken:e.token,baseUrl:e.api_url}),s={model:this.options.model,encoding:"linear16",sample_rate:String(f),mip_opt_out:"true",...this.options.eotThreshold!==void 0&&{eot_threshold:this.options.eotThreshold},...this.options.eagerEotThreshold!==void 0&&this.options.eagerEotThreshold>0&&{eager_eot_threshold:this.options.eagerEotThreshold},...this.options.eotTimeoutMs!==void 0&&{eot_timeout_ms:this.options.eotTimeoutMs},...this.options.keyterms&&this.options.keyterms.length>0&&{keyterm:this.options.keyterms}};if(this.options.model==="flux-general-multi"&&this.options.language&&(s.language_hint=this.options.language),this.connection=await n.listen.v2.connect(s),this.connection.connect(),await Promise.race([this.connection.waitForOpen(),new Promise((o,r)=>setTimeout(()=>r(new Error("Connection timeout")),R))]),this.state!=="Paused"&&(this.state="Connected"),t.info(`${i} Connection opened`),this.setupEventHandlers(),this.state==="Paused"){t.info(`${i} Pause requested during connection \u2014 staying paused`),this.resetReconnectionState();return}await this.startMicrophone(),t.info(`${i} Connected successfully`),this.resetReconnectionState()}catch(e){this.state="Disconnected",t.error(`${i} Connection error`,t.serialiseError(e)),this.shouldReconnect&&(this.emitTransientError(e),this.scheduleReconnect())}}async disconnect(){if(!(this.state==="Idle"||this.state==="Disconnected"&&!this.connection)){t.info(`${i} Disconnecting`);try{if(this.stopMicrophone(),this.connection){try{this.connection.sendCloseStream({type:"CloseStream"})}catch{}this.connection.close(),this.connection=null}}catch(e){t.error(`${i} Disconnect error`,t.serialiseError(e))}this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.state="Disconnected",this.clientMsgSend(new a(!1))}}scheduleReconnect(){if(this.reconnectAttempts>=c){t.error(`${i} Max reconnection attempts (${c}) reached`),this.clientMsgSend(new l(`Unable to connect to speech recognition service after ${c} attempts`));return}this.reconnectAttempts++,t.info(`${i} Scheduling reconnection attempt ${this.reconnectAttempts}/${c} in ${this.reconnectDelay}ms`),this.reconnectTimeoutId=setTimeout(()=>{this.connect()},this.reconnectDelay),this.reconnectDelay=Math.min(this.reconnectDelay*x,D)}resetReconnectionState(){this.reconnectAttempts=0,this.reconnectDelay=$,this.clearReconnectTimeout()}clearReconnectTimeout(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=null)}async getToken(){let e=this.options.model||"flux-general-en",n=`${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(e)}`,s=await fetch(n,{method:"GET",headers:{Authorization:`Bearer ${this.options.jwtToken}`,"Content-Type":"application/json"}});if(!s.ok)throw new Error(`Token fetch failed: ${s.status} ${s.statusText}`);return await s.json()}async startMicrophone(){try{if(t.info(`${i} Starting microphone`),this.stopMicrophone(),this.stream=await navigator.mediaDevices.getUserMedia({audio:{deviceId:this.options.microphoneDeviceId?{exact:this.options.microphoneDeviceId}:void 0,echoCancellation:this.options.echoCancellation,noiseSuppression:this.options.noiseSuppression,autoGainControl:this.options.autoGainControl}}),this.state==="Paused"){t.info(`${i} Paused during getUserMedia \u2014 keeping stream but disabling tracks`),this.stream.getTracks().forEach(o=>{o.enabled=!1});return}this.audioContext=new AudioContext({sampleRate:f});let e=this.audioContext.createMediaStreamSource(this.stream),n=new Blob([_],{type:"application/javascript"}),s=URL.createObjectURL(n);await this.audioContext.audioWorklet.addModule(s),URL.revokeObjectURL(s),this.workletNode=new AudioWorkletNode(this.audioContext,"pcm-capture-processor"),this.audioChunksSent=0,this.workletNode.port.onmessage=o=>{!this.connection||this.state!=="Connected"||(this.connection.sendMedia(o.data),this.audioChunksSent++,this.audioChunksSent%50===1&&t.debug(`${i} Audio chunks sent: ${this.audioChunksSent}, size: ${o.data.byteLength} bytes`))},e.connect(this.workletNode),this.workletNode.connect(this.audioContext.destination),t.info(`${i} Microphone started (linear16 PCM @ ${f}Hz)`),this.clientMsgSend(new a(!0))}catch(e){t.error(`${i} Microphone error`,t.serialiseError(e)),this.clientMsgSend(new k(new Error(JSON.stringify(e))))}}stopMicrophone(){this.workletNode&&(this.workletNode.port.close(),this.workletNode.disconnect(),this.workletNode=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null),t.info(`${i} Microphone stopped`)}setupEventHandlers(){this.connection&&(this.connection.on("open",()=>{this.handleConnectionOpen()}),this.connection.on("message",e=>{if(e!==null&&typeof e=="object"&&"type"in e){let n=e;n.type==="TurnInfo"?this.handleTurnInfo(e):n.type==="Connected"?t.info(`${i} v2 connection confirmed`):n.type==="ConfigureSuccess"?(this.pendingConfigRollback=null,t.info(`${i} Configure applied: ${JSON.stringify(e)}`)):n.type==="ConfigureFailure"?(this.rollbackPendingConfig(),t.warn(`${i} Configure rejected by Deepgram; rolled back persisted values`,e)):n.type==="Error"?this.handleFatalError(e):t.debug(`${i} Unhandled v2 message type: ${n.type}`)}}),this.connection.on("close",e=>{this.handleConnectionClose(e)}),this.connection.on("error",e=>{let n={};e instanceof Event&&(n.type=e.type,n.target=e.target?.url??e.target?.readyState??"unknown"),t.error(`${i} WebSocket error event`,e,n),this.emitTransientError(e)}))}handleTurnInfo(e){try{switch(t.debug(`${i} TurnInfo event: ${e.event}, transcript_length=${(e.transcript||"").length}, turn_index=${e.turn_index}, eot_confidence=${e.end_of_turn_confidence??"n/a"}`),e.event){case"StartOfTurn":this.handleStartOfTurn(e);break;case"Update":this.handleUpdate(e);break;case"EagerEndOfTurn":this.handleEagerEndOfTurn(e);break;case"TurnResumed":this.handleTurnResumed(e);break;case"EndOfTurn":this.handleEndOfTurn(e);break;default:t.debug(`${i} Unknown TurnInfo event: ${e.event}`)}}catch(n){t.error(`${i} Error processing TurnInfo`,t.serialiseError(n))}finally{this.resetSafetyNet()}}handleStartOfTurn(e){t.debug(`${i} StartOfTurn: turn_index=${e.turn_index}`),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0}handleUpdate(e){let n=e.transcript||"";if(n==="")return;if(this.isUiShowingSpeaking||(this.isUiShowingSpeaking=!0,this.turnStartedAt=Date.now(),this.clientMsgSend(new M)),this.isUserCurrentlySpeaking||(this.isUserCurrentlySpeaking=!0,this.dataChannelMsgSend(new p("start"))),this.digitalHumanSpeaking){let o=this.countWords(n);o>=m?(t.info(`${i} User speech detected during avatar speaking (${o} words) \u2014 interrupting`),this.dataChannelMsgSend(new g),this.clientMsgSend(new v),this.digitalHumanSpeaking=!1):t.debug(`${i} User speech during avatar speaking is only ${o} word(s) \u2014 holding off barge-in (potential backchannel)`)}let s={transcript:n,final:!1,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new h(s))}handleEagerEndOfTurn(e){let n=e.transcript||"";if(t.debug(`${i} EagerEndOfTurn: confidence=${e.end_of_turn_confidence}, transcript_length=${n.length}`),n.trim()==="")return;if(this.digitalHumanSpeaking&&this.countWords(n)<m){t.info(`${i} EagerEndOfTurn: dropping ${this.countWords(n)}-word backchannel while avatar speaking`);return}let s=this.options.eagerMaxTurnDurationMs??0;if(s>0&&this.turnStartedAt!==null){let o=Date.now()-this.turnStartedAt;if(o>s){t.info(`${i} EagerEndOfTurn: suppressed \u2014 turn duration ${o}ms exceeds eagerMaxTurnDurationMs=${s}; deferring to EndOfTurn`);return}}t.info(`${i} EagerEndOfTurn: sending prompt early (${this.countWords(n)} words, ${n.length} chars)`),this.eagerPromptSentForTurn=!0,this.sendChatPromptRaw(n,this.takeCancelledEagerRequestId())}takeCancelledEagerRequestId(){let e=this.cancelledEagerRequestId;return this.cancelledEagerRequestId=void 0,e}handleTurnResumed(e){t.debug(`${i} TurnResumed: turn_index=${e.turn_index}`),this.pendingPromptRequest!==null&&(this.cancelledEagerRequestId=this.pendingPromptRequest.requestId),this.eagerPromptSentForTurn&&(t.info(`${i} TurnResumed: cancelling in-flight eager prompt via StopSpeaking`),this.dataChannelMsgSend(new g)),this.clearPendingPromptRequest(),this.eagerPromptSentForTurn=!1}handleEndOfTurn(e){let n=e.transcript||"";if(t.info(`${i} EndOfTurn: transcript_length=${n.length}, confidence=${e.end_of_turn_confidence}`),n.trim()!==""){let s={transcript:n,final:!0,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new h(s)),this.digitalHumanSpeaking&&this.countWords(n)<m?(t.info(`${i} EndOfTurn: dropping ${this.countWords(n)}-word backchannel while avatar speaking`),this.clearPendingPromptRequest()):this.eagerPromptSentForTurn?(t.debug(`${i} EndOfTurn: skipping ChatPrompt \u2014 eager already fired for this turn`),this.emitPendingPromptRequest()):(this.sendChatPromptRaw(n,this.takeCancelledEagerRequestId()),this.emitPendingPromptRequest())}this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0,this.resetSpeakingStates()}handleFatalError(e){if(this.state==="Paused"&&e.code==="INACTIVE_CLIENT"){t.info(`${i} Inactivity termination while paused (${e.code}) \u2014 releasing socket; resume will reconnect`),this.releasePausedConnection();return}t.error(`${i} Fatal error from Deepgram: ${e.code} \u2014 ${e.description}`),this.clientMsgSend(new l(`Deepgram error: ${e.code} \u2014 ${e.description}`))}calculateWordConfidence(e){return!e||e.length===0?1:e.reduce((s,o)=>s+o.confidence,0)/e.length}countWords(e){return e.trim().split(/\s+/).filter(Boolean).length}handleAppMessages(){this.options.messages.subscribe(e=>{switch(e.uneeqMessageType){case"AvatarStartedSpeaking":this.digitalHumanSpeaking=!0;break;case"PromptResult":{e.promptResult.success||this.handleSpeakingEnd();break}case"AvatarAnswer":{e.answerSpeech.replace(/<[^>]*>/g,"")===""&&this.handleSpeakingEnd();break}case"AvatarStoppedSpeaking":{this.handleSpeakingEnd();break}case"SessionEnded":{this.shouldReconnect=!1,this.stopRecognition();break}case"SessionReconnecting":{this.handleSpeakingEnd(),this.shouldReconnect=!1,this.stopRecognition();break}case"CustomMetadataUpdated":{this.options.promptMetadata=e.chatMetadata;break}case"SessionBackendError":{this.handleSpeakingEnd();break}default:}})}handleConnectionOpen(){this.state!=="Paused"&&(this.state="Connected")}handleConnectionClose(e){let n=e?.code??"unknown",s=e?.reason??"";if(t.info(`${i} Connection closed \u2014 code=${n}, reason="${s}"`),this.state==="Paused"){t.info(`${i} Connection closed while paused \u2014 will reconnect on resume`),this.connection=null,this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates();return}this.state="Disconnected",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.clientMsgSend(new a(!1)),this.shouldReconnect&&(t.info(`${i} Unexpected disconnect, attempting reconnection...`),this.scheduleReconnect())}emitTransientError(e){let n=e instanceof Error?e.message:String(e);this.clientMsgSend(new b(n))}sendChatPromptRaw(e,n){if(!e||e.trim()==="")return;this.options.language&&(this.options.promptMetadata.userSpokenLocale=this.options.language);let s=n??S();n!==void 0&&t.info(`${i} sendChatPromptRaw: reusing requestId=${s} from cancelled eager prompt`);let o={...this.options.promptMetadata},r=this.turnStartedAt??Date.now(),u=Date.now()-r;this.pendingPromptRequest={prompt:e,requestId:s,metadata:o,speakingDurationMs:u,speechStartedAt:r},this.dataChannelMsgSend(new T(e,this.options.promptMetadata,s,!1))}emitPendingPromptRequest(){let e=this.pendingPromptRequest;e!==null&&(this.clientMsgSend(new y({prompt:e.prompt,requestId:e.requestId,metadata:e.metadata,speakingDurationMs:e.speakingDurationMs,speechStartedAt:e.speechStartedAt})),t.debug(`${i} PromptRequest emitted \u2014 speakingDurationMs=${e.speakingDurationMs}, requestId=${e.requestId}`),this.pendingPromptRequest=null)}clearPendingPromptRequest(){this.pendingPromptRequest=null}handleSpeakingEnd(){this.digitalHumanSpeaking=!1}resetSafetyNet(){this.clearSafetyNet(),(this.isUiShowingSpeaking||this.isUserCurrentlySpeaking)&&(this.safetyNetTimeoutId=setTimeout(()=>{t.warn(`${i} Safety net: no TurnInfo events for ${this.options.safetyNetTimeoutMs}ms while speaking \u2014 resetting`),this.resetSpeakingStates()},this.options.safetyNetTimeoutMs))}clearSafetyNet(){this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null)}releasePausedConnection(){if(this.connection){try{this.connection.close()}catch{}this.connection=null}this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates(),this.state="Paused"}resetSpeakingStates(){this.isUserCurrentlySpeaking&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new p("stop"))),this.isUiShowingSpeaking&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new C))}dataChannelMsgSend(e){this.options.sendMessage(e)}clientMsgSend(e){this.options.messages.next(e)}};export{w as DeepgramFluxSTT};
@@ -1,27 +0,0 @@
1
- import{a as E}from"./chunk-KD2RTEWK.js";import{D as a,F as y,V as l,W as g,f as t,g as S,h as T,j as k,l as h,n as C,o as M,r as v,v as p,w as b}from"./chunk-HXVOCQLA.js";var i="[Deepgram Flux STT]",R=1e4,f=16e3,P=1280,_=`
2
- class PcmCaptureProcessor extends AudioWorkletProcessor {
3
- constructor() {
4
- super()
5
- this._buffer = new Float32Array(${P})
6
- this._offset = 0
7
- }
8
- process(inputs, outputs, parameters) {
9
- const input = inputs[0]?.[0]
10
- if (!input) return true
11
- for (let i = 0; i < input.length; i++) {
12
- this._buffer[this._offset++] = input[i]
13
- if (this._offset >= this._buffer.length) {
14
- const int16 = new Int16Array(this._buffer.length)
15
- for (let j = 0; j < this._buffer.length; j++) {
16
- const s = Math.max(-1, Math.min(1, this._buffer[j]))
17
- int16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF
18
- }
19
- this.port.postMessage(int16.buffer, [int16.buffer])
20
- this._offset = 0
21
- }
22
- }
23
- return true
24
- }
25
- }
26
- registerProcessor('pcm-capture-processor', PcmCaptureProcessor)
27
- `,I=2e3,$=1e3,D=3e4,A=2,c=5,m=3;var w=class d{constructor(e){this.options=e;this.options.model=this.options.model||"flux-general-en",this.options.language=this.options.language||"en",this.options.eotThreshold=this.options.eotThreshold??.9,this.options.eagerEotThreshold=this.options.eagerEotThreshold??.5,this.options.eotTimeoutMs=this.options.eotTimeoutMs??3e3,this.options.eagerMaxTurnDurationMs=this.options.eagerMaxTurnDurationMs??5e3,this.options.safetyNetTimeoutMs=this.options.safetyNetTimeoutMs??I,this.options.echoCancellation=this.options.echoCancellation??!0,this.options.noiseSuppression=this.options.noiseSuppression??!0,this.options.autoGainControl=this.options.autoGainControl??!0;let n=this.options.eagerEotThreshold===0?"disabled":`${this.options.eagerEotThreshold}`,s=this.options.eagerMaxTurnDurationMs===0?"disabled":`${this.options.eagerMaxTurnDurationMs}ms`;t.debug(`${i} init \u2014 features: pure-flux-event-flow, eot_threshold=${this.options.eotThreshold}, eager_eot_threshold=${n}, eot_timeout_ms=${this.options.eotTimeoutMs}, eager_max_turn_duration_ms=${s}`),this.handleAppMessages()}options;connection=null;state="Idle";shouldReconnect=!0;stream=null;audioContext=null;workletNode=null;reconnectAttempts=0;reconnectDelay=$;reconnectTimeoutId=null;digitalHumanSpeaking=!1;pendingPromptRequest=null;isUserCurrentlySpeaking=!1;isUiShowingSpeaking=!1;eagerPromptSentForTurn=!1;eagerSentWordCount=0;cancelledEagerRequestId=void 0;pendingConfigRollback=null;turnStartedAt=null;safetyNetTimeoutId=null;audioChunksSent=0;async startRecognition(){t.info(`${i} Starting speech recognition`),this.shouldReconnect=!0,this.resetReconnectionState(),await this.connect()}async stopRecognition(){t.info(`${i} Stopping speech recognition`),this.shouldReconnect=!1,this.clearReconnectTimeout(),await this.disconnect()}async pause(){return t.info(`${i} Pausing speech recognition`),this.state="Paused",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.stream&&(this.stream.getTracks().forEach(e=>{e.enabled=!1}),t.debug(`${i} Audio tracks disabled`)),!0}async resume(){if(t.info(`${i} Resuming speech recognition`),this.state==="Paused"){if(this.stream)return this.state="Connected",this.stream.getTracks().forEach(e=>{e.enabled=!0}),t.debug(`${i} Audio tracks re-enabled`),!0;if(this.connection)return this.state="Connected",await this.startMicrophone(),!0;this.state="Disconnected"}return t.debug(`${i} Initiating connection`),await this.connect(),!0}setChatMetadata(e){this.options.promptMetadata=e}updateConfig(e){let n=d.pickDefined(e);if(Object.keys(n).length===0)return t.info(`${i} updateConfig: no fields supplied, nothing to update`),!0;let s={eotThreshold:this.options.eotThreshold,eagerEotThreshold:this.options.eagerEotThreshold,eotTimeoutMs:this.options.eotTimeoutMs,keyterms:this.options.keyterms};Object.assign(this.options,n);let o=d.pickDefined({eot_threshold:n.eotThreshold,eager_eot_threshold:(n.eagerEotThreshold??0)>0?n.eagerEotThreshold:void 0,eot_timeout_ms:n.eotTimeoutMs}),r={type:"Configure",...d.pickDefined({thresholds:Object.keys(o).length>0?o:void 0,keyterms:n.keyterms})};if(!this.connection||this.state!=="Connected")return t.info(`${i} updateConfig: stored for next connection, not sent now (state=${this.state})`),!0;if(r.thresholds===void 0&&r.keyterms===void 0)return t.info(`${i} updateConfig: no sendable params (eager can't be disabled mid-stream); stored for next connection`),!0;try{return this.pendingConfigRollback=s,this.connection.sendConfigure(r),t.info(`${i} updateConfig: sent Configure ${JSON.stringify(r)}`),!0}catch(u){return this.rollbackPendingConfig(),t.error(`${i} updateConfig: failed to send Configure`,t.serialiseError(u)),!1}}rollbackPendingConfig(){this.pendingConfigRollback&&(Object.assign(this.options,this.pendingConfigRollback),this.pendingConfigRollback=null)}static pickDefined(e){let n={};for(let s of Object.keys(e))e[s]!==void 0&&(n[s]=e[s]);return n}async connect(){if(this.state==="Connected"){t.warn(`${i} Already connected`);return}if(this.state==="Connecting"){t.warn(`${i} Connection already in progress`);return}this.state="Connecting";try{let e=await this.getToken();t.info(`${i} Connecting to Deepgram Flux v2 \u2014 api_url="${e.api_url}", sdk_version="${e.sdk_version}", token_length=${e.token?.length??0}`);let n=new E({accessToken:e.token,baseUrl:e.api_url}),s={model:this.options.model,encoding:"linear16",sample_rate:String(f),mip_opt_out:"true",...this.options.eotThreshold!==void 0&&{eot_threshold:this.options.eotThreshold},...this.options.eagerEotThreshold!==void 0&&this.options.eagerEotThreshold>0&&{eager_eot_threshold:this.options.eagerEotThreshold},...this.options.eotTimeoutMs!==void 0&&{eot_timeout_ms:this.options.eotTimeoutMs},...this.options.keyterms&&this.options.keyterms.length>0&&{keyterm:this.options.keyterms}};if(this.options.model==="flux-general-multi"&&this.options.language&&(s.language_hint=this.options.language),this.connection=await n.listen.v2.connect(s),this.connection.connect(),await Promise.race([this.connection.waitForOpen(),new Promise((o,r)=>setTimeout(()=>r(new Error("Connection timeout")),R))]),this.state!=="Paused"&&(this.state="Connected"),t.info(`${i} Connection opened`),this.setupEventHandlers(),this.state==="Paused"){t.info(`${i} Pause requested during connection \u2014 staying paused`),this.resetReconnectionState();return}await this.startMicrophone(),t.info(`${i} Connected successfully`),this.resetReconnectionState()}catch(e){this.state="Disconnected",t.error(`${i} Connection error`,t.serialiseError(e)),this.shouldReconnect&&(this.emitTransientError(e),this.scheduleReconnect())}}async disconnect(){if(!(this.state==="Idle"||this.state==="Disconnected"&&!this.connection)){t.info(`${i} Disconnecting`);try{if(this.stopMicrophone(),this.connection){try{this.connection.sendCloseStream({type:"CloseStream"})}catch{}this.connection.close(),this.connection=null}}catch(e){t.error(`${i} Disconnect error`,t.serialiseError(e))}this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.state="Disconnected",this.clientMsgSend(new a(!1))}}scheduleReconnect(){if(this.reconnectAttempts>=c){t.error(`${i} Max reconnection attempts (${c}) reached`),this.clientMsgSend(new p(`Unable to connect to speech recognition service after ${c} attempts`));return}this.reconnectAttempts++,t.info(`${i} Scheduling reconnection attempt ${this.reconnectAttempts}/${c} in ${this.reconnectDelay}ms`),this.reconnectTimeoutId=setTimeout(()=>{this.connect()},this.reconnectDelay),this.reconnectDelay=Math.min(this.reconnectDelay*A,D)}resetReconnectionState(){this.reconnectAttempts=0,this.reconnectDelay=$,this.clearReconnectTimeout()}clearReconnectTimeout(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=null)}async getToken(){let e=this.options.model||"flux-general-en",n=`${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(e)}`,s=await fetch(n,{method:"GET",headers:{Authorization:`Bearer ${this.options.jwtToken}`,"Content-Type":"application/json"}});if(!s.ok)throw new Error(`Token fetch failed: ${s.status} ${s.statusText}`);return await s.json()}async startMicrophone(){try{if(t.info(`${i} Starting microphone`),this.stopMicrophone(),this.stream=await navigator.mediaDevices.getUserMedia({audio:{deviceId:this.options.microphoneDeviceId?{exact:this.options.microphoneDeviceId}:void 0,echoCancellation:this.options.echoCancellation,noiseSuppression:this.options.noiseSuppression,autoGainControl:this.options.autoGainControl}}),this.state==="Paused"){t.info(`${i} Paused during getUserMedia \u2014 keeping stream but disabling tracks`),this.stream.getTracks().forEach(o=>{o.enabled=!1});return}this.audioContext=new AudioContext({sampleRate:f});let e=this.audioContext.createMediaStreamSource(this.stream),n=new Blob([_],{type:"application/javascript"}),s=URL.createObjectURL(n);await this.audioContext.audioWorklet.addModule(s),URL.revokeObjectURL(s),this.workletNode=new AudioWorkletNode(this.audioContext,"pcm-capture-processor"),this.audioChunksSent=0,this.workletNode.port.onmessage=o=>{!this.connection||this.state!=="Connected"||(this.connection.sendMedia(o.data),this.audioChunksSent++,this.audioChunksSent%50===1&&t.debug(`${i} Audio chunks sent: ${this.audioChunksSent}, size: ${o.data.byteLength} bytes`))},e.connect(this.workletNode),this.workletNode.connect(this.audioContext.destination),t.info(`${i} Microphone started (linear16 PCM @ ${f}Hz)`),this.clientMsgSend(new a(!0))}catch(e){t.error(`${i} Microphone error`,t.serialiseError(e)),this.clientMsgSend(new k(new Error(JSON.stringify(e))))}}stopMicrophone(){this.workletNode&&(this.workletNode.port.close(),this.workletNode.disconnect(),this.workletNode=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null),t.info(`${i} Microphone stopped`)}setupEventHandlers(){this.connection&&(this.connection.on("open",()=>{this.handleConnectionOpen()}),this.connection.on("message",e=>{if(e!==null&&typeof e=="object"&&"type"in e){let n=e;n.type==="TurnInfo"?this.handleTurnInfo(e):n.type==="Connected"?t.info(`${i} v2 connection confirmed`):n.type==="ConfigureSuccess"?(this.pendingConfigRollback=null,t.info(`${i} Configure applied: ${JSON.stringify(e)}`)):n.type==="ConfigureFailure"?(this.rollbackPendingConfig(),t.warn(`${i} Configure rejected by Deepgram; rolled back persisted values`,e)):n.type==="Error"?this.handleFatalError(e):t.debug(`${i} Unhandled v2 message type: ${n.type}`)}}),this.connection.on("close",e=>{this.handleConnectionClose(e)}),this.connection.on("error",e=>{let n={};e instanceof Event&&(n.type=e.type,n.target=e.target?.url??e.target?.readyState??"unknown"),t.error(`${i} WebSocket error event`,e,n),this.emitTransientError(e)}))}handleTurnInfo(e){try{switch(t.debug(`${i} TurnInfo event: ${e.event}, transcript_length=${(e.transcript||"").length}, turn_index=${e.turn_index}, eot_confidence=${e.end_of_turn_confidence??"n/a"}`),e.event){case"StartOfTurn":this.handleStartOfTurn(e);break;case"Update":this.handleUpdate(e);break;case"EagerEndOfTurn":this.handleEagerEndOfTurn(e);break;case"TurnResumed":this.handleTurnResumed(e);break;case"EndOfTurn":this.handleEndOfTurn(e);break;default:t.debug(`${i} Unknown TurnInfo event: ${e.event}`)}}catch(n){t.error(`${i} Error processing TurnInfo`,t.serialiseError(n))}finally{this.resetSafetyNet()}}handleStartOfTurn(e){t.debug(`${i} StartOfTurn: turn_index=${e.turn_index}`),this.eagerPromptSentForTurn=!1,this.eagerSentWordCount=0,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0}handleUpdate(e){let n=e.transcript||"";if(n==="")return;this.isUiShowingSpeaking||(this.isUiShowingSpeaking=!0,this.turnStartedAt=Date.now(),this.clientMsgSend(new C)),this.isUserCurrentlySpeaking||(this.isUserCurrentlySpeaking=!0,this.dataChannelMsgSend(new l("start")));let s=this.countWords(n),o=this.eagerPromptSentForTurn&&s<=this.eagerSentWordCount;if(this.digitalHumanSpeaking&&(o?t.debug(`${i} Stale same-turn Update during avatar speech (${s} words, eager sent at ${this.eagerSentWordCount}) \u2014 not barge-in`):s>=m?(t.info(`${i} User speech detected during avatar speaking (${s} words) \u2014 interrupting`),this.dataChannelMsgSend(new g),this.clientMsgSend(new v),this.digitalHumanSpeaking=!1):t.debug(`${i} User speech during avatar speaking is only ${s} word(s) \u2014 holding off barge-in (potential backchannel)`)),o)return;let r={transcript:n,final:!1,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new h(r))}handleEagerEndOfTurn(e){let n=e.transcript||"";if(t.debug(`${i} EagerEndOfTurn: confidence=${e.end_of_turn_confidence}, transcript_length=${n.length}`),n.trim()==="")return;if(this.digitalHumanSpeaking&&this.countWords(n)<m){t.info(`${i} EagerEndOfTurn: dropping ${this.countWords(n)}-word backchannel while avatar speaking`);return}let s=this.options.eagerMaxTurnDurationMs??0;if(s>0&&this.turnStartedAt!==null){let o=Date.now()-this.turnStartedAt;if(o>s){t.info(`${i} EagerEndOfTurn: suppressed \u2014 turn duration ${o}ms exceeds eagerMaxTurnDurationMs=${s}; deferring to EndOfTurn`);return}}t.info(`${i} EagerEndOfTurn: sending prompt early (${this.countWords(n)} words, ${n.length} chars)`),this.eagerPromptSentForTurn=!0,this.eagerSentWordCount=this.countWords(n),this.sendChatPromptRaw(n,this.takeCancelledEagerRequestId())}takeCancelledEagerRequestId(){let e=this.cancelledEagerRequestId;return this.cancelledEagerRequestId=void 0,e}handleTurnResumed(e){t.debug(`${i} TurnResumed: turn_index=${e.turn_index}`),this.pendingPromptRequest!==null&&(this.cancelledEagerRequestId=this.pendingPromptRequest.requestId),this.eagerPromptSentForTurn&&(t.info(`${i} TurnResumed: cancelling in-flight eager prompt via StopSpeaking`),this.dataChannelMsgSend(new g)),this.clearPendingPromptRequest(),this.eagerPromptSentForTurn=!1}handleEndOfTurn(e){let n=e.transcript||"";if(t.info(`${i} EndOfTurn: transcript_length=${n.length}, confidence=${e.end_of_turn_confidence}`),n.trim()!==""){let s={transcript:n,final:!0,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new h(s)),this.digitalHumanSpeaking&&this.countWords(n)<m?(t.info(`${i} EndOfTurn: dropping ${this.countWords(n)}-word backchannel while avatar speaking`),this.clearPendingPromptRequest()):this.eagerPromptSentForTurn?(t.debug(`${i} EndOfTurn: skipping ChatPrompt \u2014 eager already fired for this turn`),this.emitPendingPromptRequest()):(this.sendChatPromptRaw(n,this.takeCancelledEagerRequestId()),this.emitPendingPromptRequest())}this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0,this.resetSpeakingStates()}handleFatalError(e){if(this.state==="Paused"&&e.code==="INACTIVE_CLIENT"){t.info(`${i} Inactivity termination while paused (${e.code}) \u2014 releasing socket; resume will reconnect`),this.releasePausedConnection();return}t.error(`${i} Fatal error from Deepgram: ${e.code} \u2014 ${e.description}`),this.clientMsgSend(new p(`Deepgram error: ${e.code} \u2014 ${e.description}`))}calculateWordConfidence(e){return!e||e.length===0?1:e.reduce((s,o)=>s+o.confidence,0)/e.length}countWords(e){return e.trim().split(/\s+/).filter(Boolean).length}handleAppMessages(){this.options.messages.subscribe(e=>{switch(e.uneeqMessageType){case"AvatarStartedSpeaking":this.digitalHumanSpeaking=!0;break;case"PromptResult":{e.promptResult.success||this.handleSpeakingEnd();break}case"AvatarAnswer":{e.answerSpeech.replace(/<[^>]*>/g,"")===""&&this.handleSpeakingEnd();break}case"AvatarStoppedSpeaking":{this.handleSpeakingEnd();break}case"SessionEnded":{this.shouldReconnect=!1,this.stopRecognition();break}case"SessionReconnecting":{this.handleSpeakingEnd(),this.shouldReconnect=!1,this.stopRecognition();break}case"CustomMetadataUpdated":{this.options.promptMetadata=e.chatMetadata;break}case"SessionBackendError":{this.handleSpeakingEnd();break}default:}})}handleConnectionOpen(){this.state!=="Paused"&&(this.state="Connected")}handleConnectionClose(e){let n=e?.code??"unknown",s=e?.reason??"";if(t.info(`${i} Connection closed \u2014 code=${n}, reason="${s}"`),this.state==="Paused"){t.info(`${i} Connection closed while paused \u2014 will reconnect on resume`),this.connection=null,this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates();return}this.state="Disconnected",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.clientMsgSend(new a(!1)),this.shouldReconnect&&(t.info(`${i} Unexpected disconnect, attempting reconnection...`),this.scheduleReconnect())}emitTransientError(e){let n=e instanceof Error?e.message:String(e);this.clientMsgSend(new b(n))}sendChatPromptRaw(e,n){if(!e||e.trim()==="")return;this.options.language&&(this.options.promptMetadata.userSpokenLocale=this.options.language);let s=n??S();n!==void 0&&t.info(`${i} sendChatPromptRaw: reusing requestId=${s} from cancelled eager prompt`);let o={...this.options.promptMetadata},r=this.turnStartedAt??Date.now(),u=Date.now()-r;this.pendingPromptRequest={prompt:e,requestId:s,metadata:o,speakingDurationMs:u,speechStartedAt:r},this.dataChannelMsgSend(new T(e,this.options.promptMetadata,s,!1))}emitPendingPromptRequest(){let e=this.pendingPromptRequest;e!==null&&(this.clientMsgSend(new y({prompt:e.prompt,requestId:e.requestId,metadata:e.metadata,speakingDurationMs:e.speakingDurationMs,speechStartedAt:e.speechStartedAt})),t.debug(`${i} PromptRequest emitted \u2014 speakingDurationMs=${e.speakingDurationMs}, requestId=${e.requestId}`),this.pendingPromptRequest=null)}clearPendingPromptRequest(){this.pendingPromptRequest=null}handleSpeakingEnd(){this.digitalHumanSpeaking=!1}resetSafetyNet(){this.clearSafetyNet(),(this.isUiShowingSpeaking||this.isUserCurrentlySpeaking)&&(this.safetyNetTimeoutId=setTimeout(()=>{t.warn(`${i} Safety net: no TurnInfo events for ${this.options.safetyNetTimeoutMs}ms while speaking \u2014 resetting`),this.resetSpeakingStates()},this.options.safetyNetTimeoutMs))}clearSafetyNet(){this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null)}releasePausedConnection(){if(this.connection){try{this.connection.close()}catch{}this.connection=null}this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates(),this.state="Paused"}resetSpeakingStates(){this.isUserCurrentlySpeaking&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new l("stop"))),this.isUiShowingSpeaking&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new M))}dataChannelMsgSend(e){this.options.sendMessage(e)}clientMsgSend(e){this.options.messages.next(e)}};export{w as DeepgramFluxSTT};
@@ -1,27 +0,0 @@
1
- import{a as E}from"./chunk-5UQJPIVZ.js";import{D as a,F as C,U as h,V as p,f as t,g as m,h as f,j as S,l as d,n as T,o as k,r as M,v as u,w as v}from"./chunk-KSAOQLXO.js";var n="[Deepgram Flux STT]",R=1e4,l=16e3,b=1280,P=`
2
- class PcmCaptureProcessor extends AudioWorkletProcessor {
3
- constructor() {
4
- super()
5
- this._buffer = new Float32Array(${b})
6
- this._offset = 0
7
- }
8
- process(inputs, outputs, parameters) {
9
- const input = inputs[0]?.[0]
10
- if (!input) return true
11
- for (let i = 0; i < input.length; i++) {
12
- this._buffer[this._offset++] = input[i]
13
- if (this._offset >= this._buffer.length) {
14
- const int16 = new Int16Array(this._buffer.length)
15
- for (let j = 0; j < this._buffer.length; j++) {
16
- const s = Math.max(-1, Math.min(1, this._buffer[j]))
17
- int16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF
18
- }
19
- this.port.postMessage(int16.buffer, [int16.buffer])
20
- this._offset = 0
21
- }
22
- }
23
- return true
24
- }
25
- }
26
- registerProcessor('pcm-capture-processor', PcmCaptureProcessor)
27
- `,_=2e3,w=1e3,I=3e4,A=2,c=5,g=3;var $=class{constructor(e){this.options=e;this.options.model=this.options.model||"flux-general-en",this.options.language=this.options.language||"en",this.options.eotThreshold=this.options.eotThreshold??.9,this.options.eagerEotThreshold=this.options.eagerEotThreshold??.5,this.options.eotTimeoutMs=this.options.eotTimeoutMs??3e3,this.options.eagerMaxTurnDurationMs=this.options.eagerMaxTurnDurationMs??5e3,this.options.safetyNetTimeoutMs=this.options.safetyNetTimeoutMs??_,this.options.echoCancellation=this.options.echoCancellation??!0,this.options.noiseSuppression=this.options.noiseSuppression??!0,this.options.autoGainControl=this.options.autoGainControl??!0;let s=this.options.eagerEotThreshold===0?"disabled":`${this.options.eagerEotThreshold}`,i=this.options.eagerMaxTurnDurationMs===0?"disabled":`${this.options.eagerMaxTurnDurationMs}ms`;t.debug(`${n} init \u2014 features: pure-flux-event-flow, eot_threshold=${this.options.eotThreshold}, eager_eot_threshold=${s}, eot_timeout_ms=${this.options.eotTimeoutMs}, eager_max_turn_duration_ms=${i}`),this.handleAppMessages()}options;connection=null;state="Idle";shouldReconnect=!0;stream=null;audioContext=null;workletNode=null;reconnectAttempts=0;reconnectDelay=w;reconnectTimeoutId=null;digitalHumanSpeaking=!1;pendingPromptRequest=null;isUserCurrentlySpeaking=!1;isUiShowingSpeaking=!1;eagerPromptSentForTurn=!1;cancelledEagerRequestId=void 0;turnStartedAt=null;safetyNetTimeoutId=null;audioChunksSent=0;async startRecognition(){t.info(`${n} Starting speech recognition`),this.shouldReconnect=!0,this.resetReconnectionState(),await this.connect()}async stopRecognition(){t.info(`${n} Stopping speech recognition`),this.shouldReconnect=!1,this.clearReconnectTimeout(),await this.disconnect()}async pause(){return t.info(`${n} Pausing speech recognition`),this.state="Paused",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.stream&&(this.stream.getTracks().forEach(e=>{e.enabled=!1}),t.debug(`${n} Audio tracks disabled`)),!0}async resume(){if(t.info(`${n} Resuming speech recognition`),this.state==="Paused"){if(this.stream)return this.state="Connected",this.stream.getTracks().forEach(e=>{e.enabled=!0}),t.debug(`${n} Audio tracks re-enabled`),!0;if(this.connection)return this.state="Connected",await this.startMicrophone(),!0;this.state="Disconnected"}return t.debug(`${n} Initiating connection`),await this.connect(),!0}setChatMetadata(e){this.options.promptMetadata=e}async connect(){if(this.state==="Connected"){t.warn(`${n} Already connected`);return}if(this.state==="Connecting"){t.warn(`${n} Connection already in progress`);return}this.state="Connecting";try{let e=await this.getToken();t.info(`${n} Connecting to Deepgram Flux v2 \u2014 api_url="${e.api_url}", sdk_version="${e.sdk_version}", token_length=${e.token?.length??0}`);let s=new E({accessToken:e.token,baseUrl:e.api_url}),i={model:this.options.model,encoding:"linear16",sample_rate:String(l),mip_opt_out:"true",...this.options.eotThreshold!==void 0&&{eot_threshold:this.options.eotThreshold},...this.options.eagerEotThreshold!==void 0&&this.options.eagerEotThreshold>0&&{eager_eot_threshold:this.options.eagerEotThreshold},...this.options.eotTimeoutMs!==void 0&&{eot_timeout_ms:this.options.eotTimeoutMs},...this.options.keyterms&&this.options.keyterms.length>0&&{keyterm:this.options.keyterms}};if(this.options.model==="flux-general-multi"&&this.options.language&&(i.language_hint=this.options.language),this.connection=await s.listen.v2.connect(i),this.connection.connect(),await Promise.race([this.connection.waitForOpen(),new Promise((o,r)=>setTimeout(()=>r(new Error("Connection timeout")),R))]),this.state!=="Paused"&&(this.state="Connected"),t.info(`${n} Connection opened`),this.setupEventHandlers(),this.state==="Paused"){t.info(`${n} Pause requested during connection \u2014 staying paused`),this.resetReconnectionState();return}await this.startMicrophone(),t.info(`${n} Connected successfully`),this.resetReconnectionState()}catch(e){this.state="Disconnected",t.error(`${n} Connection error`,t.serialiseError(e)),this.shouldReconnect&&(this.emitTransientError(e),this.scheduleReconnect())}}async disconnect(){if(!(this.state==="Idle"||this.state==="Disconnected"&&!this.connection)){t.info(`${n} Disconnecting`);try{if(this.stopMicrophone(),this.connection){try{this.connection.sendCloseStream({type:"CloseStream"})}catch{}this.connection.close(),this.connection=null}}catch(e){t.error(`${n} Disconnect error`,t.serialiseError(e))}this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.state="Disconnected",this.clientMsgSend(new a(!1))}}scheduleReconnect(){if(this.reconnectAttempts>=c){t.error(`${n} Max reconnection attempts (${c}) reached`),this.clientMsgSend(new u(`Unable to connect to speech recognition service after ${c} attempts`));return}this.reconnectAttempts++,t.info(`${n} Scheduling reconnection attempt ${this.reconnectAttempts}/${c} in ${this.reconnectDelay}ms`),this.reconnectTimeoutId=setTimeout(()=>{this.connect()},this.reconnectDelay),this.reconnectDelay=Math.min(this.reconnectDelay*A,I)}resetReconnectionState(){this.reconnectAttempts=0,this.reconnectDelay=w,this.clearReconnectTimeout()}clearReconnectTimeout(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=null)}async getToken(){let e=this.options.model||"flux-general-en",s=`${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(e)}`,i=await fetch(s,{method:"GET",headers:{Authorization:`Bearer ${this.options.jwtToken}`,"Content-Type":"application/json"}});if(!i.ok)throw new Error(`Token fetch failed: ${i.status} ${i.statusText}`);return await i.json()}async startMicrophone(){try{if(t.info(`${n} Starting microphone`),this.stopMicrophone(),this.stream=await navigator.mediaDevices.getUserMedia({audio:{deviceId:this.options.microphoneDeviceId?{exact:this.options.microphoneDeviceId}:void 0,echoCancellation:this.options.echoCancellation,noiseSuppression:this.options.noiseSuppression,autoGainControl:this.options.autoGainControl}}),this.state==="Paused"){t.info(`${n} Paused during getUserMedia \u2014 keeping stream but disabling tracks`),this.stream.getTracks().forEach(o=>{o.enabled=!1});return}this.audioContext=new AudioContext({sampleRate:l});let e=this.audioContext.createMediaStreamSource(this.stream),s=new Blob([P],{type:"application/javascript"}),i=URL.createObjectURL(s);await this.audioContext.audioWorklet.addModule(i),URL.revokeObjectURL(i),this.workletNode=new AudioWorkletNode(this.audioContext,"pcm-capture-processor"),this.audioChunksSent=0,this.workletNode.port.onmessage=o=>{!this.connection||this.state!=="Connected"||(this.connection.sendMedia(o.data),this.audioChunksSent++,this.audioChunksSent%50===1&&t.debug(`${n} Audio chunks sent: ${this.audioChunksSent}, size: ${o.data.byteLength} bytes`))},e.connect(this.workletNode),this.workletNode.connect(this.audioContext.destination),t.info(`${n} Microphone started (linear16 PCM @ ${l}Hz)`),this.clientMsgSend(new a(!0))}catch(e){t.error(`${n} Microphone error`,t.serialiseError(e)),this.clientMsgSend(new S(new Error(JSON.stringify(e))))}}stopMicrophone(){this.workletNode&&(this.workletNode.port.close(),this.workletNode.disconnect(),this.workletNode=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null),t.info(`${n} Microphone stopped`)}setupEventHandlers(){this.connection&&(this.connection.on("open",()=>{this.handleConnectionOpen()}),this.connection.on("message",e=>{if(e!==null&&typeof e=="object"&&"type"in e){let s=e;s.type==="TurnInfo"?this.handleTurnInfo(e):s.type==="Connected"?t.info(`${n} v2 connection confirmed`):s.type==="Error"?this.handleFatalError(e):t.debug(`${n} Unhandled v2 message type: ${s.type}`)}}),this.connection.on("close",e=>{this.handleConnectionClose(e)}),this.connection.on("error",e=>{let s={};e instanceof Event&&(s.type=e.type,s.target=e.target?.url??e.target?.readyState??"unknown"),t.error(`${n} WebSocket error event`,e,s),this.emitTransientError(e)}))}handleTurnInfo(e){try{switch(t.debug(`${n} TurnInfo event: ${e.event}, transcript_length=${(e.transcript||"").length}, turn_index=${e.turn_index}, eot_confidence=${e.end_of_turn_confidence??"n/a"}`),e.event){case"StartOfTurn":this.handleStartOfTurn(e);break;case"Update":this.handleUpdate(e);break;case"EagerEndOfTurn":this.handleEagerEndOfTurn(e);break;case"TurnResumed":this.handleTurnResumed(e);break;case"EndOfTurn":this.handleEndOfTurn(e);break;default:t.debug(`${n} Unknown TurnInfo event: ${e.event}`)}}catch(s){t.error(`${n} Error processing TurnInfo`,t.serialiseError(s))}finally{this.resetSafetyNet()}}handleStartOfTurn(e){t.debug(`${n} StartOfTurn: turn_index=${e.turn_index}`),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0}handleUpdate(e){let s=e.transcript||"";if(s==="")return;if(this.isUiShowingSpeaking||(this.isUiShowingSpeaking=!0,this.turnStartedAt=Date.now(),this.clientMsgSend(new T)),this.isUserCurrentlySpeaking||(this.isUserCurrentlySpeaking=!0,this.dataChannelMsgSend(new h("start"))),this.digitalHumanSpeaking){let o=this.countWords(s);o>=g?(t.info(`${n} User speech detected during avatar speaking (${o} words) \u2014 interrupting`),this.dataChannelMsgSend(new p),this.clientMsgSend(new M),this.digitalHumanSpeaking=!1):t.debug(`${n} User speech during avatar speaking is only ${o} word(s) \u2014 holding off barge-in (potential backchannel)`)}let i={transcript:s,final:!1,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new d(i))}handleEagerEndOfTurn(e){let s=e.transcript||"";if(t.debug(`${n} EagerEndOfTurn: confidence=${e.end_of_turn_confidence}, transcript_length=${s.length}`),s.trim()==="")return;if(this.digitalHumanSpeaking&&this.countWords(s)<g){t.info(`${n} EagerEndOfTurn: dropping ${this.countWords(s)}-word backchannel while avatar speaking`);return}let i=this.options.eagerMaxTurnDurationMs??0;if(i>0&&this.turnStartedAt!==null){let o=Date.now()-this.turnStartedAt;if(o>i){t.info(`${n} EagerEndOfTurn: suppressed \u2014 turn duration ${o}ms exceeds eagerMaxTurnDurationMs=${i}; deferring to EndOfTurn`);return}}t.info(`${n} EagerEndOfTurn: sending prompt early (${this.countWords(s)} words, ${s.length} chars)`),this.eagerPromptSentForTurn=!0,this.sendChatPromptRaw(s,this.takeCancelledEagerRequestId())}takeCancelledEagerRequestId(){let e=this.cancelledEagerRequestId;return this.cancelledEagerRequestId=void 0,e}handleTurnResumed(e){t.debug(`${n} TurnResumed: turn_index=${e.turn_index}`),this.pendingPromptRequest!==null&&(this.cancelledEagerRequestId=this.pendingPromptRequest.requestId),this.eagerPromptSentForTurn&&(t.info(`${n} TurnResumed: cancelling in-flight eager prompt via StopSpeaking`),this.dataChannelMsgSend(new p)),this.clearPendingPromptRequest(),this.eagerPromptSentForTurn=!1}handleEndOfTurn(e){let s=e.transcript||"";if(t.info(`${n} EndOfTurn: transcript_length=${s.length}, confidence=${e.end_of_turn_confidence}`),s.trim()!==""){let i={transcript:s,final:!0,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new d(i)),this.digitalHumanSpeaking&&this.countWords(s)<g?(t.info(`${n} EndOfTurn: dropping ${this.countWords(s)}-word backchannel while avatar speaking`),this.clearPendingPromptRequest()):this.eagerPromptSentForTurn?(t.debug(`${n} EndOfTurn: skipping ChatPrompt \u2014 eager already fired for this turn`),this.emitPendingPromptRequest()):(this.sendChatPromptRaw(s,this.takeCancelledEagerRequestId()),this.emitPendingPromptRequest())}this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0,this.resetSpeakingStates()}handleFatalError(e){if(this.state==="Paused"&&e.code==="INACTIVE_CLIENT"){t.info(`${n} Inactivity termination while paused (${e.code}) \u2014 releasing socket; resume will reconnect`),this.releasePausedConnection();return}t.error(`${n} Fatal error from Deepgram: ${e.code} \u2014 ${e.description}`),this.clientMsgSend(new u(`Deepgram error: ${e.code} \u2014 ${e.description}`))}calculateWordConfidence(e){return!e||e.length===0?1:e.reduce((i,o)=>i+o.confidence,0)/e.length}countWords(e){return e.trim().split(/\s+/).filter(Boolean).length}handleAppMessages(){this.options.messages.subscribe(e=>{switch(e.uneeqMessageType){case"AvatarStartedSpeaking":this.digitalHumanSpeaking=!0;break;case"PromptResult":{e.promptResult.success||this.handleSpeakingEnd();break}case"AvatarAnswer":{e.answerSpeech.replace(/<[^>]*>/g,"")===""&&this.handleSpeakingEnd();break}case"AvatarStoppedSpeaking":{this.handleSpeakingEnd();break}case"SessionEnded":{this.shouldReconnect=!1,this.stopRecognition();break}case"SessionReconnecting":{this.handleSpeakingEnd(),this.shouldReconnect=!1,this.stopRecognition();break}case"CustomMetadataUpdated":{this.options.promptMetadata=e.chatMetadata;break}case"SessionBackendError":{this.handleSpeakingEnd();break}default:}})}handleConnectionOpen(){this.state!=="Paused"&&(this.state="Connected")}handleConnectionClose(e){let s=e?.code??"unknown",i=e?.reason??"";if(t.info(`${n} Connection closed \u2014 code=${s}, reason="${i}"`),this.state==="Paused"){t.info(`${n} Connection closed while paused \u2014 will reconnect on resume`),this.connection=null,this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates();return}this.state="Disconnected",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.clientMsgSend(new a(!1)),this.shouldReconnect&&(t.info(`${n} Unexpected disconnect, attempting reconnection...`),this.scheduleReconnect())}emitTransientError(e){let s=e instanceof Error?e.message:String(e);this.clientMsgSend(new v(s))}sendChatPromptRaw(e,s){if(!e||e.trim()==="")return;this.options.language&&(this.options.promptMetadata.userSpokenLocale=this.options.language);let i=s??m();s!==void 0&&t.info(`${n} sendChatPromptRaw: reusing requestId=${i} from cancelled eager prompt`);let o={...this.options.promptMetadata},r=this.turnStartedAt??Date.now(),y=Date.now()-r;this.pendingPromptRequest={prompt:e,requestId:i,metadata:o,speakingDurationMs:y,speechStartedAt:r},this.dataChannelMsgSend(new f(e,this.options.promptMetadata,i,!1))}emitPendingPromptRequest(){let e=this.pendingPromptRequest;e!==null&&(this.clientMsgSend(new C({prompt:e.prompt,requestId:e.requestId,metadata:e.metadata,speakingDurationMs:e.speakingDurationMs,speechStartedAt:e.speechStartedAt})),t.debug(`${n} PromptRequest emitted \u2014 speakingDurationMs=${e.speakingDurationMs}, requestId=${e.requestId}`),this.pendingPromptRequest=null)}clearPendingPromptRequest(){this.pendingPromptRequest=null}handleSpeakingEnd(){this.digitalHumanSpeaking=!1}resetSafetyNet(){this.clearSafetyNet(),(this.isUiShowingSpeaking||this.isUserCurrentlySpeaking)&&(this.safetyNetTimeoutId=setTimeout(()=>{t.warn(`${n} Safety net: no TurnInfo events for ${this.options.safetyNetTimeoutMs}ms while speaking \u2014 resetting`),this.resetSpeakingStates()},this.options.safetyNetTimeoutMs))}clearSafetyNet(){this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null)}releasePausedConnection(){if(this.connection){try{this.connection.close()}catch{}this.connection=null}this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates(),this.state="Paused"}resetSpeakingStates(){this.isUserCurrentlySpeaking&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new h("stop"))),this.isUiShowingSpeaking&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new k))}dataChannelMsgSend(e){this.options.sendMessage(e)}clientMsgSend(e){this.options.messages.next(e)}};export{$ as DeepgramFluxSTT};
@@ -1,27 +0,0 @@
1
- import{a as E}from"./chunk-KD2RTEWK.js";import{D as a,F as y,V as l,W as g,f as t,g as S,h as T,j as k,l as h,n as C,o as M,r as v,v as p,w as b}from"./chunk-HXVOCQLA.js";var i="[Deepgram Flux STT]",R=1e4,f=16e3,P=1280,_=`
2
- class PcmCaptureProcessor extends AudioWorkletProcessor {
3
- constructor() {
4
- super()
5
- this._buffer = new Float32Array(${P})
6
- this._offset = 0
7
- }
8
- process(inputs, outputs, parameters) {
9
- const input = inputs[0]?.[0]
10
- if (!input) return true
11
- for (let i = 0; i < input.length; i++) {
12
- this._buffer[this._offset++] = input[i]
13
- if (this._offset >= this._buffer.length) {
14
- const int16 = new Int16Array(this._buffer.length)
15
- for (let j = 0; j < this._buffer.length; j++) {
16
- const s = Math.max(-1, Math.min(1, this._buffer[j]))
17
- int16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF
18
- }
19
- this.port.postMessage(int16.buffer, [int16.buffer])
20
- this._offset = 0
21
- }
22
- }
23
- return true
24
- }
25
- }
26
- registerProcessor('pcm-capture-processor', PcmCaptureProcessor)
27
- `,I=2e3,$=1e3,D=3e4,x=2,c=5,m=3;var w=class d{constructor(e){this.options=e;this.options.model=this.options.model||"flux-general-en",this.options.language=this.options.language||"en",this.options.eotThreshold=this.options.eotThreshold??.9,this.options.eagerEotThreshold=this.options.eagerEotThreshold??.5,this.options.eotTimeoutMs=this.options.eotTimeoutMs??3e3,this.options.eagerMaxTurnDurationMs=this.options.eagerMaxTurnDurationMs??5e3,this.options.safetyNetTimeoutMs=this.options.safetyNetTimeoutMs??I,this.options.echoCancellation=this.options.echoCancellation??!0,this.options.noiseSuppression=this.options.noiseSuppression??!0,this.options.autoGainControl=this.options.autoGainControl??!0;let n=this.options.eagerEotThreshold===0?"disabled":`${this.options.eagerEotThreshold}`,s=this.options.eagerMaxTurnDurationMs===0?"disabled":`${this.options.eagerMaxTurnDurationMs}ms`;t.debug(`${i} init \u2014 features: pure-flux-event-flow, eot_threshold=${this.options.eotThreshold}, eager_eot_threshold=${n}, eot_timeout_ms=${this.options.eotTimeoutMs}, eager_max_turn_duration_ms=${s}`),this.handleAppMessages()}options;connection=null;state="Idle";shouldReconnect=!0;stream=null;audioContext=null;workletNode=null;reconnectAttempts=0;reconnectDelay=$;reconnectTimeoutId=null;digitalHumanSpeaking=!1;pendingPromptRequest=null;isUserCurrentlySpeaking=!1;isUiShowingSpeaking=!1;eagerPromptSentForTurn=!1;eagerSentWordCount=0;cancelledEagerRequestId=void 0;pendingConfigRollback=null;turnStartedAt=null;safetyNetTimeoutId=null;audioChunksSent=0;async startRecognition(){t.info(`${i} Starting speech recognition`),this.shouldReconnect=!0,this.resetReconnectionState(),await this.connect()}async stopRecognition(){t.info(`${i} Stopping speech recognition`),this.shouldReconnect=!1,this.clearReconnectTimeout(),await this.disconnect()}async pause(){return t.info(`${i} Pausing speech recognition`),this.state="Paused",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.stream&&(this.stream.getTracks().forEach(e=>{e.enabled=!1}),t.debug(`${i} Audio tracks disabled`)),!0}async resume(){if(t.info(`${i} Resuming speech recognition`),this.state==="Paused"){if(this.stream)return this.state="Connected",this.stream.getTracks().forEach(e=>{e.enabled=!0}),t.debug(`${i} Audio tracks re-enabled`),!0;if(this.connection)return this.state="Connected",await this.startMicrophone(),!0;this.state="Disconnected"}return t.debug(`${i} Initiating connection`),await this.connect(),!0}setChatMetadata(e){this.options.promptMetadata=e}updateConfig(e){let n=d.pickDefined(e);if(Object.keys(n).length===0)return t.info(`${i} updateConfig: no fields supplied, nothing to update`),!0;let s={eotThreshold:this.options.eotThreshold,eagerEotThreshold:this.options.eagerEotThreshold,eotTimeoutMs:this.options.eotTimeoutMs,keyterms:this.options.keyterms};Object.assign(this.options,n);let o=d.pickDefined({eot_threshold:n.eotThreshold,eager_eot_threshold:(n.eagerEotThreshold??0)>0?n.eagerEotThreshold:void 0,eot_timeout_ms:n.eotTimeoutMs}),r={type:"Configure",...d.pickDefined({thresholds:Object.keys(o).length>0?o:void 0,keyterms:n.keyterms})};if(!this.connection||this.state!=="Connected")return t.info(`${i} updateConfig: stored for next connection, not sent now (state=${this.state})`),!0;if(r.thresholds===void 0&&r.keyterms===void 0)return t.info(`${i} updateConfig: no sendable params (eager can't be disabled mid-stream); stored for next connection`),!0;try{return this.pendingConfigRollback=s,this.connection.sendConfigure(r),t.info(`${i} updateConfig: sent Configure ${JSON.stringify(r)}`),!0}catch(u){return this.rollbackPendingConfig(),t.error(`${i} updateConfig: failed to send Configure`,t.serialiseError(u)),!1}}rollbackPendingConfig(){this.pendingConfigRollback&&(Object.assign(this.options,this.pendingConfigRollback),this.pendingConfigRollback=null)}static pickDefined(e){let n={};for(let s of Object.keys(e))e[s]!==void 0&&(n[s]=e[s]);return n}async connect(){if(this.state==="Connected"){t.warn(`${i} Already connected`);return}if(this.state==="Connecting"){t.warn(`${i} Connection already in progress`);return}this.state="Connecting";try{let e=await this.getToken();t.info(`${i} Connecting to Deepgram Flux v2 \u2014 api_url="${e.api_url}", sdk_version="${e.sdk_version}", token_length=${e.token?.length??0}`);let n=new E({accessToken:e.token,baseUrl:e.api_url}),s={model:this.options.model,encoding:"linear16",sample_rate:String(f),mip_opt_out:"true",...this.options.eotThreshold!==void 0&&{eot_threshold:this.options.eotThreshold},...this.options.eagerEotThreshold!==void 0&&this.options.eagerEotThreshold>0&&{eager_eot_threshold:this.options.eagerEotThreshold},...this.options.eotTimeoutMs!==void 0&&{eot_timeout_ms:this.options.eotTimeoutMs},...this.options.keyterms&&this.options.keyterms.length>0&&{keyterm:this.options.keyterms}};if(this.options.model==="flux-general-multi"&&this.options.language&&(s.language_hint=this.options.language),this.connection=await n.listen.v2.connect(s),this.connection.connect(),await Promise.race([this.connection.waitForOpen(),new Promise((o,r)=>setTimeout(()=>r(new Error("Connection timeout")),R))]),this.state!=="Paused"&&(this.state="Connected"),t.info(`${i} Connection opened`),this.setupEventHandlers(),this.state==="Paused"){t.info(`${i} Pause requested during connection \u2014 staying paused`),this.resetReconnectionState();return}await this.startMicrophone(),t.info(`${i} Connected successfully`),this.resetReconnectionState()}catch(e){this.state="Disconnected",t.error(`${i} Connection error`,t.serialiseError(e)),this.shouldReconnect&&(this.emitTransientError(e),this.scheduleReconnect())}}async disconnect(){if(!(this.state==="Idle"||this.state==="Disconnected"&&!this.connection)){t.info(`${i} Disconnecting`);try{if(this.stopMicrophone(),this.connection){try{this.connection.sendCloseStream({type:"CloseStream"})}catch{}this.connection.close(),this.connection=null}}catch(e){t.error(`${i} Disconnect error`,t.serialiseError(e))}this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.state="Disconnected",this.clientMsgSend(new a(!1))}}scheduleReconnect(){if(this.reconnectAttempts>=c){t.error(`${i} Max reconnection attempts (${c}) reached`),this.clientMsgSend(new p(`Unable to connect to speech recognition service after ${c} attempts`));return}this.reconnectAttempts++,t.info(`${i} Scheduling reconnection attempt ${this.reconnectAttempts}/${c} in ${this.reconnectDelay}ms`),this.reconnectTimeoutId=setTimeout(()=>{this.connect()},this.reconnectDelay),this.reconnectDelay=Math.min(this.reconnectDelay*x,D)}resetReconnectionState(){this.reconnectAttempts=0,this.reconnectDelay=$,this.clearReconnectTimeout()}clearReconnectTimeout(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=null)}async getToken(){let e=this.options.model||"flux-general-en",n=`${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(e)}`,s=await fetch(n,{method:"GET",headers:{Authorization:`Bearer ${this.options.jwtToken}`,"Content-Type":"application/json"}});if(!s.ok)throw new Error(`Token fetch failed: ${s.status} ${s.statusText}`);return await s.json()}async startMicrophone(){try{if(t.info(`${i} Starting microphone`),this.stopMicrophone(),this.stream=await navigator.mediaDevices.getUserMedia({audio:{deviceId:this.options.microphoneDeviceId?{exact:this.options.microphoneDeviceId}:void 0,echoCancellation:this.options.echoCancellation,noiseSuppression:this.options.noiseSuppression,autoGainControl:this.options.autoGainControl}}),this.state==="Paused"){t.info(`${i} Paused during getUserMedia \u2014 keeping stream but disabling tracks`),this.stream.getTracks().forEach(o=>{o.enabled=!1});return}this.audioContext=new AudioContext({sampleRate:f});let e=this.audioContext.createMediaStreamSource(this.stream),n=new Blob([_],{type:"application/javascript"}),s=URL.createObjectURL(n);await this.audioContext.audioWorklet.addModule(s),URL.revokeObjectURL(s),this.workletNode=new AudioWorkletNode(this.audioContext,"pcm-capture-processor"),this.audioChunksSent=0,this.workletNode.port.onmessage=o=>{!this.connection||this.state!=="Connected"||(this.connection.sendMedia(o.data),this.audioChunksSent++,this.audioChunksSent%50===1&&t.debug(`${i} Audio chunks sent: ${this.audioChunksSent}, size: ${o.data.byteLength} bytes`))},e.connect(this.workletNode),this.workletNode.connect(this.audioContext.destination),t.info(`${i} Microphone started (linear16 PCM @ ${f}Hz)`),this.clientMsgSend(new a(!0))}catch(e){t.error(`${i} Microphone error`,t.serialiseError(e)),this.clientMsgSend(new k(new Error(JSON.stringify(e))))}}stopMicrophone(){this.workletNode&&(this.workletNode.port.close(),this.workletNode.disconnect(),this.workletNode=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null),t.info(`${i} Microphone stopped`)}setupEventHandlers(){this.connection&&(this.connection.on("open",()=>{this.handleConnectionOpen()}),this.connection.on("message",e=>{if(e!==null&&typeof e=="object"&&"type"in e){let n=e;n.type==="TurnInfo"?this.handleTurnInfo(e):n.type==="Connected"?t.info(`${i} v2 connection confirmed`):n.type==="ConfigureSuccess"?(this.pendingConfigRollback=null,t.info(`${i} Configure applied: ${JSON.stringify(e)}`)):n.type==="ConfigureFailure"?(this.rollbackPendingConfig(),t.warn(`${i} Configure rejected by Deepgram; rolled back persisted values`,e)):n.type==="Error"?this.handleFatalError(e):t.debug(`${i} Unhandled v2 message type: ${n.type}`)}}),this.connection.on("close",e=>{this.handleConnectionClose(e)}),this.connection.on("error",e=>{let n={};e instanceof Event&&(n.type=e.type,n.target=e.target?.url??e.target?.readyState??"unknown"),t.error(`${i} WebSocket error event`,e,n),this.emitTransientError(e)}))}handleTurnInfo(e){try{switch(t.debug(`${i} TurnInfo event: ${e.event}, transcript_length=${(e.transcript||"").length}, turn_index=${e.turn_index}, eot_confidence=${e.end_of_turn_confidence??"n/a"}`),e.event){case"StartOfTurn":this.handleStartOfTurn(e);break;case"Update":this.handleUpdate(e);break;case"EagerEndOfTurn":this.handleEagerEndOfTurn(e);break;case"TurnResumed":this.handleTurnResumed(e);break;case"EndOfTurn":this.handleEndOfTurn(e);break;default:t.debug(`${i} Unknown TurnInfo event: ${e.event}`)}}catch(n){t.error(`${i} Error processing TurnInfo`,t.serialiseError(n))}finally{this.resetSafetyNet()}}handleStartOfTurn(e){t.debug(`${i} StartOfTurn: turn_index=${e.turn_index}`),this.eagerPromptSentForTurn=!1,this.eagerSentWordCount=0,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0}handleUpdate(e){let n=e.transcript||"";if(n==="")return;if(this.isUiShowingSpeaking||(this.isUiShowingSpeaking=!0,this.turnStartedAt=Date.now(),this.clientMsgSend(new C)),this.isUserCurrentlySpeaking||(this.isUserCurrentlySpeaking=!0,this.dataChannelMsgSend(new l("start"))),this.digitalHumanSpeaking){let o=this.countWords(n);this.eagerPromptSentForTurn&&o<=this.eagerSentWordCount?t.debug(`${i} Stale same-turn Update during avatar speech (${o} words, eager sent at ${this.eagerSentWordCount}) \u2014 not barge-in`):o>=m?(t.info(`${i} User speech detected during avatar speaking (${o} words) \u2014 interrupting`),this.dataChannelMsgSend(new g),this.clientMsgSend(new v),this.digitalHumanSpeaking=!1):t.debug(`${i} User speech during avatar speaking is only ${o} word(s) \u2014 holding off barge-in (potential backchannel)`)}let s={transcript:n,final:!1,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new h(s))}handleEagerEndOfTurn(e){let n=e.transcript||"";if(t.debug(`${i} EagerEndOfTurn: confidence=${e.end_of_turn_confidence}, transcript_length=${n.length}`),n.trim()==="")return;if(this.digitalHumanSpeaking&&this.countWords(n)<m){t.info(`${i} EagerEndOfTurn: dropping ${this.countWords(n)}-word backchannel while avatar speaking`);return}let s=this.options.eagerMaxTurnDurationMs??0;if(s>0&&this.turnStartedAt!==null){let o=Date.now()-this.turnStartedAt;if(o>s){t.info(`${i} EagerEndOfTurn: suppressed \u2014 turn duration ${o}ms exceeds eagerMaxTurnDurationMs=${s}; deferring to EndOfTurn`);return}}t.info(`${i} EagerEndOfTurn: sending prompt early (${this.countWords(n)} words, ${n.length} chars)`),this.eagerPromptSentForTurn=!0,this.eagerSentWordCount=this.countWords(n),this.sendChatPromptRaw(n,this.takeCancelledEagerRequestId())}takeCancelledEagerRequestId(){let e=this.cancelledEagerRequestId;return this.cancelledEagerRequestId=void 0,e}handleTurnResumed(e){t.debug(`${i} TurnResumed: turn_index=${e.turn_index}`),this.pendingPromptRequest!==null&&(this.cancelledEagerRequestId=this.pendingPromptRequest.requestId),this.eagerPromptSentForTurn&&(t.info(`${i} TurnResumed: cancelling in-flight eager prompt via StopSpeaking`),this.dataChannelMsgSend(new g)),this.clearPendingPromptRequest(),this.eagerPromptSentForTurn=!1}handleEndOfTurn(e){let n=e.transcript||"";if(t.info(`${i} EndOfTurn: transcript_length=${n.length}, confidence=${e.end_of_turn_confidence}`),n.trim()!==""){let s={transcript:n,final:!0,confidence:this.calculateWordConfidence(e.words),language_code:this.options.language||""};this.clientMsgSend(new h(s)),this.digitalHumanSpeaking&&this.countWords(n)<m?(t.info(`${i} EndOfTurn: dropping ${this.countWords(n)}-word backchannel while avatar speaking`),this.clearPendingPromptRequest()):this.eagerPromptSentForTurn?(t.debug(`${i} EndOfTurn: skipping ChatPrompt \u2014 eager already fired for this turn`),this.emitPendingPromptRequest()):(this.sendChatPromptRaw(n,this.takeCancelledEagerRequestId()),this.emitPendingPromptRequest())}this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.cancelledEagerRequestId=void 0,this.resetSpeakingStates()}handleFatalError(e){if(this.state==="Paused"&&e.code==="INACTIVE_CLIENT"){t.info(`${i} Inactivity termination while paused (${e.code}) \u2014 releasing socket; resume will reconnect`),this.releasePausedConnection();return}t.error(`${i} Fatal error from Deepgram: ${e.code} \u2014 ${e.description}`),this.clientMsgSend(new p(`Deepgram error: ${e.code} \u2014 ${e.description}`))}calculateWordConfidence(e){return!e||e.length===0?1:e.reduce((s,o)=>s+o.confidence,0)/e.length}countWords(e){return e.trim().split(/\s+/).filter(Boolean).length}handleAppMessages(){this.options.messages.subscribe(e=>{switch(e.uneeqMessageType){case"AvatarStartedSpeaking":this.digitalHumanSpeaking=!0;break;case"PromptResult":{e.promptResult.success||this.handleSpeakingEnd();break}case"AvatarAnswer":{e.answerSpeech.replace(/<[^>]*>/g,"")===""&&this.handleSpeakingEnd();break}case"AvatarStoppedSpeaking":{this.handleSpeakingEnd();break}case"SessionEnded":{this.shouldReconnect=!1,this.stopRecognition();break}case"SessionReconnecting":{this.handleSpeakingEnd(),this.shouldReconnect=!1,this.stopRecognition();break}case"CustomMetadataUpdated":{this.options.promptMetadata=e.chatMetadata;break}case"SessionBackendError":{this.handleSpeakingEnd();break}default:}})}handleConnectionOpen(){this.state!=="Paused"&&(this.state="Connected")}handleConnectionClose(e){let n=e?.code??"unknown",s=e?.reason??"";if(t.info(`${i} Connection closed \u2014 code=${n}, reason="${s}"`),this.state==="Paused"){t.info(`${i} Connection closed while paused \u2014 will reconnect on resume`),this.connection=null,this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates();return}this.state="Disconnected",this.clearSafetyNet(),this.resetSpeakingStates(),this.eagerPromptSentForTurn=!1,this.turnStartedAt=null,this.pendingPromptRequest=null,this.cancelledEagerRequestId=void 0,this.clientMsgSend(new a(!1)),this.shouldReconnect&&(t.info(`${i} Unexpected disconnect, attempting reconnection...`),this.scheduleReconnect())}emitTransientError(e){let n=e instanceof Error?e.message:String(e);this.clientMsgSend(new b(n))}sendChatPromptRaw(e,n){if(!e||e.trim()==="")return;this.options.language&&(this.options.promptMetadata.userSpokenLocale=this.options.language);let s=n??S();n!==void 0&&t.info(`${i} sendChatPromptRaw: reusing requestId=${s} from cancelled eager prompt`);let o={...this.options.promptMetadata},r=this.turnStartedAt??Date.now(),u=Date.now()-r;this.pendingPromptRequest={prompt:e,requestId:s,metadata:o,speakingDurationMs:u,speechStartedAt:r},this.dataChannelMsgSend(new T(e,this.options.promptMetadata,s,!1))}emitPendingPromptRequest(){let e=this.pendingPromptRequest;e!==null&&(this.clientMsgSend(new y({prompt:e.prompt,requestId:e.requestId,metadata:e.metadata,speakingDurationMs:e.speakingDurationMs,speechStartedAt:e.speechStartedAt})),t.debug(`${i} PromptRequest emitted \u2014 speakingDurationMs=${e.speakingDurationMs}, requestId=${e.requestId}`),this.pendingPromptRequest=null)}clearPendingPromptRequest(){this.pendingPromptRequest=null}handleSpeakingEnd(){this.digitalHumanSpeaking=!1}resetSafetyNet(){this.clearSafetyNet(),(this.isUiShowingSpeaking||this.isUserCurrentlySpeaking)&&(this.safetyNetTimeoutId=setTimeout(()=>{t.warn(`${i} Safety net: no TurnInfo events for ${this.options.safetyNetTimeoutMs}ms while speaking \u2014 resetting`),this.resetSpeakingStates()},this.options.safetyNetTimeoutMs))}clearSafetyNet(){this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null)}releasePausedConnection(){if(this.connection){try{this.connection.close()}catch{}this.connection=null}this.stopMicrophone(),this.clearSafetyNet(),this.resetSpeakingStates(),this.state="Paused"}resetSpeakingStates(){this.isUserCurrentlySpeaking&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new l("stop"))),this.isUiShowingSpeaking&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new M))}dataChannelMsgSend(e){this.options.sendMessage(e)}clientMsgSend(e){this.options.messages.next(e)}};export{w as DeepgramFluxSTT};
@@ -1 +0,0 @@
1
- import{a as b}from"./chunk-KD2RTEWK.js";import{D as p,V as h,W as C,f as t,h as f,j as T,l as g,n as v,o as S,r as k,v as y,w as M}from"./chunk-HXVOCQLA.js";var n="[Deepgram STT]",E=1e4,R=250,U=48e3,$=1e3,D=3e4,N=2,d=5,l=2e3;var m=3,w=class{constructor(e){this.options=e;this.options.model=this.options.model||"nova-3",this.options.language=this.options.language||"en",this.options.smartFormat=this.options.smartFormat??!0,this.options.interimResults=this.options.interimResults??!0,this.options.utteranceEndMs=this.options.utteranceEndMs??1500,this.options.vadEvents=this.options.vadEvents??!0,this.options.fillerWords=this.options.fillerWords??!1,this.options.endpointing=this.options.endpointing??500,this.options.echoCancellation=this.options.echoCancellation??!0,this.options.noiseSuppression=this.options.noiseSuppression??!0,this.options.autoGainControl=this.options.autoGainControl??!0,this.options.interruptionWordThreshold=this.options.interruptionWordThreshold??m,this.options.noDelay=this.options.noDelay??!1,this.options.safetyNetTimeoutMs=this.options.safetyNetTimeoutMs??l,this.options.safetyNetTimeoutMs<=500?(t.warn(`${n} safetyNetTimeoutMs is set to ${this.options.safetyNetTimeoutMs}ms. This is very short and may cause premature transcript finalization. Ignoring and default the value to ${l}ms.`),this.options.safetyNetTimeoutMs=l):this.options.safetyNetTimeoutMs<=1e3?t.warn(`${n} safetyNetTimeoutMs is set to ${this.options.safetyNetTimeoutMs}ms. This is very short and may cause premature transcript finalization. Recommended value is ${l}ms.`):t.info(`${n} safetyNetTimeoutMs is set to ${this.options.safetyNetTimeoutMs}ms.`),this.handleAppMessages()}options;connection=null;state="Idle";shouldReconnect=!0;microphone=null;stream=null;reconnectAttempts=0;reconnectDelay=$;reconnectTimeoutId=null;digitalHumanSpeaking=!1;isUserCurrentlySpeaking=!1;isUiShowingSpeaking=!1;accumulatedTranscript="";accumulatedConfidenceSum=0;accumulatedWordCount=0;lastDeepgramEventTime=0;safetyNetTimeoutId=null;async startRecognition(){t.info(`${n} Starting speech recognition`),this.shouldReconnect=!0,this.resetReconnectionState(),await this.connect()}async stopRecognition(){t.info(`${n} Stopping speech recognition`),this.shouldReconnect=!1,this.clearReconnectTimeout(),await this.disconnect()}async pause(){return t.info(`${n} Pausing speech recognition`),this.state="Paused",this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),this.resetAccumulatedState(),this.resetSpeakingStates(),this.stream&&(this.stream.getTracks().forEach(e=>{e.enabled=!1}),t.debug(`${n} Audio tracks disabled`)),!0}async resume(){if(t.info(`${n} Resuming speech recognition`),this.state==="Paused"){if(this.stream)return this.state="Connected",this.stream.getTracks().forEach(e=>{e.enabled=!0}),t.debug(`${n} Audio tracks re-enabled`),!0;if(this.connection)return this.state="Connected",await this.startMicrophone(),!0;this.state="Disconnected"}return t.debug(`${n} Initiating connection`),await this.connect(),!0}setChatMetadata(e){this.options.promptMetadata=e}async connect(){if(this.state==="Connected"){t.warn(`${n} Already connected`);return}if(this.state==="Connecting"){t.warn(`${n} Connection already in progress`);return}this.state="Connecting";try{let e=await this.getToken();t.info(`${n} Connecting to Deepgram`);let i=new b({accessToken:e.token,baseUrl:e.api_url}),a={model:this.options.model,language:this.options.language,smart_format:String(this.options.smartFormat),interim_results:String(this.options.interimResults),utterance_end_ms:this.options.utteranceEndMs,vad_events:String(this.options.vadEvents),filler_words:String(this.options.fillerWords),endpointing:this.options.endpointing,mip_opt_out:"true",...this.options.keyterms&&this.options.keyterms.length>0&&{keyterm:this.options.keyterms},...this.options.noDelay&&{queryParams:{no_delay:"true"}}},s=i.listen;if(this.connection=await s.v1.connect(a),this.connection.connect(),await Promise.race([this.connection.waitForOpen(),new Promise((o,r)=>setTimeout(()=>r(new Error("Connection timeout")),E))]),this.state!=="Paused"&&this.state!=="Disconnected"&&(this.state="Connected"),t.info(`${n} Connection opened`),this.setupEventHandlers(),this.state==="Paused"){t.info(`${n} Pause requested during connection \u2014 staying paused`),this.resetReconnectionState();return}if(this.state==="Disconnected"){t.info(`${n} Recognition stopped during connection \u2014 aborting`),this.connection&&(this.connection.close(),this.connection=null);return}await this.startMicrophone(),t.info(`${n} Connected successfully`),this.resetReconnectionState()}catch(e){this.state="Disconnected",t.error(`${n} Connection error`,t.serialiseError(e)),this.shouldReconnect&&(this.emitTransientError(e),this.scheduleReconnect())}}async disconnect(){if(!(this.state==="Idle"||this.state==="Disconnected"&&!this.connection)){t.info(`${n} Disconnecting`),this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null);try{this.stopMicrophone(),this.connection&&(this.connection.close(),this.connection=null)}catch(e){t.error(`${n} Disconnect error`,t.serialiseError(e))}this.resetAccumulatedState(),this.resetSpeakingStates(),this.state="Disconnected",this.clientMsgSend(new p(!1))}}scheduleReconnect(){if(this.reconnectAttempts>=d){t.error(`${n} Max reconnection attempts (${d}) reached`),this.clientMsgSend(new y(`Unable to connect to speech recognition service after ${d} attempts`));return}this.reconnectAttempts++,t.info(`${n} Scheduling reconnection attempt ${this.reconnectAttempts}/${d} in ${this.reconnectDelay}ms`),this.reconnectTimeoutId=setTimeout(()=>{this.connect()},this.reconnectDelay),this.reconnectDelay=Math.min(this.reconnectDelay*N,D)}resetReconnectionState(){this.reconnectAttempts=0,this.reconnectDelay=$,this.clearReconnectTimeout()}clearReconnectTimeout(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=null)}async getToken(){let e=this.options.model||"nova-3",i=`${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(e)}`,a=await fetch(i,{method:"GET",headers:{Authorization:`Bearer ${this.options.jwtToken}`,"Content-Type":"application/json"}});if(!a.ok)throw new Error(`Token fetch failed: ${a.status} ${a.statusText}`);return await a.json()}async startMicrophone(){try{if(t.info(`${n} Starting microphone`),this.stopMicrophone(),!navigator.mediaDevices?.getUserMedia)throw new Error("Microphone access is not available in this context");if(this.stream=await navigator.mediaDevices.getUserMedia({audio:{deviceId:this.options.microphoneDeviceId?{exact:this.options.microphoneDeviceId}:void 0,echoCancellation:this.options.echoCancellation,noiseSuppression:this.options.noiseSuppression,autoGainControl:this.options.autoGainControl}}),this.state==="Paused"){t.info(`${n} Paused during getUserMedia \u2014 keeping stream but disabling tracks`),this.stream.getTracks().forEach(e=>{e.enabled=!1});return}if(this.state==="Disconnected"){t.info(`${n} Recognition stopped during getUserMedia \u2014 releasing stream`),this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null;return}this.microphone=new MediaRecorder(this.stream,{mimeType:"audio/webm;codecs=opus",audioBitsPerSecond:U}),this.microphone.ondataavailable=e=>{e.data.size>0&&this.connection&&this.state==="Connected"&&e.data.arrayBuffer().then(i=>{this.connection?.sendMedia(i)}).catch(i=>{t.error(`${n} Error converting audio data`,t.serialiseError(i))})},this.microphone.start(R),t.debug(`${n} Microphone started`),this.clientMsgSend(new p(!0))}catch(e){t.error(`${n} Microphone error`,t.serialiseError(e)),this.clientMsgSend(new T(new Error(JSON.stringify(e))))}}stopMicrophone(){this.microphone&&this.microphone.state==="recording"&&(this.microphone.stop(),this.microphone=null),this.stream&&(this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null),t.debug(`${n} Microphone stopped`)}setupEventHandlers(){this.connection&&(this.connection.on("open",()=>{this.handleConnectionOpen()}),this.connection.on("message",e=>{if(e!==null&&typeof e=="object"&&"type"in e){let i=e;i.type==="Results"?this.handleTranscript(e):i.type==="UtteranceEnd"?this.handleUtteranceEnd(e):i.type==="Metadata"&&t.debug(`${n} Metadata`,e)}}),this.connection.on("close",()=>{this.handleConnectionClose()}),this.connection.on("error",e=>{t.error(`${n} WebSocket error event`,t.serialiseError(e)),this.emitTransientError(e)}))}handleAppMessages(){this.options.messages.subscribe(e=>{switch(e.uneeqMessageType){case"AvatarStartedSpeaking":this.digitalHumanSpeaking=!0;break;case"PromptResult":{e.promptResult.success||this.handleSpeakingEnd();break}case"AvatarAnswer":{e.answerSpeech.replace(/<[^>]*>/g,"")===""&&this.handleSpeakingEnd();break}case"AvatarStoppedSpeaking":{this.handleSpeakingEnd();break}case"SessionEnded":{this.shouldReconnect=!1,this.stopRecognition();break}case"SessionReconnecting":{this.handleSpeakingEnd(),this.pause();break}case"CustomMetadataUpdated":{this.options.promptMetadata=e.chatMetadata;break}case"SessionBackendError":{this.handleSpeakingEnd();break}default:}})}handleTranscript(e){try{this.lastDeepgramEventTime=Date.now();let i=e.channel;if(!i?.alternatives||i.alternatives.length===0)return;let a=i.alternatives[0],s=String(a.transcript||""),o=e.is_final,r=e.speech_final;if(t.debug(`${n} Transcript event: is_final=${o}, speech_final=${r}, transcript="${s.substring(0,50)}${s.length>50?"...":""}", accumulated="${this.accumulatedTranscript.substring(0,30)}${this.accumulatedTranscript.length>30?"...":""}", uiSpeaking=${this.isUiShowingSpeaking}, userSpeaking=${this.isUserCurrentlySpeaking}`),s===""&&r){this.endsWithPunctuation(this.accumulatedTranscript)?(this.sendAccumulatedTranscript("Final transcript (from accumulated)"),this.resetSpeakingStates()):t.debug(`${n} speech_final with empty transcript but no punctuation, waiting for more speech or safety net`);return}if(s==="")return;this.processTranscriptChunk(s,a.confidence,o,r),this.updateSpeakingAndInterruptionState(s,r),this.emitTranscriptionResult(s,a.confidence,r),this.resetSafetyNetTimeout()}catch(i){t.error(`${n} Error processing transcript`,t.serialiseError(i))}}processTranscriptChunk(e,i,a,s){if(a&&!s){this.accumulatedTranscript!==""&&(this.accumulatedTranscript+=" "),this.accumulatedTranscript+=e;let o=e.trim().split(/\s+/).length,r=i??1;this.accumulatedConfidenceSum+=r*o,this.accumulatedWordCount+=o,t.debug(`${n} Accumulated transcript: "${this.accumulatedTranscript}"`)}}updateSpeakingAndInterruptionState(e,i){let s=(this.accumulatedTranscript!==""?this.accumulatedTranscript:e).trim().split(/\s+/).length,o=this.options.interruptionWordThreshold??m;this.isUiShowingSpeaking||(this.isUiShowingSpeaking=!0,this.clientMsgSend(new v));let r=!this.digitalHumanSpeaking||s>=o,c=this.accumulatedTranscript!==""?this.accumulatedTranscript+" "+e:e,u=i&&this.endsWithPunctuation(c);!this.isUserCurrentlySpeaking&&r&&(this.isUserCurrentlySpeaking=!0,this.dataChannelMsgSend(new h("start"))),this.digitalHumanSpeaking&&s>=o&&(t.debug(`${n} Interrupting digital human`),this.dataChannelMsgSend(new C),this.clientMsgSend(new k),this.digitalHumanSpeaking=!1),this.isUserCurrentlySpeaking&&u&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new h("stop"))),this.isUiShowingSpeaking&&u&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new S))}emitTranscriptionResult(e,i,a){let s=this.accumulatedTranscript!==""?this.accumulatedTranscript+" "+e:e,o=a&&this.endsWithPunctuation(s),r={transcript:a?s:e,final:o,confidence:i??1,language_code:this.options.language||""};if(this.clientMsgSend(new g(r)),o){let c=s.trim().split(/\s+/).length,u=this.options.interruptionWordThreshold??m;this.digitalHumanSpeaking&&c<u?t.debug(`${n} Discarding utterance during speaking (${c} words < ${u} threshold): "${s}"`):(t.info(`${n} Final transcript: "${s}"`),this.sendChatPrompt(s)),this.resetAccumulatedState()}else if(a){this.accumulatedTranscript!==""&&(this.accumulatedTranscript+=" "),this.accumulatedTranscript+=e;let c=e.trim().split(/\s+/).length;this.accumulatedConfidenceSum+=(i??1)*c,this.accumulatedWordCount+=c,t.debug(`${n} speech_final without punctuation, accumulated for safety net: "${this.accumulatedTranscript}"`)}}handleUtteranceEnd(e){this.lastDeepgramEventTime=Date.now(),t.debug(`${n} UtteranceEnd event received: last_word_end=${e?.last_word_end}, accumulated="${this.accumulatedTranscript.substring(0,50)}...", uiSpeaking=${this.isUiShowingSpeaking}, userSpeaking=${this.isUserCurrentlySpeaking}`),this.accumulatedTranscript.trim()!==""?this.endsWithPunctuation(this.accumulatedTranscript)?(this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),t.debug(`${n} UtteranceEnd fallback triggered with transcript: "${this.accumulatedTranscript}"`),this.sendAccumulatedTranscript("UtteranceEnd fallback"),this.resetSpeakingStates(),t.debug(`${n} UtteranceEnd: reset speaking states`)):t.debug(`${n} UtteranceEnd: no punctuation, waiting for more speech or safety net`):(this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),this.resetSpeakingStates(),t.debug(`${n} UtteranceEnd: no transcript, reset speaking states`))}resetSafetyNetTimeout(){this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),(this.isUiShowingSpeaking||this.isUserCurrentlySpeaking)&&this.accumulatedTranscript.trim()!==""&&(this.safetyNetTimeoutId=setTimeout(()=>{this.triggerSafetyNet()},this.options.safetyNetTimeoutMs))}triggerSafetyNet(){t.warn(`${n} Safety net triggered: no Deepgram events for ${this.options.safetyNetTimeoutMs}ms while speaking`),t.debug(`${n} Safety net triggered: accumulated="${this.accumulatedTranscript}", uiSpeaking=${this.isUiShowingSpeaking}, userSpeaking=${this.isUserCurrentlySpeaking}, timeSinceLastEvent=${Date.now()-this.lastDeepgramEventTime}ms`),this.sendAccumulatedTranscript("Safety net"),this.resetSpeakingStates(),this.safetyNetTimeoutId=null}sendAccumulatedTranscript(e){if(this.accumulatedTranscript.trim()==="")return;if(e!=="Safety net"&&!this.endsWithPunctuation(this.accumulatedTranscript)){t.debug(`${n} sendAccumulatedTranscript: not sending as source is ${e} and transcript doesn't end in punctuation: "${this.accumulatedTranscript}"`);return}let i=this.options.interruptionWordThreshold??m,a=this.accumulatedWordCount>0?this.accumulatedConfidenceSum/this.accumulatedWordCount:1,s={transcript:this.accumulatedTranscript,final:!0,confidence:a,language_code:this.options.language||""};this.clientMsgSend(new g(s));let o=this.accumulatedTranscript.trim().split(/\s+/).length;this.digitalHumanSpeaking&&o<i?t.debug(`${n} Discarding utterance during speaking (${o} words < ${i} threshold): "${this.accumulatedTranscript}"`):(t.info(`${n} ${e}: "${this.accumulatedTranscript}"`),this.sendChatPrompt(this.accumulatedTranscript)),this.resetAccumulatedState()}endsWithPunctuation(e){let i=e.trim();return i.length===0?!1:/[.!?;:]$/.test(i)}resetAccumulatedState(){this.accumulatedTranscript="",this.accumulatedConfidenceSum=0,this.accumulatedWordCount=0}resetSpeakingStates(){this.isUserCurrentlySpeaking&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new h("stop"))),this.isUiShowingSpeaking&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new S))}handleConnectionOpen(){this.state!=="Paused"&&(this.state="Connected")}handleConnectionClose(){if(t.info(`${n} Connection closed`),this.state==="Paused"){t.info(`${n} Connection closed while paused \u2014 will reconnect on resume`),this.connection=null,this.stopMicrophone();return}this.state="Disconnected",this.clientMsgSend(new p(!1)),this.shouldReconnect&&(t.info(`${n} Unexpected disconnect, attempting reconnection...`),this.scheduleReconnect())}sendChatPrompt(e){e&&e.trim()!==""&&(this.options.language&&(this.options.promptMetadata.userSpokenLocale=this.options.language),this.dataChannelMsgSend(new f(e,this.options.promptMetadata)))}handleSpeakingEnd(){this.digitalHumanSpeaking=!1}emitTransientError(e){let i=e instanceof Error?e.message:String(e);this.clientMsgSend(new M(i))}dataChannelMsgSend(e){this.options.sendMessage(e)}clientMsgSend(e){this.options.messages.next(e)}};export{w as DeepgramSTT};
@@ -1 +0,0 @@
1
- import{a as b}from"./chunk-5UQJPIVZ.js";import{D as p,U as h,V as C,f as t,h as f,j as T,l as g,n as v,o as S,r as k,v as y,w as M}from"./chunk-KSAOQLXO.js";var n="[Deepgram STT]",E=1e4,R=250,U=48e3,$=1e3,D=3e4,N=2,d=5,l=2e3;var m=3,w=class{constructor(e){this.options=e;this.options.model=this.options.model||"nova-3",this.options.language=this.options.language||"en",this.options.smartFormat=this.options.smartFormat??!0,this.options.interimResults=this.options.interimResults??!0,this.options.utteranceEndMs=this.options.utteranceEndMs??1500,this.options.vadEvents=this.options.vadEvents??!0,this.options.fillerWords=this.options.fillerWords??!1,this.options.endpointing=this.options.endpointing??500,this.options.echoCancellation=this.options.echoCancellation??!0,this.options.noiseSuppression=this.options.noiseSuppression??!0,this.options.autoGainControl=this.options.autoGainControl??!0,this.options.interruptionWordThreshold=this.options.interruptionWordThreshold??m,this.options.noDelay=this.options.noDelay??!1,this.options.safetyNetTimeoutMs=this.options.safetyNetTimeoutMs??l,this.options.safetyNetTimeoutMs<=500?(t.warn(`${n} safetyNetTimeoutMs is set to ${this.options.safetyNetTimeoutMs}ms. This is very short and may cause premature transcript finalization. Ignoring and default the value to ${l}ms.`),this.options.safetyNetTimeoutMs=l):this.options.safetyNetTimeoutMs<=1e3?t.warn(`${n} safetyNetTimeoutMs is set to ${this.options.safetyNetTimeoutMs}ms. This is very short and may cause premature transcript finalization. Recommended value is ${l}ms.`):t.info(`${n} safetyNetTimeoutMs is set to ${this.options.safetyNetTimeoutMs}ms.`),this.handleAppMessages()}options;connection=null;state="Idle";shouldReconnect=!0;microphone=null;stream=null;reconnectAttempts=0;reconnectDelay=$;reconnectTimeoutId=null;digitalHumanSpeaking=!1;isUserCurrentlySpeaking=!1;isUiShowingSpeaking=!1;accumulatedTranscript="";accumulatedConfidenceSum=0;accumulatedWordCount=0;lastDeepgramEventTime=0;safetyNetTimeoutId=null;async startRecognition(){t.info(`${n} Starting speech recognition`),this.shouldReconnect=!0,this.resetReconnectionState(),await this.connect()}async stopRecognition(){t.info(`${n} Stopping speech recognition`),this.shouldReconnect=!1,this.clearReconnectTimeout(),await this.disconnect()}async pause(){return t.info(`${n} Pausing speech recognition`),this.state="Paused",this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),this.resetAccumulatedState(),this.resetSpeakingStates(),this.stream&&(this.stream.getTracks().forEach(e=>{e.enabled=!1}),t.debug(`${n} Audio tracks disabled`)),!0}async resume(){if(t.info(`${n} Resuming speech recognition`),this.state==="Paused"){if(this.stream)return this.state="Connected",this.stream.getTracks().forEach(e=>{e.enabled=!0}),t.debug(`${n} Audio tracks re-enabled`),!0;if(this.connection)return this.state="Connected",await this.startMicrophone(),!0;this.state="Disconnected"}return t.debug(`${n} Initiating connection`),await this.connect(),!0}setChatMetadata(e){this.options.promptMetadata=e}async connect(){if(this.state==="Connected"){t.warn(`${n} Already connected`);return}if(this.state==="Connecting"){t.warn(`${n} Connection already in progress`);return}this.state="Connecting";try{let e=await this.getToken();t.info(`${n} Connecting to Deepgram`);let i=new b({accessToken:e.token,baseUrl:e.api_url}),a={model:this.options.model,language:this.options.language,smart_format:String(this.options.smartFormat),interim_results:String(this.options.interimResults),utterance_end_ms:this.options.utteranceEndMs,vad_events:String(this.options.vadEvents),filler_words:String(this.options.fillerWords),endpointing:this.options.endpointing,mip_opt_out:"true",...this.options.keyterms&&this.options.keyterms.length>0&&{keyterm:this.options.keyterms},...this.options.noDelay&&{queryParams:{no_delay:"true"}}},s=i.listen;if(this.connection=await s.v1.connect(a),this.connection.connect(),await Promise.race([this.connection.waitForOpen(),new Promise((o,r)=>setTimeout(()=>r(new Error("Connection timeout")),E))]),this.state!=="Paused"&&this.state!=="Disconnected"&&(this.state="Connected"),t.info(`${n} Connection opened`),this.setupEventHandlers(),this.state==="Paused"){t.info(`${n} Pause requested during connection \u2014 staying paused`),this.resetReconnectionState();return}if(this.state==="Disconnected"){t.info(`${n} Recognition stopped during connection \u2014 aborting`),this.connection&&(this.connection.close(),this.connection=null);return}await this.startMicrophone(),t.info(`${n} Connected successfully`),this.resetReconnectionState()}catch(e){this.state="Disconnected",t.error(`${n} Connection error`,t.serialiseError(e)),this.shouldReconnect&&(this.emitTransientError(e),this.scheduleReconnect())}}async disconnect(){if(!(this.state==="Idle"||this.state==="Disconnected"&&!this.connection)){t.info(`${n} Disconnecting`),this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null);try{this.stopMicrophone(),this.connection&&(this.connection.close(),this.connection=null)}catch(e){t.error(`${n} Disconnect error`,t.serialiseError(e))}this.resetAccumulatedState(),this.resetSpeakingStates(),this.state="Disconnected",this.clientMsgSend(new p(!1))}}scheduleReconnect(){if(this.reconnectAttempts>=d){t.error(`${n} Max reconnection attempts (${d}) reached`),this.clientMsgSend(new y(`Unable to connect to speech recognition service after ${d} attempts`));return}this.reconnectAttempts++,t.info(`${n} Scheduling reconnection attempt ${this.reconnectAttempts}/${d} in ${this.reconnectDelay}ms`),this.reconnectTimeoutId=setTimeout(()=>{this.connect()},this.reconnectDelay),this.reconnectDelay=Math.min(this.reconnectDelay*N,D)}resetReconnectionState(){this.reconnectAttempts=0,this.reconnectDelay=$,this.clearReconnectTimeout()}clearReconnectTimeout(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=null)}async getToken(){let e=this.options.model||"nova-3",i=`${this.options.connectionUrl}/speech-recognition-service/deepgram/token?model=${encodeURIComponent(e)}`,a=await fetch(i,{method:"GET",headers:{Authorization:`Bearer ${this.options.jwtToken}`,"Content-Type":"application/json"}});if(!a.ok)throw new Error(`Token fetch failed: ${a.status} ${a.statusText}`);return await a.json()}async startMicrophone(){try{if(t.info(`${n} Starting microphone`),this.stopMicrophone(),!navigator.mediaDevices?.getUserMedia)throw new Error("Microphone access is not available in this context");if(this.stream=await navigator.mediaDevices.getUserMedia({audio:{deviceId:this.options.microphoneDeviceId?{exact:this.options.microphoneDeviceId}:void 0,echoCancellation:this.options.echoCancellation,noiseSuppression:this.options.noiseSuppression,autoGainControl:this.options.autoGainControl}}),this.state==="Paused"){t.info(`${n} Paused during getUserMedia \u2014 keeping stream but disabling tracks`),this.stream.getTracks().forEach(e=>{e.enabled=!1});return}if(this.state==="Disconnected"){t.info(`${n} Recognition stopped during getUserMedia \u2014 releasing stream`),this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null;return}this.microphone=new MediaRecorder(this.stream,{mimeType:"audio/webm;codecs=opus",audioBitsPerSecond:U}),this.microphone.ondataavailable=e=>{e.data.size>0&&this.connection&&this.state==="Connected"&&e.data.arrayBuffer().then(i=>{this.connection?.sendMedia(i)}).catch(i=>{t.error(`${n} Error converting audio data`,t.serialiseError(i))})},this.microphone.start(R),t.debug(`${n} Microphone started`),this.clientMsgSend(new p(!0))}catch(e){t.error(`${n} Microphone error`,t.serialiseError(e)),this.clientMsgSend(new T(new Error(JSON.stringify(e))))}}stopMicrophone(){this.microphone&&this.microphone.state==="recording"&&(this.microphone.stop(),this.microphone=null),this.stream&&(this.stream.getTracks().forEach(e=>{e.stop()}),this.stream=null),t.debug(`${n} Microphone stopped`)}setupEventHandlers(){this.connection&&(this.connection.on("open",()=>{this.handleConnectionOpen()}),this.connection.on("message",e=>{if(e!==null&&typeof e=="object"&&"type"in e){let i=e;i.type==="Results"?this.handleTranscript(e):i.type==="UtteranceEnd"?this.handleUtteranceEnd(e):i.type==="Metadata"&&t.debug(`${n} Metadata`,e)}}),this.connection.on("close",()=>{this.handleConnectionClose()}),this.connection.on("error",e=>{t.error(`${n} WebSocket error event`,t.serialiseError(e)),this.emitTransientError(e)}))}handleAppMessages(){this.options.messages.subscribe(e=>{switch(e.uneeqMessageType){case"AvatarStartedSpeaking":this.digitalHumanSpeaking=!0;break;case"PromptResult":{e.promptResult.success||this.handleSpeakingEnd();break}case"AvatarAnswer":{e.answerSpeech.replace(/<[^>]*>/g,"")===""&&this.handleSpeakingEnd();break}case"AvatarStoppedSpeaking":{this.handleSpeakingEnd();break}case"SessionEnded":{this.shouldReconnect=!1,this.stopRecognition();break}case"SessionReconnecting":{this.handleSpeakingEnd(),this.pause();break}case"CustomMetadataUpdated":{this.options.promptMetadata=e.chatMetadata;break}case"SessionBackendError":{this.handleSpeakingEnd();break}default:}})}handleTranscript(e){try{this.lastDeepgramEventTime=Date.now();let i=e.channel;if(!i?.alternatives||i.alternatives.length===0)return;let a=i.alternatives[0],s=String(a.transcript||""),o=e.is_final,r=e.speech_final;if(t.debug(`${n} Transcript event: is_final=${o}, speech_final=${r}, transcript="${s.substring(0,50)}${s.length>50?"...":""}", accumulated="${this.accumulatedTranscript.substring(0,30)}${this.accumulatedTranscript.length>30?"...":""}", uiSpeaking=${this.isUiShowingSpeaking}, userSpeaking=${this.isUserCurrentlySpeaking}`),s===""&&r){this.endsWithPunctuation(this.accumulatedTranscript)?(this.sendAccumulatedTranscript("Final transcript (from accumulated)"),this.resetSpeakingStates()):t.debug(`${n} speech_final with empty transcript but no punctuation, waiting for more speech or safety net`);return}if(s==="")return;this.processTranscriptChunk(s,a.confidence,o,r),this.updateSpeakingAndInterruptionState(s,r),this.emitTranscriptionResult(s,a.confidence,r),this.resetSafetyNetTimeout()}catch(i){t.error(`${n} Error processing transcript`,t.serialiseError(i))}}processTranscriptChunk(e,i,a,s){if(a&&!s){this.accumulatedTranscript!==""&&(this.accumulatedTranscript+=" "),this.accumulatedTranscript+=e;let o=e.trim().split(/\s+/).length,r=i??1;this.accumulatedConfidenceSum+=r*o,this.accumulatedWordCount+=o,t.debug(`${n} Accumulated transcript: "${this.accumulatedTranscript}"`)}}updateSpeakingAndInterruptionState(e,i){let s=(this.accumulatedTranscript!==""?this.accumulatedTranscript:e).trim().split(/\s+/).length,o=this.options.interruptionWordThreshold??m;this.isUiShowingSpeaking||(this.isUiShowingSpeaking=!0,this.clientMsgSend(new v));let r=!this.digitalHumanSpeaking||s>=o,c=this.accumulatedTranscript!==""?this.accumulatedTranscript+" "+e:e,u=i&&this.endsWithPunctuation(c);!this.isUserCurrentlySpeaking&&r&&(this.isUserCurrentlySpeaking=!0,this.dataChannelMsgSend(new h("start"))),this.digitalHumanSpeaking&&s>=o&&(t.debug(`${n} Interrupting digital human`),this.dataChannelMsgSend(new C),this.clientMsgSend(new k),this.digitalHumanSpeaking=!1),this.isUserCurrentlySpeaking&&u&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new h("stop"))),this.isUiShowingSpeaking&&u&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new S))}emitTranscriptionResult(e,i,a){let s=this.accumulatedTranscript!==""?this.accumulatedTranscript+" "+e:e,o=a&&this.endsWithPunctuation(s),r={transcript:a?s:e,final:o,confidence:i??1,language_code:this.options.language||""};if(this.clientMsgSend(new g(r)),o){let c=s.trim().split(/\s+/).length,u=this.options.interruptionWordThreshold??m;this.digitalHumanSpeaking&&c<u?t.debug(`${n} Discarding utterance during speaking (${c} words < ${u} threshold): "${s}"`):(t.info(`${n} Final transcript: "${s}"`),this.sendChatPrompt(s)),this.resetAccumulatedState()}else if(a){this.accumulatedTranscript!==""&&(this.accumulatedTranscript+=" "),this.accumulatedTranscript+=e;let c=e.trim().split(/\s+/).length;this.accumulatedConfidenceSum+=(i??1)*c,this.accumulatedWordCount+=c,t.debug(`${n} speech_final without punctuation, accumulated for safety net: "${this.accumulatedTranscript}"`)}}handleUtteranceEnd(e){this.lastDeepgramEventTime=Date.now(),t.debug(`${n} UtteranceEnd event received: last_word_end=${e?.last_word_end}, accumulated="${this.accumulatedTranscript.substring(0,50)}...", uiSpeaking=${this.isUiShowingSpeaking}, userSpeaking=${this.isUserCurrentlySpeaking}`),this.accumulatedTranscript.trim()!==""?this.endsWithPunctuation(this.accumulatedTranscript)?(this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),t.debug(`${n} UtteranceEnd fallback triggered with transcript: "${this.accumulatedTranscript}"`),this.sendAccumulatedTranscript("UtteranceEnd fallback"),this.resetSpeakingStates(),t.debug(`${n} UtteranceEnd: reset speaking states`)):t.debug(`${n} UtteranceEnd: no punctuation, waiting for more speech or safety net`):(this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),this.resetSpeakingStates(),t.debug(`${n} UtteranceEnd: no transcript, reset speaking states`))}resetSafetyNetTimeout(){this.safetyNetTimeoutId&&(clearTimeout(this.safetyNetTimeoutId),this.safetyNetTimeoutId=null),(this.isUiShowingSpeaking||this.isUserCurrentlySpeaking)&&this.accumulatedTranscript.trim()!==""&&(this.safetyNetTimeoutId=setTimeout(()=>{this.triggerSafetyNet()},this.options.safetyNetTimeoutMs))}triggerSafetyNet(){t.warn(`${n} Safety net triggered: no Deepgram events for ${this.options.safetyNetTimeoutMs}ms while speaking`),t.debug(`${n} Safety net triggered: accumulated="${this.accumulatedTranscript}", uiSpeaking=${this.isUiShowingSpeaking}, userSpeaking=${this.isUserCurrentlySpeaking}, timeSinceLastEvent=${Date.now()-this.lastDeepgramEventTime}ms`),this.sendAccumulatedTranscript("Safety net"),this.resetSpeakingStates(),this.safetyNetTimeoutId=null}sendAccumulatedTranscript(e){if(this.accumulatedTranscript.trim()==="")return;if(e!=="Safety net"&&!this.endsWithPunctuation(this.accumulatedTranscript)){t.debug(`${n} sendAccumulatedTranscript: not sending as source is ${e} and transcript doesn't end in punctuation: "${this.accumulatedTranscript}"`);return}let i=this.options.interruptionWordThreshold??m,a=this.accumulatedWordCount>0?this.accumulatedConfidenceSum/this.accumulatedWordCount:1,s={transcript:this.accumulatedTranscript,final:!0,confidence:a,language_code:this.options.language||""};this.clientMsgSend(new g(s));let o=this.accumulatedTranscript.trim().split(/\s+/).length;this.digitalHumanSpeaking&&o<i?t.debug(`${n} Discarding utterance during speaking (${o} words < ${i} threshold): "${this.accumulatedTranscript}"`):(t.info(`${n} ${e}: "${this.accumulatedTranscript}"`),this.sendChatPrompt(this.accumulatedTranscript)),this.resetAccumulatedState()}endsWithPunctuation(e){let i=e.trim();return i.length===0?!1:/[.!?;:]$/.test(i)}resetAccumulatedState(){this.accumulatedTranscript="",this.accumulatedConfidenceSum=0,this.accumulatedWordCount=0}resetSpeakingStates(){this.isUserCurrentlySpeaking&&(this.isUserCurrentlySpeaking=!1,this.dataChannelMsgSend(new h("stop"))),this.isUiShowingSpeaking&&(this.isUiShowingSpeaking=!1,this.clientMsgSend(new S))}handleConnectionOpen(){this.state!=="Paused"&&(this.state="Connected")}handleConnectionClose(){if(t.info(`${n} Connection closed`),this.state==="Paused"){t.info(`${n} Connection closed while paused \u2014 will reconnect on resume`),this.connection=null,this.stopMicrophone();return}this.state="Disconnected",this.clientMsgSend(new p(!1)),this.shouldReconnect&&(t.info(`${n} Unexpected disconnect, attempting reconnection...`),this.scheduleReconnect())}sendChatPrompt(e){e&&e.trim()!==""&&(this.options.language&&(this.options.promptMetadata.userSpokenLocale=this.options.language),this.dataChannelMsgSend(new f(e,this.options.promptMetadata)))}handleSpeakingEnd(){this.digitalHumanSpeaking=!1}emitTransientError(e){let i=e instanceof Error?e.message:String(e);this.clientMsgSend(new M(i))}dataChannelMsgSend(e){this.options.sendMessage(e)}clientMsgSend(e){this.options.messages.next(e)}};export{w as DeepgramSTT};