@absolutejs/voice 0.0.22-beta.527 → 0.0.22-beta.528

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/index.js CHANGED
@@ -5748,9 +5748,6 @@ var createVoiceSession = (options) => {
5748
5748
  return api;
5749
5749
  };
5750
5750
 
5751
- // src/generated/htmxBootstrapBundle.ts
5752
- var HTMX_BOOTSTRAP_BUNDLE = 'var Hn=(n)=>{if(typeof n!=="string")return n;return document.querySelector(n)},Gn=(n,c,o,e)=>{let i=c??n.getAttribute("hx-get")??"";if(!i)return"";let l=new URL(i,window.location.origin);if(e)l.searchParams.set(o,e);else l.searchParams.delete(o);return`${l.pathname}${l.search}${l.hash}`},gn=(n,c)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let o=Hn(c.element);if(!o)return()=>{};let e=c.eventName??"voice-refresh",i=c.sessionQueryParam??"sessionId",l=()=>{let d=window,g=Gn(o,c.route,i,n.sessionId);if(g)o.setAttribute("hx-get",g);d.htmx?.process?.(o),d.htmx?.trigger?.(o,e)},t=n.subscribe(l);return l(),()=>{t()}};var Bn=(n)=>Math.max(-1,Math.min(1,n)),Wn=(n)=>{let c=new Int16Array(n.length);for(let o=0;o<n.length;o+=1){let e=Bn(n[o]??0);c[o]=e<0?e*32768:e*32767}return new Uint8Array(c.buffer)},$n=(n)=>{let c=n instanceof Uint8Array?n:new Uint8Array(n);if(c.byteLength<2)return 0;let o=new Int16Array(c.buffer,c.byteOffset,Math.floor(c.byteLength/2));if(o.length===0)return 0;let e=0;for(let i of o){let l=i/32768;e+=l*l}return Math.min(1,Math.max(0,Math.sqrt(e/o.length)*5.5))},qn=(n,c,o)=>{if(c===o)return n;let e=c/o,i=Math.round(n.length/e),l=new Float32Array(i),t=0,d=0;while(t<l.length){let g=Math.round((t+1)*e),y=0,a=0;for(let h=d;h<g&&h<n.length;h+=1)y+=n[h]??0,a+=1;l[t]=a>0?y/a:0,t+=1,d=g}return l},An=(n)=>{let c=null,o=null,e=null,i=null;return{start:async()=>{if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let d=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!d)throw Error("Browser microphone capture requires AudioContext support.");i=await navigator.mediaDevices.getUserMedia({audio:{channelCount:n.channelCount??1}}),c=new d,o=c.createMediaStreamSource(i),e=c.createScriptProcessor(4096,1,1),e.onaudioprocess=(g)=>{let y=g.inputBuffer.getChannelData(0),a=qn(y,c?.sampleRate??48000,n.sampleRateHz??16000),h=Wn(a);n.onLevel?.($n(h)),n.onAudio(h)},o.connect(e),e.connect(c.destination)},stop:()=>{e?.disconnect(),o?.disconnect(),i?.getTracks().forEach((d)=>d.stop()),c?.close(),n.onLevel?.(0),c=null,i=null,e=null,o=null}}};var nn=(n)=>{if(typeof n==="string"&&n.trim())return n;if(n instanceof Error&&n.message.trim())return n.message;if(n&&typeof n==="object"){let c=n;for(let o of["message","reason","description"]){let e=c[o];if(typeof e==="string"&&e.trim())return e}if("error"in c)return nn(c.error);if("cause"in c)return nn(c.cause);try{return JSON.stringify(n)}catch{}}return"Unexpected error"},hn=(n)=>{switch(n.type){case"audio":return{chunk:Uint8Array.from(atob(n.chunkBase64),(c)=>c.charCodeAt(0)),format:n.format,receivedAt:n.receivedAt,turnId:n.turnId,type:"audio"};case"assistant":return{text:n.text,type:"assistant"};case"complete":return{sessionId:n.sessionId,type:"complete"};case"connection":return{reconnect:n.reconnect,type:"connection"};case"call_lifecycle":return{event:n.event,sessionId:n.sessionId,type:"call_lifecycle"};case"error":return{message:nn(n.message),type:"error"};case"final":return{transcript:n.transcript,type:"final"};case"partial":return{transcript:n.transcript,type:"partial"};case"replay":return{assistantTexts:n.assistantTexts,call:n.call,partial:n.partial,scenarioId:n.scenarioId,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,status:n.status,turns:n.turns,type:"replay"};case"session":return{sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,type:"session"};case"turn":return{turn:n.turn,type:"turn"};default:return null}};var Hc=Math.PI*2;var G=(n,c,o,e)=>{n.push({code:o,message:e,severity:c})};var Xn=(n)=>n.length===0?void 0:n.reduce((c,o)=>c+o,0)/n.length,K=(n)=>n.length===0?void 0:Math.max(...n);var b=(n,c)=>{let o=n[c];return typeof o==="number"&&Number.isFinite(o)?o:void 0},Z=(n,c)=>{let o=n[c];return typeof o==="boolean"?o:void 0},O=(n,c)=>{let o=n[c];return typeof o==="string"?o:void 0},cn=(n)=>String(n.id??O(n,"ssrc")??b(n,"ssrc")??O(n,"trackIdentifier")??O(n,"mid")??"unknown"),yn=(n)=>n===void 0?void 0:n*1000;var un=(n)=>{let c={};for(let[o,e]of Object.entries(n))if(e===null||typeof e==="boolean"||typeof e==="number"||typeof e==="string")c[o]=e;return c};var Cn=(n={})=>{let c=n.stats??[],o=[],e=c.filter((s)=>s.type==="inbound-rtp"&&O(s,"kind")!=="video"),i=c.filter((s)=>s.type==="outbound-rtp"&&O(s,"kind")!=="video"),l=c.filter((s)=>s.type==="candidate-pair"),t=c.filter((s)=>(s.type==="track"||s.type==="media-source")&&O(s,"kind")==="audio"),d=l.filter((s)=>Z(s,"selected")===!0||Z(s,"nominated")===!0||O(s,"state")==="succeeded").length,g=t.filter((s)=>O(s,"readyState")!=="ended"&&O(s,"trackState")!=="ended"&&Z(s,"ended")!==!0).length,y=t.filter((s)=>O(s,"readyState")==="ended"||O(s,"trackState")==="ended"||Z(s,"ended")===!0).length,a=e.reduce((s,V)=>s+(b(V,"packetsReceived")??0),0),h=i.reduce((s,V)=>s+(b(V,"packetsSent")??0),0),r=[...e,...i].reduce((s,V)=>s+Math.max(0,b(V,"packetsLost")??0),0),M=a+r,C=M===0?0:r/M,S=e.reduce((s,V)=>s+(b(V,"bytesReceived")??0),0),w=i.reduce((s,V)=>s+(b(V,"bytesSent")??0),0),E=K(l.map((s)=>yn(b(s,"currentRoundTripTime")??b(s,"roundTripTime"))).filter((s)=>s!==void 0)),_=K([...e,...i].map((s)=>yn(b(s,"jitter"))).filter((s)=>s!==void 0)),U=K(e.map((s)=>{let V=b(s,"jitterBufferDelay"),R=b(s,"jitterBufferEmittedCount");return V!==void 0&&R!==void 0&&R>0?V/R*1000:void 0}).filter((s)=>s!==void 0)),N=t.map((s)=>b(s,"audioLevel")).filter((s)=>s!==void 0);if(n.requireConnectedCandidatePair&&l.length>0&&d===0)G(o,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(n.requireLiveAudioTrack&&g===0)G(o,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(n.maxPacketLossRatio!==void 0&&C>n.maxPacketLossRatio)G(o,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(C)} above ${String(n.maxPacketLossRatio)}.`);if(n.maxRoundTripTimeMs!==void 0&&E!==void 0&&E>n.maxRoundTripTimeMs)G(o,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(E)}ms above ${String(n.maxRoundTripTimeMs)}ms.`);if(n.maxJitterMs!==void 0&&_!==void 0&&_>n.maxJitterMs)G(o,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(_)}ms above ${String(n.maxJitterMs)}ms.`);return{activeCandidatePairs:d,audioLevelAverage:Xn(N),bytesReceived:S,bytesSent:w,checkedAt:Date.now(),endedAudioTracks:y,inboundPackets:a,issues:o,jitterBufferDelayMs:U,jitterMs:_,liveAudioTracks:g,outboundPackets:h,packetLossRatio:C,packetsLost:r,roundTripTimeMs:E,status:o.some((s)=>s.severity==="error")?"fail":o.length>0?"warn":"pass",totalStats:c.length}},Tn=async(n)=>{return[...(await n.peerConnection.getStats(n.selector??null)).values()].map(un)};var In=(n={})=>{let c=n.stats??[],o=n.previousStats??[],e=[],i=new Map(o.map((r)=>[cn(r),r])),t=c.filter((r)=>(r.type==="inbound-rtp"||r.type==="outbound-rtp")&&O(r,"kind")!=="video"&&O(r,"mediaType")!=="video").map((r)=>{let M=r.type==="outbound-rtp"?"outbound":"inbound",C=M==="outbound"?"packetsSent":"packetsReceived",S=M==="outbound"?"bytesSent":"bytesReceived",w=i.get(cn(r)),E=b(r,C),_=w?b(w,C):void 0,U=b(r,S),N=w?b(w,S):void 0,s=r.timestamp!==void 0&&w?.timestamp!==void 0?r.timestamp-w.timestamp:void 0;return{bytesDelta:U!==void 0&&N!==void 0?U-N:void 0,currentPackets:E,direction:M,id:cn(r),packetDelta:E!==void 0&&_!==void 0?E-_:void 0,previousPackets:_,timeDeltaMs:s}}),d=t.filter((r)=>r.direction==="inbound"),g=t.filter((r)=>r.direction==="outbound"),y=K(t.map((r)=>r.timeDeltaMs).filter((r)=>r!==void 0)),a=d.filter((r)=>n.maxInboundPacketStallMs!==void 0&&r.timeDeltaMs!==void 0&&r.timeDeltaMs>=n.maxInboundPacketStallMs&&r.packetDelta!==void 0&&r.packetDelta<=0).length,h=g.filter((r)=>n.maxOutboundPacketStallMs!==void 0&&r.timeDeltaMs!==void 0&&r.timeDeltaMs>=n.maxOutboundPacketStallMs&&r.packetDelta!==void 0&&r.packetDelta<=0).length;if(n.requireInboundAudio&&d.length===0)G(e,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(n.requireOutboundAudio&&g.length===0)G(e,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(n.maxGapMs!==void 0&&y!==void 0&&y>n.maxGapMs)G(e,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(y)}ms above ${String(n.maxGapMs)}ms.`);if(a>0)G(e,"error","media.webrtc_inbound_stalled",`${String(a)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)G(e,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:d.length,issues:e,maxObservedGapMs:y,outboundAudioStreams:g.length,stalledInboundStreams:a,stalledOutboundStreams:h,status:e.some((r)=>r.severity==="error")?"fail":e.length>0?"warn":"pass",streams:t,totalStats:c.length}};var Yn="/api/voice/browser-media",Jn=5000,Qn=async(n)=>n.peerConnection??await n.getPeerConnection?.()??null,kn=async(n,c)=>{let o=c.fetch??globalThis.fetch;if(!o)return;await o(c.path??Yn,{body:JSON.stringify(n),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},Vn=(n)=>{let c=null,o=[],e=async()=>{let t=await Qn(n);if(!t)return;let d=await Tn({peerConnection:t}),g=Cn({...n,stats:d}),y=n.continuity===!1?void 0:In({...n.continuity,previousStats:o,stats:d}),a={at:Date.now(),continuity:y,report:g,scenarioId:n.getScenarioId?.()??null,sessionId:n.getSessionId?.()??null};return o=d,n.onReport?.(a),await kn(a,n),a},i=()=>{e().catch((t)=>{n.onError?.(t)})},l=()=>{if(c)clearInterval(c),c=null};return{close:l,reportOnce:e,start:()=>{if(c)return;i(),c=setInterval(i,n.intervalMs??Jn)},stop:l}};var W=()=>{},zn=()=>W,Zn={callControl:W,close:W,endTurn:W,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",send:W,sendAudio:W,simulateDisconnect:W,start:()=>{},subscribe:zn},Kn=()=>crypto.randomUUID(),jn=(n,c,o)=>{let{hostname:e,port:i,protocol:l}=window.location,t=l==="https:"?"wss:":"ws:",d=i?`:${i}`:"",g=new URL(`${t}//${e}${d}${n}`);if(g.searchParams.set("sessionId",c),o)g.searchParams.set("scenarioId",o);return g.toString()},Fn=(n)=>{if(!n||typeof n!=="object"||!("type"in n))return!1;switch(n.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}},vn=(n)=>{if(typeof n.data!=="string")return null;try{let c=JSON.parse(n.data);return Fn(c)?c:null}catch{return null}},Mn=(n,c={})=>{if(typeof window>"u")return Zn;let o=new Set,e=c.reconnect!==!1,i=c.maxReconnectAttempts??10,l=c.pingInterval??30000,t={isConnected:!1,pendingMessages:[],scenarioId:c.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:c.sessionId??Kn(),ws:null},d=(s)=>{o.forEach((V)=>V(s))},g=()=>{if(t.pingInterval)clearInterval(t.pingInterval),t.pingInterval=null;if(t.reconnectTimeout)clearTimeout(t.reconnectTimeout),t.reconnectTimeout=null},y=()=>{if(t.ws?.readyState!==1)return;while(t.pendingMessages.length>0){let s=t.pendingMessages.shift();if(s!==void 0)t.ws.send(s)}},a=()=>{let s=Date.now()+500;t.reconnectAttempts+=1,d({reconnect:{attempts:t.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:i,nextAttemptAt:s,status:"reconnecting"},type:"connection"}),t.reconnectTimeout=setTimeout(()=>{if(t.reconnectAttempts>i){d({reconnect:{attempts:t.reconnectAttempts,maxAttempts:i,status:"exhausted"},type:"connection"});return}h()},500)},h=()=>{let s=new WebSocket(jn(n,t.sessionId,t.scenarioId));s.binaryType="arraybuffer",s.onopen=()=>{let V=t.reconnectAttempts>0;if(t.isConnected=!0,y(),V)d({reconnect:{attempts:t.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:i,status:"resumed"},type:"connection"}),t.reconnectAttempts=0;o.forEach((R)=>R({scenarioId:t.scenarioId??void 0,sessionId:t.sessionId,status:"active",type:"session"})),t.pingInterval=setInterval(()=>{if(s.readyState===1)s.send(JSON.stringify({type:"ping"}))},l)},s.onmessage=(V)=>{let R=vn(V);if(!R)return;if(R.type==="session")t.sessionId=R.sessionId,t.scenarioId=R.scenarioId??t.scenarioId;o.forEach((Y)=>Y(R))},s.onclose=(V)=>{if(t.isConnected=!1,g(),e&&V.code!==1000&&t.reconnectAttempts<i)a();else if(e&&V.code!==1000)d({reconnect:{attempts:t.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:i,status:"exhausted"},type:"connection"})},t.ws=s},r=(s)=>{if(t.ws?.readyState===1){t.ws.send(s);return}t.pendingMessages.push(s)},M=(s)=>{r(JSON.stringify(s))},C=(s={})=>{if(s.sessionId)t.sessionId=s.sessionId;if(s.scenarioId)t.scenarioId=s.scenarioId;M({type:"start",sessionId:t.sessionId,scenarioId:t.scenarioId??void 0})},S=(s)=>{r(s)},w=()=>{M({type:"end_turn"})},E=(s)=>{M({...s,type:"call_control"})},_=()=>{if(g(),t.ws)t.ws.close(1000),t.ws=null;t.isConnected=!1,o.clear()},U=()=>{if(t.ws?.readyState===1)t.ws.close(4000,"absolutejs-voice-reconnect-proof")},N=(s)=>{return o.add(s),()=>{o.delete(s)}};return h(),{callControl:E,close:_,endTurn:w,getReadyState:()=>t.ws?.readyState??3,getScenarioId:()=>t.scenarioId??"",getSessionId:()=>t.sessionId,send:M,sendAudio:S,simulateDisconnect:U,start:C,subscribe:N}};var mn=()=>({attempts:0,maxAttempts:0,status:"idle"}),pn=()=>({assistantAudio:[],assistantTexts:[],call:null,error:null,isConnected:!1,sessionMetadata:null,scenarioId:null,partial:"",reconnect:mn(),sessionId:null,status:"idle",turns:[]}),Sn=()=>{let n=pn(),c=new Set,o=()=>{c.forEach((i)=>i())};return{dispatch:(i)=>{switch(i.type){case"audio":n={...n,assistantAudio:[...n.assistantAudio,{chunk:i.chunk,format:i.format,receivedAt:i.receivedAt,turnId:i.turnId}]};break;case"assistant":n={...n,assistantTexts:[...n.assistantTexts,i.text]};break;case"complete":n={...n,sessionId:i.sessionId,status:"completed"};break;case"call_lifecycle":n={...n,call:{...n.call,disposition:i.event.type==="end"?i.event.disposition:n.call?.disposition,endedAt:i.event.type==="end"?i.event.at:n.call?.endedAt,events:[...n.call?.events??[],i.event],lastEventAt:i.event.at,startedAt:n.call?.startedAt??i.event.at},sessionId:i.sessionId};break;case"connected":n={...n,isConnected:!0,reconnect:n.reconnect.status==="reconnecting"?{...n.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:n.reconnect};break;case"connection":n={...n,reconnect:i.reconnect};break;case"disconnected":n={...n,isConnected:!1};break;case"error":n={...n,error:i.message};break;case"final":n={...n,partial:i.transcript.text,turns:n.turns.map((l)=>l)};break;case"partial":n={...n,partial:i.transcript.text};break;case"replay":n={...n,assistantTexts:[...i.assistantTexts],call:i.call??null,error:null,isConnected:i.status==="active",partial:i.partial,reconnect:n.reconnect.status==="reconnecting"?{...n.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:n.reconnect,scenarioId:i.scenarioId??n.scenarioId,sessionId:i.sessionId,sessionMetadata:i.sessionMetadata??n.sessionMetadata,status:i.status,turns:[...i.turns]};break;case"session":n={...n,error:null,scenarioId:i.scenarioId??n.scenarioId,isConnected:i.status==="active",sessionId:i.sessionId,sessionMetadata:i.sessionMetadata??n.sessionMetadata,status:i.status};break;case"turn":n={...n,partial:"",turns:[...n.turns,i.turn]};break}o()},getServerSnapshot:()=>n,getSnapshot:()=>n,subscribe:(i)=>{return c.add(i),()=>{c.delete(i)}}}};var Ln=(n,c={})=>{let o=Mn(n,c),e=Sn(),i=c.browserMedia&&typeof window<"u"?Vn({...c.browserMedia,getScenarioId:()=>c.browserMedia?c.browserMedia.getScenarioId?.()??o.getScenarioId():o.getScenarioId(),getSessionId:()=>c.browserMedia?c.browserMedia.getSessionId?.()??o.getSessionId():o.getSessionId()}):null,l=new Set,t=(a)=>Promise.resolve().then(()=>{if(!a?.sessionId&&!a?.scenarioId)return;o.start(a),i?.start()}),d=()=>{l.forEach((a)=>a())},g=()=>{if(!c.reconnectReportPath||typeof fetch>"u")return;let a=e.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:a.reconnect,scenarioId:a.scenarioId,sessionId:o.getSessionId(),turnIds:a.turns.map((r)=>r.id)});fetch(c.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},y=o.subscribe((a)=>{let h=hn(a);if(h){if(e.dispatch(h),a.type==="connection")g();d()}});return{callControl(a){o.callControl(a)},close(){y(),i?.close(),o.close(),e.dispatch({type:"disconnected"}),d()},endTurn(){o.endTurn()},get error(){return e.getSnapshot().error},getServerSnapshot(){return e.getServerSnapshot()},getSnapshot(){return e.getSnapshot()},get isConnected(){return e.getSnapshot().isConnected},get scenarioId(){return e.getSnapshot().scenarioId},get sessionMetadata(){return e.getSnapshot().sessionMetadata},start:t,get partial(){return e.getSnapshot().partial},get reconnect(){return e.getSnapshot().reconnect},get sessionId(){return o.getSessionId()},get status(){return e.getSnapshot().status},get turns(){return e.getSnapshot().turns},get assistantTexts(){return e.getSnapshot().assistantTexts},get assistantAudio(){return e.getSnapshot().assistantAudio},get call(){return e.getSnapshot().call},sendAudio(a){o.sendAudio(a)},simulateDisconnect(){o.simulateDisconnect()},subscribe(a){return l.add(a),()=>{l.delete(a)}}}};var wn=(n)=>{if(!n||n.enabled===!1)return;return{enabled:!0,maxGain:n.maxGain??3,noiseGateAttenuation:n.noiseGateAttenuation??0.15,noiseGateThreshold:n.noiseGateThreshold??0.006,targetLevel:n.targetLevel??0.08}};var nc={balanced:{qualityProfile:"general",silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:"general",silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},"long-form":{qualityProfile:"general",silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},cc={general:{},"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var Rn=(n)=>{let c=n?.profile??"fast",o=n?.qualityProfile??"general",e=nc[c],i=cc[o];return{profile:c,qualityProfile:o,silenceMs:n?.silenceMs??i.silenceMs??e.silenceMs,speechThreshold:n?.speechThreshold??i.speechThreshold??e.speechThreshold,transcriptStabilityMs:n?.transcriptStabilityMs??i.transcriptStabilityMs??e.transcriptStabilityMs}};var ec={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:{qualityProfile:"short-command",profile:"balanced"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{qualityProfile:"general",profile:"fast"}},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:{qualityProfile:"accent-heavy",profile:"long-form"}},"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:{qualityProfile:"accent-heavy",profile:"long-form"}},"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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form",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:{qualityProfile:"noisy-room",profile:"long-form"}}},_n=(n="default")=>{let c=ec[n];return{audioConditioning:wn(c.audioConditioning),capture:{channelCount:c.capture?.channelCount??1,sampleRateHz:c.capture?.sampleRateHz??16000},connection:{...c.connection},name:n,sttLifecycle:c.sttLifecycle??"continuous",turnDetection:Rn(c.turnDetection)}};var oc=(n)=>({assistantAudio:[...n.assistantAudio],assistantTexts:[...n.assistantTexts],call:n.call,error:n.error,isConnected:n.isConnected,isRecording:!1,partial:n.partial,reconnect:n.reconnect,recordingError:null,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,turns:[...n.turns]}),j=(n,c={})=>{let o=_n(c.preset),e=Ln(n,{...o.connection,...c.connection}),i=null,l=oc(e),t=new Set,d=()=>{for(let C of t)C()},g=()=>{if(l={...l,assistantAudio:[...e.assistantAudio],assistantTexts:[...e.assistantTexts],call:e.call,error:e.error,isConnected:e.isConnected,partial:e.partial,reconnect:e.reconnect,sessionId:e.sessionId,sessionMetadata:e.sessionMetadata,scenarioId:e.scenarioId,status:e.status,turns:[...e.turns]},c.autoStopOnComplete!==!1&&l.status==="completed"&&l.isRecording)i?.stop(),i=null,l={...l,isRecording:!1};d()},y=e.subscribe(g);g();let a=()=>{if(i)return i;return i=An({channelCount:c.capture?.channelCount??o.capture.channelCount,onLevel:c.capture?.onLevel,onAudio:(C)=>{if(c.capture?.onAudio){c.capture.onAudio(C,e.sendAudio);return}e.sendAudio(C)},sampleRateHz:c.capture?.sampleRateHz??o.capture.sampleRateHz}),i},h=()=>{i?.stop(),i=null,l={...l,isRecording:!1},d()},r=async()=>{if(l.isRecording)return;try{l={...l,recordingError:null},d(),await a().start(),l={...l,isRecording:!0},d()}catch(C){throw i=null,l={...l,isRecording:!1,recordingError:C instanceof Error?C.message:String(C)},d(),C}};return{bindHTMX(C){return gn(e,C)},callControl:(C)=>e.callControl(C),close:()=>{y(),h(),e.close()},endTurn:()=>e.endTurn(),get error(){return l.error},getServerSnapshot:()=>l,getSnapshot:()=>l,get isConnected(){return l.isConnected},get isRecording(){return l.isRecording},get partial(){return l.partial},get recordingError(){return l.recordingError},get reconnect(){return l.reconnect},sendAudio:(C)=>e.sendAudio(C),simulateDisconnect:()=>e.simulateDisconnect(),get sessionId(){return l.sessionId},get sessionMetadata(){return l.sessionMetadata},get scenarioId(){return l.scenarioId},startRecording:r,get status(){return l.status},stopRecording:h,subscribe:(C)=>{return t.add(C),()=>{t.delete(C)}},toggleRecording:async()=>{if(l.isRecording){h();return}await r()},get turns(){return l.turns},get assistantTexts(){return l.assistantTexts},get assistantAudio(){return l.assistantAudio},get call(){return l.call}}};var tc=()=>({activeSourceCount:0,error:null,isActive:!1,isPlaying:!1,lastInterruptLatencyMs:void 0,lastPlaybackStopLatencyMs:void 0,processedChunkCount:0,queuedChunkCount:0}),ic=()=>{if(typeof window>"u")return typeof AudioContext>"u"?void 0:AudioContext;return window.AudioContext??window.webkitAudioContext},lc=(n,c)=>{let o=c.format;if(o.container!=="raw"||o.encoding!=="pcm_s16le")throw Error(`Unsupported assistant audio format: ${o.container}/${o.encoding}`);let e=c.chunk,i=Math.max(1,o.channels),l=Math.floor(e.byteLength/2),t=Math.max(1,Math.floor(l/i)),d=n.createBuffer(i,t,o.sampleRateHz),g=new DataView(e.buffer,e.byteOffset,e.byteLength);for(let y=0;y<i;y+=1){let a=d.getChannelData(y);for(let h=0;h<t;h+=1){let M=(h*i+y)*2;if(M+1>=e.byteLength){a[h]=0;continue}a[h]=g.getInt16(M,!0)/32768}}return d},F=(n,c={})=>{let o=new Set,e=new Set,i=(c.lookaheadMs??15)/1000,l=tc(),t=null,d=null,g=0,y=Promise.resolve(),a=null,h=null,r=null,M=null,C=()=>{for(let A of o)A()},S=(A)=>{l={...l,...A},C()},w=()=>{if(l.error!==null)S({error:null})},E=()=>{if(M!==null)clearTimeout(M),M=null},_=(A)=>{E(),a=null,S({activeSourceCount:e.size,isPlaying:!1,lastInterruptLatencyMs:A,lastPlaybackStopLatencyMs:l.lastPlaybackStopLatencyMs??A}),r?.(),r=null,h=null},U=(A)=>{if(!A)return 0;return Math.max(0,((A.baseLatency??0)+(A.outputLatency??0))*1000)},N=(A)=>{if(!d)return;let T=1;if(d.gain.setValueAtTime){d.gain.setValueAtTime(T,A?.currentTime??0);return}d.gain.value=T},s=(A)=>{if(!d)return;let T=0;if(d.gain.setValueAtTime){d.gain.setValueAtTime(T,A?.currentTime??0);return}d.gain.value=T},V=()=>{if(a===null||e.size>0)return;_(Date.now()-a)},R=async()=>{if(t)return t;if(c.createAudioContext)t=c.createAudioContext();else{let A=ic();if(!A)throw Error("Assistant audio playback requires AudioContext support.");t=new A}if(t.createGain)d=t.createGain(),d.connect?.(t.destination);return g=t.currentTime,t},Y=async(A)=>{let T=await R(),P=lc(T,A),L=T.createBufferSource();L.buffer=P,L.connect(d??T.destination),L.onended=()=>{e.delete(L),L.disconnect?.(),S({activeSourceCount:e.size,isPlaying:e.size>0&&l.isActive}),V()};let Q=Math.max(T.currentTime+i,g);g=Q+P.duration,e.add(L),S({activeSourceCount:e.size,isPlaying:!0}),L.start(Q)},f=(A)=>{for(let T of[...e])T.stop?.();if(g=t?t.currentTime:0,A?.forceClear){for(let T of e)T.disconnect?.();e.clear(),V()}},$=async()=>{if(!l.isActive)return;let A=n.assistantAudio.slice(l.processedChunkCount);if(A.length===0)return;try{w();for(let T of A)await Y(T);S({processedChunkCount:n.assistantAudio.length,queuedChunkCount:l.queuedChunkCount+A.length})}catch(T){S({error:T instanceof Error?T.message:String(T)})}},D=()=>{return y=y.then(()=>$(),()=>$()),y},q=n.subscribe(()=>{if(c.autoStart&&!l.isActive&&n.assistantAudio.length>0){H.start();return}if(l.isActive)D()}),H={close:async()=>{if(q(),f({forceClear:!0}),E(),r?.(),r=null,h=null,a=null,t&&t.state!=="closed")await t.close();t=null,d?.disconnect?.(),d=null,g=0,S({activeSourceCount:0,isActive:!1,isPlaying:!1})},get activeSourceCount(){return l.activeSourceCount},get error(){return l.error},getSnapshot:()=>l,get isActive(){return l.isActive},get isPlaying(){return l.isPlaying},interrupt:async()=>{let A=Date.now(),T=await R();a=A,s(T);let P=Date.now()-A+U(T);if(S({isActive:!1,isPlaying:e.size>0,lastPlaybackStopLatencyMs:P}),e.size===0){_(P);return}if(!h)h=new Promise((L)=>{r=L});E(),M=setTimeout(()=>{for(let L of e)L.disconnect?.();e.clear(),_(Date.now()-A)},250),f(),await h},get lastInterruptLatencyMs(){return l.lastInterruptLatencyMs},get lastPlaybackStopLatencyMs(){return l.lastPlaybackStopLatencyMs},pause:async()=>{if(!t){S({activeSourceCount:0,isActive:!1,isPlaying:!1});return}await t.suspend(),S({activeSourceCount:e.size,isActive:!1,isPlaying:!1})},get processedChunkCount(){return l.processedChunkCount},get queuedChunkCount(){return l.queuedChunkCount},start:async()=>{try{w();let A=await R();if(N(A),A.state==="suspended")await A.resume();S({activeSourceCount:e.size,isActive:!0,isPlaying:A.state==="running"}),await D()}catch(A){throw S({error:A instanceof Error?A.message:String(A),isActive:!1,isPlaying:!1}),A}},subscribe:(A)=>{return o.add(A),()=>{o.delete(A)}}};return H};var sc=()=>`barge-in:${Date.now()}:${crypto.randomUUID?.()??Math.random().toString(36).slice(2)}`,dc=(n,c)=>{let o=n.filter((t)=>t.status==="stopped"),e=o.map((t)=>t.latencyMs).filter((t)=>typeof t==="number"),i=o.filter((t)=>typeof t.latencyMs==="number"&&t.latencyMs>c).length,l=o.length-i;return{averageLatencyMs:e.length>0?Math.round(e.reduce((t,d)=>t+d,0)/e.length):void 0,events:[...n],failed:i,lastEvent:n.at(-1),passed:l,status:n.length===0?"empty":i>0?"fail":o.length===0?"warn":"pass",thresholdMs:c,total:o.length}},En=(n={})=>{let c=new Set,o=n.thresholdMs??250,e=n.fetch??globalThis.fetch,i=[],l=()=>{for(let g of c)g()},t=(g)=>{if(!n.path||typeof e!=="function")return;e(n.path,{body:JSON.stringify(g),headers:{"Content-Type":"application/json"},method:"POST"}).catch(()=>{})},d=(g,y)=>{let a={at:Date.now(),id:sc(),latencyMs:y.latencyMs,playbackStopLatencyMs:y.playbackStopLatencyMs,reason:y.reason,sessionId:y.sessionId,status:g,thresholdMs:o};return i.push(a),t(a),l(),a};return{getSnapshot:()=>dc(i,o),recordRequested:(g)=>d("requested",g),recordSkipped:(g)=>d("skipped",g),recordStopped:(g)=>d("stopped",g),subscribe:(g)=>{return c.add(g),()=>{c.delete(g)}}}};var rc=0.08,ac=(n,c={})=>(c.enabled??!0)&&n>=(c.interruptThreshold??rc),en=(n,c,o={})=>{let e=n.partial,i=(t)=>{if(!c.isPlaying||o.enabled===!1){o.monitor?.recordSkipped({reason:t,sessionId:n.sessionId});return}o.monitor?.recordRequested({reason:t,sessionId:n.sessionId}),c.interrupt().then(()=>{o.monitor?.recordStopped({latencyMs:c.lastInterruptLatencyMs,playbackStopLatencyMs:c.lastPlaybackStopLatencyMs,reason:t,sessionId:n.sessionId})})},l=n.subscribe(()=>{if(o.interruptOnPartial===!1){e=n.partial;return}if(!e&&n.partial)i("partial-transcript");e=n.partial});return{close:()=>{l()},handleLevel:(t)=>{if(ac(t,o))i("input-level")},sendAudio:(t)=>{i("manual-audio"),n.sendAudio(t)}}};var dn=48,gc=320,Ac=88,hc="Guided test",yc="General recording",Cc="Pick a scenario to begin the demo.",Tc="I can walk you through a short guided voice test.",Ic="I can capture one freeform recording and confirm that it landed.",Vc="Choose a scenario to begin. Guided test asks follow-up prompts. General recording just captures what you say.",Mc="Click Start general recording to capture one freeform answer.",Pn="Speak freely. When you pause, the recording will be captured.",ln="Recording saved. Start again if you want another capture.",Dn="Guided test complete. Review the saved summary below.",On="All prompts are covered. You can stop the microphone or keep speaking for extra detail.",Sc="Ready. Start guided test or general recording to begin.",Lc="Live. Answer the prompt, then click Stop microphone when finished.",bn=["Start with a quick introduction about who you are.","Now describe what you are trying to do or test.","Finish with any detail that feels blocked, risky, or unclear."],xn=(n,c,o)=>Math.min(o,Math.max(c,n)),u=(n)=>n.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll(\'"\',"&quot;").replaceAll("\'","&#39;"),on=(n,c)=>{let o=n[c];if(typeof o==="string"&&o.trim())return o;return null},sn=(n)=>{if(typeof n==="string"&&n.trim())return n;if(n instanceof Error&&n.message.trim())return n.message;if(n&&typeof n==="object"){let c=n,o=on(c,"message")??on(c,"reason")??on(c,"description");if(o)return o;if("error"in c)return sn(c.error);if("cause"in c)return sn(c.cause);try{return JSON.stringify(n)}catch{}}return"Unexpected error"},wc=(n)=>{let c=[n.status];if(n.attempts>0||n.maxAttempts>0)c.push(`${n.attempts}/${n.maxAttempts} attempts`);if(n.nextAttemptAt){let o=Math.max(0,n.nextAttemptAt-Date.now());c.push(`retry in ${Math.ceil(o/100)/10}s`)}return c.join(" \xB7 ")},v=(n=dn)=>Array.from({length:n},()=>0),fn=(n,c,o=dn)=>{let e=n.slice(-(o-1));e.push(xn(c,0,1));while(e.length<o)e.unshift(0);return e},Rc=(n,c=gc,o=Ac)=>{let e=n.length>1?n:v(dn),i=c/(e.length-1),l=o/2,t=o*0.34;if(Math.max(...e,0)<=0.015)return`M 0 ${l} L ${c} ${l}`;let g=e.map((a,h)=>{let r=h*0.76,M=Math.sin(r)*0.78+Math.sin(r*0.41)*0.22,C=a*t,S=i*h,w=xn(l+M*C,8,o-8);return{x:S,y:w}});if(g.length===0)return`M 0 ${l} L ${c} ${l}`;let y=`M ${g[0]?.x??0} ${g[0]?.y??l}`;for(let a=1;a<g.length;a+=1){let h=g[a-1],r=g[a];if(!h||!r)continue;let M=(h.x+r.x)/2;y+=` Q ${M} ${h.y} ${r.x} ${r.y}`}return y},_c=(n)=>{if(!n)return bn;try{let c=JSON.parse(n);if(Array.isArray(c)){let o=c.filter((e)=>typeof e==="string").map((e)=>e.trim()).filter(Boolean);if(o.length>0)return o}}catch{}return bn},tn=(n)=>{if(!n)return;let c=Number(n);return Number.isFinite(c)?c:void 0},Ec=(n,c,o)=>{if(!c)return null;let e=document.querySelector(c);return e instanceof o?e:null},x=(n,c,o,e)=>{let i=c?document.querySelector(c):null;if(i instanceof o)return i;let l=n.querySelector(`#${e}`);if(l instanceof o)return l;throw Error(`Voice HTMX bootstrap could not find the required element "${e}".`)},bc=(n)=>{if(!n.mode)return Cc;if(!n.hasStarted)return n.mode==="guided"?Tc:Ic;if(n.status==="completed")return n.mode==="guided"?Dn:ln;if(n.mode==="general")return Pn;return n.guidedPrompts[n.turnCount]??On},fc=(n)=>{if(!n.mode)return Vc;if(n.status==="completed")return n.mode==="guided"?Dn:ln;if(!n.hasStarted)return n.mode==="guided"?`Click Start guided test to begin. First prompt: ${n.guidedPrompts[0]??"Answer the first prompt."}`:Mc;if(n.mode==="general")return n.turnCount===0?Pn:ln;return n.guidedPrompts[n.turnCount]??On},Pc=(n)=>{let c=n.dataset.voiceGuidedPath,o=n.dataset.voiceGeneralPath;if(!c||!o)throw Error("Voice HTMX bootstrap requires data-voice-guided-path and data-voice-general-path.");let e=_c(n.dataset.voiceGuidedPrompts),i=n.dataset.voiceGuidedLabel??hc,l=n.dataset.voiceGeneralLabel??yc,t=n.dataset.voiceReconnectReportPath,d=n.dataset.voiceBargeInPath,g=d?En({path:d,thresholdMs:tn(n.dataset.voiceBargeInThresholdMs)}):null,y=tn(n.dataset.voiceBargeInRecentWindowMs)??4000,a=tn(n.dataset.voiceBargeInSpeechThreshold)??0.04,h=x(document,n.dataset.voiceSync,HTMLElement,"voice-htmx-sync"),r=x(n,n.dataset.voiceConnection,HTMLElement,"metric-connection"),M=x(n,n.dataset.voiceError,HTMLElement,"status-error"),C=x(n,n.dataset.voiceMicrophone,HTMLElement,"status-mic"),S=x(n,n.dataset.voicePrompt,HTMLElement,"status-prompt"),w=Ec(n,n.dataset.voiceReconnect,HTMLElement),E=x(n,n.dataset.voiceChat,HTMLElement,"chat-list"),_=x(n,n.dataset.voiceStartGuided,HTMLButtonElement,"start-guided"),U=x(n,n.dataset.voiceStartGeneral,HTMLButtonElement,"start-general"),N=x(n,n.dataset.voiceStop,HTMLButtonElement,"stop-mic"),s=x(n,n.dataset.voiceMonitor,HTMLElement,"voice-monitor"),V=x(n,n.dataset.voiceMonitorCopy,HTMLElement,"voice-monitor-copy"),R=x(n,n.dataset.voiceWaveGlow,SVGPathElement,"voice-wave-glow"),Y=x(n,n.dataset.voiceWavePath,SVGPathElement,"voice-wave-path"),f=null,$={general:!1,guided:!1},D=!1,q=null,H=v(),A=null,T=null,P=j(c,{capture:{onAudio:(I,B)=>{if(A){A.sendAudio(I);return}B(I)},onLevel:(I)=>{A?.handleLevel(I),H=fn(H,I),m()}},connection:{reconnectReportPath:t},preset:"guided-intake"}),L=j(o,{capture:{onAudio:(I,B)=>{if(T){T.sendAudio(I);return}B(I)},onLevel:(I)=>{T?.handleLevel(I),H=fn(H,I),m()}},connection:{reconnectReportPath:t},preset:"dictation"}),Q=P.bindHTMX({element:h}),Un=L.bindHTMX({element:h}),k=F(P),z=F(L);A=en(P,k,{interruptThreshold:a,monitor:g??void 0}),T=en(L,z,{interruptThreshold:a,monitor:g??void 0});let J=()=>f==="general"?L:P,Oc=()=>f==="general"?z:k,m=()=>{let I=Rc(H);R.setAttribute("d",I),Y.setAttribute("d",I),V.innerHTML=`<span class="voice-live-dot"></span>${D?"Microphone live":"Microphone idle"}`,V.classList.toggle("is-live",D),s.classList.toggle("is-live",D)},X=()=>{let I=J(),B=(f?$[f]:!1)||I.turns.length>0,an=I.status;if(r.textContent=I.isConnected?"Connected":"Waiting",M.textContent=q||I.error||"None",w)w.textContent=wc(I.reconnect);C.textContent=D?Lc:Sc,S.textContent=fc({guidedPrompts:e,hasStarted:B,mode:f,status:an,turnCount:I.turns.length}),_.hidden=D,U.hidden=D,N.hidden=!D,E.innerHTML=`<article class="voice-chat-message assistant">\n <div class="voice-chat-role">${u(f==="general"?l:f==="guided"?i:"Voice demo")}</div>\n <p class="voice-turn-text">${u(bc({generalLabel:l,guidedLabel:i,guidedPrompts:e,hasStarted:B,mode:f,status:an,turnCount:I.turns.length}))}</p>\n</article>${I.turns.map((p)=>`<div class="voice-chat-stack">\n <article class="voice-chat-message user">\n <div class="voice-chat-role">You</div>\n <p class="voice-turn-text">${u(p.text)}</p>\n </article>\n ${p.assistantText?`<article class="voice-chat-message assistant">\n <div class="voice-chat-role">${u(f==="general"?l:f==="guided"?i:"Guide")}</div>\n <p class="voice-turn-text">${u(p.assistantText)}</p>\n </article>`:""}\n</div>`).join("")}${I.partial?`<article class="voice-chat-message user pending">\n <div class="voice-chat-role">Speaking</div>\n <p class="voice-turn-text">${u(I.partial)}</p>\n</article>`:""}`,m()},Nn=()=>{J().stopRecording(),D=!1,q=null,H=v(),X()},rn=async(I)=>{f=I,$={...$,[I]:!0};try{await J().startRecording(),q=null,D=!0,X()}catch(B){J().stopRecording(),D=!1,H=v(),q=sn(B),X()}};P.subscribe(()=>{if(P.assistantAudio.length>0)k.start().catch(()=>{});X()}),L.subscribe(()=>{if(L.assistantAudio.length>0)z.start().catch(()=>{});X()}),_.addEventListener("click",()=>{rn("guided")}),U.addEventListener("click",()=>{rn("general")}),N.addEventListener("click",()=>{Nn()}),n.addEventListener("absolute-voice-simulate-disconnect",()=>{J().simulateDisconnect()}),window.addEventListener("beforeunload",()=>{P.stopRecording(),L.stopRecording(),A?.close(),T?.close(),k.close(),z.close(),Q(),Un(),P.close(),L.close()}),X()},Dc=()=>{if(typeof window>"u"||typeof document>"u")return;let n=Array.from(document.querySelectorAll("[data-voice-htmx]"));for(let c of n)if(c instanceof HTMLElement)Pc(c)};Dc();export{Dc as initVoiceHTMX};\n';
5753
-
5754
5751
  // src/profileSwitchRecommendation.ts
5755
5752
  import { Elysia } from "elysia";
5756
5753
 
@@ -38391,9 +38388,6 @@ var loadHTMXBootstrap = (() => {
38391
38388
  return cached;
38392
38389
  }
38393
38390
  cached = (async () => {
38394
- if (HTMX_BOOTSTRAP_BUNDLE) {
38395
- return HTMX_BOOTSTRAP_BUNDLE;
38396
- }
38397
38391
  for (const candidate of HTMX_BOOTSTRAP_DIST_CANDIDATES) {
38398
38392
  const asset = Bun.file(candidate);
38399
38393
  if (await asset.exists()) {
@@ -47564,22 +47558,27 @@ var DEFAULT_AUDIO_FORMAT = {
47564
47558
  };
47565
47559
  var DEFAULT_TELEPHONY_SAMPLE_RATE_HZ = 8000;
47566
47560
  var DEFAULT_MULTI_SPEAKER_SILENCE_MS = 350;
47567
- var FIXTURE_DIR_CANDIDATES = [
47568
- resolve2(import.meta.dir, "..", "..", "fixtures"),
47569
- resolve2(import.meta.dir, "..", "..", "..", "fixtures"),
47570
- resolve2(import.meta.dir, "..", "..", "..", "..", "fixtures")
47571
- ];
47572
47561
  var EXTERNAL_FIXTURE_ENV_KEYS = [
47573
47562
  "VOICE_FIXTURE_DIR",
47574
47563
  "VOICE_FIXTURE_DIRS"
47575
47564
  ];
47565
+ var resolveDefaultFixtureCandidates = () => {
47566
+ const envDirs = EXTERNAL_FIXTURE_ENV_KEYS.flatMap((key) => (process.env[key] ?? "").split(/[\n,]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0));
47567
+ return [
47568
+ ...envDirs.map((dir) => resolve2(dir)),
47569
+ resolve2(process.cwd(), "fixtures"),
47570
+ resolve2(process.cwd(), "test", "fixtures", "audio"),
47571
+ resolve2(import.meta.dir, "..", "..", "test", "fixtures", "audio"),
47572
+ resolve2(import.meta.dir, "..", "..", "..", "test", "fixtures", "audio")
47573
+ ];
47574
+ };
47576
47575
  var resolveFixtureDirectory = async () => {
47577
- for (const candidate of FIXTURE_DIR_CANDIDATES) {
47576
+ for (const candidate of resolveDefaultFixtureCandidates()) {
47578
47577
  if (await Bun.file(resolve2(candidate, "manifest.json")).exists()) {
47579
47578
  return candidate;
47580
47579
  }
47581
47580
  }
47582
- throw new Error("Unable to locate the bundled voice test fixtures. Expected fixtures/manifest.json next to the package root.");
47581
+ throw new Error("Unable to locate voice test fixtures. Set VOICE_FIXTURE_DIR/VOICE_FIXTURE_DIRS, or provide a fixtures/ directory (with manifest.json) in the working directory.");
47583
47582
  };
47584
47583
  var getVoiceFixtureDirectory = async () => resolveFixtureDirectory();
47585
47584
  var toUniqueDirectories = (directories) => directories.filter((directory, index, list) => directory.trim().length > 0 && list.indexOf(directory) === index);
@@ -3557,22 +3557,27 @@ var DEFAULT_AUDIO_FORMAT = {
3557
3557
  };
3558
3558
  var DEFAULT_TELEPHONY_SAMPLE_RATE_HZ = 8000;
3559
3559
  var DEFAULT_MULTI_SPEAKER_SILENCE_MS = 350;
3560
- var FIXTURE_DIR_CANDIDATES = [
3561
- resolve(import.meta.dir, "..", "..", "fixtures"),
3562
- resolve(import.meta.dir, "..", "..", "..", "fixtures"),
3563
- resolve(import.meta.dir, "..", "..", "..", "..", "fixtures")
3564
- ];
3565
3560
  var EXTERNAL_FIXTURE_ENV_KEYS = [
3566
3561
  "VOICE_FIXTURE_DIR",
3567
3562
  "VOICE_FIXTURE_DIRS"
3568
3563
  ];
3564
+ var resolveDefaultFixtureCandidates = () => {
3565
+ const envDirs = EXTERNAL_FIXTURE_ENV_KEYS.flatMap((key) => (process.env[key] ?? "").split(/[\n,]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0));
3566
+ return [
3567
+ ...envDirs.map((dir) => resolve(dir)),
3568
+ resolve(process.cwd(), "fixtures"),
3569
+ resolve(process.cwd(), "test", "fixtures", "audio"),
3570
+ resolve(import.meta.dir, "..", "..", "test", "fixtures", "audio"),
3571
+ resolve(import.meta.dir, "..", "..", "..", "test", "fixtures", "audio")
3572
+ ];
3573
+ };
3569
3574
  var resolveFixtureDirectory = async () => {
3570
- for (const candidate of FIXTURE_DIR_CANDIDATES) {
3575
+ for (const candidate of resolveDefaultFixtureCandidates()) {
3571
3576
  if (await Bun.file(resolve(candidate, "manifest.json")).exists()) {
3572
3577
  return candidate;
3573
3578
  }
3574
3579
  }
3575
- throw new Error("Unable to locate the bundled voice test fixtures. Expected fixtures/manifest.json next to the package root.");
3580
+ throw new Error("Unable to locate voice test fixtures. Set VOICE_FIXTURE_DIR/VOICE_FIXTURE_DIRS, or provide a fixtures/ directory (with manifest.json) in the working directory.");
3576
3581
  };
3577
3582
  var getVoiceFixtureDirectory = async () => resolveFixtureDirectory();
3578
3583
  var toUniqueDirectories = (directories) => directories.filter((directory, index, list) => directory.trim().length > 0 && list.indexOf(directory) === index);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.527",
3
+ "version": "0.0.22-beta.528",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,7 +8,6 @@
8
8
  },
9
9
  "files": [
10
10
  "dist",
11
- "fixtures",
12
11
  "README.md"
13
12
  ],
14
13
  "main": "./dist/index.js",
@@ -16,7 +15,7 @@
16
15
  "license": "CC BY-NC 4.0",
17
16
  "author": "Alex Kahn",
18
17
  "scripts": {
19
- "build": "bun run ./scripts/build-htmx-bootstrap-asset.ts && rm -rf dist && bun build ./src/index.ts ./src/client/index.ts ./src/react/index.ts ./src/vue/index.ts ./src/svelte/index.ts ./src/angular/index.ts ./src/testing/index.ts --outdir dist --target bun --external elysia --external react --external vue --external @angular/core --external @absolutejs/absolute --external @absolutejs/ai --external @absolutejs/media && bun build ./src/client/htmxBootstrap.ts --outdir dist/client --target browser --format esm && bun build ./src/embed/index.ts --outfile dist/embed/voice-widget.js --target browser --format iife --minify && bun build ./src/embed/index.ts --outdir dist/embed --target browser --format esm && tsc --emitDeclarationOnly --project tsconfig.json",
18
+ "build": "rm -rf dist && bun build ./src/index.ts ./src/client/index.ts ./src/react/index.ts ./src/vue/index.ts ./src/svelte/index.ts ./src/angular/index.ts ./src/testing/index.ts --outdir dist --target bun --external elysia --external react --external vue --external @angular/core --external @absolutejs/absolute --external @absolutejs/ai --external @absolutejs/media && bun build ./src/client/htmxBootstrap.ts --outdir dist/client --target browser --format esm && bun build ./src/embed/index.ts --outfile dist/embed/voice-widget.js --target browser --format iife --minify && bun build ./src/embed/index.ts --outdir dist/embed --target browser --format esm && tsc --emitDeclarationOnly --project tsconfig.json",
20
19
  "format": "prettier --write \"./**/*.{js,jsx,ts,tsx,json,md}\"",
21
20
  "lint": "eslint ./src",
22
21
  "release": "bun run format && bun run build && bun publish",
@@ -1 +0,0 @@
1
- export declare const HTMX_BOOTSTRAP_BUNDLE = "var Hn=(n)=>{if(typeof n!==\"string\")return n;return document.querySelector(n)},Gn=(n,c,o,e)=>{let i=c??n.getAttribute(\"hx-get\")??\"\";if(!i)return\"\";let l=new URL(i,window.location.origin);if(e)l.searchParams.set(o,e);else l.searchParams.delete(o);return`${l.pathname}${l.search}${l.hash}`},gn=(n,c)=>{if(typeof window>\"u\"||typeof document>\"u\")return()=>{};let o=Hn(c.element);if(!o)return()=>{};let e=c.eventName??\"voice-refresh\",i=c.sessionQueryParam??\"sessionId\",l=()=>{let d=window,g=Gn(o,c.route,i,n.sessionId);if(g)o.setAttribute(\"hx-get\",g);d.htmx?.process?.(o),d.htmx?.trigger?.(o,e)},t=n.subscribe(l);return l(),()=>{t()}};var Bn=(n)=>Math.max(-1,Math.min(1,n)),Wn=(n)=>{let c=new Int16Array(n.length);for(let o=0;o<n.length;o+=1){let e=Bn(n[o]??0);c[o]=e<0?e*32768:e*32767}return new Uint8Array(c.buffer)},$n=(n)=>{let c=n instanceof Uint8Array?n:new Uint8Array(n);if(c.byteLength<2)return 0;let o=new Int16Array(c.buffer,c.byteOffset,Math.floor(c.byteLength/2));if(o.length===0)return 0;let e=0;for(let i of o){let l=i/32768;e+=l*l}return Math.min(1,Math.max(0,Math.sqrt(e/o.length)*5.5))},qn=(n,c,o)=>{if(c===o)return n;let e=c/o,i=Math.round(n.length/e),l=new Float32Array(i),t=0,d=0;while(t<l.length){let g=Math.round((t+1)*e),y=0,a=0;for(let h=d;h<g&&h<n.length;h+=1)y+=n[h]??0,a+=1;l[t]=a>0?y/a:0,t+=1,d=g}return l},An=(n)=>{let c=null,o=null,e=null,i=null;return{start:async()=>{if(typeof navigator>\"u\"||!navigator.mediaDevices?.getUserMedia)throw Error(\"Browser microphone capture requires navigator.mediaDevices.getUserMedia.\");let d=(typeof window<\"u\"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!d)throw Error(\"Browser microphone capture requires AudioContext support.\");i=await navigator.mediaDevices.getUserMedia({audio:{channelCount:n.channelCount??1}}),c=new d,o=c.createMediaStreamSource(i),e=c.createScriptProcessor(4096,1,1),e.onaudioprocess=(g)=>{let y=g.inputBuffer.getChannelData(0),a=qn(y,c?.sampleRate??48000,n.sampleRateHz??16000),h=Wn(a);n.onLevel?.($n(h)),n.onAudio(h)},o.connect(e),e.connect(c.destination)},stop:()=>{e?.disconnect(),o?.disconnect(),i?.getTracks().forEach((d)=>d.stop()),c?.close(),n.onLevel?.(0),c=null,i=null,e=null,o=null}}};var nn=(n)=>{if(typeof n===\"string\"&&n.trim())return n;if(n instanceof Error&&n.message.trim())return n.message;if(n&&typeof n===\"object\"){let c=n;for(let o of[\"message\",\"reason\",\"description\"]){let e=c[o];if(typeof e===\"string\"&&e.trim())return e}if(\"error\"in c)return nn(c.error);if(\"cause\"in c)return nn(c.cause);try{return JSON.stringify(n)}catch{}}return\"Unexpected error\"},hn=(n)=>{switch(n.type){case\"audio\":return{chunk:Uint8Array.from(atob(n.chunkBase64),(c)=>c.charCodeAt(0)),format:n.format,receivedAt:n.receivedAt,turnId:n.turnId,type:\"audio\"};case\"assistant\":return{text:n.text,type:\"assistant\"};case\"complete\":return{sessionId:n.sessionId,type:\"complete\"};case\"connection\":return{reconnect:n.reconnect,type:\"connection\"};case\"call_lifecycle\":return{event:n.event,sessionId:n.sessionId,type:\"call_lifecycle\"};case\"error\":return{message:nn(n.message),type:\"error\"};case\"final\":return{transcript:n.transcript,type:\"final\"};case\"partial\":return{transcript:n.transcript,type:\"partial\"};case\"replay\":return{assistantTexts:n.assistantTexts,call:n.call,partial:n.partial,scenarioId:n.scenarioId,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,status:n.status,turns:n.turns,type:\"replay\"};case\"session\":return{sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,type:\"session\"};case\"turn\":return{turn:n.turn,type:\"turn\"};default:return null}};var Hc=Math.PI*2;var G=(n,c,o,e)=>{n.push({code:o,message:e,severity:c})};var Xn=(n)=>n.length===0?void 0:n.reduce((c,o)=>c+o,0)/n.length,K=(n)=>n.length===0?void 0:Math.max(...n);var b=(n,c)=>{let o=n[c];return typeof o===\"number\"&&Number.isFinite(o)?o:void 0},Z=(n,c)=>{let o=n[c];return typeof o===\"boolean\"?o:void 0},O=(n,c)=>{let o=n[c];return typeof o===\"string\"?o:void 0},cn=(n)=>String(n.id??O(n,\"ssrc\")??b(n,\"ssrc\")??O(n,\"trackIdentifier\")??O(n,\"mid\")??\"unknown\"),yn=(n)=>n===void 0?void 0:n*1000;var un=(n)=>{let c={};for(let[o,e]of Object.entries(n))if(e===null||typeof e===\"boolean\"||typeof e===\"number\"||typeof e===\"string\")c[o]=e;return c};var Cn=(n={})=>{let c=n.stats??[],o=[],e=c.filter((s)=>s.type===\"inbound-rtp\"&&O(s,\"kind\")!==\"video\"),i=c.filter((s)=>s.type===\"outbound-rtp\"&&O(s,\"kind\")!==\"video\"),l=c.filter((s)=>s.type===\"candidate-pair\"),t=c.filter((s)=>(s.type===\"track\"||s.type===\"media-source\")&&O(s,\"kind\")===\"audio\"),d=l.filter((s)=>Z(s,\"selected\")===!0||Z(s,\"nominated\")===!0||O(s,\"state\")===\"succeeded\").length,g=t.filter((s)=>O(s,\"readyState\")!==\"ended\"&&O(s,\"trackState\")!==\"ended\"&&Z(s,\"ended\")!==!0).length,y=t.filter((s)=>O(s,\"readyState\")===\"ended\"||O(s,\"trackState\")===\"ended\"||Z(s,\"ended\")===!0).length,a=e.reduce((s,V)=>s+(b(V,\"packetsReceived\")??0),0),h=i.reduce((s,V)=>s+(b(V,\"packetsSent\")??0),0),r=[...e,...i].reduce((s,V)=>s+Math.max(0,b(V,\"packetsLost\")??0),0),M=a+r,C=M===0?0:r/M,S=e.reduce((s,V)=>s+(b(V,\"bytesReceived\")??0),0),w=i.reduce((s,V)=>s+(b(V,\"bytesSent\")??0),0),E=K(l.map((s)=>yn(b(s,\"currentRoundTripTime\")??b(s,\"roundTripTime\"))).filter((s)=>s!==void 0)),_=K([...e,...i].map((s)=>yn(b(s,\"jitter\"))).filter((s)=>s!==void 0)),U=K(e.map((s)=>{let V=b(s,\"jitterBufferDelay\"),R=b(s,\"jitterBufferEmittedCount\");return V!==void 0&&R!==void 0&&R>0?V/R*1000:void 0}).filter((s)=>s!==void 0)),N=t.map((s)=>b(s,\"audioLevel\")).filter((s)=>s!==void 0);if(n.requireConnectedCandidatePair&&l.length>0&&d===0)G(o,\"error\",\"media.webrtc_candidate_pair_missing\",\"No active WebRTC candidate pair was observed.\");if(n.requireLiveAudioTrack&&g===0)G(o,\"error\",\"media.webrtc_audio_track_missing\",\"No live WebRTC audio track was observed.\");if(n.maxPacketLossRatio!==void 0&&C>n.maxPacketLossRatio)G(o,\"warning\",\"media.webrtc_packet_loss\",`Observed WebRTC packet loss ratio ${String(C)} above ${String(n.maxPacketLossRatio)}.`);if(n.maxRoundTripTimeMs!==void 0&&E!==void 0&&E>n.maxRoundTripTimeMs)G(o,\"warning\",\"media.webrtc_round_trip_time\",`Observed WebRTC RTT ${String(E)}ms above ${String(n.maxRoundTripTimeMs)}ms.`);if(n.maxJitterMs!==void 0&&_!==void 0&&_>n.maxJitterMs)G(o,\"warning\",\"media.webrtc_jitter\",`Observed WebRTC jitter ${String(_)}ms above ${String(n.maxJitterMs)}ms.`);return{activeCandidatePairs:d,audioLevelAverage:Xn(N),bytesReceived:S,bytesSent:w,checkedAt:Date.now(),endedAudioTracks:y,inboundPackets:a,issues:o,jitterBufferDelayMs:U,jitterMs:_,liveAudioTracks:g,outboundPackets:h,packetLossRatio:C,packetsLost:r,roundTripTimeMs:E,status:o.some((s)=>s.severity===\"error\")?\"fail\":o.length>0?\"warn\":\"pass\",totalStats:c.length}},Tn=async(n)=>{return[...(await n.peerConnection.getStats(n.selector??null)).values()].map(un)};var In=(n={})=>{let c=n.stats??[],o=n.previousStats??[],e=[],i=new Map(o.map((r)=>[cn(r),r])),t=c.filter((r)=>(r.type===\"inbound-rtp\"||r.type===\"outbound-rtp\")&&O(r,\"kind\")!==\"video\"&&O(r,\"mediaType\")!==\"video\").map((r)=>{let M=r.type===\"outbound-rtp\"?\"outbound\":\"inbound\",C=M===\"outbound\"?\"packetsSent\":\"packetsReceived\",S=M===\"outbound\"?\"bytesSent\":\"bytesReceived\",w=i.get(cn(r)),E=b(r,C),_=w?b(w,C):void 0,U=b(r,S),N=w?b(w,S):void 0,s=r.timestamp!==void 0&&w?.timestamp!==void 0?r.timestamp-w.timestamp:void 0;return{bytesDelta:U!==void 0&&N!==void 0?U-N:void 0,currentPackets:E,direction:M,id:cn(r),packetDelta:E!==void 0&&_!==void 0?E-_:void 0,previousPackets:_,timeDeltaMs:s}}),d=t.filter((r)=>r.direction===\"inbound\"),g=t.filter((r)=>r.direction===\"outbound\"),y=K(t.map((r)=>r.timeDeltaMs).filter((r)=>r!==void 0)),a=d.filter((r)=>n.maxInboundPacketStallMs!==void 0&&r.timeDeltaMs!==void 0&&r.timeDeltaMs>=n.maxInboundPacketStallMs&&r.packetDelta!==void 0&&r.packetDelta<=0).length,h=g.filter((r)=>n.maxOutboundPacketStallMs!==void 0&&r.timeDeltaMs!==void 0&&r.timeDeltaMs>=n.maxOutboundPacketStallMs&&r.packetDelta!==void 0&&r.packetDelta<=0).length;if(n.requireInboundAudio&&d.length===0)G(e,\"error\",\"media.webrtc_inbound_audio_missing\",\"No inbound WebRTC audio RTP stream was observed.\");if(n.requireOutboundAudio&&g.length===0)G(e,\"error\",\"media.webrtc_outbound_audio_missing\",\"No outbound WebRTC audio RTP stream was observed.\");if(n.maxGapMs!==void 0&&y!==void 0&&y>n.maxGapMs)G(e,\"warning\",\"media.webrtc_stream_gap\",`Observed WebRTC stream sample gap ${String(y)}ms above ${String(n.maxGapMs)}ms.`);if(a>0)G(e,\"error\",\"media.webrtc_inbound_stalled\",`${String(a)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)G(e,\"error\",\"media.webrtc_outbound_stalled\",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:d.length,issues:e,maxObservedGapMs:y,outboundAudioStreams:g.length,stalledInboundStreams:a,stalledOutboundStreams:h,status:e.some((r)=>r.severity===\"error\")?\"fail\":e.length>0?\"warn\":\"pass\",streams:t,totalStats:c.length}};var Yn=\"/api/voice/browser-media\",Jn=5000,Qn=async(n)=>n.peerConnection??await n.getPeerConnection?.()??null,kn=async(n,c)=>{let o=c.fetch??globalThis.fetch;if(!o)return;await o(c.path??Yn,{body:JSON.stringify(n),headers:{\"Content-Type\":\"application/json\"},keepalive:!0,method:\"POST\"})},Vn=(n)=>{let c=null,o=[],e=async()=>{let t=await Qn(n);if(!t)return;let d=await Tn({peerConnection:t}),g=Cn({...n,stats:d}),y=n.continuity===!1?void 0:In({...n.continuity,previousStats:o,stats:d}),a={at:Date.now(),continuity:y,report:g,scenarioId:n.getScenarioId?.()??null,sessionId:n.getSessionId?.()??null};return o=d,n.onReport?.(a),await kn(a,n),a},i=()=>{e().catch((t)=>{n.onError?.(t)})},l=()=>{if(c)clearInterval(c),c=null};return{close:l,reportOnce:e,start:()=>{if(c)return;i(),c=setInterval(i,n.intervalMs??Jn)},stop:l}};var W=()=>{},zn=()=>W,Zn={callControl:W,close:W,endTurn:W,getReadyState:()=>3,getScenarioId:()=>\"\",getSessionId:()=>\"\",send:W,sendAudio:W,simulateDisconnect:W,start:()=>{},subscribe:zn},Kn=()=>crypto.randomUUID(),jn=(n,c,o)=>{let{hostname:e,port:i,protocol:l}=window.location,t=l===\"https:\"?\"wss:\":\"ws:\",d=i?`:${i}`:\"\",g=new URL(`${t}//${e}${d}${n}`);if(g.searchParams.set(\"sessionId\",c),o)g.searchParams.set(\"scenarioId\",o);return g.toString()},Fn=(n)=>{if(!n||typeof n!==\"object\"||!(\"type\"in n))return!1;switch(n.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}},vn=(n)=>{if(typeof n.data!==\"string\")return null;try{let c=JSON.parse(n.data);return Fn(c)?c:null}catch{return null}},Mn=(n,c={})=>{if(typeof window>\"u\")return Zn;let o=new Set,e=c.reconnect!==!1,i=c.maxReconnectAttempts??10,l=c.pingInterval??30000,t={isConnected:!1,pendingMessages:[],scenarioId:c.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:c.sessionId??Kn(),ws:null},d=(s)=>{o.forEach((V)=>V(s))},g=()=>{if(t.pingInterval)clearInterval(t.pingInterval),t.pingInterval=null;if(t.reconnectTimeout)clearTimeout(t.reconnectTimeout),t.reconnectTimeout=null},y=()=>{if(t.ws?.readyState!==1)return;while(t.pendingMessages.length>0){let s=t.pendingMessages.shift();if(s!==void 0)t.ws.send(s)}},a=()=>{let s=Date.now()+500;t.reconnectAttempts+=1,d({reconnect:{attempts:t.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:i,nextAttemptAt:s,status:\"reconnecting\"},type:\"connection\"}),t.reconnectTimeout=setTimeout(()=>{if(t.reconnectAttempts>i){d({reconnect:{attempts:t.reconnectAttempts,maxAttempts:i,status:\"exhausted\"},type:\"connection\"});return}h()},500)},h=()=>{let s=new WebSocket(jn(n,t.sessionId,t.scenarioId));s.binaryType=\"arraybuffer\",s.onopen=()=>{let V=t.reconnectAttempts>0;if(t.isConnected=!0,y(),V)d({reconnect:{attempts:t.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:i,status:\"resumed\"},type:\"connection\"}),t.reconnectAttempts=0;o.forEach((R)=>R({scenarioId:t.scenarioId??void 0,sessionId:t.sessionId,status:\"active\",type:\"session\"})),t.pingInterval=setInterval(()=>{if(s.readyState===1)s.send(JSON.stringify({type:\"ping\"}))},l)},s.onmessage=(V)=>{let R=vn(V);if(!R)return;if(R.type===\"session\")t.sessionId=R.sessionId,t.scenarioId=R.scenarioId??t.scenarioId;o.forEach((Y)=>Y(R))},s.onclose=(V)=>{if(t.isConnected=!1,g(),e&&V.code!==1000&&t.reconnectAttempts<i)a();else if(e&&V.code!==1000)d({reconnect:{attempts:t.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:i,status:\"exhausted\"},type:\"connection\"})},t.ws=s},r=(s)=>{if(t.ws?.readyState===1){t.ws.send(s);return}t.pendingMessages.push(s)},M=(s)=>{r(JSON.stringify(s))},C=(s={})=>{if(s.sessionId)t.sessionId=s.sessionId;if(s.scenarioId)t.scenarioId=s.scenarioId;M({type:\"start\",sessionId:t.sessionId,scenarioId:t.scenarioId??void 0})},S=(s)=>{r(s)},w=()=>{M({type:\"end_turn\"})},E=(s)=>{M({...s,type:\"call_control\"})},_=()=>{if(g(),t.ws)t.ws.close(1000),t.ws=null;t.isConnected=!1,o.clear()},U=()=>{if(t.ws?.readyState===1)t.ws.close(4000,\"absolutejs-voice-reconnect-proof\")},N=(s)=>{return o.add(s),()=>{o.delete(s)}};return h(),{callControl:E,close:_,endTurn:w,getReadyState:()=>t.ws?.readyState??3,getScenarioId:()=>t.scenarioId??\"\",getSessionId:()=>t.sessionId,send:M,sendAudio:S,simulateDisconnect:U,start:C,subscribe:N}};var mn=()=>({attempts:0,maxAttempts:0,status:\"idle\"}),pn=()=>({assistantAudio:[],assistantTexts:[],call:null,error:null,isConnected:!1,sessionMetadata:null,scenarioId:null,partial:\"\",reconnect:mn(),sessionId:null,status:\"idle\",turns:[]}),Sn=()=>{let n=pn(),c=new Set,o=()=>{c.forEach((i)=>i())};return{dispatch:(i)=>{switch(i.type){case\"audio\":n={...n,assistantAudio:[...n.assistantAudio,{chunk:i.chunk,format:i.format,receivedAt:i.receivedAt,turnId:i.turnId}]};break;case\"assistant\":n={...n,assistantTexts:[...n.assistantTexts,i.text]};break;case\"complete\":n={...n,sessionId:i.sessionId,status:\"completed\"};break;case\"call_lifecycle\":n={...n,call:{...n.call,disposition:i.event.type===\"end\"?i.event.disposition:n.call?.disposition,endedAt:i.event.type===\"end\"?i.event.at:n.call?.endedAt,events:[...n.call?.events??[],i.event],lastEventAt:i.event.at,startedAt:n.call?.startedAt??i.event.at},sessionId:i.sessionId};break;case\"connected\":n={...n,isConnected:!0,reconnect:n.reconnect.status===\"reconnecting\"?{...n.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:\"resumed\"}:n.reconnect};break;case\"connection\":n={...n,reconnect:i.reconnect};break;case\"disconnected\":n={...n,isConnected:!1};break;case\"error\":n={...n,error:i.message};break;case\"final\":n={...n,partial:i.transcript.text,turns:n.turns.map((l)=>l)};break;case\"partial\":n={...n,partial:i.transcript.text};break;case\"replay\":n={...n,assistantTexts:[...i.assistantTexts],call:i.call??null,error:null,isConnected:i.status===\"active\",partial:i.partial,reconnect:n.reconnect.status===\"reconnecting\"?{...n.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:\"resumed\"}:n.reconnect,scenarioId:i.scenarioId??n.scenarioId,sessionId:i.sessionId,sessionMetadata:i.sessionMetadata??n.sessionMetadata,status:i.status,turns:[...i.turns]};break;case\"session\":n={...n,error:null,scenarioId:i.scenarioId??n.scenarioId,isConnected:i.status===\"active\",sessionId:i.sessionId,sessionMetadata:i.sessionMetadata??n.sessionMetadata,status:i.status};break;case\"turn\":n={...n,partial:\"\",turns:[...n.turns,i.turn]};break}o()},getServerSnapshot:()=>n,getSnapshot:()=>n,subscribe:(i)=>{return c.add(i),()=>{c.delete(i)}}}};var Ln=(n,c={})=>{let o=Mn(n,c),e=Sn(),i=c.browserMedia&&typeof window<\"u\"?Vn({...c.browserMedia,getScenarioId:()=>c.browserMedia?c.browserMedia.getScenarioId?.()??o.getScenarioId():o.getScenarioId(),getSessionId:()=>c.browserMedia?c.browserMedia.getSessionId?.()??o.getSessionId():o.getSessionId()}):null,l=new Set,t=(a)=>Promise.resolve().then(()=>{if(!a?.sessionId&&!a?.scenarioId)return;o.start(a),i?.start()}),d=()=>{l.forEach((a)=>a())},g=()=>{if(!c.reconnectReportPath||typeof fetch>\"u\")return;let a=e.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:a.reconnect,scenarioId:a.scenarioId,sessionId:o.getSessionId(),turnIds:a.turns.map((r)=>r.id)});fetch(c.reconnectReportPath,{body:h,headers:{\"Content-Type\":\"application/json\"},keepalive:!0,method:\"POST\"}).catch(()=>{})},y=o.subscribe((a)=>{let h=hn(a);if(h){if(e.dispatch(h),a.type===\"connection\")g();d()}});return{callControl(a){o.callControl(a)},close(){y(),i?.close(),o.close(),e.dispatch({type:\"disconnected\"}),d()},endTurn(){o.endTurn()},get error(){return e.getSnapshot().error},getServerSnapshot(){return e.getServerSnapshot()},getSnapshot(){return e.getSnapshot()},get isConnected(){return e.getSnapshot().isConnected},get scenarioId(){return e.getSnapshot().scenarioId},get sessionMetadata(){return e.getSnapshot().sessionMetadata},start:t,get partial(){return e.getSnapshot().partial},get reconnect(){return e.getSnapshot().reconnect},get sessionId(){return o.getSessionId()},get status(){return e.getSnapshot().status},get turns(){return e.getSnapshot().turns},get assistantTexts(){return e.getSnapshot().assistantTexts},get assistantAudio(){return e.getSnapshot().assistantAudio},get call(){return e.getSnapshot().call},sendAudio(a){o.sendAudio(a)},simulateDisconnect(){o.simulateDisconnect()},subscribe(a){return l.add(a),()=>{l.delete(a)}}}};var wn=(n)=>{if(!n||n.enabled===!1)return;return{enabled:!0,maxGain:n.maxGain??3,noiseGateAttenuation:n.noiseGateAttenuation??0.15,noiseGateThreshold:n.noiseGateThreshold??0.006,targetLevel:n.targetLevel??0.08}};var nc={balanced:{qualityProfile:\"general\",silenceMs:1400,speechThreshold:0.012,transcriptStabilityMs:1000},fast:{qualityProfile:\"general\",silenceMs:700,speechThreshold:0.015,transcriptStabilityMs:450},\"long-form\":{qualityProfile:\"general\",silenceMs:2200,speechThreshold:0.01,transcriptStabilityMs:1500}},cc={general:{},\"accent-heavy\":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},\"noisy-room\":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},\"short-command\":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var Rn=(n)=>{let c=n?.profile??\"fast\",o=n?.qualityProfile??\"general\",e=nc[c],i=cc[o];return{profile:c,qualityProfile:o,silenceMs:n?.silenceMs??i.silenceMs??e.silenceMs,speechThreshold:n?.speechThreshold??i.speechThreshold??e.speechThreshold,transcriptStabilityMs:n?.transcriptStabilityMs??i.transcriptStabilityMs??e.transcriptStabilityMs}};var ec={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:{qualityProfile:\"short-command\",profile:\"balanced\"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:\"continuous\",turnDetection:{qualityProfile:\"general\",profile:\"fast\"}},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:{qualityProfile:\"accent-heavy\",profile:\"long-form\"}},\"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:{qualityProfile:\"accent-heavy\",profile:\"long-form\"}},\"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:{qualityProfile:\"noisy-room\",profile:\"long-form\",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:{qualityProfile:\"noisy-room\",profile:\"long-form\",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:{qualityProfile:\"noisy-room\",profile:\"long-form\",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:{qualityProfile:\"noisy-room\",profile:\"long-form\"}}},_n=(n=\"default\")=>{let c=ec[n];return{audioConditioning:wn(c.audioConditioning),capture:{channelCount:c.capture?.channelCount??1,sampleRateHz:c.capture?.sampleRateHz??16000},connection:{...c.connection},name:n,sttLifecycle:c.sttLifecycle??\"continuous\",turnDetection:Rn(c.turnDetection)}};var oc=(n)=>({assistantAudio:[...n.assistantAudio],assistantTexts:[...n.assistantTexts],call:n.call,error:n.error,isConnected:n.isConnected,isRecording:!1,partial:n.partial,reconnect:n.reconnect,recordingError:null,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,turns:[...n.turns]}),j=(n,c={})=>{let o=_n(c.preset),e=Ln(n,{...o.connection,...c.connection}),i=null,l=oc(e),t=new Set,d=()=>{for(let C of t)C()},g=()=>{if(l={...l,assistantAudio:[...e.assistantAudio],assistantTexts:[...e.assistantTexts],call:e.call,error:e.error,isConnected:e.isConnected,partial:e.partial,reconnect:e.reconnect,sessionId:e.sessionId,sessionMetadata:e.sessionMetadata,scenarioId:e.scenarioId,status:e.status,turns:[...e.turns]},c.autoStopOnComplete!==!1&&l.status===\"completed\"&&l.isRecording)i?.stop(),i=null,l={...l,isRecording:!1};d()},y=e.subscribe(g);g();let a=()=>{if(i)return i;return i=An({channelCount:c.capture?.channelCount??o.capture.channelCount,onLevel:c.capture?.onLevel,onAudio:(C)=>{if(c.capture?.onAudio){c.capture.onAudio(C,e.sendAudio);return}e.sendAudio(C)},sampleRateHz:c.capture?.sampleRateHz??o.capture.sampleRateHz}),i},h=()=>{i?.stop(),i=null,l={...l,isRecording:!1},d()},r=async()=>{if(l.isRecording)return;try{l={...l,recordingError:null},d(),await a().start(),l={...l,isRecording:!0},d()}catch(C){throw i=null,l={...l,isRecording:!1,recordingError:C instanceof Error?C.message:String(C)},d(),C}};return{bindHTMX(C){return gn(e,C)},callControl:(C)=>e.callControl(C),close:()=>{y(),h(),e.close()},endTurn:()=>e.endTurn(),get error(){return l.error},getServerSnapshot:()=>l,getSnapshot:()=>l,get isConnected(){return l.isConnected},get isRecording(){return l.isRecording},get partial(){return l.partial},get recordingError(){return l.recordingError},get reconnect(){return l.reconnect},sendAudio:(C)=>e.sendAudio(C),simulateDisconnect:()=>e.simulateDisconnect(),get sessionId(){return l.sessionId},get sessionMetadata(){return l.sessionMetadata},get scenarioId(){return l.scenarioId},startRecording:r,get status(){return l.status},stopRecording:h,subscribe:(C)=>{return t.add(C),()=>{t.delete(C)}},toggleRecording:async()=>{if(l.isRecording){h();return}await r()},get turns(){return l.turns},get assistantTexts(){return l.assistantTexts},get assistantAudio(){return l.assistantAudio},get call(){return l.call}}};var tc=()=>({activeSourceCount:0,error:null,isActive:!1,isPlaying:!1,lastInterruptLatencyMs:void 0,lastPlaybackStopLatencyMs:void 0,processedChunkCount:0,queuedChunkCount:0}),ic=()=>{if(typeof window>\"u\")return typeof AudioContext>\"u\"?void 0:AudioContext;return window.AudioContext??window.webkitAudioContext},lc=(n,c)=>{let o=c.format;if(o.container!==\"raw\"||o.encoding!==\"pcm_s16le\")throw Error(`Unsupported assistant audio format: ${o.container}/${o.encoding}`);let e=c.chunk,i=Math.max(1,o.channels),l=Math.floor(e.byteLength/2),t=Math.max(1,Math.floor(l/i)),d=n.createBuffer(i,t,o.sampleRateHz),g=new DataView(e.buffer,e.byteOffset,e.byteLength);for(let y=0;y<i;y+=1){let a=d.getChannelData(y);for(let h=0;h<t;h+=1){let M=(h*i+y)*2;if(M+1>=e.byteLength){a[h]=0;continue}a[h]=g.getInt16(M,!0)/32768}}return d},F=(n,c={})=>{let o=new Set,e=new Set,i=(c.lookaheadMs??15)/1000,l=tc(),t=null,d=null,g=0,y=Promise.resolve(),a=null,h=null,r=null,M=null,C=()=>{for(let A of o)A()},S=(A)=>{l={...l,...A},C()},w=()=>{if(l.error!==null)S({error:null})},E=()=>{if(M!==null)clearTimeout(M),M=null},_=(A)=>{E(),a=null,S({activeSourceCount:e.size,isPlaying:!1,lastInterruptLatencyMs:A,lastPlaybackStopLatencyMs:l.lastPlaybackStopLatencyMs??A}),r?.(),r=null,h=null},U=(A)=>{if(!A)return 0;return Math.max(0,((A.baseLatency??0)+(A.outputLatency??0))*1000)},N=(A)=>{if(!d)return;let T=1;if(d.gain.setValueAtTime){d.gain.setValueAtTime(T,A?.currentTime??0);return}d.gain.value=T},s=(A)=>{if(!d)return;let T=0;if(d.gain.setValueAtTime){d.gain.setValueAtTime(T,A?.currentTime??0);return}d.gain.value=T},V=()=>{if(a===null||e.size>0)return;_(Date.now()-a)},R=async()=>{if(t)return t;if(c.createAudioContext)t=c.createAudioContext();else{let A=ic();if(!A)throw Error(\"Assistant audio playback requires AudioContext support.\");t=new A}if(t.createGain)d=t.createGain(),d.connect?.(t.destination);return g=t.currentTime,t},Y=async(A)=>{let T=await R(),P=lc(T,A),L=T.createBufferSource();L.buffer=P,L.connect(d??T.destination),L.onended=()=>{e.delete(L),L.disconnect?.(),S({activeSourceCount:e.size,isPlaying:e.size>0&&l.isActive}),V()};let Q=Math.max(T.currentTime+i,g);g=Q+P.duration,e.add(L),S({activeSourceCount:e.size,isPlaying:!0}),L.start(Q)},f=(A)=>{for(let T of[...e])T.stop?.();if(g=t?t.currentTime:0,A?.forceClear){for(let T of e)T.disconnect?.();e.clear(),V()}},$=async()=>{if(!l.isActive)return;let A=n.assistantAudio.slice(l.processedChunkCount);if(A.length===0)return;try{w();for(let T of A)await Y(T);S({processedChunkCount:n.assistantAudio.length,queuedChunkCount:l.queuedChunkCount+A.length})}catch(T){S({error:T instanceof Error?T.message:String(T)})}},D=()=>{return y=y.then(()=>$(),()=>$()),y},q=n.subscribe(()=>{if(c.autoStart&&!l.isActive&&n.assistantAudio.length>0){H.start();return}if(l.isActive)D()}),H={close:async()=>{if(q(),f({forceClear:!0}),E(),r?.(),r=null,h=null,a=null,t&&t.state!==\"closed\")await t.close();t=null,d?.disconnect?.(),d=null,g=0,S({activeSourceCount:0,isActive:!1,isPlaying:!1})},get activeSourceCount(){return l.activeSourceCount},get error(){return l.error},getSnapshot:()=>l,get isActive(){return l.isActive},get isPlaying(){return l.isPlaying},interrupt:async()=>{let A=Date.now(),T=await R();a=A,s(T);let P=Date.now()-A+U(T);if(S({isActive:!1,isPlaying:e.size>0,lastPlaybackStopLatencyMs:P}),e.size===0){_(P);return}if(!h)h=new Promise((L)=>{r=L});E(),M=setTimeout(()=>{for(let L of e)L.disconnect?.();e.clear(),_(Date.now()-A)},250),f(),await h},get lastInterruptLatencyMs(){return l.lastInterruptLatencyMs},get lastPlaybackStopLatencyMs(){return l.lastPlaybackStopLatencyMs},pause:async()=>{if(!t){S({activeSourceCount:0,isActive:!1,isPlaying:!1});return}await t.suspend(),S({activeSourceCount:e.size,isActive:!1,isPlaying:!1})},get processedChunkCount(){return l.processedChunkCount},get queuedChunkCount(){return l.queuedChunkCount},start:async()=>{try{w();let A=await R();if(N(A),A.state===\"suspended\")await A.resume();S({activeSourceCount:e.size,isActive:!0,isPlaying:A.state===\"running\"}),await D()}catch(A){throw S({error:A instanceof Error?A.message:String(A),isActive:!1,isPlaying:!1}),A}},subscribe:(A)=>{return o.add(A),()=>{o.delete(A)}}};return H};var sc=()=>`barge-in:${Date.now()}:${crypto.randomUUID?.()??Math.random().toString(36).slice(2)}`,dc=(n,c)=>{let o=n.filter((t)=>t.status===\"stopped\"),e=o.map((t)=>t.latencyMs).filter((t)=>typeof t===\"number\"),i=o.filter((t)=>typeof t.latencyMs===\"number\"&&t.latencyMs>c).length,l=o.length-i;return{averageLatencyMs:e.length>0?Math.round(e.reduce((t,d)=>t+d,0)/e.length):void 0,events:[...n],failed:i,lastEvent:n.at(-1),passed:l,status:n.length===0?\"empty\":i>0?\"fail\":o.length===0?\"warn\":\"pass\",thresholdMs:c,total:o.length}},En=(n={})=>{let c=new Set,o=n.thresholdMs??250,e=n.fetch??globalThis.fetch,i=[],l=()=>{for(let g of c)g()},t=(g)=>{if(!n.path||typeof e!==\"function\")return;e(n.path,{body:JSON.stringify(g),headers:{\"Content-Type\":\"application/json\"},method:\"POST\"}).catch(()=>{})},d=(g,y)=>{let a={at:Date.now(),id:sc(),latencyMs:y.latencyMs,playbackStopLatencyMs:y.playbackStopLatencyMs,reason:y.reason,sessionId:y.sessionId,status:g,thresholdMs:o};return i.push(a),t(a),l(),a};return{getSnapshot:()=>dc(i,o),recordRequested:(g)=>d(\"requested\",g),recordSkipped:(g)=>d(\"skipped\",g),recordStopped:(g)=>d(\"stopped\",g),subscribe:(g)=>{return c.add(g),()=>{c.delete(g)}}}};var rc=0.08,ac=(n,c={})=>(c.enabled??!0)&&n>=(c.interruptThreshold??rc),en=(n,c,o={})=>{let e=n.partial,i=(t)=>{if(!c.isPlaying||o.enabled===!1){o.monitor?.recordSkipped({reason:t,sessionId:n.sessionId});return}o.monitor?.recordRequested({reason:t,sessionId:n.sessionId}),c.interrupt().then(()=>{o.monitor?.recordStopped({latencyMs:c.lastInterruptLatencyMs,playbackStopLatencyMs:c.lastPlaybackStopLatencyMs,reason:t,sessionId:n.sessionId})})},l=n.subscribe(()=>{if(o.interruptOnPartial===!1){e=n.partial;return}if(!e&&n.partial)i(\"partial-transcript\");e=n.partial});return{close:()=>{l()},handleLevel:(t)=>{if(ac(t,o))i(\"input-level\")},sendAudio:(t)=>{i(\"manual-audio\"),n.sendAudio(t)}}};var dn=48,gc=320,Ac=88,hc=\"Guided test\",yc=\"General recording\",Cc=\"Pick a scenario to begin the demo.\",Tc=\"I can walk you through a short guided voice test.\",Ic=\"I can capture one freeform recording and confirm that it landed.\",Vc=\"Choose a scenario to begin. Guided test asks follow-up prompts. General recording just captures what you say.\",Mc=\"Click Start general recording to capture one freeform answer.\",Pn=\"Speak freely. When you pause, the recording will be captured.\",ln=\"Recording saved. Start again if you want another capture.\",Dn=\"Guided test complete. Review the saved summary below.\",On=\"All prompts are covered. You can stop the microphone or keep speaking for extra detail.\",Sc=\"Ready. Start guided test or general recording to begin.\",Lc=\"Live. Answer the prompt, then click Stop microphone when finished.\",bn=[\"Start with a quick introduction about who you are.\",\"Now describe what you are trying to do or test.\",\"Finish with any detail that feels blocked, risky, or unclear.\"],xn=(n,c,o)=>Math.min(o,Math.max(c,n)),u=(n)=>n.replaceAll(\"&\",\"&amp;\").replaceAll(\"<\",\"&lt;\").replaceAll(\">\",\"&gt;\").replaceAll('\"',\"&quot;\").replaceAll(\"'\",\"&#39;\"),on=(n,c)=>{let o=n[c];if(typeof o===\"string\"&&o.trim())return o;return null},sn=(n)=>{if(typeof n===\"string\"&&n.trim())return n;if(n instanceof Error&&n.message.trim())return n.message;if(n&&typeof n===\"object\"){let c=n,o=on(c,\"message\")??on(c,\"reason\")??on(c,\"description\");if(o)return o;if(\"error\"in c)return sn(c.error);if(\"cause\"in c)return sn(c.cause);try{return JSON.stringify(n)}catch{}}return\"Unexpected error\"},wc=(n)=>{let c=[n.status];if(n.attempts>0||n.maxAttempts>0)c.push(`${n.attempts}/${n.maxAttempts} attempts`);if(n.nextAttemptAt){let o=Math.max(0,n.nextAttemptAt-Date.now());c.push(`retry in ${Math.ceil(o/100)/10}s`)}return c.join(\" \u00B7 \")},v=(n=dn)=>Array.from({length:n},()=>0),fn=(n,c,o=dn)=>{let e=n.slice(-(o-1));e.push(xn(c,0,1));while(e.length<o)e.unshift(0);return e},Rc=(n,c=gc,o=Ac)=>{let e=n.length>1?n:v(dn),i=c/(e.length-1),l=o/2,t=o*0.34;if(Math.max(...e,0)<=0.015)return`M 0 ${l} L ${c} ${l}`;let g=e.map((a,h)=>{let r=h*0.76,M=Math.sin(r)*0.78+Math.sin(r*0.41)*0.22,C=a*t,S=i*h,w=xn(l+M*C,8,o-8);return{x:S,y:w}});if(g.length===0)return`M 0 ${l} L ${c} ${l}`;let y=`M ${g[0]?.x??0} ${g[0]?.y??l}`;for(let a=1;a<g.length;a+=1){let h=g[a-1],r=g[a];if(!h||!r)continue;let M=(h.x+r.x)/2;y+=` Q ${M} ${h.y} ${r.x} ${r.y}`}return y},_c=(n)=>{if(!n)return bn;try{let c=JSON.parse(n);if(Array.isArray(c)){let o=c.filter((e)=>typeof e===\"string\").map((e)=>e.trim()).filter(Boolean);if(o.length>0)return o}}catch{}return bn},tn=(n)=>{if(!n)return;let c=Number(n);return Number.isFinite(c)?c:void 0},Ec=(n,c,o)=>{if(!c)return null;let e=document.querySelector(c);return e instanceof o?e:null},x=(n,c,o,e)=>{let i=c?document.querySelector(c):null;if(i instanceof o)return i;let l=n.querySelector(`#${e}`);if(l instanceof o)return l;throw Error(`Voice HTMX bootstrap could not find the required element \"${e}\".`)},bc=(n)=>{if(!n.mode)return Cc;if(!n.hasStarted)return n.mode===\"guided\"?Tc:Ic;if(n.status===\"completed\")return n.mode===\"guided\"?Dn:ln;if(n.mode===\"general\")return Pn;return n.guidedPrompts[n.turnCount]??On},fc=(n)=>{if(!n.mode)return Vc;if(n.status===\"completed\")return n.mode===\"guided\"?Dn:ln;if(!n.hasStarted)return n.mode===\"guided\"?`Click Start guided test to begin. First prompt: ${n.guidedPrompts[0]??\"Answer the first prompt.\"}`:Mc;if(n.mode===\"general\")return n.turnCount===0?Pn:ln;return n.guidedPrompts[n.turnCount]??On},Pc=(n)=>{let c=n.dataset.voiceGuidedPath,o=n.dataset.voiceGeneralPath;if(!c||!o)throw Error(\"Voice HTMX bootstrap requires data-voice-guided-path and data-voice-general-path.\");let e=_c(n.dataset.voiceGuidedPrompts),i=n.dataset.voiceGuidedLabel??hc,l=n.dataset.voiceGeneralLabel??yc,t=n.dataset.voiceReconnectReportPath,d=n.dataset.voiceBargeInPath,g=d?En({path:d,thresholdMs:tn(n.dataset.voiceBargeInThresholdMs)}):null,y=tn(n.dataset.voiceBargeInRecentWindowMs)??4000,a=tn(n.dataset.voiceBargeInSpeechThreshold)??0.04,h=x(document,n.dataset.voiceSync,HTMLElement,\"voice-htmx-sync\"),r=x(n,n.dataset.voiceConnection,HTMLElement,\"metric-connection\"),M=x(n,n.dataset.voiceError,HTMLElement,\"status-error\"),C=x(n,n.dataset.voiceMicrophone,HTMLElement,\"status-mic\"),S=x(n,n.dataset.voicePrompt,HTMLElement,\"status-prompt\"),w=Ec(n,n.dataset.voiceReconnect,HTMLElement),E=x(n,n.dataset.voiceChat,HTMLElement,\"chat-list\"),_=x(n,n.dataset.voiceStartGuided,HTMLButtonElement,\"start-guided\"),U=x(n,n.dataset.voiceStartGeneral,HTMLButtonElement,\"start-general\"),N=x(n,n.dataset.voiceStop,HTMLButtonElement,\"stop-mic\"),s=x(n,n.dataset.voiceMonitor,HTMLElement,\"voice-monitor\"),V=x(n,n.dataset.voiceMonitorCopy,HTMLElement,\"voice-monitor-copy\"),R=x(n,n.dataset.voiceWaveGlow,SVGPathElement,\"voice-wave-glow\"),Y=x(n,n.dataset.voiceWavePath,SVGPathElement,\"voice-wave-path\"),f=null,$={general:!1,guided:!1},D=!1,q=null,H=v(),A=null,T=null,P=j(c,{capture:{onAudio:(I,B)=>{if(A){A.sendAudio(I);return}B(I)},onLevel:(I)=>{A?.handleLevel(I),H=fn(H,I),m()}},connection:{reconnectReportPath:t},preset:\"guided-intake\"}),L=j(o,{capture:{onAudio:(I,B)=>{if(T){T.sendAudio(I);return}B(I)},onLevel:(I)=>{T?.handleLevel(I),H=fn(H,I),m()}},connection:{reconnectReportPath:t},preset:\"dictation\"}),Q=P.bindHTMX({element:h}),Un=L.bindHTMX({element:h}),k=F(P),z=F(L);A=en(P,k,{interruptThreshold:a,monitor:g??void 0}),T=en(L,z,{interruptThreshold:a,monitor:g??void 0});let J=()=>f===\"general\"?L:P,Oc=()=>f===\"general\"?z:k,m=()=>{let I=Rc(H);R.setAttribute(\"d\",I),Y.setAttribute(\"d\",I),V.innerHTML=`<span class=\"voice-live-dot\"></span>${D?\"Microphone live\":\"Microphone idle\"}`,V.classList.toggle(\"is-live\",D),s.classList.toggle(\"is-live\",D)},X=()=>{let I=J(),B=(f?$[f]:!1)||I.turns.length>0,an=I.status;if(r.textContent=I.isConnected?\"Connected\":\"Waiting\",M.textContent=q||I.error||\"None\",w)w.textContent=wc(I.reconnect);C.textContent=D?Lc:Sc,S.textContent=fc({guidedPrompts:e,hasStarted:B,mode:f,status:an,turnCount:I.turns.length}),_.hidden=D,U.hidden=D,N.hidden=!D,E.innerHTML=`<article class=\"voice-chat-message assistant\">\n <div class=\"voice-chat-role\">${u(f===\"general\"?l:f===\"guided\"?i:\"Voice demo\")}</div>\n <p class=\"voice-turn-text\">${u(bc({generalLabel:l,guidedLabel:i,guidedPrompts:e,hasStarted:B,mode:f,status:an,turnCount:I.turns.length}))}</p>\n</article>${I.turns.map((p)=>`<div class=\"voice-chat-stack\">\n <article class=\"voice-chat-message user\">\n <div class=\"voice-chat-role\">You</div>\n <p class=\"voice-turn-text\">${u(p.text)}</p>\n </article>\n ${p.assistantText?`<article class=\"voice-chat-message assistant\">\n <div class=\"voice-chat-role\">${u(f===\"general\"?l:f===\"guided\"?i:\"Guide\")}</div>\n <p class=\"voice-turn-text\">${u(p.assistantText)}</p>\n </article>`:\"\"}\n</div>`).join(\"\")}${I.partial?`<article class=\"voice-chat-message user pending\">\n <div class=\"voice-chat-role\">Speaking</div>\n <p class=\"voice-turn-text\">${u(I.partial)}</p>\n</article>`:\"\"}`,m()},Nn=()=>{J().stopRecording(),D=!1,q=null,H=v(),X()},rn=async(I)=>{f=I,$={...$,[I]:!0};try{await J().startRecording(),q=null,D=!0,X()}catch(B){J().stopRecording(),D=!1,H=v(),q=sn(B),X()}};P.subscribe(()=>{if(P.assistantAudio.length>0)k.start().catch(()=>{});X()}),L.subscribe(()=>{if(L.assistantAudio.length>0)z.start().catch(()=>{});X()}),_.addEventListener(\"click\",()=>{rn(\"guided\")}),U.addEventListener(\"click\",()=>{rn(\"general\")}),N.addEventListener(\"click\",()=>{Nn()}),n.addEventListener(\"absolute-voice-simulate-disconnect\",()=>{J().simulateDisconnect()}),window.addEventListener(\"beforeunload\",()=>{P.stopRecording(),L.stopRecording(),A?.close(),T?.close(),k.close(),z.close(),Q(),Un(),P.close(),L.close()}),X()},Dc=()=>{if(typeof window>\"u\"||typeof document>\"u\")return;let n=Array.from(document.querySelectorAll(\"[data-voice-htmx]\"));for(let c of n)if(c instanceof HTMLElement)Pc(c)};Dc();export{Dc as initVoiceHTMX};\n";
@@ -1,57 +0,0 @@
1
- ## Bundled Fixtures
2
-
3
- This directory contains small public benchmark fixtures for `@absolutejs/voice`.
4
-
5
- ### Sources
6
-
7
- - `quietly-alone-clean.pcm`
8
- - `traveled-back-route-clean.pcm`
9
- - `rainstorms-noisy.pcm`
10
-
11
- These are derived from public-domain LibriSpeech material, with the noisy variant created by mixing synthetic noise into a clean base utterance for adapter comparison.
12
-
13
- - `stella-india-english37.pcm`
14
- - `stella-ghana-english507.pcm`
15
- - `stella-singapore-english655.pcm`
16
- - `stella-pakistan-english519.pcm`
17
- - `stella-jamaica-jamaican-creole-english1.pcm`
18
- - `stella-liberia-liberian-pidgin-english2.pcm`
19
- - `stella-sierra-leone-krio5.pcm`
20
- - `stella-bulgaria-bulgarian20.pcm`
21
-
22
- These are derived from the Speech Accent Archive at George Mason University using the shared "Please call Stella..." elicitation paragraph.
23
-
24
- Archive:
25
-
26
- - https://accent.gmu.edu/
27
-
28
- License:
29
-
30
- - https://creativecommons.org/licenses/by-nc-sa/2.0/
31
-
32
- Selected speaker pages:
33
-
34
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=96
35
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=1800
36
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=3033
37
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=1882
38
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=967
39
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=2141
40
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=1140
41
- - https://accent.gmu.edu/browse_language.php?function=detail&speakerid=2691
42
-
43
- ### Synthetic Multi-Turn Fixtures
44
-
45
- - `multiturn-two-clean.pcm`
46
- - `multiturn-three-mixed.pcm`
47
- - `dialogue-two-clean.pcm`
48
- - `dialogue-two-noisy.pcm`
49
- - `dialogue-three-clean.pcm`
50
- - `dialogue-three-mixed.pcm`
51
-
52
- These are synthetic conversation-style fixtures created by concatenating the bundled public-domain base clips with inserted silence to exercise turn commit behavior.
53
-
54
- - `multiturn-*` are stress fixtures with tighter pauses.
55
- - `dialogue-*` are dialogue-style fixtures with longer pause boundaries intended to approximate normal guided multi-turn voice use.
56
- - `dialogue-three-clean` is the clean long-form baseline for multi-turn guided capture.
57
- - `dialogue-two-noisy` and `dialogue-three-mixed` keep noisy utterances in the dialogue-style set so turn behavior can be compared against a more realistic clean baseline.
@@ -1,358 +0,0 @@
1
- [
2
- {
3
- "id": "quietly-alone-clean",
4
- "title": "Short clean utterance",
5
- "audioPath": "quietly-alone-clean.pcm",
6
- "expectedText": "GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
7
- "expectedTerms": ["quietly alone", "no harm"],
8
- "chunkDurationMs": 100,
9
- "difficulty": "clean",
10
- "tags": ["clean", "short", "librispeech"]
11
- },
12
- {
13
- "id": "traveled-back-route-clean",
14
- "title": "Long clean utterance",
15
- "audioPath": "traveled-back-route-clean.pcm",
16
- "expectedText": "WE PASSED AROUND ATLANTA CROSSED THE CHATTAHOOCHEE AND TRAVELED BACK OVER THE SAME ROUTE ON WHICH WE HAD MADE THE ARDUOUS CAMPAIGN UNDER JOE JOHNSTON",
17
- "expectedTerms": ["atlanta", "chattahoochee", "joe johnston"],
18
- "chunkDurationMs": 100,
19
- "difficulty": "clean",
20
- "tags": ["clean", "long", "librispeech"]
21
- },
22
- {
23
- "id": "rainstorms-noisy",
24
- "title": "Noisy utterance with synthetic pink noise",
25
- "audioPath": "rainstorms-noisy.pcm",
26
- "expectedText": "SLIGHT RAINSTORMS ARE LIKELY TO BE ENCOUNTERED IN A TRIP ROUND THE MOUNTAIN BUT ONE MAY EASILY FIND SHELTER BENEATH WELL THATCHED TREES THAT SHED THE RAIN LIKE A ROOF",
27
- "expectedTerms": ["rainstorms", "thatched trees"],
28
- "chunkDurationMs": 100,
29
- "difficulty": "noisy",
30
- "tags": ["noisy", "long", "synthetic-noise", "librispeech"]
31
- },
32
- {
33
- "id": "stella-india-english37",
34
- "title": "International English accent from India",
35
- "audioPath": "stella-india-english37.pcm",
36
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
37
- "expectedTerms": [
38
- "stella",
39
- "snow peas",
40
- "blue cheese",
41
- "brother bob",
42
- "plastic snake",
43
- "toy frog",
44
- "three red bags",
45
- "train station"
46
- ],
47
- "chunkDurationMs": 100,
48
- "difficulty": "challenging",
49
- "tags": [
50
- "accent",
51
- "challenging",
52
- "india",
53
- "international",
54
- "speech-accent-archive"
55
- ]
56
- },
57
- {
58
- "id": "stella-ghana-english507",
59
- "title": "International English accent from Ghana",
60
- "audioPath": "stella-ghana-english507.pcm",
61
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
62
- "expectedTerms": [
63
- "stella",
64
- "snow peas",
65
- "blue cheese",
66
- "brother bob",
67
- "plastic snake",
68
- "toy frog",
69
- "three red bags",
70
- "train station"
71
- ],
72
- "chunkDurationMs": 100,
73
- "difficulty": "challenging",
74
- "tags": [
75
- "accent",
76
- "challenging",
77
- "ghana",
78
- "international",
79
- "speech-accent-archive"
80
- ]
81
- },
82
- {
83
- "id": "stella-singapore-english655",
84
- "title": "International English accent from Singapore",
85
- "audioPath": "stella-singapore-english655.pcm",
86
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
87
- "expectedTerms": [
88
- "stella",
89
- "snow peas",
90
- "blue cheese",
91
- "brother bob",
92
- "plastic snake",
93
- "toy frog",
94
- "three red bags",
95
- "train station"
96
- ],
97
- "chunkDurationMs": 100,
98
- "difficulty": "challenging",
99
- "tags": [
100
- "accent",
101
- "challenging",
102
- "international",
103
- "singapore",
104
- "speech-accent-archive"
105
- ]
106
- },
107
- {
108
- "id": "stella-pakistan-english519",
109
- "title": "International English accent from Pakistan",
110
- "audioPath": "stella-pakistan-english519.pcm",
111
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
112
- "expectedTerms": [
113
- "stella",
114
- "snow peas",
115
- "blue cheese",
116
- "brother bob",
117
- "plastic snake",
118
- "toy frog",
119
- "three red bags",
120
- "train station"
121
- ],
122
- "chunkDurationMs": 100,
123
- "difficulty": "challenging",
124
- "tags": [
125
- "accent",
126
- "challenging",
127
- "international",
128
- "pakistan",
129
- "speech-accent-archive"
130
- ]
131
- },
132
- {
133
- "id": "stella-jamaica-jamaican-creole-english1",
134
- "title": "International English accent from Jamaica",
135
- "audioPath": "stella-jamaica-jamaican-creole-english1.pcm",
136
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
137
- "expectedTerms": [
138
- "stella",
139
- "snow peas",
140
- "blue cheese",
141
- "brother bob",
142
- "plastic snake",
143
- "toy frog",
144
- "three red bags",
145
- "train station"
146
- ],
147
- "chunkDurationMs": 100,
148
- "difficulty": "challenging",
149
- "tags": [
150
- "accent",
151
- "challenging",
152
- "international",
153
- "jamaica",
154
- "speech-accent-archive"
155
- ]
156
- },
157
- {
158
- "id": "stella-liberia-liberian-pidgin-english2",
159
- "title": "International English accent from Liberia",
160
- "audioPath": "stella-liberia-liberian-pidgin-english2.pcm",
161
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
162
- "expectedTerms": [
163
- "stella",
164
- "snow peas",
165
- "blue cheese",
166
- "brother bob",
167
- "plastic snake",
168
- "toy frog",
169
- "three red bags",
170
- "train station"
171
- ],
172
- "chunkDurationMs": 100,
173
- "difficulty": "challenging",
174
- "tags": [
175
- "accent",
176
- "challenging",
177
- "international",
178
- "liberia",
179
- "speech-accent-archive"
180
- ]
181
- },
182
- {
183
- "id": "stella-sierra-leone-krio5",
184
- "title": "International English accent from Sierra Leone",
185
- "audioPath": "stella-sierra-leone-krio5.pcm",
186
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
187
- "expectedTerms": [
188
- "stella",
189
- "snow peas",
190
- "blue cheese",
191
- "brother bob",
192
- "plastic snake",
193
- "toy frog",
194
- "three red bags",
195
- "train station"
196
- ],
197
- "chunkDurationMs": 100,
198
- "difficulty": "challenging",
199
- "tags": [
200
- "accent",
201
- "challenging",
202
- "international",
203
- "sierra-leone",
204
- "speech-accent-archive"
205
- ]
206
- },
207
- {
208
- "id": "stella-bulgaria-bulgarian20",
209
- "title": "International English accent from Bulgaria",
210
- "audioPath": "stella-bulgaria-bulgarian20.pcm",
211
- "expectedText": "PLEASE CALL STELLA ASK HER TO BRING THESE THINGS WITH HER FROM THE STORE SIX SPOONS OF FRESH SNOW PEAS FIVE THICK SLABS OF BLUE CHEESE AND MAYBE A SNACK FOR HER BROTHER BOB WE ALSO NEED A SMALL PLASTIC SNAKE AND A BIG TOY FROG FOR THE KIDS SHE CAN SCOOP THESE THINGS INTO THREE RED BAGS AND WE WILL GO MEET HER WEDNESDAY AT THE TRAIN STATION",
212
- "expectedTerms": [
213
- "stella",
214
- "snow peas",
215
- "blue cheese",
216
- "brother bob",
217
- "plastic snake",
218
- "toy frog",
219
- "three red bags",
220
- "train station"
221
- ],
222
- "chunkDurationMs": 100,
223
- "difficulty": "challenging",
224
- "tags": [
225
- "accent",
226
- "challenging",
227
- "bulgaria",
228
- "international",
229
- "speech-accent-archive"
230
- ]
231
- },
232
- {
233
- "id": "multiturn-two-clean",
234
- "title": "Synthetic two-turn clean conversation",
235
- "audioPath": "multiturn-two-clean.pcm",
236
- "expectedText": "GO QUIETLY ALONE NO HARM WILL BEFALL YOU WE PASSED AROUND ATLANTA CROSSED THE CHATTAHOOCHEE AND TRAVELED BACK OVER THE SAME ROUTE ON WHICH WE HAD MADE THE ARDUOUS CAMPAIGN UNDER JOE JOHNSTON",
237
- "expectedTerms": [
238
- "quietly alone",
239
- "atlanta",
240
- "chattahoochee",
241
- "joe johnston"
242
- ],
243
- "expectedTurnTexts": [
244
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
245
- "WE PASSED AROUND ATLANTA CROSSED THE CHATTAHOOCHEE AND TRAVELED BACK OVER THE SAME ROUTE ON WHICH WE HAD MADE THE ARDUOUS CAMPAIGN UNDER JOE JOHNSTON"
246
- ],
247
- "chunkDurationMs": 100,
248
- "difficulty": "clean",
249
- "tags": ["clean", "conversation", "multi-turn", "synthetic"]
250
- },
251
- {
252
- "id": "multiturn-three-mixed",
253
- "title": "Synthetic three-turn mixed conversation",
254
- "audioPath": "multiturn-three-mixed.pcm",
255
- "expectedText": "GO QUIETLY ALONE NO HARM WILL BEFALL YOU SLIGHT RAINSTORMS ARE LIKELY TO BE ENCOUNTERED IN A TRIP ROUND THE MOUNTAIN BUT ONE MAY EASILY FIND SHELTER BENEATH WELL THATCHED TREES THAT SHED THE RAIN LIKE A ROOF GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
256
- "expectedTerms": ["quietly alone", "rainstorms", "thatched trees"],
257
- "expectedTurnTexts": [
258
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
259
- "SLIGHT RAINSTORMS ARE LIKELY TO BE ENCOUNTERED IN A TRIP ROUND THE MOUNTAIN BUT ONE MAY EASILY FIND SHELTER BENEATH WELL THATCHED TREES THAT SHED THE RAIN LIKE A ROOF",
260
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU"
261
- ],
262
- "chunkDurationMs": 100,
263
- "difficulty": "challenging",
264
- "tags": ["conversation", "multi-turn", "noisy", "stress", "synthetic"]
265
- },
266
- {
267
- "id": "dialogue-two-clean",
268
- "title": "Dialogue-style two-turn clean conversation",
269
- "audioPath": "dialogue-two-clean.pcm",
270
- "expectedText": "GO QUIETLY ALONE NO HARM WILL BEFALL YOU WE PASSED AROUND ATLANTA CROSSED THE CHATTAHOOCHEE AND TRAVELED BACK OVER THE SAME ROUTE ON WHICH WE HAD MADE THE ARDUOUS CAMPAIGN UNDER JOE JOHNSTON",
271
- "expectedTerms": [
272
- "quietly alone",
273
- "atlanta",
274
- "chattahoochee",
275
- "joe johnston"
276
- ],
277
- "expectedTurnTexts": [
278
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
279
- "WE PASSED AROUND ATLANTA CROSSED THE CHATTAHOOCHEE AND TRAVELED BACK OVER THE SAME ROUTE ON WHICH WE HAD MADE THE ARDUOUS CAMPAIGN UNDER JOE JOHNSTON"
280
- ],
281
- "chunkDurationMs": 100,
282
- "difficulty": "clean",
283
- "tags": [
284
- "clean",
285
- "conversation",
286
- "dialogue-style",
287
- "multi-turn",
288
- "synthetic"
289
- ]
290
- },
291
- {
292
- "id": "dialogue-two-noisy",
293
- "title": "Dialogue-style two-turn mixed clean and noisy conversation",
294
- "audioPath": "dialogue-two-noisy.pcm",
295
- "expectedText": "GO QUIETLY ALONE NO HARM WILL BEFALL YOU SLIGHT RAINSTORMS ARE LIKELY TO BE ENCOUNTERED IN A TRIP ROUND THE MOUNTAIN BUT ONE MAY EASILY FIND SHELTER BENEATH WELL THATCHED TREES THAT SHED THE RAIN LIKE A ROOF",
296
- "expectedTerms": ["quietly alone", "rainstorms", "thatched trees"],
297
- "expectedTurnTexts": [
298
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
299
- "SLIGHT RAINSTORMS ARE LIKELY TO BE ENCOUNTERED IN A TRIP ROUND THE MOUNTAIN BUT ONE MAY EASILY FIND SHELTER BENEATH WELL THATCHED TREES THAT SHED THE RAIN LIKE A ROOF"
300
- ],
301
- "chunkDurationMs": 100,
302
- "difficulty": "challenging",
303
- "tags": [
304
- "conversation",
305
- "dialogue-style",
306
- "multi-turn",
307
- "noisy",
308
- "synthetic"
309
- ]
310
- },
311
- {
312
- "id": "dialogue-three-clean",
313
- "title": "Dialogue-style three-turn clean conversation",
314
- "audioPath": "dialogue-three-clean.pcm",
315
- "expectedText": "GO QUIETLY ALONE NO HARM WILL BEFALL YOU WE PASSED AROUND ATLANTA CROSSED THE CHATTAHOOCHEE AND TRAVELED BACK OVER THE SAME ROUTE ON WHICH WE HAD MADE THE ARDUOUS CAMPAIGN UNDER JOE JOHNSTON GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
316
- "expectedTerms": [
317
- "quietly alone",
318
- "atlanta",
319
- "chattahoochee",
320
- "joe johnston"
321
- ],
322
- "expectedTurnTexts": [
323
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
324
- "WE PASSED AROUND ATLANTA CROSSED THE CHATTAHOOCHEE AND TRAVELED BACK OVER THE SAME ROUTE ON WHICH WE HAD MADE THE ARDUOUS CAMPAIGN UNDER JOE JOHNSTON",
325
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU"
326
- ],
327
- "chunkDurationMs": 100,
328
- "difficulty": "clean",
329
- "tags": [
330
- "clean",
331
- "conversation",
332
- "dialogue-style",
333
- "multi-turn",
334
- "synthetic"
335
- ]
336
- },
337
- {
338
- "id": "dialogue-three-mixed",
339
- "title": "Dialogue-style three-turn mixed conversation",
340
- "audioPath": "dialogue-three-mixed.pcm",
341
- "expectedText": "GO QUIETLY ALONE NO HARM WILL BEFALL YOU SLIGHT RAINSTORMS ARE LIKELY TO BE ENCOUNTERED IN A TRIP ROUND THE MOUNTAIN BUT ONE MAY EASILY FIND SHELTER BENEATH WELL THATCHED TREES THAT SHED THE RAIN LIKE A ROOF GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
342
- "expectedTerms": ["quietly alone", "rainstorms", "thatched trees"],
343
- "expectedTurnTexts": [
344
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU",
345
- "SLIGHT RAINSTORMS ARE LIKELY TO BE ENCOUNTERED IN A TRIP ROUND THE MOUNTAIN BUT ONE MAY EASILY FIND SHELTER BENEATH WELL THATCHED TREES THAT SHED THE RAIN LIKE A ROOF",
346
- "GO QUIETLY ALONE NO HARM WILL BEFALL YOU"
347
- ],
348
- "chunkDurationMs": 100,
349
- "difficulty": "challenging",
350
- "tags": [
351
- "conversation",
352
- "dialogue-style",
353
- "multi-turn",
354
- "noisy",
355
- "synthetic"
356
- ]
357
- }
358
- ]
Binary file
Binary file
Binary file