@absolutejs/voice 0.0.22-beta.597 → 0.0.22-beta.599
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/index.js +6 -127
- package/dist/client/htmxBootstrap.js +6 -12
- package/dist/client/index.js +6 -127
- package/dist/core/semanticTurn.d.ts +11 -1
- package/dist/core/turnDetection.d.ts +1 -1
- package/dist/core/types.d.ts +2 -4
- package/dist/embed/index.js +6 -12
- package/dist/embed/voice-widget.js +8 -8
- package/dist/index.js +171 -184
- package/dist/react/index.js +6 -127
- package/dist/svelte/index.js +6 -127
- package/dist/testing/index.js +42 -57
- package/dist/vue/index.js +6 -127
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(()=>{var{defineProperty:E,getOwnPropertyNames:I0,getOwnPropertyDescriptor:H0}=Object,_0=Object.prototype.hasOwnProperty;function G0(g){return this[g]}var L0=(g)=>{var A=(x??=new WeakMap).get(g),C;if(A)return A;if(A=E({},"__esModule",{value:!0}),g&&typeof g==="object"||typeof g==="function"){for(var V of I0(g))if(!_0.call(A,V))E(A,V,{get:G0.bind(g,V),enumerable:!(C=H0(g,V))||C.enumerable})}return x.set(g,A),A},x;var U0=(g)=>g;function w0(g,A){this[g]=U0.bind(null,A)}var y0=(g,A)=>{for(var C in A)E(g,C,{get:A[C],enumerable:!0,configurable:!0,set:w0.bind(A,C)})};var r0={};y0(r0,{mount:()=>V0,default:()=>s0,VOICE_EMBED_VERSION:()=>C0});var X0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},h0=(g,A,C,V)=>{let I=A??g.getAttribute("hx-get")??"";if(!I)return"";let R=new URL(I,window.location.origin);if(V)R.searchParams.set(C,V);else R.searchParams.delete(C);return`${R.pathname}${R.search}${R.hash}`},F=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=X0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",I=A.sessionQueryParam??"sessionId",R=()=>{let L=window,$=h0(C,A.route,I,g.sessionId);if($)C.setAttribute("hx-get",$);L.htmx?.process?.(C),L.htmx?.trigger?.(C,V)},w=g.subscribe(R);return R(),()=>{w()}};var D0=(g)=>Math.max(-1,Math.min(1,g)),J0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=D0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},Y0=(g)=>{let A=g instanceof Uint8Array?g:new Uint8Array(g);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let V=0;for(let I of C){let R=I/32768;V+=R*R}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},Z0=(g,A,C)=>{if(A===C)return g;let V=A/C,I=Math.round(g.length/V),R=new Float32Array(I),w=0,L=0;while(w<R.length){let $=Math.round((w+1)*V),X=0,G=0;for(let h=L;h<$&&h<g.length;h+=1)X+=g[h]??0,G+=1;R[w]=G>0?X/G:0,w+=1,L=$}return R},f=(g)=>{let A=null,C=null,V=null,I=null;return{start:async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let L=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!L)throw Error("Browser microphone capture requires AudioContext support.");if(I=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new L,A.state==="suspended")await A.resume();C=A.createMediaStreamSource(I),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=($)=>{let X=$.inputBuffer.getChannelData(0),G=Z0(X,A?.sampleRate??48000,g.sampleRateHz??16000),h=J0(G);g.onLevel?.(Y0(h)),g.onAudio(h)},C.connect(V),V.connect(A.destination)},stop:()=>{V?.disconnect(),C?.disconnect(),I?.getTracks().forEach((L)=>L.stop()),A?.close(),g.onLevel?.(0),A=null,I=null,V=null,C=null}}};var M=(g)=>{if(typeof g==="string"&&g.trim())return g;if(g instanceof Error&&g.message.trim())return g.message;if(g&&typeof g==="object"){let A=g;for(let C of["message","reason","description"]){let V=A[C];if(typeof V==="string"&&V.trim())return V}if("error"in A)return M(A.error);if("cause"in A)return M(A.cause);try{return JSON.stringify(g)}catch{}}return"Unexpected error"},l=(g)=>{switch(g.type){case"audio":return{chunk:Uint8Array.from(atob(g.chunkBase64),(A)=>A.charCodeAt(0)),format:g.format,receivedAt:g.receivedAt,turnId:g.turnId,type:"audio"};case"assistant":return{text:g.text,turnId:g.turnId,type:"assistant"};case"assistant_delta":return{delta:g.delta,turnId:g.turnId,type:"assistant_delta"};case"complete":return{sessionId:g.sessionId,type:"complete"};case"connection":return{reconnect:g.reconnect,type:"connection"};case"call_lifecycle":return{event:g.event,sessionId:g.sessionId,type:"call_lifecycle"};case"error":return{message:M(g.message),type:"error"};case"final":return{transcript:g.transcript,type:"final"};case"partial":return{transcript:g.transcript,type:"partial"};case"replay":return{assistantTexts:g.assistantTexts,call:g.call,partial:g.partial,scenarioId:g.scenarioId,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,status:g.status,turns:g.turns,type:"replay"};case"session":return{sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,type:"session"};case"turn":return{turn:g.turn,type:"turn"};default:return null}};var gg=Math.PI*2;var T=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var O0=(g)=>g.length===0?void 0:g.reduce((A,C)=>A+C,0)/g.length,z=(g)=>g.length===0?void 0:Math.max(...g);var D=(g,A)=>{let C=g[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},B=(g,A)=>{let C=g[A];return typeof C==="boolean"?C:void 0},Y=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},k=(g)=>String(g.id??Y(g,"ssrc")??D(g,"ssrc")??Y(g,"trackIdentifier")??Y(g,"mid")??"unknown"),d=(g)=>g===void 0?void 0:g*1000;var S0=(g)=>{let A={};for(let[C,V]of Object.entries(g))if(V===null||typeof V==="boolean"||typeof V==="number"||typeof V==="string")A[C]=V;return A};var v=(g={})=>{let A=g.stats??[],C=[],V=A.filter((H)=>H.type==="inbound-rtp"&&Y(H,"kind")!=="video"),I=A.filter((H)=>H.type==="outbound-rtp"&&Y(H,"kind")!=="video"),R=A.filter((H)=>H.type==="candidate-pair"),w=A.filter((H)=>(H.type==="track"||H.type==="media-source")&&Y(H,"kind")==="audio"),L=R.filter((H)=>B(H,"selected")===!0||B(H,"nominated")===!0||Y(H,"state")==="succeeded").length,$=w.filter((H)=>Y(H,"readyState")!=="ended"&&Y(H,"trackState")!=="ended"&&B(H,"ended")!==!0).length,X=w.filter((H)=>Y(H,"readyState")==="ended"||Y(H,"trackState")==="ended"||B(H,"ended")===!0).length,G=V.reduce((H,J)=>H+(D(J,"packetsReceived")??0),0),h=I.reduce((H,J)=>H+(D(J,"packetsSent")??0),0),_=[...V,...I].reduce((H,J)=>H+Math.max(0,D(J,"packetsLost")??0),0),Z=G+_,y=Z===0?0:_/Z,K=V.reduce((H,J)=>H+(D(J,"bytesReceived")??0),0),O=I.reduce((H,J)=>H+(D(J,"bytesSent")??0),0),S=z(R.map((H)=>d(D(H,"currentRoundTripTime")??D(H,"roundTripTime"))).filter((H)=>H!==void 0)),W=z([...V,...I].map((H)=>d(D(H,"jitter"))).filter((H)=>H!==void 0)),N=z(V.map((H)=>{let J=D(H,"jitterBufferDelay"),U=D(H,"jitterBufferEmittedCount");return J!==void 0&&U!==void 0&&U>0?J/U*1000:void 0}).filter((H)=>H!==void 0)),j=w.map((H)=>D(H,"audioLevel")).filter((H)=>H!==void 0);if(g.requireConnectedCandidatePair&&R.length>0&&L===0)T(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&$===0)T(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&y>g.maxPacketLossRatio)T(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(y)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&S!==void 0&&S>g.maxRoundTripTimeMs)T(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(S)}ms above ${String(g.maxRoundTripTimeMs)}ms.`);if(g.maxJitterMs!==void 0&&W!==void 0&&W>g.maxJitterMs)T(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(W)}ms above ${String(g.maxJitterMs)}ms.`);return{activeCandidatePairs:L,audioLevelAverage:O0(j),bytesReceived:K,bytesSent:O,checkedAt:Date.now(),endedAudioTracks:X,inboundPackets:G,issues:C,jitterBufferDelayMs:N,jitterMs:W,liveAudioTracks:$,outboundPackets:h,packetLossRatio:y,packetsLost:_,roundTripTimeMs:S,status:C.some((H)=>H.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},i=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(S0)};var o=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],I=new Map(C.map((_)=>[k(_),_])),w=A.filter((_)=>(_.type==="inbound-rtp"||_.type==="outbound-rtp")&&Y(_,"kind")!=="video"&&Y(_,"mediaType")!=="video").map((_)=>{let Z=_.type==="outbound-rtp"?"outbound":"inbound",y=Z==="outbound"?"packetsSent":"packetsReceived",K=Z==="outbound"?"bytesSent":"bytesReceived",O=I.get(k(_)),S=D(_,y),W=O?D(O,y):void 0,N=D(_,K),j=O?D(O,K):void 0,H=_.timestamp!==void 0&&O?.timestamp!==void 0?_.timestamp-O.timestamp:void 0;return{bytesDelta:N!==void 0&&j!==void 0?N-j:void 0,currentPackets:S,direction:Z,id:k(_),packetDelta:S!==void 0&&W!==void 0?S-W:void 0,previousPackets:W,timeDeltaMs:H}}),L=w.filter((_)=>_.direction==="inbound"),$=w.filter((_)=>_.direction==="outbound"),X=z(w.map((_)=>_.timeDeltaMs).filter((_)=>_!==void 0)),G=L.filter((_)=>g.maxInboundPacketStallMs!==void 0&&_.timeDeltaMs!==void 0&&_.timeDeltaMs>=g.maxInboundPacketStallMs&&_.packetDelta!==void 0&&_.packetDelta<=0).length,h=$.filter((_)=>g.maxOutboundPacketStallMs!==void 0&&_.timeDeltaMs!==void 0&&_.timeDeltaMs>=g.maxOutboundPacketStallMs&&_.packetDelta!==void 0&&_.packetDelta<=0).length;if(g.requireInboundAudio&&L.length===0)T(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&$.length===0)T(V,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(g.maxGapMs!==void 0&&X!==void 0&&X>g.maxGapMs)T(V,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(X)}ms above ${String(g.maxGapMs)}ms.`);if(G>0)T(V,"error","media.webrtc_inbound_stalled",`${String(G)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)T(V,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:L.length,issues:V,maxObservedGapMs:X,outboundAudioStreams:$.length,stalledInboundStreams:G,stalledOutboundStreams:h,status:V.some((_)=>_.severity==="error")?"fail":V.length>0?"warn":"pass",streams:w,totalStats:A.length}};var W0="/api/voice/browser-media",Q0=5000,T0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,c0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??W0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},n=(g)=>{let A=null,C=[],V=async()=>{let w=await T0(g);if(!w)return;let L=await i({peerConnection:w}),$=v({...g,stats:L}),X=g.continuity===!1?void 0:o({...g.continuity,previousStats:C,stats:L}),G={at:Date.now(),continuity:X,report:$,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=L,g.onReport?.(G),await c0(G,g),G},I=()=>{V().catch((w)=>{g.onError?.(w)})},R=()=>{if(A)clearInterval(A),A=null};return{close:R,reportOnce:V,stop:R,start:()=>{if(A)return;I(),A=setInterval(I,g.intervalMs??Q0)}}};var K0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));var q=()=>{},P0=()=>q,q0={callControl:q,close:q,endTurn:q,send:q,sendAudio:q,simulateDisconnect:q,subscribe:P0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},N0=()=>crypto.randomUUID(),j0=(g,A,C)=>{let{hostname:V,port:I,protocol:R}=window.location,w=R==="https:"?"wss:":"ws:",L=I?`:${I}`:"",$=new URL(`${w}//${V}${L}${g}`);if($.searchParams.set("sessionId",A),C)$.searchParams.set("scenarioId",C);return $.toString()},B0=(g)=>{if(!g||typeof g!=="object"||!("type"in g))return!1;switch(g.type){case"audio":case"assistant":case"call_lifecycle":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},z0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return B0(A)?A:null}catch{return null}},m=(g,A={})=>{if(typeof window>"u")return q0;let C=new Set,V=A.reconnect!==!1,I=A.maxReconnectAttempts??15,R=A.reconnectMaxDelayMs??8000,w=A.pingInterval??30000,L=(U)=>K0(U,500,R),$={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:A.sessionId??N0(),ws:null},X=(U)=>{C.forEach((Q)=>Q(U))},G=()=>{if($.pingInterval)clearInterval($.pingInterval),$.pingInterval=null;if($.reconnectTimeout)clearTimeout($.reconnectTimeout),$.reconnectTimeout=null},h=()=>{if($.ws?.readyState!==1)return;while($.pendingMessages.length>0){let U=$.pendingMessages.shift();if(U!==void 0)$.ws.send(U)}},_=()=>{$.reconnectAttempts+=1;let U=L($.reconnectAttempts),Q=Date.now()+U;X({reconnect:{attempts:$.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:I,nextAttemptAt:Q,status:"reconnecting"},type:"connection"}),$.reconnectTimeout=setTimeout(()=>{if($.reconnectAttempts>I){X({reconnect:{attempts:$.reconnectAttempts,maxAttempts:I,status:"exhausted"},type:"connection"});return}Z()},U)},Z=()=>{let U=new WebSocket(j0(g,$.sessionId,$.scenarioId));U.binaryType="arraybuffer",U.onopen=()=>{let Q=$.reconnectAttempts>0;if($.isConnected=!0,h(),Q)X({reconnect:{attempts:$.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:I,status:"resumed"},type:"connection"}),$.reconnectAttempts=0;C.forEach((P)=>P({scenarioId:$.scenarioId??void 0,sessionId:$.sessionId,status:"active",type:"session"})),$.pingInterval=setInterval(()=>{if(U.readyState===1)U.send(JSON.stringify({type:"ping"}))},w)},U.onmessage=(Q)=>{let P=z0(Q);if(!P)return;if(P.type==="session")$.sessionId=P.sessionId,$.scenarioId=P.scenarioId??$.scenarioId;C.forEach(($0)=>$0(P))},U.onclose=(Q)=>{if($.isConnected=!1,G(),V&&Q.code!==1000&&$.reconnectAttempts<I)_();else if(V&&Q.code!==1000)X({reconnect:{attempts:$.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:I,status:"exhausted"},type:"connection"})},$.ws=U},y=(U)=>{if($.ws?.readyState===1){$.ws.send(U);return}$.pendingMessages.push(U)},K=(U)=>{y(JSON.stringify(U))},O=(U={})=>{if(U.sessionId)$.sessionId=U.sessionId;if(U.scenarioId)$.scenarioId=U.scenarioId;K({scenarioId:$.scenarioId??void 0,sessionId:$.sessionId,type:"start"})},S=(U)=>{y(U)},W=()=>{K({type:"end_turn"})},N=(U)=>{K({...U,type:"call_control"})},j=()=>{if(G(),$.ws)$.ws.close(1000),$.ws=null;$.isConnected=!1,C.clear()},H=()=>{if($.ws?.readyState===1)$.ws.close(4000,"absolutejs-voice-reconnect-proof")},J=(U)=>{return C.add(U),()=>{C.delete(U)}};return Z(),{callControl:N,close:j,endTurn:W,send:K,sendAudio:S,simulateDisconnect:H,start:O,subscribe:J,getReadyState:()=>$.ws?.readyState??3,getScenarioId:()=>$.scenarioId??"",getSessionId:()=>$.sessionId}};var b0=()=>({attempts:0,maxAttempts:0,status:"idle"}),E0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return g;if(!g)return C;if(g===C||g.endsWith(C))return g;if(C.includes(g))return C;return`${g} ${C}`},M0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},k0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:b0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),u=()=>{let g=k0(),A="",C=new Set,V=()=>{C.forEach((R)=>R())};return{dispatch:(R)=>{switch(R.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:R.chunk,format:R.format,receivedAt:R.receivedAt,turnId:R.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,R.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${R.delta}`};break;case"complete":g={...g,sessionId:R.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:R.event.type==="end"?R.event.disposition:g.call?.disposition,endedAt:R.event.type==="end"?R.event.at:g.call?.endedAt,events:[...g.call?.events??[],R.event],lastEventAt:R.event.at,startedAt:g.call?.startedAt??R.event.at},sessionId:R.sessionId};break;case"connected":g={...g,isConnected:!0,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect};break;case"connection":g={...g,reconnect:R.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:R.message};break;case"final":A=E0(A,R.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:M0(A,R.transcript.text)};break;case"replay":A=R.partial,g={...g,assistantStreamingText:"",assistantTexts:[...R.assistantTexts],call:R.call??null,error:null,isConnected:R.status==="active",partial:R.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:R.scenarioId??g.scenarioId,sessionId:R.sessionId,sessionMetadata:R.sessionMetadata??g.sessionMetadata,status:R.status,turns:[...R.turns]};break;case"session":g={...g,error:null,scenarioId:R.scenarioId??g.scenarioId,isConnected:R.status==="active",sessionId:R.sessionId,sessionMetadata:R.sessionMetadata??g.sessionMetadata,status:R.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,R.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(R)=>{return C.add(R),()=>{C.delete(R)}}}};var r=(g,A={})=>{let C=m(g,A),V=u(),I=A.browserMedia&&typeof window<"u"?n({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,R=new Set,w=(G)=>Promise.resolve().then(()=>{if(!G?.sessionId&&!G?.scenarioId)return;C.start(G),I?.start()}),L=()=>{R.forEach((G)=>G())},$=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let G=V.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:G.reconnect,scenarioId:G.scenarioId,sessionId:C.getSessionId(),turnIds:G.turns.map((_)=>_.id)});fetch(A.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},X=C.subscribe((G)=>{let h=l(G);if(h){if(V.dispatch(h),G.type==="connection")$();L()}});return{start:w,get assistantAudio(){return V.getSnapshot().assistantAudio},get assistantTexts(){return V.getSnapshot().assistantTexts},get assistantStreamingText(){return V.getSnapshot().assistantStreamingText},get call(){return V.getSnapshot().call},callControl(G){C.callControl(G)},close(){X(),I?.close(),C.close(),V.dispatch({type:"disconnected"}),L()},endTurn(){C.endTurn()},get error(){return V.getSnapshot().error},getServerSnapshot(){return V.getServerSnapshot()},getSnapshot(){return V.getSnapshot()},get isConnected(){return V.getSnapshot().isConnected},get partial(){return V.getSnapshot().partial},get reconnect(){return V.getSnapshot().reconnect},get scenarioId(){return V.getSnapshot().scenarioId},sendAudio(G){C.sendAudio(G)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(G){return R.add(G),()=>{R.delete(G)}},get turns(){return V.getSnapshot().turns}}};var s=(g)=>{if(!g||g.enabled===!1)return;return{enabled:!0,maxGain:g.maxGain??3,noiseGateAttenuation:g.noiseGateAttenuation??0.15,noiseGateThreshold:g.noiseGateThreshold??0.006,targetLevel:g.targetLevel??0.08}};var b=1200;var x0={balanced:{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:b,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:b,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",semanticVetoMaxMs:0,semanticVetoRecheckMs:b,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},F0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}},f0="fast",l0="general",a=(g)=>{let A=g?.profile??f0,C=g?.qualityProfile??l0,V=x0[A],I=F0[C];return{profile:A,qualityProfile:C,semanticVetoMaxMs:g?.semanticVetoMaxMs??V.semanticVetoMaxMs,semanticVetoRecheckMs:g?.semanticVetoRecheckMs??V.semanticVetoRecheckMs,silenceMs:g?.silenceMs??I.silenceMs??V.silenceMs,speechThreshold:g?.speechThreshold??I.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??I.transcriptStabilityMs??V.transcriptStabilityMs}};var d0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},p=(g="default")=>{let A=d0[g];return{audioConditioning:s(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:a(A.turnDetection)}};var v0=(g)=>({assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,isRecording:!1,partial:g.partial,reconnect:g.reconnect,recordingError:null,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]}),t=(g,A={})=>{let C=p(A.preset),V=r(g,{...C.connection,...A.connection}),I=null,R=v0(V),w=new Set,L=()=>{for(let y of w)y()},$=()=>{if(R={...R,assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,partial:V.partial,reconnect:V.reconnect,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]},A.autoStopOnComplete!==!1&&R.status==="completed"&&R.isRecording)I?.stop(),I=null,R={...R,isRecording:!1};L()},X=V.subscribe($);$();let G=()=>{if(I)return I;return I=f({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(y)=>{if(A.capture?.onAudio){A.capture.onAudio(y,V.sendAudio);return}V.sendAudio(y)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),I},h=()=>{I?.stop(),I=null,R={...R,isRecording:!1},L()},_=async()=>{if(R.isRecording)return;try{R={...R,recordingError:null},L(),await G().start(),R={...R,isRecording:!0},L()}catch(y){throw I=null,R={...R,isRecording:!1,recordingError:y instanceof Error?y.message:String(y)},L(),y}};return{close:()=>{X(),h(),V.close()},startRecording:_,stopRecording:h,get assistantAudio(){return R.assistantAudio},get assistantTexts(){return R.assistantTexts},get assistantStreamingText(){return R.assistantStreamingText},bindHTMX(y){return F(V,y)},get call(){return R.call},callControl:(y)=>V.callControl(y),endTurn:()=>V.endTurn(),get error(){return R.error},getServerSnapshot:()=>R,getSnapshot:()=>R,get isConnected(){return R.isConnected},get isRecording(){return R.isRecording},get partial(){return R.partial},get reconnect(){return R.reconnect},get recordingError(){return R.recordingError},get scenarioId(){return R.scenarioId},sendAudio:(y)=>V.sendAudio(y),get sessionId(){return R.sessionId},get sessionMetadata(){return R.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return R.status},subscribe:(y)=>{return w.add(y),()=>{w.delete(y)}},toggleRecording:async()=>{if(R.isRecording){h();return}await _()},get turns(){return R.turns}}};var c=(g)=>String(g).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var e=(g)=>{if(!g.isConnected)return"idle";if(g.isPlaying)return"speaking";if(g.isRecording&&g.hasActivePartial)return"listening";if(g.isRecording)return"listening";if(g.lastTranscriptAt&&!g.lastAssistantAt)return"thinking";if(g.lastTranscriptAt&&g.lastAssistantAt&&g.lastTranscriptAt>g.lastAssistantAt)return"thinking";return"idle"};var i0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},o0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},n0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},g0=(g)=>{let A={...i0,...g.theme},C={...o0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,I=g.state.turns.at(-1)?.committedAt,R=e({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:I}),w=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,L=g.state.error?"Error":w?C.connecting:g.state.status==="completed"?C.callEnded:n0(R,C);return{agentState:R,classes:{container:`absolute-voice-widget absolute-voice-widget--${R}`,dot:`absolute-voice-widget__dot${g.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:g.state.isConnected,canMute:g.state.isRecording,canStart:!g.state.isRecording&&g.state.status!=="completed"},errorMessage:g.state.error??void 0,labels:C,partial:g.state.partial||void 0,statusLabel:L,theme:A,title:g.title??"Voice"}},m0=(g)=>typeof g==="number"?`${g}px`:g,A0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${m0(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,V=`background:${g.errorMessage?A.errorAccent:g.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,I=[];if(g.controls.canStart)I.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${c(g.labels.startCall)}</button>`);if(g.controls.canMute)I.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${c(g.labels.mute)}</button>`);if(g.controls.canEnd)I.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${c(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${c(g.classes.container)}" style="${C}">
|
|
1
|
+
(()=>{var{defineProperty:j,getOwnPropertyNames:_0,getOwnPropertyDescriptor:c0}=Object,R0=Object.prototype.hasOwnProperty;function $0(g){return this[g]}var I0=(g)=>{var A=(x??=new WeakMap).get(g),C;if(A)return A;if(A=j({},"__esModule",{value:!0}),g&&typeof g==="object"||typeof g==="function"){for(var V of _0(g))if(!R0.call(A,V))j(A,V,{get:$0.bind(g,V),enumerable:!(C=c0(g,V))||C.enumerable})}return x.set(g,A),A},x;var H0=(g)=>g;function U0(g,A){this[g]=H0.bind(null,A)}var L0=(g,A)=>{for(var C in A)j(g,C,{get:A[C],enumerable:!0,configurable:!0,set:U0.bind(A,C)})};var o0={};L0(o0,{mount:()=>A0,default:()=>m0,VOICE_EMBED_VERSION:()=>V0});var G0=(g)=>{if(typeof g!=="string")return g;return document.querySelector(g)},W0=(g,A,C,V)=>{let c=A??g.getAttribute("hx-get")??"";if(!c)return"";let T=new URL(c,window.location.origin);if(V)T.searchParams.set(C,V);else T.searchParams.delete(C);return`${T.pathname}${T.search}${T.hash}`},k=(g,A)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let C=G0(A.element);if(!C)return()=>{};let V=A.eventName??"voice-refresh",c=A.sessionQueryParam??"sessionId",T=()=>{let H=window,_=W0(C,A.route,c,g.sessionId);if(_)C.setAttribute("hx-get",_);H.htmx?.process?.(C),H.htmx?.trigger?.(C,V)},L=g.subscribe(T);return T(),()=>{L()}};var y0=(g)=>Math.max(-1,Math.min(1,g)),w0=(g)=>{let A=new Int16Array(g.length);for(let C=0;C<g.length;C+=1){let V=y0(g[C]??0);A[C]=V<0?V*32768:V*32767}return new Uint8Array(A.buffer)},D0=(g)=>{let A=g instanceof Uint8Array?g:new Uint8Array(g);if(A.byteLength<2)return 0;let C=new Int16Array(A.buffer,A.byteOffset,Math.floor(A.byteLength/2));if(C.length===0)return 0;let V=0;for(let c of C){let T=c/32768;V+=T*T}return Math.min(1,Math.max(0,Math.sqrt(V/C.length)*5.5))},S0=(g,A,C)=>{if(A===C)return g;let V=A/C,c=Math.round(g.length/V),T=new Float32Array(c),L=0,H=0;while(L<T.length){let _=Math.round((L+1)*V),W=0,I=0;for(let y=H;y<_&&y<g.length;y+=1)W+=g[y]??0,I+=1;T[L]=I>0?W/I:0,L+=1,H=_}return T},F=(g)=>{let A=null,C=null,V=null,c=null;return{start:async()=>{if(!g.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let H=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!H)throw Error("Browser microphone capture requires AudioContext support.");if(c=g.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:g.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),A=new H,A.state==="suspended")await A.resume();C=A.createMediaStreamSource(c),V=A.createScriptProcessor(4096,1,1),V.onaudioprocess=(_)=>{let W=_.inputBuffer.getChannelData(0),I=S0(W,A?.sampleRate??48000,g.sampleRateHz??16000),y=w0(I);g.onLevel?.(D0(y)),g.onAudio(y)},C.connect(V),V.connect(A.destination)},stop:()=>{V?.disconnect(),C?.disconnect(),c?.getTracks().forEach((H)=>H.stop()),A?.close(),g.onLevel?.(0),A=null,c=null,V=null,C=null}}};var B=(g)=>{if(typeof g==="string"&&g.trim())return g;if(g instanceof Error&&g.message.trim())return g.message;if(g&&typeof g==="object"){let A=g;for(let C of["message","reason","description"]){let V=A[C];if(typeof V==="string"&&V.trim())return V}if("error"in A)return B(A.error);if("cause"in A)return B(A.cause);try{return JSON.stringify(g)}catch{}}return"Unexpected error"},l=(g)=>{switch(g.type){case"audio":return{chunk:Uint8Array.from(atob(g.chunkBase64),(A)=>A.charCodeAt(0)),format:g.format,receivedAt:g.receivedAt,turnId:g.turnId,type:"audio"};case"assistant":return{text:g.text,turnId:g.turnId,type:"assistant"};case"assistant_delta":return{delta:g.delta,turnId:g.turnId,type:"assistant_delta"};case"complete":return{sessionId:g.sessionId,type:"complete"};case"connection":return{reconnect:g.reconnect,type:"connection"};case"call_lifecycle":return{event:g.event,sessionId:g.sessionId,type:"call_lifecycle"};case"error":return{message:B(g.message),type:"error"};case"final":return{transcript:g.transcript,type:"final"};case"partial":return{transcript:g.transcript,type:"partial"};case"replay":return{assistantTexts:g.assistantTexts,call:g.call,partial:g.partial,scenarioId:g.scenarioId,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,status:g.status,turns:g.turns,type:"replay"};case"session":return{sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,type:"session"};case"turn":return{turn:g.turn,type:"turn"};default:return null}};var p0=Math.PI*2;var Z=(g,A,C,V)=>{g.push({code:C,message:V,severity:A})};var X0=(g)=>g.length===0?void 0:g.reduce((A,C)=>A+C,0)/g.length,b=(g)=>g.length===0?void 0:Math.max(...g);var w=(g,A)=>{let C=g[A];return typeof C==="number"&&Number.isFinite(C)?C:void 0},z=(g,A)=>{let C=g[A];return typeof C==="boolean"?C:void 0},S=(g,A)=>{let C=g[A];return typeof C==="string"?C:void 0},M=(g)=>String(g.id??S(g,"ssrc")??w(g,"ssrc")??S(g,"trackIdentifier")??S(g,"mid")??"unknown"),f=(g)=>g===void 0?void 0:g*1000;var h0=(g)=>{let A={};for(let[C,V]of Object.entries(g))if(V===null||typeof V==="boolean"||typeof V==="number"||typeof V==="string")A[C]=V;return A};var d=(g={})=>{let A=g.stats??[],C=[],V=A.filter((R)=>R.type==="inbound-rtp"&&S(R,"kind")!=="video"),c=A.filter((R)=>R.type==="outbound-rtp"&&S(R,"kind")!=="video"),T=A.filter((R)=>R.type==="candidate-pair"),L=A.filter((R)=>(R.type==="track"||R.type==="media-source")&&S(R,"kind")==="audio"),H=T.filter((R)=>z(R,"selected")===!0||z(R,"nominated")===!0||S(R,"state")==="succeeded").length,_=L.filter((R)=>S(R,"readyState")!=="ended"&&S(R,"trackState")!=="ended"&&z(R,"ended")!==!0).length,W=L.filter((R)=>S(R,"readyState")==="ended"||S(R,"trackState")==="ended"||z(R,"ended")===!0).length,I=V.reduce((R,D)=>R+(w(D,"packetsReceived")??0),0),y=c.reduce((R,D)=>R+(w(D,"packetsSent")??0),0),$=[...V,...c].reduce((R,D)=>R+Math.max(0,w(D,"packetsLost")??0),0),X=I+$,G=X===0?0:$/X,P=V.reduce((R,D)=>R+(w(D,"bytesReceived")??0),0),h=c.reduce((R,D)=>R+(w(D,"bytesSent")??0),0),O=b(T.map((R)=>f(w(R,"currentRoundTripTime")??w(R,"roundTripTime"))).filter((R)=>R!==void 0)),J=b([...V,...c].map((R)=>f(w(R,"jitter"))).filter((R)=>R!==void 0)),E=b(V.map((R)=>{let D=w(R,"jitterBufferDelay"),U=w(R,"jitterBufferEmittedCount");return D!==void 0&&U!==void 0&&U>0?D/U*1000:void 0}).filter((R)=>R!==void 0)),N=L.map((R)=>w(R,"audioLevel")).filter((R)=>R!==void 0);if(g.requireConnectedCandidatePair&&T.length>0&&H===0)Z(C,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(g.requireLiveAudioTrack&&_===0)Z(C,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(g.maxPacketLossRatio!==void 0&&G>g.maxPacketLossRatio)Z(C,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(G)} above ${String(g.maxPacketLossRatio)}.`);if(g.maxRoundTripTimeMs!==void 0&&O!==void 0&&O>g.maxRoundTripTimeMs)Z(C,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(O)}ms above ${String(g.maxRoundTripTimeMs)}ms.`);if(g.maxJitterMs!==void 0&&J!==void 0&&J>g.maxJitterMs)Z(C,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(J)}ms above ${String(g.maxJitterMs)}ms.`);return{activeCandidatePairs:H,audioLevelAverage:X0(N),bytesReceived:P,bytesSent:h,checkedAt:Date.now(),endedAudioTracks:W,inboundPackets:I,issues:C,jitterBufferDelayMs:E,jitterMs:J,liveAudioTracks:_,outboundPackets:y,packetLossRatio:G,packetsLost:$,roundTripTimeMs:O,status:C.some((R)=>R.severity==="error")?"fail":C.length>0?"warn":"pass",totalStats:A.length}},v=async(g)=>{return[...(await g.peerConnection.getStats(g.selector??null)).values()].map(h0)};var i=(g={})=>{let A=g.stats??[],C=g.previousStats??[],V=[],c=new Map(C.map(($)=>[M($),$])),L=A.filter(($)=>($.type==="inbound-rtp"||$.type==="outbound-rtp")&&S($,"kind")!=="video"&&S($,"mediaType")!=="video").map(($)=>{let X=$.type==="outbound-rtp"?"outbound":"inbound",G=X==="outbound"?"packetsSent":"packetsReceived",P=X==="outbound"?"bytesSent":"bytesReceived",h=c.get(M($)),O=w($,G),J=h?w(h,G):void 0,E=w($,P),N=h?w(h,P):void 0,R=$.timestamp!==void 0&&h?.timestamp!==void 0?$.timestamp-h.timestamp:void 0;return{bytesDelta:E!==void 0&&N!==void 0?E-N:void 0,currentPackets:O,direction:X,id:M($),packetDelta:O!==void 0&&J!==void 0?O-J:void 0,previousPackets:J,timeDeltaMs:R}}),H=L.filter(($)=>$.direction==="inbound"),_=L.filter(($)=>$.direction==="outbound"),W=b(L.map(($)=>$.timeDeltaMs).filter(($)=>$!==void 0)),I=H.filter(($)=>g.maxInboundPacketStallMs!==void 0&&$.timeDeltaMs!==void 0&&$.timeDeltaMs>=g.maxInboundPacketStallMs&&$.packetDelta!==void 0&&$.packetDelta<=0).length,y=_.filter(($)=>g.maxOutboundPacketStallMs!==void 0&&$.timeDeltaMs!==void 0&&$.timeDeltaMs>=g.maxOutboundPacketStallMs&&$.packetDelta!==void 0&&$.packetDelta<=0).length;if(g.requireInboundAudio&&H.length===0)Z(V,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(g.requireOutboundAudio&&_.length===0)Z(V,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(g.maxGapMs!==void 0&&W!==void 0&&W>g.maxGapMs)Z(V,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(W)}ms above ${String(g.maxGapMs)}ms.`);if(I>0)Z(V,"error","media.webrtc_inbound_stalled",`${String(I)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(y>0)Z(V,"error","media.webrtc_outbound_stalled",`${String(y)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:H.length,issues:V,maxObservedGapMs:W,outboundAudioStreams:_.length,stalledInboundStreams:I,stalledOutboundStreams:y,status:V.some(($)=>$.severity==="error")?"fail":V.length>0?"warn":"pass",streams:L,totalStats:A.length}};var O0="/api/voice/browser-media",J0=5000,Y0=async(g)=>g.peerConnection??await g.getPeerConnection?.()??null,Z0=async(g,A)=>{let C=A.fetch??globalThis.fetch;if(!C)return;await C(A.path??O0,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},n=(g)=>{let A=null,C=[],V=async()=>{let L=await Y0(g);if(!L)return;let H=await v({peerConnection:L}),_=d({...g,stats:H}),W=g.continuity===!1?void 0:i({...g.continuity,previousStats:C,stats:H}),I={at:Date.now(),continuity:W,report:_,scenarioId:g.getScenarioId?.()??null,sessionId:g.getSessionId?.()??null};return C=H,g.onReport?.(I),await Z0(I,g),I},c=()=>{V().catch((L)=>{g.onError?.(L)})},T=()=>{if(A)clearInterval(A),A=null};return{close:T,reportOnce:V,stop:T,start:()=>{if(A)return;c(),A=setInterval(c,g.intervalMs??J0)}}};var Q0=(g,A,C)=>Math.min(C,A*2**(Math.max(1,g)-1));var q=()=>{},P0=()=>q,K0={callControl:q,close:q,endTurn:q,send:q,sendAudio:q,simulateDisconnect:q,subscribe:P0,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},q0=()=>crypto.randomUUID(),E0=(g,A,C)=>{let{hostname:V,port:c,protocol:T}=window.location,L=T==="https:"?"wss:":"ws:",H=c?`:${c}`:"",_=new URL(`${L}//${V}${H}${g}`);if(_.searchParams.set("sessionId",A),C)_.searchParams.set("scenarioId",C);return _.toString()},N0=(g)=>{if(!g||typeof g!=="object"||!("type"in g))return!1;switch(g.type){case"audio":case"assistant":case"call_lifecycle":case"complete":case"connection":case"error":case"final":case"partial":case"pong":case"replay":case"session":case"turn":return!0;default:return!1}},z0=(g)=>{if(typeof g.data!=="string")return null;try{let A=JSON.parse(g.data);return N0(A)?A:null}catch{return null}},o=(g,A={})=>{if(typeof window>"u")return K0;let C=new Set,V=A.reconnect!==!1,c=A.maxReconnectAttempts??15,T=A.reconnectMaxDelayMs??8000,L=A.pingInterval??30000,H=(U)=>Q0(U,500,T),_={isConnected:!1,pendingMessages:[],scenarioId:A.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:A.sessionId??q0(),ws:null},W=(U)=>{C.forEach((Y)=>Y(U))},I=()=>{if(_.pingInterval)clearInterval(_.pingInterval),_.pingInterval=null;if(_.reconnectTimeout)clearTimeout(_.reconnectTimeout),_.reconnectTimeout=null},y=()=>{if(_.ws?.readyState!==1)return;while(_.pendingMessages.length>0){let U=_.pendingMessages.shift();if(U!==void 0)_.ws.send(U)}},$=()=>{_.reconnectAttempts+=1;let U=H(_.reconnectAttempts),Y=Date.now()+U;W({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,nextAttemptAt:Y,status:"reconnecting"},type:"connection"}),_.reconnectTimeout=setTimeout(()=>{if(_.reconnectAttempts>c){W({reconnect:{attempts:_.reconnectAttempts,maxAttempts:c,status:"exhausted"},type:"connection"});return}X()},U)},X=()=>{let U=new WebSocket(E0(g,_.sessionId,_.scenarioId));U.binaryType="arraybuffer",U.onopen=()=>{let Y=_.reconnectAttempts>0;if(_.isConnected=!0,y(),Y)W({reconnect:{attempts:_.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:c,status:"resumed"},type:"connection"}),_.reconnectAttempts=0;C.forEach((K)=>K({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,status:"active",type:"session"})),_.pingInterval=setInterval(()=>{if(U.readyState===1)U.send(JSON.stringify({type:"ping"}))},L)},U.onmessage=(Y)=>{let K=z0(Y);if(!K)return;if(K.type==="session")_.sessionId=K.sessionId,_.scenarioId=K.scenarioId??_.scenarioId;C.forEach((T0)=>T0(K))},U.onclose=(Y)=>{if(_.isConnected=!1,I(),V&&Y.code!==1000&&_.reconnectAttempts<c)$();else if(V&&Y.code!==1000)W({reconnect:{attempts:_.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:c,status:"exhausted"},type:"connection"})},_.ws=U},G=(U)=>{if(_.ws?.readyState===1){_.ws.send(U);return}_.pendingMessages.push(U)},P=(U)=>{G(JSON.stringify(U))},h=(U={})=>{if(U.sessionId)_.sessionId=U.sessionId;if(U.scenarioId)_.scenarioId=U.scenarioId;P({scenarioId:_.scenarioId??void 0,sessionId:_.sessionId,type:"start"})},O=(U)=>{G(U)},J=()=>{P({type:"end_turn"})},E=(U)=>{P({...U,type:"call_control"})},N=()=>{if(I(),_.ws)_.ws.close(1000),_.ws=null;_.isConnected=!1,C.clear()},R=()=>{if(_.ws?.readyState===1)_.ws.close(4000,"absolutejs-voice-reconnect-proof")},D=(U)=>{return C.add(U),()=>{C.delete(U)}};return X(),{callControl:E,close:N,endTurn:J,send:P,sendAudio:O,simulateDisconnect:R,start:h,subscribe:D,getReadyState:()=>_.ws?.readyState??3,getScenarioId:()=>_.scenarioId??"",getSessionId:()=>_.sessionId}};var b0=()=>({attempts:0,maxAttempts:0,status:"idle"}),j0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!C)return g;if(!g)return C;if(g===C||g.endsWith(C))return g;if(C.includes(g))return C;return`${g} ${C}`},B0=(g,A)=>{let C=A.trim().replace(/\s+/g," ");if(!g)return C;if(!C||g.endsWith(C))return g;return`${g} ${C}`},M0=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:b0(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),m=()=>{let g=M0(),A="",C=new Set,V=()=>{C.forEach((T)=>T())};return{dispatch:(T)=>{switch(T.type){case"audio":g={...g,assistantAudio:[...g.assistantAudio,{chunk:T.chunk,format:T.format,receivedAt:T.receivedAt,turnId:T.turnId}]};break;case"assistant":g={...g,assistantStreamingText:"",assistantTexts:[...g.assistantTexts,T.text]};break;case"assistant_delta":g={...g,assistantStreamingText:`${g.assistantStreamingText}${T.delta}`};break;case"complete":g={...g,sessionId:T.sessionId,status:"completed"};break;case"call_lifecycle":g={...g,call:{...g.call,disposition:T.event.type==="end"?T.event.disposition:g.call?.disposition,endedAt:T.event.type==="end"?T.event.at:g.call?.endedAt,events:[...g.call?.events??[],T.event],lastEventAt:T.event.at,startedAt:g.call?.startedAt??T.event.at},sessionId:T.sessionId};break;case"connected":g={...g,isConnected:!0,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect};break;case"connection":g={...g,reconnect:T.reconnect};break;case"disconnected":g={...g,isConnected:!1};break;case"error":g={...g,error:T.message};break;case"final":A=j0(A,T.transcript.text),g={...g,partial:A};break;case"partial":g={...g,partial:B0(A,T.transcript.text)};break;case"replay":A=T.partial,g={...g,assistantStreamingText:"",assistantTexts:[...T.assistantTexts],call:T.call??null,error:null,isConnected:T.status==="active",partial:T.partial,reconnect:g.reconnect.status==="reconnecting"?{...g.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:g.reconnect,scenarioId:T.scenarioId??g.scenarioId,sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??g.sessionMetadata,status:T.status,turns:[...T.turns]};break;case"session":g={...g,error:null,scenarioId:T.scenarioId??g.scenarioId,isConnected:T.status==="active",sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??g.sessionMetadata,status:T.status};break;case"turn":A="",g={...g,partial:"",turns:[...g.turns,T.turn]};break}V()},getServerSnapshot:()=>g,getSnapshot:()=>g,subscribe:(T)=>{return C.add(T),()=>{C.delete(T)}}}};var r=(g,A={})=>{let C=o(g,A),V=m(),c=A.browserMedia&&typeof window<"u"?n({...A.browserMedia,getScenarioId:()=>A.browserMedia?A.browserMedia.getScenarioId?.()??C.getScenarioId():C.getScenarioId(),getSessionId:()=>A.browserMedia?A.browserMedia.getSessionId?.()??C.getSessionId():C.getSessionId()}):null,T=new Set,L=(I)=>Promise.resolve().then(()=>{if(!I?.sessionId&&!I?.scenarioId)return;C.start(I),c?.start()}),H=()=>{T.forEach((I)=>I())},_=()=>{if(!A.reconnectReportPath||typeof fetch>"u")return;let I=V.getSnapshot(),y=JSON.stringify({at:Date.now(),reconnect:I.reconnect,scenarioId:I.scenarioId,sessionId:C.getSessionId(),turnIds:I.turns.map(($)=>$.id)});fetch(A.reconnectReportPath,{body:y,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},W=C.subscribe((I)=>{let y=l(I);if(y){if(V.dispatch(y),I.type==="connection")_();H()}});return{start:L,get assistantAudio(){return V.getSnapshot().assistantAudio},get assistantTexts(){return V.getSnapshot().assistantTexts},get assistantStreamingText(){return V.getSnapshot().assistantStreamingText},get call(){return V.getSnapshot().call},callControl(I){C.callControl(I)},close(){W(),c?.close(),C.close(),V.dispatch({type:"disconnected"}),H()},endTurn(){C.endTurn()},get error(){return V.getSnapshot().error},getServerSnapshot(){return V.getServerSnapshot()},getSnapshot(){return V.getSnapshot()},get isConnected(){return V.getSnapshot().isConnected},get partial(){return V.getSnapshot().partial},get reconnect(){return V.getSnapshot().reconnect},get scenarioId(){return V.getSnapshot().scenarioId},sendAudio(I){C.sendAudio(I)},get sessionId(){return C.getSessionId()},get sessionMetadata(){return V.getSnapshot().sessionMetadata},simulateDisconnect(){C.simulateDisconnect()},get status(){return V.getSnapshot().status},subscribe(I){return T.add(I),()=>{T.delete(I)}},get turns(){return V.getSnapshot().turns}}};var u=(g)=>{if(!g||g.enabled===!1)return;return{enabled:!0,maxGain:g.maxGain??3,noiseGateAttenuation:g.noiseGateAttenuation??0.15,noiseGateThreshold:g.noiseGateThreshold??0.006,targetLevel:g.targetLevel??0.08}};var x0={balanced:{qualityProfile:"general",minSilenceMs:400,silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",minSilenceMs:300,silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",minSilenceMs:600,silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},k0={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var s=(g)=>{let A=g?.profile??"fast",C=g?.qualityProfile??"general",V=x0[A],c=k0[C],T=g?.silenceMs??c.silenceMs??V.silenceMs;return{profile:A,qualityProfile:C,minSilenceMs:Math.min(T,g?.minSilenceMs??c.minSilenceMs??V.minSilenceMs),silenceMs:T,speechThreshold:g?.speechThreshold??c.speechThreshold??V.speechThreshold,transcriptStabilityMs:g?.transcriptStabilityMs??c.transcriptStabilityMs??V.transcriptStabilityMs}};var F0={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},a=(g="default")=>{let A=F0[g];return{audioConditioning:u(A.audioConditioning),capture:{channelCount:A.capture?.channelCount??1,sampleRateHz:A.capture?.sampleRateHz??16000},connection:{...A.connection},name:g,sttLifecycle:A.sttLifecycle??"continuous",turnDetection:s(A.turnDetection)}};var l0=(g)=>({assistantAudio:[...g.assistantAudio],assistantStreamingText:g.assistantStreamingText,assistantTexts:[...g.assistantTexts],call:g.call,error:g.error,isConnected:g.isConnected,isRecording:!1,partial:g.partial,reconnect:g.reconnect,recordingError:null,sessionId:g.sessionId,sessionMetadata:g.sessionMetadata,scenarioId:g.scenarioId,status:g.status,turns:[...g.turns]}),p=(g,A={})=>{let C=a(A.preset),V=r(g,{...C.connection,...A.connection}),c=null,T=l0(V),L=new Set,H=()=>{for(let G of L)G()},_=()=>{if(T={...T,assistantAudio:[...V.assistantAudio],assistantStreamingText:V.assistantStreamingText,assistantTexts:[...V.assistantTexts],call:V.call,error:V.error,isConnected:V.isConnected,partial:V.partial,reconnect:V.reconnect,sessionId:V.sessionId,sessionMetadata:V.sessionMetadata,scenarioId:V.scenarioId,status:V.status,turns:[...V.turns]},A.autoStopOnComplete!==!1&&T.status==="completed"&&T.isRecording)c?.stop(),c=null,T={...T,isRecording:!1};H()},W=V.subscribe(_);_();let I=()=>{if(c)return c;return c=F({channelCount:A.capture?.channelCount??C.capture.channelCount,onLevel:A.capture?.onLevel,onAudio:(G)=>{if(A.capture?.onAudio){A.capture.onAudio(G,V.sendAudio);return}V.sendAudio(G)},sampleRateHz:A.capture?.sampleRateHz??C.capture.sampleRateHz,...A.capture?.stream?{stream:A.capture.stream}:{}}),c},y=()=>{c?.stop(),c=null,T={...T,isRecording:!1},H()},$=async()=>{if(T.isRecording)return;try{T={...T,recordingError:null},H(),await I().start(),T={...T,isRecording:!0},H()}catch(G){throw c=null,T={...T,isRecording:!1,recordingError:G instanceof Error?G.message:String(G)},H(),G}};return{close:()=>{W(),y(),V.close()},startRecording:$,stopRecording:y,get assistantAudio(){return T.assistantAudio},get assistantTexts(){return T.assistantTexts},get assistantStreamingText(){return T.assistantStreamingText},bindHTMX(G){return k(V,G)},get call(){return T.call},callControl:(G)=>V.callControl(G),endTurn:()=>V.endTurn(),get error(){return T.error},getServerSnapshot:()=>T,getSnapshot:()=>T,get isConnected(){return T.isConnected},get isRecording(){return T.isRecording},get partial(){return T.partial},get reconnect(){return T.reconnect},get recordingError(){return T.recordingError},get scenarioId(){return T.scenarioId},sendAudio:(G)=>V.sendAudio(G),get sessionId(){return T.sessionId},get sessionMetadata(){return T.sessionMetadata},simulateDisconnect:()=>V.simulateDisconnect(),get status(){return T.status},subscribe:(G)=>{return L.add(G),()=>{L.delete(G)}},toggleRecording:async()=>{if(T.isRecording){y();return}await $()},get turns(){return T.turns}}};var Q=(g)=>String(g).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var t=(g)=>{if(!g.isConnected)return"idle";if(g.isPlaying)return"speaking";if(g.isRecording&&g.hasActivePartial)return"listening";if(g.isRecording)return"listening";if(g.lastTranscriptAt&&!g.lastAssistantAt)return"thinking";if(g.lastTranscriptAt&&g.lastAssistantAt&&g.lastTranscriptAt>g.lastAssistantAt)return"thinking";return"idle"};var f0={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},d0={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},v0=(g,A)=>{switch(g){case"listening":return A.listening;case"speaking":return A.speaking;case"thinking":return A.thinking;case"idle":return A.idle}},e=(g)=>{let A={...f0,...g.theme},C={...d0,...g.labels},V=g.state.assistantAudio.at(-1)?.receivedAt,c=g.state.turns.at(-1)?.committedAt,T=t({hasActivePartial:g.state.partial.length>0,isConnected:g.state.isConnected,isPlaying:!1,isRecording:g.state.isRecording,lastAssistantAt:V,lastTranscriptAt:c}),L=!g.state.isConnected&&g.state.status!=="idle"&&!g.state.error,H=g.state.error?"Error":L?C.connecting:g.state.status==="completed"?C.callEnded:v0(T,C);return{agentState:T,classes:{container:`absolute-voice-widget absolute-voice-widget--${T}`,dot:`absolute-voice-widget__dot${g.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:g.state.isConnected,canMute:g.state.isRecording,canStart:!g.state.isRecording&&g.state.status!=="completed"},errorMessage:g.state.error??void 0,labels:C,partial:g.state.partial||void 0,statusLabel:H,theme:A,title:g.title??"Voice"}},i0=(g)=>typeof g==="number"?`${g}px`:g,g0=(g)=>{let A=g.theme,C=`background:${A.background};border-radius:${i0(A.radius)};color:${A.foreground};font-family:${A.fontFamily};min-width:240px;padding:20px 22px;`,V=`background:${g.errorMessage?A.errorAccent:g.agentState==="idle"?"rgba(148,163,184,0.6)":A.accent};border-radius:50%;height:10px;width:10px;`,c=[];if(g.controls.canStart)c.push(`<button type="button" data-action="start" style="background:${A.accent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${Q(g.labels.startCall)}</button>`);if(g.controls.canMute)c.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${Q(g.labels.mute)}</button>`);if(g.controls.canEnd)c.push(`<button type="button" data-action="end" style="background:${A.errorAccent};border:none;border-radius:12px;color:${A.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${Q(g.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${g.agentState}" class="${Q(g.classes.container)}" style="${C}">
|
|
2
2
|
<div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
|
|
3
|
-
<span aria-hidden="true" class="${
|
|
4
|
-
<strong style="font-size:15px;">${
|
|
5
|
-
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${
|
|
3
|
+
<span aria-hidden="true" class="${Q(g.classes.dot)}" style="${V}"></span>
|
|
4
|
+
<strong style="font-size:15px;">${Q(g.title)}</strong>
|
|
5
|
+
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${Q(g.statusLabel)}</span>
|
|
6
6
|
</div>
|
|
7
|
-
${g.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${
|
|
8
|
-
<div style="display:flex;gap:10px;">${
|
|
9
|
-
${g.errorMessage?`<p style="color:${A.errorAccent};font-size:12px;margin-top:12px;">${
|
|
10
|
-
</div>`};var
|
|
7
|
+
${g.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${Q(g.partial)}”</p>`:""}
|
|
8
|
+
<div style="display:flex;gap:10px;">${c.join("")}</div>
|
|
9
|
+
${g.errorMessage?`<p style="color:${A.errorAccent};font-size:12px;margin-top:12px;">${Q(g.errorMessage)}</p>`:""}
|
|
10
|
+
</div>`};var n0=(g)=>{if(typeof g!=="string")return g;let A=document.querySelector(g);if(!A)throw Error(`AbsoluteVoice.mount: no element matches "${g}"`);return A},A0=(g,A={})=>{let C=n0(g),V=p(A.path??"/voice",A.controllerOptions),c=null,T=null,L=()=>{let _=e({...A.labels!==void 0?{labels:A.labels}:{},state:{assistantAudio:V.assistantAudio,error:V.error,isConnected:V.isConnected,isRecording:V.isRecording,partial:V.partial,status:V.status,turns:V.turns},...A.theme!==void 0?{theme:A.theme}:{},...A.title!==void 0?{title:A.title}:{}});C.innerHTML=g0(_);for(let W of C.querySelectorAll("button[data-action]")){let{action:I}=W.dataset;W.addEventListener("click",()=>{if(I==="start")V.startRecording();else if(I==="mute")V.stopRecording();else if(I==="end")V.close()})}if(V.error&&V.error!==c)c=V.error,A.onError?.(V.error);if(V.status!==T)T=V.status,A.onStatusChange?.(V.status)},H=V.subscribe(L);if(L(),A.autoStart)V.startRecording();return{controller:V,async end(){await V.close()},mute(){V.stopRecording()},async start(){await V.startRecording()},unmount(){H(),V.close(),C.innerHTML=""}}},V0="0.0.22-beta.516",C0={mount:A0,version:V0};if(typeof globalThis<"u")globalThis.AbsoluteVoice=C0;var m0=C0;})();
|
package/dist/index.js
CHANGED
|
@@ -391,146 +391,25 @@ var resolveLogger = (logger) => ({
|
|
|
391
391
|
...logger
|
|
392
392
|
});
|
|
393
393
|
|
|
394
|
-
// src/core/turnDetection.ts
|
|
395
|
-
var DEFAULT_SILENCE_MS = 700;
|
|
396
|
-
var DEFAULT_SPEECH_THRESHOLD = 0.015;
|
|
397
|
-
var DEFAULT_SEMANTIC_VETO_RECHECK_MS = 1200;
|
|
398
|
-
var toUint8Array = (audio) => {
|
|
399
|
-
if (audio instanceof ArrayBuffer) {
|
|
400
|
-
return new Uint8Array(audio);
|
|
401
|
-
}
|
|
402
|
-
return new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
403
|
-
};
|
|
404
|
-
var measureAudioLevel = (audio) => {
|
|
405
|
-
const bytes = toUint8Array(audio);
|
|
406
|
-
if (bytes.byteLength < 2) {
|
|
407
|
-
return 0;
|
|
408
|
-
}
|
|
409
|
-
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
410
|
-
if (samples.length === 0) {
|
|
411
|
-
return 0;
|
|
412
|
-
}
|
|
413
|
-
let sumSquares = 0;
|
|
414
|
-
for (const sample of samples) {
|
|
415
|
-
const normalized = sample / 32768;
|
|
416
|
-
sumSquares += normalized * normalized;
|
|
417
|
-
}
|
|
418
|
-
return Math.sqrt(sumSquares / samples.length);
|
|
419
|
-
};
|
|
420
|
-
var normalizeText = (value) => value.trim().replace(/\s+/g, " ");
|
|
421
|
-
var countWords = (value) => value.length > 0 ? value.split(" ").length : 0;
|
|
422
|
-
var selectPreferredTranscriptText = (currentText, nextText) => {
|
|
423
|
-
const current = normalizeText(currentText);
|
|
424
|
-
const next = normalizeText(nextText);
|
|
425
|
-
if (!current) {
|
|
426
|
-
return next;
|
|
427
|
-
}
|
|
428
|
-
if (!next) {
|
|
429
|
-
return current;
|
|
430
|
-
}
|
|
431
|
-
if (current === next || current.includes(next)) {
|
|
432
|
-
return current;
|
|
433
|
-
}
|
|
434
|
-
if (next.includes(current)) {
|
|
435
|
-
return next;
|
|
436
|
-
}
|
|
437
|
-
if (countWords(next) > countWords(current)) {
|
|
438
|
-
return next;
|
|
439
|
-
}
|
|
440
|
-
if (countWords(next) === countWords(current) && next.length > current.length) {
|
|
441
|
-
return next;
|
|
442
|
-
}
|
|
443
|
-
return current;
|
|
444
|
-
};
|
|
445
|
-
var mergeSequentialTranscriptText = (currentText, nextText) => {
|
|
446
|
-
const current = normalizeText(currentText);
|
|
447
|
-
const next = normalizeText(nextText);
|
|
448
|
-
if (!current) {
|
|
449
|
-
return next;
|
|
450
|
-
}
|
|
451
|
-
if (!next) {
|
|
452
|
-
return current;
|
|
453
|
-
}
|
|
454
|
-
const currentWords = current.split(" ");
|
|
455
|
-
const nextWords = next.split(" ");
|
|
456
|
-
const maxOverlap = Math.min(currentWords.length, nextWords.length);
|
|
457
|
-
for (let overlap = maxOverlap;overlap > 0; overlap -= 1) {
|
|
458
|
-
const currentSuffix = currentWords.slice(-overlap).join(" ");
|
|
459
|
-
const nextPrefix = nextWords.slice(0, overlap).join(" ");
|
|
460
|
-
if (currentSuffix === nextPrefix) {
|
|
461
|
-
return [...currentWords, ...nextWords.slice(overlap)].join(" ");
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return `${current} ${next}`.trim();
|
|
465
|
-
};
|
|
466
|
-
var countCommonPrefixWords = (currentText, nextText) => {
|
|
467
|
-
const currentWords = normalizeText(currentText).split(" ").filter(Boolean);
|
|
468
|
-
const nextWords = normalizeText(nextText).split(" ").filter(Boolean);
|
|
469
|
-
const maxWords = Math.min(currentWords.length, nextWords.length);
|
|
470
|
-
let count = 0;
|
|
471
|
-
for (let index = 0;index < maxWords; index += 1) {
|
|
472
|
-
if (currentWords[index] !== nextWords[index]) {
|
|
473
|
-
break;
|
|
474
|
-
}
|
|
475
|
-
count += 1;
|
|
476
|
-
}
|
|
477
|
-
return count;
|
|
478
|
-
};
|
|
479
|
-
var mergeTranscriptTexts = (transcripts) => {
|
|
480
|
-
const merged = [];
|
|
481
|
-
for (const transcript of transcripts) {
|
|
482
|
-
const nextText = normalizeText(transcript.text);
|
|
483
|
-
if (!nextText) {
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
const previous = merged.at(-1);
|
|
487
|
-
if (!previous) {
|
|
488
|
-
merged.push(nextText);
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
if (nextText === previous || previous.includes(nextText)) {
|
|
492
|
-
continue;
|
|
493
|
-
}
|
|
494
|
-
if (nextText.includes(previous)) {
|
|
495
|
-
merged[merged.length - 1] = nextText;
|
|
496
|
-
continue;
|
|
497
|
-
}
|
|
498
|
-
merged.push(nextText);
|
|
499
|
-
}
|
|
500
|
-
return merged.join(" ").trim();
|
|
501
|
-
};
|
|
502
|
-
var buildTurnText = (transcripts, partialText, options = {}) => {
|
|
503
|
-
const finalText = mergeTranscriptTexts(transcripts);
|
|
504
|
-
const nextPartial = normalizeText(partialText);
|
|
505
|
-
const lastFinalEndedAtMs = [...transcripts].reverse().find((transcript) => typeof transcript.endedAtMs === "number")?.endedAtMs;
|
|
506
|
-
if (finalText && nextPartial && typeof lastFinalEndedAtMs === "number" && typeof options.partialStartedAtMs === "number" && options.partialStartedAtMs - lastFinalEndedAtMs >= 250 && countCommonPrefixWords(finalText, nextPartial) === 0) {
|
|
507
|
-
return mergeSequentialTranscriptText(finalText, nextPartial);
|
|
508
|
-
}
|
|
509
|
-
return selectPreferredTranscriptText(finalText, nextPartial);
|
|
510
|
-
};
|
|
511
|
-
|
|
512
394
|
// src/core/turnProfiles.ts
|
|
513
395
|
var TURN_PROFILE_DEFAULTS = {
|
|
514
396
|
balanced: {
|
|
515
397
|
qualityProfile: "general",
|
|
516
|
-
|
|
517
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
398
|
+
minSilenceMs: 400,
|
|
518
399
|
silenceMs: 1400,
|
|
519
400
|
speechThreshold: 0.012,
|
|
520
401
|
transcriptStabilityMs: 1000
|
|
521
402
|
},
|
|
522
403
|
fast: {
|
|
523
404
|
qualityProfile: "general",
|
|
524
|
-
|
|
525
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
405
|
+
minSilenceMs: 300,
|
|
526
406
|
silenceMs: 700,
|
|
527
407
|
speechThreshold: 0.015,
|
|
528
408
|
transcriptStabilityMs: 450
|
|
529
409
|
},
|
|
530
410
|
"long-form": {
|
|
531
411
|
qualityProfile: "general",
|
|
532
|
-
|
|
533
|
-
semanticVetoRecheckMs: DEFAULT_SEMANTIC_VETO_RECHECK_MS,
|
|
412
|
+
minSilenceMs: 600,
|
|
534
413
|
silenceMs: 2200,
|
|
535
414
|
speechThreshold: 0.01,
|
|
536
415
|
transcriptStabilityMs: 1500
|
|
@@ -561,12 +440,12 @@ var resolveTurnDetectionConfig = (config) => {
|
|
|
561
440
|
const qualityProfile = config?.qualityProfile ?? DEFAULT_QUALITY_PROFILE;
|
|
562
441
|
const preset = TURN_PROFILE_DEFAULTS[profile];
|
|
563
442
|
const quality = QUALITY_PROFILE_DEFAULTS[qualityProfile];
|
|
443
|
+
const silenceMs = config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs;
|
|
564
444
|
return {
|
|
565
445
|
profile,
|
|
566
446
|
qualityProfile,
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
silenceMs: config?.silenceMs ?? quality.silenceMs ?? preset.silenceMs,
|
|
447
|
+
minSilenceMs: Math.min(silenceMs, config?.minSilenceMs ?? quality.minSilenceMs ?? preset.minSilenceMs),
|
|
448
|
+
silenceMs,
|
|
570
449
|
speechThreshold: config?.speechThreshold ?? quality.speechThreshold ?? preset.speechThreshold,
|
|
571
450
|
transcriptStabilityMs: config?.transcriptStabilityMs ?? quality.transcriptStabilityMs ?? preset.transcriptStabilityMs
|
|
572
451
|
};
|
|
@@ -3580,6 +3459,124 @@ var createVoiceTwilioRedirectHandoffAdapter = (options) => ({
|
|
|
3580
3459
|
}
|
|
3581
3460
|
});
|
|
3582
3461
|
|
|
3462
|
+
// src/core/turnDetection.ts
|
|
3463
|
+
var DEFAULT_SILENCE_MS = 700;
|
|
3464
|
+
var DEFAULT_SPEECH_THRESHOLD = 0.015;
|
|
3465
|
+
var DEFAULT_MIN_SILENCE_MS = 400;
|
|
3466
|
+
var toUint8Array = (audio) => {
|
|
3467
|
+
if (audio instanceof ArrayBuffer) {
|
|
3468
|
+
return new Uint8Array(audio);
|
|
3469
|
+
}
|
|
3470
|
+
return new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
3471
|
+
};
|
|
3472
|
+
var measureAudioLevel = (audio) => {
|
|
3473
|
+
const bytes = toUint8Array(audio);
|
|
3474
|
+
if (bytes.byteLength < 2) {
|
|
3475
|
+
return 0;
|
|
3476
|
+
}
|
|
3477
|
+
const samples = new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));
|
|
3478
|
+
if (samples.length === 0) {
|
|
3479
|
+
return 0;
|
|
3480
|
+
}
|
|
3481
|
+
let sumSquares = 0;
|
|
3482
|
+
for (const sample of samples) {
|
|
3483
|
+
const normalized = sample / 32768;
|
|
3484
|
+
sumSquares += normalized * normalized;
|
|
3485
|
+
}
|
|
3486
|
+
return Math.sqrt(sumSquares / samples.length);
|
|
3487
|
+
};
|
|
3488
|
+
var normalizeText = (value) => value.trim().replace(/\s+/g, " ");
|
|
3489
|
+
var countWords = (value) => value.length > 0 ? value.split(" ").length : 0;
|
|
3490
|
+
var selectPreferredTranscriptText = (currentText, nextText) => {
|
|
3491
|
+
const current = normalizeText(currentText);
|
|
3492
|
+
const next = normalizeText(nextText);
|
|
3493
|
+
if (!current) {
|
|
3494
|
+
return next;
|
|
3495
|
+
}
|
|
3496
|
+
if (!next) {
|
|
3497
|
+
return current;
|
|
3498
|
+
}
|
|
3499
|
+
if (current === next || current.includes(next)) {
|
|
3500
|
+
return current;
|
|
3501
|
+
}
|
|
3502
|
+
if (next.includes(current)) {
|
|
3503
|
+
return next;
|
|
3504
|
+
}
|
|
3505
|
+
if (countWords(next) > countWords(current)) {
|
|
3506
|
+
return next;
|
|
3507
|
+
}
|
|
3508
|
+
if (countWords(next) === countWords(current) && next.length > current.length) {
|
|
3509
|
+
return next;
|
|
3510
|
+
}
|
|
3511
|
+
return current;
|
|
3512
|
+
};
|
|
3513
|
+
var mergeSequentialTranscriptText = (currentText, nextText) => {
|
|
3514
|
+
const current = normalizeText(currentText);
|
|
3515
|
+
const next = normalizeText(nextText);
|
|
3516
|
+
if (!current) {
|
|
3517
|
+
return next;
|
|
3518
|
+
}
|
|
3519
|
+
if (!next) {
|
|
3520
|
+
return current;
|
|
3521
|
+
}
|
|
3522
|
+
const currentWords = current.split(" ");
|
|
3523
|
+
const nextWords = next.split(" ");
|
|
3524
|
+
const maxOverlap = Math.min(currentWords.length, nextWords.length);
|
|
3525
|
+
for (let overlap = maxOverlap;overlap > 0; overlap -= 1) {
|
|
3526
|
+
const currentSuffix = currentWords.slice(-overlap).join(" ");
|
|
3527
|
+
const nextPrefix = nextWords.slice(0, overlap).join(" ");
|
|
3528
|
+
if (currentSuffix === nextPrefix) {
|
|
3529
|
+
return [...currentWords, ...nextWords.slice(overlap)].join(" ");
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
return `${current} ${next}`.trim();
|
|
3533
|
+
};
|
|
3534
|
+
var countCommonPrefixWords = (currentText, nextText) => {
|
|
3535
|
+
const currentWords = normalizeText(currentText).split(" ").filter(Boolean);
|
|
3536
|
+
const nextWords = normalizeText(nextText).split(" ").filter(Boolean);
|
|
3537
|
+
const maxWords = Math.min(currentWords.length, nextWords.length);
|
|
3538
|
+
let count = 0;
|
|
3539
|
+
for (let index = 0;index < maxWords; index += 1) {
|
|
3540
|
+
if (currentWords[index] !== nextWords[index]) {
|
|
3541
|
+
break;
|
|
3542
|
+
}
|
|
3543
|
+
count += 1;
|
|
3544
|
+
}
|
|
3545
|
+
return count;
|
|
3546
|
+
};
|
|
3547
|
+
var mergeTranscriptTexts = (transcripts) => {
|
|
3548
|
+
const merged = [];
|
|
3549
|
+
for (const transcript of transcripts) {
|
|
3550
|
+
const nextText = normalizeText(transcript.text);
|
|
3551
|
+
if (!nextText) {
|
|
3552
|
+
continue;
|
|
3553
|
+
}
|
|
3554
|
+
const previous = merged.at(-1);
|
|
3555
|
+
if (!previous) {
|
|
3556
|
+
merged.push(nextText);
|
|
3557
|
+
continue;
|
|
3558
|
+
}
|
|
3559
|
+
if (nextText === previous || previous.includes(nextText)) {
|
|
3560
|
+
continue;
|
|
3561
|
+
}
|
|
3562
|
+
if (nextText.includes(previous)) {
|
|
3563
|
+
merged[merged.length - 1] = nextText;
|
|
3564
|
+
continue;
|
|
3565
|
+
}
|
|
3566
|
+
merged.push(nextText);
|
|
3567
|
+
}
|
|
3568
|
+
return merged.join(" ").trim();
|
|
3569
|
+
};
|
|
3570
|
+
var buildTurnText = (transcripts, partialText, options = {}) => {
|
|
3571
|
+
const finalText = mergeTranscriptTexts(transcripts);
|
|
3572
|
+
const nextPartial = normalizeText(partialText);
|
|
3573
|
+
const lastFinalEndedAtMs = [...transcripts].reverse().find((transcript) => typeof transcript.endedAtMs === "number")?.endedAtMs;
|
|
3574
|
+
if (finalText && nextPartial && typeof lastFinalEndedAtMs === "number" && typeof options.partialStartedAtMs === "number" && options.partialStartedAtMs - lastFinalEndedAtMs >= 250 && countCommonPrefixWords(finalText, nextPartial) === 0) {
|
|
3575
|
+
return mergeSequentialTranscriptText(finalText, nextPartial);
|
|
3576
|
+
}
|
|
3577
|
+
return selectPreferredTranscriptText(finalText, nextPartial);
|
|
3578
|
+
};
|
|
3579
|
+
|
|
3583
3580
|
// src/core/types.ts
|
|
3584
3581
|
var ttsAdapterSessionCanCancel = (session) => typeof session.cancel === "function";
|
|
3585
3582
|
|
|
@@ -3926,14 +3923,22 @@ var createVoiceSession = (options) => {
|
|
|
3926
3923
|
strategy: options.reconnect.strategy ?? "resume-last-turn",
|
|
3927
3924
|
timeout: options.reconnect.timeout ?? DEFAULT_RECONNECT_TIMEOUT
|
|
3928
3925
|
};
|
|
3926
|
+
const resolvedSilenceMs = options.turnDetection.silenceMs ?? DEFAULT_SILENCE_MS;
|
|
3929
3927
|
const turnDetection = {
|
|
3930
|
-
silenceMs:
|
|
3928
|
+
silenceMs: resolvedSilenceMs,
|
|
3929
|
+
minSilenceMs: Math.min(resolvedSilenceMs, options.turnDetection.minSilenceMs ?? DEFAULT_MIN_SILENCE_MS),
|
|
3931
3930
|
speechThreshold: options.turnDetection.speechThreshold ?? DEFAULT_SPEECH_THRESHOLD,
|
|
3932
|
-
transcriptStabilityMs: options.turnDetection.transcriptStabilityMs ?? DEFAULT_TRANSCRIPT_STABILITY_MS
|
|
3933
|
-
|
|
3934
|
-
|
|
3931
|
+
transcriptStabilityMs: options.turnDetection.transcriptStabilityMs ?? DEFAULT_TRANSCRIPT_STABILITY_MS
|
|
3932
|
+
};
|
|
3933
|
+
let lastTurnCompleteConfidence = null;
|
|
3934
|
+
const adaptiveSilenceMs = () => {
|
|
3935
|
+
const { minSilenceMs, silenceMs } = turnDetection;
|
|
3936
|
+
if (lastTurnCompleteConfidence === null || silenceMs <= minSilenceMs) {
|
|
3937
|
+
return silenceMs;
|
|
3938
|
+
}
|
|
3939
|
+
const complete = Math.max(0, Math.min(1, lastTurnCompleteConfidence));
|
|
3940
|
+
return Math.round(minSilenceMs + (silenceMs - minSilenceMs) * (1 - complete));
|
|
3935
3941
|
};
|
|
3936
|
-
let semanticVetoElapsedMs = 0;
|
|
3937
3942
|
const sttFallback = options.sttFallback ? {
|
|
3938
3943
|
adapter: options.sttFallback.adapter,
|
|
3939
3944
|
completionTimeoutMs: options.sttFallback.completionTimeoutMs ?? DEFAULT_FALLBACK_COMPLETION_TIMEOUT_MS,
|
|
@@ -4137,6 +4142,17 @@ var createVoiceSession = (options) => {
|
|
|
4137
4142
|
pruneTurnAudio();
|
|
4138
4143
|
return currentTurnAudio.map((audio) => audio.chunk);
|
|
4139
4144
|
};
|
|
4145
|
+
const turnAudioInputFormat = recordingConfig?.userInputFormat ?? options.realtimeInputFormat ?? DEFAULT_REALTIME_FORMAT;
|
|
4146
|
+
const getTurnAudioForDetector = () => {
|
|
4147
|
+
if (!options.semanticTurnDetector || currentTurnAudio.length === 0) {
|
|
4148
|
+
return { turnAudio: undefined, turnAudioFormat: undefined };
|
|
4149
|
+
}
|
|
4150
|
+
const turnAudio = currentTurnAudio.map((audio) => {
|
|
4151
|
+
const c = audio.chunk;
|
|
4152
|
+
return c instanceof ArrayBuffer ? new Uint8Array(c) : new Uint8Array(c.buffer, c.byteOffset, c.byteLength);
|
|
4153
|
+
});
|
|
4154
|
+
return { turnAudio, turnAudioFormat: turnAudioInputFormat };
|
|
4155
|
+
};
|
|
4140
4156
|
const clearSilenceTimer = () => {
|
|
4141
4157
|
if (!silenceTimer) {
|
|
4142
4158
|
return;
|
|
@@ -4455,46 +4471,8 @@ var createVoiceSession = (options) => {
|
|
|
4455
4471
|
runScheduledCommit(reason);
|
|
4456
4472
|
}, delayMs);
|
|
4457
4473
|
};
|
|
4458
|
-
const scheduleSilenceCommit = (delayMs =
|
|
4459
|
-
const shouldDeferSilenceCommit = async (reason) => {
|
|
4460
|
-
if (reason !== "silence" || turnDetection.semanticVetoMaxMs <= 0 || !options.semanticTurnDetector || semanticVetoElapsedMs >= turnDetection.semanticVetoMaxMs) {
|
|
4461
|
-
return false;
|
|
4462
|
-
}
|
|
4463
|
-
const session = await readSession();
|
|
4464
|
-
const { partialText, transcripts } = session.currentTurn;
|
|
4465
|
-
const userText = buildTurnText(transcripts, partialText, {
|
|
4466
|
-
partialEndedAtMs: session.currentTurn.partialEndedAt,
|
|
4467
|
-
partialStartedAtMs: session.currentTurn.partialStartedAt
|
|
4468
|
-
});
|
|
4469
|
-
if (!userText) {
|
|
4470
|
-
return false;
|
|
4471
|
-
}
|
|
4472
|
-
const silenceMs = session.currentTurn.silenceStartedAt !== undefined ? Date.now() - session.currentTurn.silenceStartedAt : turnDetection.silenceMs;
|
|
4473
|
-
let endOfTurn = true;
|
|
4474
|
-
try {
|
|
4475
|
-
const verdict = await Promise.resolve(options.semanticTurnDetector.evaluate({
|
|
4476
|
-
lastFinalTranscript: transcripts.at(-1),
|
|
4477
|
-
partialText,
|
|
4478
|
-
silenceMs,
|
|
4479
|
-
transcripts
|
|
4480
|
-
}));
|
|
4481
|
-
endOfTurn = verdict.endOfTurn;
|
|
4482
|
-
} catch {
|
|
4483
|
-
return false;
|
|
4484
|
-
}
|
|
4485
|
-
if (endOfTurn !== false) {
|
|
4486
|
-
return false;
|
|
4487
|
-
}
|
|
4488
|
-
const remaining = turnDetection.semanticVetoMaxMs - semanticVetoElapsedMs;
|
|
4489
|
-
const extendMs = Math.max(1, Math.min(turnDetection.semanticVetoRecheckMs, remaining));
|
|
4490
|
-
semanticVetoElapsedMs += extendMs;
|
|
4491
|
-
scheduleTurnCommit(extendMs, reason);
|
|
4492
|
-
return true;
|
|
4493
|
-
};
|
|
4474
|
+
const scheduleSilenceCommit = (delayMs = adaptiveSilenceMs(), reset = true) => scheduleTurnCommit(delayMs, "silence", reset);
|
|
4494
4475
|
const runScheduledCommit = async (reason) => {
|
|
4495
|
-
if (await shouldDeferSilenceCommit(reason)) {
|
|
4496
|
-
return;
|
|
4497
|
-
}
|
|
4498
4476
|
await api.commitTurn(reason);
|
|
4499
4477
|
};
|
|
4500
4478
|
const requestTurnCommit = async (reason) => {
|
|
@@ -5234,7 +5212,7 @@ var createVoiceSession = (options) => {
|
|
|
5234
5212
|
session2.lastActivityAt = Date.now();
|
|
5235
5213
|
session2.status = "active";
|
|
5236
5214
|
});
|
|
5237
|
-
|
|
5215
|
+
lastTurnCompleteConfidence = null;
|
|
5238
5216
|
if (silenceTimer && pendingCommitReason === "vendor") {
|
|
5239
5217
|
scheduleTurnCommit(getVendorCommitDelayMs(), "vendor");
|
|
5240
5218
|
}
|
|
@@ -5261,8 +5239,15 @@ var createVoiceSession = (options) => {
|
|
|
5261
5239
|
lastFinalTranscript: transcript,
|
|
5262
5240
|
partialText: session.currentTurn.partialText,
|
|
5263
5241
|
silenceMs: session.currentTurn.silenceStartedAt !== undefined ? Date.now() - session.currentTurn.silenceStartedAt : 0,
|
|
5264
|
-
transcripts: session.currentTurn.transcripts
|
|
5242
|
+
transcripts: session.currentTurn.transcripts,
|
|
5243
|
+
...getTurnAudioForDetector()
|
|
5265
5244
|
}));
|
|
5245
|
+
if (typeof verdict.confidence === "number") {
|
|
5246
|
+
lastTurnCompleteConfidence = verdict.confidence;
|
|
5247
|
+
if (silenceTimer && pendingCommitReason === "silence") {
|
|
5248
|
+
scheduleSilenceCommit();
|
|
5249
|
+
}
|
|
5250
|
+
}
|
|
5266
5251
|
if (verdict.endOfTurn) {
|
|
5267
5252
|
clearSilenceTimer();
|
|
5268
5253
|
await requestTurnCommit("vendor");
|
|
@@ -5958,7 +5943,7 @@ var createVoiceSession = (options) => {
|
|
|
5958
5943
|
};
|
|
5959
5944
|
const commitTurnInternal = async (reason = "manual") => {
|
|
5960
5945
|
clearSilenceTimer();
|
|
5961
|
-
|
|
5946
|
+
lastTurnCompleteConfidence = null;
|
|
5962
5947
|
backchannelDriver?.reset();
|
|
5963
5948
|
amdLastTurnCommitAt = Date.now();
|
|
5964
5949
|
const session = await readSession();
|
|
@@ -42561,16 +42546,18 @@ var createVoiceConfiguration = (configuration) => configuration;
|
|
|
42561
42546
|
var DEFAULT_SPEECH_THRESHOLD2 = 0.015;
|
|
42562
42547
|
var DEFAULT_SILENCE_MS2 = 700;
|
|
42563
42548
|
var DEFAULT_TRANSCRIPT_STABILITY_MS2 = 200;
|
|
42564
|
-
var
|
|
42565
|
-
var resolveTurnDetection = (input) =>
|
|
42566
|
-
|
|
42567
|
-
|
|
42568
|
-
|
|
42569
|
-
|
|
42570
|
-
|
|
42571
|
-
|
|
42572
|
-
|
|
42573
|
-
|
|
42549
|
+
var DEFAULT_MIN_SILENCE_MS2 = 400;
|
|
42550
|
+
var resolveTurnDetection = (input) => {
|
|
42551
|
+
const silenceMs = input?.silenceMs ?? DEFAULT_SILENCE_MS2;
|
|
42552
|
+
return {
|
|
42553
|
+
profile: input?.profile ?? "balanced",
|
|
42554
|
+
qualityProfile: input?.qualityProfile ?? "general",
|
|
42555
|
+
minSilenceMs: Math.min(silenceMs, input?.minSilenceMs ?? DEFAULT_MIN_SILENCE_MS2),
|
|
42556
|
+
silenceMs,
|
|
42557
|
+
speechThreshold: input?.speechThreshold ?? DEFAULT_SPEECH_THRESHOLD2,
|
|
42558
|
+
transcriptStabilityMs: input?.transcriptStabilityMs ?? DEFAULT_TRANSCRIPT_STABILITY_MS2
|
|
42559
|
+
};
|
|
42560
|
+
};
|
|
42574
42561
|
var resolveReconnect = (input) => ({
|
|
42575
42562
|
maxAttempts: input?.maxAttempts ?? 3,
|
|
42576
42563
|
strategy: input?.strategy ?? "resume-last-turn",
|