@absolutejs/voice 0.0.22-beta.579 → 0.0.22-beta.580
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/index.js +4 -3
- package/dist/client/htmxBootstrap.js +4 -3
- package/dist/client/index.js +4 -3
- package/dist/client/microphone.d.ts +1 -0
- package/dist/core/types.d.ts +9 -0
- package/dist/embed/index.js +4 -3
- package/dist/embed/voice-widget.js +7 -7
- package/dist/react/index.js +4 -3
- package/dist/svelte/index.js +4 -3
- package/dist/testing/index.js +4 -3
- package/dist/vue/index.js +4 -3
- package/package.json +1 -1
package/dist/angular/index.js
CHANGED
|
@@ -336,14 +336,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
336
336
|
let processorNode = null;
|
|
337
337
|
let mediaStream = null;
|
|
338
338
|
const start = async () => {
|
|
339
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
339
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
340
340
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
341
341
|
}
|
|
342
342
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
343
343
|
if (!AudioContextCtor) {
|
|
344
344
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
345
345
|
}
|
|
346
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
346
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
347
347
|
audio: {
|
|
348
348
|
autoGainControl: true,
|
|
349
349
|
channelCount: options.channelCount ?? 1,
|
|
@@ -1534,7 +1534,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1534
1534
|
}
|
|
1535
1535
|
stream.sendAudio(audio);
|
|
1536
1536
|
},
|
|
1537
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1537
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
1538
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
1538
1539
|
});
|
|
1539
1540
|
return capture;
|
|
1540
1541
|
};
|
|
@@ -104,14 +104,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
104
104
|
let processorNode = null;
|
|
105
105
|
let mediaStream = null;
|
|
106
106
|
const start = async () => {
|
|
107
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
107
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
108
108
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
109
109
|
}
|
|
110
110
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
111
111
|
if (!AudioContextCtor) {
|
|
112
112
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
113
113
|
}
|
|
114
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
114
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
115
115
|
audio: {
|
|
116
116
|
autoGainControl: true,
|
|
117
117
|
channelCount: options.channelCount ?? 1,
|
|
@@ -1414,7 +1414,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1414
1414
|
}
|
|
1415
1415
|
stream.sendAudio(audio);
|
|
1416
1416
|
},
|
|
1417
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1417
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
1418
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
1418
1419
|
});
|
|
1419
1420
|
return capture;
|
|
1420
1421
|
};
|
package/dist/client/index.js
CHANGED
|
@@ -1524,14 +1524,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
1524
1524
|
let processorNode = null;
|
|
1525
1525
|
let mediaStream = null;
|
|
1526
1526
|
const start = async () => {
|
|
1527
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
1527
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
1528
1528
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
1529
1529
|
}
|
|
1530
1530
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
1531
1531
|
if (!AudioContextCtor) {
|
|
1532
1532
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
1533
1533
|
}
|
|
1534
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
1534
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
1535
1535
|
audio: {
|
|
1536
1536
|
autoGainControl: true,
|
|
1537
1537
|
channelCount: options.channelCount ?? 1,
|
|
@@ -1960,7 +1960,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1960
1960
|
}
|
|
1961
1961
|
stream.sendAudio(audio);
|
|
1962
1962
|
},
|
|
1963
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1963
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
1964
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
1964
1965
|
});
|
|
1965
1966
|
return capture;
|
|
1966
1967
|
};
|
|
@@ -4,6 +4,7 @@ type MicrophoneCaptureOptions = {
|
|
|
4
4
|
onLevel?: VoiceCaptureOptions["onLevel"];
|
|
5
5
|
onAudio: (audio: Uint8Array) => void;
|
|
6
6
|
sampleRateHz?: VoiceCaptureOptions["sampleRateHz"];
|
|
7
|
+
stream?: VoiceCaptureOptions["stream"];
|
|
7
8
|
};
|
|
8
9
|
type MicrophoneCapture = {
|
|
9
10
|
start: () => Promise<void>;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1136,6 +1136,15 @@ export type VoiceCaptureOptions = {
|
|
|
1136
1136
|
onAudio?: (audio: Uint8Array | ArrayBuffer, sendAudio: (audio: Uint8Array | ArrayBuffer) => void) => void;
|
|
1137
1137
|
onLevel?: (level: number) => void;
|
|
1138
1138
|
sampleRateHz?: number;
|
|
1139
|
+
/**
|
|
1140
|
+
* A pre-acquired microphone MediaStream. When set, capture uses it instead of
|
|
1141
|
+
* calling getUserMedia — so a host that requested permission UP FRONT (before
|
|
1142
|
+
* connecting, so the prompt can't interrupt the assistant's greeting) can hand
|
|
1143
|
+
* the SAME stream in rather than release-and-reacquire (a second getUserMedia
|
|
1144
|
+
* + a track stop can trigger an audio-device change that suspends playback and
|
|
1145
|
+
* cuts the greeting). Capture owns it after handoff and stops it on close.
|
|
1146
|
+
*/
|
|
1147
|
+
stream?: MediaStream;
|
|
1139
1148
|
};
|
|
1140
1149
|
export type VoiceControllerOptions = {
|
|
1141
1150
|
preset?: VoiceRuntimePreset;
|
package/dist/embed/index.js
CHANGED
|
@@ -101,14 +101,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
101
101
|
let processorNode = null;
|
|
102
102
|
let mediaStream = null;
|
|
103
103
|
const start = async () => {
|
|
104
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
104
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
105
105
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
106
106
|
}
|
|
107
107
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
108
108
|
if (!AudioContextCtor) {
|
|
109
109
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
110
110
|
}
|
|
111
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
111
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
112
112
|
audio: {
|
|
113
113
|
autoGainControl: true,
|
|
114
114
|
channelCount: options.channelCount ?? 1,
|
|
@@ -1411,7 +1411,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1411
1411
|
}
|
|
1412
1412
|
stream.sendAudio(audio);
|
|
1413
1413
|
},
|
|
1414
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1414
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
1415
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
1415
1416
|
});
|
|
1416
1417
|
return capture;
|
|
1417
1418
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(()=>{var{defineProperty:X,getOwnPropertyNames:Ac,getOwnPropertyDescriptor:Tc}=Object,Cc=Object.prototype.hasOwnProperty;function Ic(c){return this[c]}var Vc=(c)=>{var g=(J??=new WeakMap).get(c),A;if(g)return g;if(g=X({},"__esModule",{value:!0}),c&&typeof c==="object"||typeof c==="function"){for(var n of Ac(c))if(!Cc.call(g,n))X(g,n,{get:Ic.bind(c,n),enumerable:!(A=Tc(c,n))||A.enumerable})}return J.set(c,g),g},J;var lc=(c)=>c;function Sc(c,g){this[c]=lc.bind(null,g)}var yc=(c,g)=>{for(var A in g)X(c,A,{get:g[A],enumerable:!0,configurable:!0,set:Sc.bind(g,A)})};var Bc={};yc(Bc,{mount:()=>p,default:()=>jc,VOICE_EMBED_VERSION:()=>cc});var _c=(c)=>{if(typeof c!=="string")return c;return document.querySelector(c)},Rc=(c,g,A,n)=>{let T=g??c.getAttribute("hx-get")??"";if(!T)return"";let V=new URL(T,window.location.origin);if(n)V.searchParams.set(A,n);else V.searchParams.delete(A);return`${V.pathname}${V.search}${V.hash}`},Z=(c,g)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let A=_c(g.element);if(!A)return()=>{};let n=g.eventName??"voice-refresh",T=g.sessionQueryParam??"sessionId",V=()=>{let y=window,_=Rc(A,g.route,T,c.sessionId);if(_)A.setAttribute("hx-get",_);y.htmx?.process?.(A),y.htmx?.trigger?.(A,n)},I=c.subscribe(V);return V(),()=>{I()}};var hc=(c)=>Math.max(-1,Math.min(1,c)),Lc=(c)=>{let g=new Int16Array(c.length);for(let A=0;A<c.length;A+=1){let n=hc(c[A]??0);g[A]=n<0?n*32768:n*32767}return new Uint8Array(g.buffer)},Uc=(c)=>{let g=c instanceof Uint8Array?c:new Uint8Array(c);if(g.byteLength<2)return 0;let A=new Int16Array(g.buffer,g.byteOffset,Math.floor(g.byteLength/2));if(A.length===0)return 0;let n=0;for(let T of A){let V=T/32768;n+=V*V}return Math.min(1,Math.max(0,Math.sqrt(n/A.length)*5.5))},wc=(c,g,A)=>{if(g===A)return c;let n=g/A,T=Math.round(c.length/n),V=new Float32Array(T),I=0,y=0;while(I<V.length){let _=Math.round((I+1)*n),L=0,S=0;for(let h=y;h<_&&h<c.length;h+=1)L+=c[h]??0,S+=1;V[I]=S>0?L/S:0,I+=1,y=_}return V},q=(c)=>{let g=null,A=null,n=null,T=null;return{start:async()=>{if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let y=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!y)throw Error("Browser microphone capture requires AudioContext support.");if(T=await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:c.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),g=new y,g.state==="suspended")await g.resume();A=g.createMediaStreamSource(T),n=g.createScriptProcessor(4096,1,1),n.onaudioprocess=(_)=>{let L=_.inputBuffer.getChannelData(0),S=wc(L,g?.sampleRate??48000,c.sampleRateHz??16000),h=Lc(S);c.onLevel?.(Uc(h)),c.onAudio(h)},A.connect(n),n.connect(g.destination)},stop:()=>{n?.disconnect(),A?.disconnect(),T?.getTracks().forEach((y)=>y.stop()),g?.close(),c.onLevel?.(0),g=null,T=null,n=null,A=null}}};var Y=(c)=>{if(typeof c==="string"&&c.trim())return c;if(c instanceof Error&&c.message.trim())return c.message;if(c&&typeof c==="object"){let g=c;for(let A of["message","reason","description"]){let n=g[A];if(typeof n==="string"&&n.trim())return n}if("error"in g)return Y(g.error);if("cause"in g)return Y(g.cause);try{return JSON.stringify(c)}catch{}}return"Unexpected error"},z=(c)=>{switch(c.type){case"audio":return{chunk:Uint8Array.from(atob(c.chunkBase64),(g)=>g.charCodeAt(0)),format:c.format,receivedAt:c.receivedAt,turnId:c.turnId,type:"audio"};case"assistant":return{text:c.text,turnId:c.turnId,type:"assistant"};case"assistant_delta":return{delta:c.delta,turnId:c.turnId,type:"assistant_delta"};case"complete":return{sessionId:c.sessionId,type:"complete"};case"connection":return{reconnect:c.reconnect,type:"connection"};case"call_lifecycle":return{event:c.event,sessionId:c.sessionId,type:"call_lifecycle"};case"error":return{message:Y(c.message),type:"error"};case"final":return{transcript:c.transcript,type:"final"};case"partial":return{transcript:c.transcript,type:"partial"};case"replay":return{assistantTexts:c.assistantTexts,call:c.call,partial:c.partial,scenarioId:c.scenarioId,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,status:c.status,turns:c.turns,type:"replay"};case"session":return{sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,type:"session"};case"turn":return{turn:c.turn,type:"turn"};default:return null}};var tc=Math.PI*2;var $=(c,g,A,n)=>{c.push({code:A,message:n,severity:g})};var Dc=(c)=>c.length===0?void 0:c.reduce((g,A)=>g+A,0)/c.length,G=(c)=>c.length===0?void 0:Math.max(...c);var w=(c,g)=>{let A=c[g];return typeof A==="number"&&Number.isFinite(A)?A:void 0},x=(c,g)=>{let A=c[g];return typeof A==="boolean"?A:void 0},D=(c,g)=>{let A=c[g];return typeof A==="string"?A:void 0},Q=(c)=>String(c.id??D(c,"ssrc")??w(c,"ssrc")??D(c,"trackIdentifier")??D(c,"mid")??"unknown"),K=(c)=>c===void 0?void 0:c*1000;var bc=(c)=>{let g={};for(let[A,n]of Object.entries(c))if(n===null||typeof n==="boolean"||typeof n==="number"||typeof n==="string")g[A]=n;return g};var o=(c={})=>{let g=c.stats??[],A=[],n=g.filter((C)=>C.type==="inbound-rtp"&&D(C,"kind")!=="video"),T=g.filter((C)=>C.type==="outbound-rtp"&&D(C,"kind")!=="video"),V=g.filter((C)=>C.type==="candidate-pair"),I=g.filter((C)=>(C.type==="track"||C.type==="media-source")&&D(C,"kind")==="audio"),y=V.filter((C)=>x(C,"selected")===!0||x(C,"nominated")===!0||D(C,"state")==="succeeded").length,_=I.filter((C)=>D(C,"readyState")!=="ended"&&D(C,"trackState")!=="ended"&&x(C,"ended")!==!0).length,L=I.filter((C)=>D(C,"readyState")==="ended"||D(C,"trackState")==="ended"||x(C,"ended")===!0).length,S=n.reduce((C,U)=>C+(w(U,"packetsReceived")??0),0),h=T.reduce((C,U)=>C+(w(U,"packetsSent")??0),0),l=[...n,...T].reduce((C,U)=>C+Math.max(0,w(U,"packetsLost")??0),0),b=S+l,R=b===0?0:l/b,W=n.reduce((C,U)=>C+(w(U,"bytesReceived")??0),0),E=T.reduce((C,U)=>C+(w(U,"bytesSent")??0),0),M=G(V.map((C)=>K(w(C,"currentRoundTripTime")??w(C,"roundTripTime"))).filter((C)=>C!==void 0)),i=G([...n,...T].map((C)=>K(w(C,"jitter"))).filter((C)=>C!==void 0)),d=G(n.map((C)=>{let U=w(C,"jitterBufferDelay"),O=w(C,"jitterBufferEmittedCount");return U!==void 0&&O!==void 0&&O>0?U/O*1000:void 0}).filter((C)=>C!==void 0)),N=I.map((C)=>w(C,"audioLevel")).filter((C)=>C!==void 0);if(c.requireConnectedCandidatePair&&V.length>0&&y===0)$(A,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(c.requireLiveAudioTrack&&_===0)$(A,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(c.maxPacketLossRatio!==void 0&&R>c.maxPacketLossRatio)$(A,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(R)} above ${String(c.maxPacketLossRatio)}.`);if(c.maxRoundTripTimeMs!==void 0&&M!==void 0&&M>c.maxRoundTripTimeMs)$(A,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(M)}ms above ${String(c.maxRoundTripTimeMs)}ms.`);if(c.maxJitterMs!==void 0&&i!==void 0&&i>c.maxJitterMs)$(A,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(i)}ms above ${String(c.maxJitterMs)}ms.`);return{activeCandidatePairs:y,audioLevelAverage:Dc(N),bytesReceived:W,bytesSent:E,checkedAt:Date.now(),endedAudioTracks:L,inboundPackets:S,issues:A,jitterBufferDelayMs:d,jitterMs:i,liveAudioTracks:_,outboundPackets:h,packetLossRatio:R,packetsLost:l,roundTripTimeMs:M,status:A.some((C)=>C.severity==="error")?"fail":A.length>0?"warn":"pass",totalStats:g.length}},B=async(c)=>{return[...(await c.peerConnection.getStats(c.selector??null)).values()].map(bc)};var j=(c={})=>{let g=c.stats??[],A=c.previousStats??[],n=[],T=new Map(A.map((l)=>[Q(l),l])),I=g.filter((l)=>(l.type==="inbound-rtp"||l.type==="outbound-rtp")&&D(l,"kind")!=="video"&&D(l,"mediaType")!=="video").map((l)=>{let b=l.type==="outbound-rtp"?"outbound":"inbound",R=b==="outbound"?"packetsSent":"packetsReceived",W=b==="outbound"?"bytesSent":"bytesReceived",E=T.get(Q(l)),M=w(l,R),i=E?w(E,R):void 0,d=w(l,W),N=E?w(E,W):void 0,C=l.timestamp!==void 0&&E?.timestamp!==void 0?l.timestamp-E.timestamp:void 0;return{bytesDelta:d!==void 0&&N!==void 0?d-N:void 0,currentPackets:M,direction:b,id:Q(l),packetDelta:M!==void 0&&i!==void 0?M-i:void 0,previousPackets:i,timeDeltaMs:C}}),y=I.filter((l)=>l.direction==="inbound"),_=I.filter((l)=>l.direction==="outbound"),L=G(I.map((l)=>l.timeDeltaMs).filter((l)=>l!==void 0)),S=y.filter((l)=>c.maxInboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=c.maxInboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length,h=_.filter((l)=>c.maxOutboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=c.maxOutboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length;if(c.requireInboundAudio&&y.length===0)$(n,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(c.requireOutboundAudio&&_.length===0)$(n,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(c.maxGapMs!==void 0&&L!==void 0&&L>c.maxGapMs)$(n,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(L)}ms above ${String(c.maxGapMs)}ms.`);if(S>0)$(n,"error","media.webrtc_inbound_stalled",`${String(S)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)$(n,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:y.length,issues:n,maxObservedGapMs:L,outboundAudioStreams:_.length,stalledInboundStreams:S,stalledOutboundStreams:h,status:n.some((l)=>l.severity==="error")?"fail":n.length>0?"warn":"pass",streams:I,totalStats:g.length}};var Oc="/api/voice/browser-media",Ec=5000,Mc=async(c)=>c.peerConnection??await c.getPeerConnection?.()??null,ic=async(c,g)=>{let A=g.fetch??globalThis.fetch;if(!A)return;await A(g.path??Oc,{body:JSON.stringify(c),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},s=(c)=>{let g=null,A=[],n=async()=>{let I=await Mc(c);if(!I)return;let y=await B({peerConnection:I}),_=o({...c,stats:y}),L=c.continuity===!1?void 0:j({...c.continuity,previousStats:A,stats:y}),S={at:Date.now(),continuity:L,report:_,scenarioId:c.getScenarioId?.()??null,sessionId:c.getSessionId?.()??null};return A=y,c.onReport?.(S),await ic(S,c),S},T=()=>{n().catch((I)=>{c.onError?.(I)})},V=()=>{if(g)clearInterval(g),g=null};return{close:V,reportOnce:n,stop:V,start:()=>{if(g)return;T(),g=setInterval(T,c.intervalMs??Ec)}}};var H=()=>{},$c=()=>H,Pc={callControl:H,close:H,endTurn:H,send:H,sendAudio:H,simulateDisconnect:H,subscribe:$c,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},Hc=()=>crypto.randomUUID(),Wc=(c,g,A)=>{let{hostname:n,port:T,protocol:V}=window.location,I=V==="https:"?"wss:":"ws:",y=T?`:${T}`:"",_=new URL(`${I}//${n}${y}${c}`);if(_.searchParams.set("sessionId",g),A)_.searchParams.set("scenarioId",A);return _.toString()},dc=(c)=>{if(!c||typeof c!=="object"||!("type"in c))return!1;switch(c.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}},Nc=(c)=>{if(typeof c.data!=="string")return null;try{let g=JSON.parse(c.data);return dc(g)?g:null}catch{return null}},k=(c,g={})=>{if(typeof window>"u")return Pc;let A=new Set,n=g.reconnect!==!1,T=g.maxReconnectAttempts??10,V=g.pingInterval??30000,I={isConnected:!1,pendingMessages:[],scenarioId:g.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:g.sessionId??Hc(),ws:null},y=(C)=>{A.forEach((U)=>U(C))},_=()=>{if(I.pingInterval)clearInterval(I.pingInterval),I.pingInterval=null;if(I.reconnectTimeout)clearTimeout(I.reconnectTimeout),I.reconnectTimeout=null},L=()=>{if(I.ws?.readyState!==1)return;while(I.pendingMessages.length>0){let C=I.pendingMessages.shift();if(C!==void 0)I.ws.send(C)}},S=()=>{let C=Date.now()+500;I.reconnectAttempts+=1,y({reconnect:{attempts:I.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,nextAttemptAt:C,status:"reconnecting"},type:"connection"}),I.reconnectTimeout=setTimeout(()=>{if(I.reconnectAttempts>T){y({reconnect:{attempts:I.reconnectAttempts,maxAttempts:T,status:"exhausted"},type:"connection"});return}h()},500)},h=()=>{let C=new WebSocket(Wc(c,I.sessionId,I.scenarioId));C.binaryType="arraybuffer",C.onopen=()=>{let U=I.reconnectAttempts>0;if(I.isConnected=!0,L(),U)y({reconnect:{attempts:I.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:T,status:"resumed"},type:"connection"}),I.reconnectAttempts=0;A.forEach((O)=>O({scenarioId:I.scenarioId??void 0,sessionId:I.sessionId,status:"active",type:"session"})),I.pingInterval=setInterval(()=>{if(C.readyState===1)C.send(JSON.stringify({type:"ping"}))},V)},C.onmessage=(U)=>{let O=Nc(U);if(!O)return;if(O.type==="session")I.sessionId=O.sessionId,I.scenarioId=O.scenarioId??I.scenarioId;A.forEach((nc)=>nc(O))},C.onclose=(U)=>{if(I.isConnected=!1,_(),n&&U.code!==1000&&I.reconnectAttempts<T)S();else if(n&&U.code!==1000)y({reconnect:{attempts:I.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,status:"exhausted"},type:"connection"})},I.ws=C},l=(C)=>{if(I.ws?.readyState===1){I.ws.send(C);return}I.pendingMessages.push(C)},b=(C)=>{l(JSON.stringify(C))},R=(C={})=>{if(C.sessionId)I.sessionId=C.sessionId;if(C.scenarioId)I.scenarioId=C.scenarioId;b({scenarioId:I.scenarioId??void 0,sessionId:I.sessionId,type:"start"})},W=(C)=>{l(C)},E=()=>{b({type:"end_turn"})},M=(C)=>{b({...C,type:"call_control"})},i=()=>{if(_(),I.ws)I.ws.close(1000),I.ws=null;I.isConnected=!1,A.clear()},d=()=>{if(I.ws?.readyState===1)I.ws.close(4000,"absolutejs-voice-reconnect-proof")},N=(C)=>{return A.add(C),()=>{A.delete(C)}};return h(),{callControl:M,close:i,endTurn:E,send:b,sendAudio:W,simulateDisconnect:d,start:R,subscribe:N,getReadyState:()=>I.ws?.readyState??3,getScenarioId:()=>I.scenarioId??"",getSessionId:()=>I.sessionId}};var xc=()=>({attempts:0,maxAttempts:0,status:"idle"}),Gc=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:xc(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),f=()=>{let c=Gc(),g=new Set,A=()=>{g.forEach((T)=>T())};return{dispatch:(T)=>{switch(T.type){case"audio":c={...c,assistantAudio:[...c.assistantAudio,{chunk:T.chunk,format:T.format,receivedAt:T.receivedAt,turnId:T.turnId}]};break;case"assistant":c={...c,assistantStreamingText:"",assistantTexts:[...c.assistantTexts,T.text]};break;case"assistant_delta":c={...c,assistantStreamingText:`${c.assistantStreamingText}${T.delta}`};break;case"complete":c={...c,sessionId:T.sessionId,status:"completed"};break;case"call_lifecycle":c={...c,call:{...c.call,disposition:T.event.type==="end"?T.event.disposition:c.call?.disposition,endedAt:T.event.type==="end"?T.event.at:c.call?.endedAt,events:[...c.call?.events??[],T.event],lastEventAt:T.event.at,startedAt:c.call?.startedAt??T.event.at},sessionId:T.sessionId};break;case"connected":c={...c,isConnected:!0,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect};break;case"connection":c={...c,reconnect:T.reconnect};break;case"disconnected":c={...c,isConnected:!1};break;case"error":c={...c,error:T.message};break;case"final":c={...c,partial:T.transcript.text,turns:c.turns.map((V)=>V)};break;case"partial":c={...c,partial:T.transcript.text};break;case"replay":c={...c,assistantStreamingText:"",assistantTexts:[...T.assistantTexts],call:T.call??null,error:null,isConnected:T.status==="active",partial:T.partial,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect,scenarioId:T.scenarioId??c.scenarioId,sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??c.sessionMetadata,status:T.status,turns:[...T.turns]};break;case"session":c={...c,error:null,scenarioId:T.scenarioId??c.scenarioId,isConnected:T.status==="active",sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??c.sessionMetadata,status:T.status};break;case"turn":c={...c,partial:"",turns:[...c.turns,T.turn]};break}A()},getServerSnapshot:()=>c,getSnapshot:()=>c,subscribe:(T)=>{return g.add(T),()=>{g.delete(T)}}}};var F=(c,g={})=>{let A=k(c,g),n=f(),T=g.browserMedia&&typeof window<"u"?s({...g.browserMedia,getScenarioId:()=>g.browserMedia?g.browserMedia.getScenarioId?.()??A.getScenarioId():A.getScenarioId(),getSessionId:()=>g.browserMedia?g.browserMedia.getSessionId?.()??A.getSessionId():A.getSessionId()}):null,V=new Set,I=(S)=>Promise.resolve().then(()=>{if(!S?.sessionId&&!S?.scenarioId)return;A.start(S),T?.start()}),y=()=>{V.forEach((S)=>S())},_=()=>{if(!g.reconnectReportPath||typeof fetch>"u")return;let S=n.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:S.reconnect,scenarioId:S.scenarioId,sessionId:A.getSessionId(),turnIds:S.turns.map((l)=>l.id)});fetch(g.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=A.subscribe((S)=>{let h=z(S);if(h){if(n.dispatch(h),S.type==="connection")_();y()}});return{start:I,get assistantAudio(){return n.getSnapshot().assistantAudio},get assistantTexts(){return n.getSnapshot().assistantTexts},get assistantStreamingText(){return n.getSnapshot().assistantStreamingText},get call(){return n.getSnapshot().call},callControl(S){A.callControl(S)},close(){L(),T?.close(),A.close(),n.dispatch({type:"disconnected"}),y()},endTurn(){A.endTurn()},get error(){return n.getSnapshot().error},getServerSnapshot(){return n.getServerSnapshot()},getSnapshot(){return n.getSnapshot()},get isConnected(){return n.getSnapshot().isConnected},get partial(){return n.getSnapshot().partial},get reconnect(){return n.getSnapshot().reconnect},get scenarioId(){return n.getSnapshot().scenarioId},sendAudio(S){A.sendAudio(S)},get sessionId(){return A.getSessionId()},get sessionMetadata(){return n.getSnapshot().sessionMetadata},simulateDisconnect(){A.simulateDisconnect()},get status(){return n.getSnapshot().status},subscribe(S){return V.add(S),()=>{V.delete(S)}},get turns(){return n.getSnapshot().turns}}};var t=(c)=>{if(!c||c.enabled===!1)return;return{enabled:!0,maxGain:c.maxGain??3,noiseGateAttenuation:c.noiseGateAttenuation??0.15,noiseGateThreshold:c.noiseGateThreshold??0.006,targetLevel:c.targetLevel??0.08}};var Xc={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}},Yc={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var e=(c)=>{let g=c?.profile??"fast",A=c?.qualityProfile??"general",n=Xc[g],T=Yc[A];return{profile:g,qualityProfile:A,silenceMs:c?.silenceMs??T.silenceMs??n.silenceMs,speechThreshold:c?.speechThreshold??T.speechThreshold??n.speechThreshold,transcriptStabilityMs:c?.transcriptStabilityMs??T.transcriptStabilityMs??n.transcriptStabilityMs}};var Qc={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},v=(c="default")=>{let g=Qc[c];return{audioConditioning:t(g.audioConditioning),capture:{channelCount:g.capture?.channelCount??1,sampleRateHz:g.capture?.sampleRateHz??16000},connection:{...g.connection},name:c,sttLifecycle:g.sttLifecycle??"continuous",turnDetection:e(g.turnDetection)}};var Jc=(c)=>({assistantAudio:[...c.assistantAudio],assistantStreamingText:c.assistantStreamingText,assistantTexts:[...c.assistantTexts],call:c.call,error:c.error,isConnected:c.isConnected,isRecording:!1,partial:c.partial,reconnect:c.reconnect,recordingError:null,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,turns:[...c.turns]}),r=(c,g={})=>{let A=v(g.preset),n=F(c,{...A.connection,...g.connection}),T=null,V=Jc(n),I=new Set,y=()=>{for(let R of I)R()},_=()=>{if(V={...V,assistantAudio:[...n.assistantAudio],assistantStreamingText:n.assistantStreamingText,assistantTexts:[...n.assistantTexts],call:n.call,error:n.error,isConnected:n.isConnected,partial:n.partial,reconnect:n.reconnect,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,turns:[...n.turns]},g.autoStopOnComplete!==!1&&V.status==="completed"&&V.isRecording)T?.stop(),T=null,V={...V,isRecording:!1};y()},L=n.subscribe(_);_();let S=()=>{if(T)return T;return T=q({channelCount:g.capture?.channelCount??A.capture.channelCount,onLevel:g.capture?.onLevel,onAudio:(R)=>{if(g.capture?.onAudio){g.capture.onAudio(R,n.sendAudio);return}n.sendAudio(R)},sampleRateHz:g.capture?.sampleRateHz??A.capture.sampleRateHz}),T},h=()=>{T?.stop(),T=null,V={...V,isRecording:!1},y()},l=async()=>{if(V.isRecording)return;try{V={...V,recordingError:null},y(),await S().start(),V={...V,isRecording:!0},y()}catch(R){throw T=null,V={...V,isRecording:!1,recordingError:R instanceof Error?R.message:String(R)},y(),R}};return{close:()=>{L(),h(),n.close()},startRecording:l,stopRecording:h,get assistantAudio(){return V.assistantAudio},get assistantTexts(){return V.assistantTexts},get assistantStreamingText(){return V.assistantStreamingText},bindHTMX(R){return Z(n,R)},get call(){return V.call},callControl:(R)=>n.callControl(R),endTurn:()=>n.endTurn(),get error(){return V.error},getServerSnapshot:()=>V,getSnapshot:()=>V,get isConnected(){return V.isConnected},get isRecording(){return V.isRecording},get partial(){return V.partial},get reconnect(){return V.reconnect},get recordingError(){return V.recordingError},get scenarioId(){return V.scenarioId},sendAudio:(R)=>n.sendAudio(R),get sessionId(){return V.sessionId},get sessionMetadata(){return V.sessionMetadata},simulateDisconnect:()=>n.simulateDisconnect(),get status(){return V.status},subscribe:(R)=>{return I.add(R),()=>{I.delete(R)}},toggleRecording:async()=>{if(V.isRecording){h();return}await l()},get turns(){return V.turns}}};var P=(c)=>String(c).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var a=(c)=>{if(!c.isConnected)return"idle";if(c.isPlaying)return"speaking";if(c.isRecording&&c.hasActivePartial)return"listening";if(c.isRecording)return"listening";if(c.lastTranscriptAt&&!c.lastAssistantAt)return"thinking";if(c.lastTranscriptAt&&c.lastAssistantAt&&c.lastTranscriptAt>c.lastAssistantAt)return"thinking";return"idle"};var Zc={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},qc={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},zc=(c,g)=>{switch(c){case"listening":return g.listening;case"speaking":return g.speaking;case"thinking":return g.thinking;case"idle":return g.idle}},m=(c)=>{let g={...Zc,...c.theme},A={...qc,...c.labels},n=c.state.assistantAudio.at(-1)?.receivedAt,T=c.state.turns.at(-1)?.committedAt,V=a({hasActivePartial:c.state.partial.length>0,isConnected:c.state.isConnected,isPlaying:!1,isRecording:c.state.isRecording,lastAssistantAt:n,lastTranscriptAt:T}),I=!c.state.isConnected&&c.state.status!=="idle"&&!c.state.error,y=c.state.error?"Error":I?A.connecting:c.state.status==="completed"?A.callEnded:zc(V,A);return{agentState:V,classes:{container:`absolute-voice-widget absolute-voice-widget--${V}`,dot:`absolute-voice-widget__dot${c.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:c.state.isConnected,canMute:c.state.isRecording,canStart:!c.state.isRecording&&c.state.status!=="completed"},errorMessage:c.state.error??void 0,labels:A,partial:c.state.partial||void 0,statusLabel:y,theme:g,title:c.title??"Voice"}},Kc=(c)=>typeof c==="number"?`${c}px`:c,u=(c)=>{let g=c.theme,A=`background:${g.background};border-radius:${Kc(g.radius)};color:${g.foreground};font-family:${g.fontFamily};min-width:240px;padding:20px 22px;`,n=`background:${c.errorMessage?g.errorAccent:c.agentState==="idle"?"rgba(148,163,184,0.6)":g.accent};border-radius:50%;height:10px;width:10px;`,T=[];if(c.controls.canStart)T.push(`<button type="button" data-action="start" style="background:${g.accent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${P(c.labels.startCall)}</button>`);if(c.controls.canMute)T.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${P(c.labels.mute)}</button>`);if(c.controls.canEnd)T.push(`<button type="button" data-action="end" style="background:${g.errorAccent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${P(c.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${c.agentState}" class="${P(c.classes.container)}" style="${A}">
|
|
1
|
+
(()=>{var{defineProperty:X,getOwnPropertyNames:Ac,getOwnPropertyDescriptor:Tc}=Object,Cc=Object.prototype.hasOwnProperty;function Ic(c){return this[c]}var Vc=(c)=>{var g=(J??=new WeakMap).get(c),A;if(g)return g;if(g=X({},"__esModule",{value:!0}),c&&typeof c==="object"||typeof c==="function"){for(var n of Ac(c))if(!Cc.call(g,n))X(g,n,{get:Ic.bind(c,n),enumerable:!(A=Tc(c,n))||A.enumerable})}return J.set(c,g),g},J;var lc=(c)=>c;function Sc(c,g){this[c]=lc.bind(null,g)}var yc=(c,g)=>{for(var A in g)X(c,A,{get:g[A],enumerable:!0,configurable:!0,set:Sc.bind(g,A)})};var jc={};yc(jc,{mount:()=>p,default:()=>oc,VOICE_EMBED_VERSION:()=>cc});var _c=(c)=>{if(typeof c!=="string")return c;return document.querySelector(c)},Rc=(c,g,A,n)=>{let T=g??c.getAttribute("hx-get")??"";if(!T)return"";let V=new URL(T,window.location.origin);if(n)V.searchParams.set(A,n);else V.searchParams.delete(A);return`${V.pathname}${V.search}${V.hash}`},Z=(c,g)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let A=_c(g.element);if(!A)return()=>{};let n=g.eventName??"voice-refresh",T=g.sessionQueryParam??"sessionId",V=()=>{let y=window,_=Rc(A,g.route,T,c.sessionId);if(_)A.setAttribute("hx-get",_);y.htmx?.process?.(A),y.htmx?.trigger?.(A,n)},I=c.subscribe(V);return V(),()=>{I()}};var hc=(c)=>Math.max(-1,Math.min(1,c)),Lc=(c)=>{let g=new Int16Array(c.length);for(let A=0;A<c.length;A+=1){let n=hc(c[A]??0);g[A]=n<0?n*32768:n*32767}return new Uint8Array(g.buffer)},Uc=(c)=>{let g=c instanceof Uint8Array?c:new Uint8Array(c);if(g.byteLength<2)return 0;let A=new Int16Array(g.buffer,g.byteOffset,Math.floor(g.byteLength/2));if(A.length===0)return 0;let n=0;for(let T of A){let V=T/32768;n+=V*V}return Math.min(1,Math.max(0,Math.sqrt(n/A.length)*5.5))},wc=(c,g,A)=>{if(g===A)return c;let n=g/A,T=Math.round(c.length/n),V=new Float32Array(T),I=0,y=0;while(I<V.length){let _=Math.round((I+1)*n),L=0,S=0;for(let h=y;h<_&&h<c.length;h+=1)L+=c[h]??0,S+=1;V[I]=S>0?L/S:0,I+=1,y=_}return V},q=(c)=>{let g=null,A=null,n=null,T=null;return{start:async()=>{if(!c.stream&&(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia))throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let y=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!y)throw Error("Browser microphone capture requires AudioContext support.");if(T=c.stream??await navigator.mediaDevices.getUserMedia({audio:{autoGainControl:!0,channelCount:c.channelCount??1,echoCancellation:!0,noiseSuppression:!0}}),g=new y,g.state==="suspended")await g.resume();A=g.createMediaStreamSource(T),n=g.createScriptProcessor(4096,1,1),n.onaudioprocess=(_)=>{let L=_.inputBuffer.getChannelData(0),S=wc(L,g?.sampleRate??48000,c.sampleRateHz??16000),h=Lc(S);c.onLevel?.(Uc(h)),c.onAudio(h)},A.connect(n),n.connect(g.destination)},stop:()=>{n?.disconnect(),A?.disconnect(),T?.getTracks().forEach((y)=>y.stop()),g?.close(),c.onLevel?.(0),g=null,T=null,n=null,A=null}}};var Y=(c)=>{if(typeof c==="string"&&c.trim())return c;if(c instanceof Error&&c.message.trim())return c.message;if(c&&typeof c==="object"){let g=c;for(let A of["message","reason","description"]){let n=g[A];if(typeof n==="string"&&n.trim())return n}if("error"in g)return Y(g.error);if("cause"in g)return Y(g.cause);try{return JSON.stringify(c)}catch{}}return"Unexpected error"},z=(c)=>{switch(c.type){case"audio":return{chunk:Uint8Array.from(atob(c.chunkBase64),(g)=>g.charCodeAt(0)),format:c.format,receivedAt:c.receivedAt,turnId:c.turnId,type:"audio"};case"assistant":return{text:c.text,turnId:c.turnId,type:"assistant"};case"assistant_delta":return{delta:c.delta,turnId:c.turnId,type:"assistant_delta"};case"complete":return{sessionId:c.sessionId,type:"complete"};case"connection":return{reconnect:c.reconnect,type:"connection"};case"call_lifecycle":return{event:c.event,sessionId:c.sessionId,type:"call_lifecycle"};case"error":return{message:Y(c.message),type:"error"};case"final":return{transcript:c.transcript,type:"final"};case"partial":return{transcript:c.transcript,type:"partial"};case"replay":return{assistantTexts:c.assistantTexts,call:c.call,partial:c.partial,scenarioId:c.scenarioId,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,status:c.status,turns:c.turns,type:"replay"};case"session":return{sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,type:"session"};case"turn":return{turn:c.turn,type:"turn"};default:return null}};var ec=Math.PI*2;var P=(c,g,A,n)=>{c.push({code:A,message:n,severity:g})};var Dc=(c)=>c.length===0?void 0:c.reduce((g,A)=>g+A,0)/c.length,G=(c)=>c.length===0?void 0:Math.max(...c);var w=(c,g)=>{let A=c[g];return typeof A==="number"&&Number.isFinite(A)?A:void 0},x=(c,g)=>{let A=c[g];return typeof A==="boolean"?A:void 0},D=(c,g)=>{let A=c[g];return typeof A==="string"?A:void 0},Q=(c)=>String(c.id??D(c,"ssrc")??w(c,"ssrc")??D(c,"trackIdentifier")??D(c,"mid")??"unknown"),K=(c)=>c===void 0?void 0:c*1000;var bc=(c)=>{let g={};for(let[A,n]of Object.entries(c))if(n===null||typeof n==="boolean"||typeof n==="number"||typeof n==="string")g[A]=n;return g};var B=(c={})=>{let g=c.stats??[],A=[],n=g.filter((C)=>C.type==="inbound-rtp"&&D(C,"kind")!=="video"),T=g.filter((C)=>C.type==="outbound-rtp"&&D(C,"kind")!=="video"),V=g.filter((C)=>C.type==="candidate-pair"),I=g.filter((C)=>(C.type==="track"||C.type==="media-source")&&D(C,"kind")==="audio"),y=V.filter((C)=>x(C,"selected")===!0||x(C,"nominated")===!0||D(C,"state")==="succeeded").length,_=I.filter((C)=>D(C,"readyState")!=="ended"&&D(C,"trackState")!=="ended"&&x(C,"ended")!==!0).length,L=I.filter((C)=>D(C,"readyState")==="ended"||D(C,"trackState")==="ended"||x(C,"ended")===!0).length,S=n.reduce((C,U)=>C+(w(U,"packetsReceived")??0),0),h=T.reduce((C,U)=>C+(w(U,"packetsSent")??0),0),l=[...n,...T].reduce((C,U)=>C+Math.max(0,w(U,"packetsLost")??0),0),b=S+l,R=b===0?0:l/b,W=n.reduce((C,U)=>C+(w(U,"bytesReceived")??0),0),E=T.reduce((C,U)=>C+(w(U,"bytesSent")??0),0),M=G(V.map((C)=>K(w(C,"currentRoundTripTime")??w(C,"roundTripTime"))).filter((C)=>C!==void 0)),$=G([...n,...T].map((C)=>K(w(C,"jitter"))).filter((C)=>C!==void 0)),d=G(n.map((C)=>{let U=w(C,"jitterBufferDelay"),O=w(C,"jitterBufferEmittedCount");return U!==void 0&&O!==void 0&&O>0?U/O*1000:void 0}).filter((C)=>C!==void 0)),N=I.map((C)=>w(C,"audioLevel")).filter((C)=>C!==void 0);if(c.requireConnectedCandidatePair&&V.length>0&&y===0)P(A,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(c.requireLiveAudioTrack&&_===0)P(A,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(c.maxPacketLossRatio!==void 0&&R>c.maxPacketLossRatio)P(A,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(R)} above ${String(c.maxPacketLossRatio)}.`);if(c.maxRoundTripTimeMs!==void 0&&M!==void 0&&M>c.maxRoundTripTimeMs)P(A,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(M)}ms above ${String(c.maxRoundTripTimeMs)}ms.`);if(c.maxJitterMs!==void 0&&$!==void 0&&$>c.maxJitterMs)P(A,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String($)}ms above ${String(c.maxJitterMs)}ms.`);return{activeCandidatePairs:y,audioLevelAverage:Dc(N),bytesReceived:W,bytesSent:E,checkedAt:Date.now(),endedAudioTracks:L,inboundPackets:S,issues:A,jitterBufferDelayMs:d,jitterMs:$,liveAudioTracks:_,outboundPackets:h,packetLossRatio:R,packetsLost:l,roundTripTimeMs:M,status:A.some((C)=>C.severity==="error")?"fail":A.length>0?"warn":"pass",totalStats:g.length}},j=async(c)=>{return[...(await c.peerConnection.getStats(c.selector??null)).values()].map(bc)};var o=(c={})=>{let g=c.stats??[],A=c.previousStats??[],n=[],T=new Map(A.map((l)=>[Q(l),l])),I=g.filter((l)=>(l.type==="inbound-rtp"||l.type==="outbound-rtp")&&D(l,"kind")!=="video"&&D(l,"mediaType")!=="video").map((l)=>{let b=l.type==="outbound-rtp"?"outbound":"inbound",R=b==="outbound"?"packetsSent":"packetsReceived",W=b==="outbound"?"bytesSent":"bytesReceived",E=T.get(Q(l)),M=w(l,R),$=E?w(E,R):void 0,d=w(l,W),N=E?w(E,W):void 0,C=l.timestamp!==void 0&&E?.timestamp!==void 0?l.timestamp-E.timestamp:void 0;return{bytesDelta:d!==void 0&&N!==void 0?d-N:void 0,currentPackets:M,direction:b,id:Q(l),packetDelta:M!==void 0&&$!==void 0?M-$:void 0,previousPackets:$,timeDeltaMs:C}}),y=I.filter((l)=>l.direction==="inbound"),_=I.filter((l)=>l.direction==="outbound"),L=G(I.map((l)=>l.timeDeltaMs).filter((l)=>l!==void 0)),S=y.filter((l)=>c.maxInboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=c.maxInboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length,h=_.filter((l)=>c.maxOutboundPacketStallMs!==void 0&&l.timeDeltaMs!==void 0&&l.timeDeltaMs>=c.maxOutboundPacketStallMs&&l.packetDelta!==void 0&&l.packetDelta<=0).length;if(c.requireInboundAudio&&y.length===0)P(n,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(c.requireOutboundAudio&&_.length===0)P(n,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(c.maxGapMs!==void 0&&L!==void 0&&L>c.maxGapMs)P(n,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(L)}ms above ${String(c.maxGapMs)}ms.`);if(S>0)P(n,"error","media.webrtc_inbound_stalled",`${String(S)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)P(n,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:y.length,issues:n,maxObservedGapMs:L,outboundAudioStreams:_.length,stalledInboundStreams:S,stalledOutboundStreams:h,status:n.some((l)=>l.severity==="error")?"fail":n.length>0?"warn":"pass",streams:I,totalStats:g.length}};var Oc="/api/voice/browser-media",Ec=5000,Mc=async(c)=>c.peerConnection??await c.getPeerConnection?.()??null,$c=async(c,g)=>{let A=g.fetch??globalThis.fetch;if(!A)return;await A(g.path??Oc,{body:JSON.stringify(c),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},s=(c)=>{let g=null,A=[],n=async()=>{let I=await Mc(c);if(!I)return;let y=await j({peerConnection:I}),_=B({...c,stats:y}),L=c.continuity===!1?void 0:o({...c.continuity,previousStats:A,stats:y}),S={at:Date.now(),continuity:L,report:_,scenarioId:c.getScenarioId?.()??null,sessionId:c.getSessionId?.()??null};return A=y,c.onReport?.(S),await $c(S,c),S},T=()=>{n().catch((I)=>{c.onError?.(I)})},V=()=>{if(g)clearInterval(g),g=null};return{close:V,reportOnce:n,stop:V,start:()=>{if(g)return;T(),g=setInterval(T,c.intervalMs??Ec)}}};var H=()=>{},Pc=()=>H,ic={callControl:H,close:H,endTurn:H,send:H,sendAudio:H,simulateDisconnect:H,subscribe:Pc,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",start:()=>{}},Hc=()=>crypto.randomUUID(),Wc=(c,g,A)=>{let{hostname:n,port:T,protocol:V}=window.location,I=V==="https:"?"wss:":"ws:",y=T?`:${T}`:"",_=new URL(`${I}//${n}${y}${c}`);if(_.searchParams.set("sessionId",g),A)_.searchParams.set("scenarioId",A);return _.toString()},dc=(c)=>{if(!c||typeof c!=="object"||!("type"in c))return!1;switch(c.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}},Nc=(c)=>{if(typeof c.data!=="string")return null;try{let g=JSON.parse(c.data);return dc(g)?g:null}catch{return null}},k=(c,g={})=>{if(typeof window>"u")return ic;let A=new Set,n=g.reconnect!==!1,T=g.maxReconnectAttempts??10,V=g.pingInterval??30000,I={isConnected:!1,pendingMessages:[],scenarioId:g.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:g.sessionId??Hc(),ws:null},y=(C)=>{A.forEach((U)=>U(C))},_=()=>{if(I.pingInterval)clearInterval(I.pingInterval),I.pingInterval=null;if(I.reconnectTimeout)clearTimeout(I.reconnectTimeout),I.reconnectTimeout=null},L=()=>{if(I.ws?.readyState!==1)return;while(I.pendingMessages.length>0){let C=I.pendingMessages.shift();if(C!==void 0)I.ws.send(C)}},S=()=>{let C=Date.now()+500;I.reconnectAttempts+=1,y({reconnect:{attempts:I.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,nextAttemptAt:C,status:"reconnecting"},type:"connection"}),I.reconnectTimeout=setTimeout(()=>{if(I.reconnectAttempts>T){y({reconnect:{attempts:I.reconnectAttempts,maxAttempts:T,status:"exhausted"},type:"connection"});return}h()},500)},h=()=>{let C=new WebSocket(Wc(c,I.sessionId,I.scenarioId));C.binaryType="arraybuffer",C.onopen=()=>{let U=I.reconnectAttempts>0;if(I.isConnected=!0,L(),U)y({reconnect:{attempts:I.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:T,status:"resumed"},type:"connection"}),I.reconnectAttempts=0;A.forEach((O)=>O({scenarioId:I.scenarioId??void 0,sessionId:I.sessionId,status:"active",type:"session"})),I.pingInterval=setInterval(()=>{if(C.readyState===1)C.send(JSON.stringify({type:"ping"}))},V)},C.onmessage=(U)=>{let O=Nc(U);if(!O)return;if(O.type==="session")I.sessionId=O.sessionId,I.scenarioId=O.scenarioId??I.scenarioId;A.forEach((nc)=>nc(O))},C.onclose=(U)=>{if(I.isConnected=!1,_(),n&&U.code!==1000&&I.reconnectAttempts<T)S();else if(n&&U.code!==1000)y({reconnect:{attempts:I.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:T,status:"exhausted"},type:"connection"})},I.ws=C},l=(C)=>{if(I.ws?.readyState===1){I.ws.send(C);return}I.pendingMessages.push(C)},b=(C)=>{l(JSON.stringify(C))},R=(C={})=>{if(C.sessionId)I.sessionId=C.sessionId;if(C.scenarioId)I.scenarioId=C.scenarioId;b({scenarioId:I.scenarioId??void 0,sessionId:I.sessionId,type:"start"})},W=(C)=>{l(C)},E=()=>{b({type:"end_turn"})},M=(C)=>{b({...C,type:"call_control"})},$=()=>{if(_(),I.ws)I.ws.close(1000),I.ws=null;I.isConnected=!1,A.clear()},d=()=>{if(I.ws?.readyState===1)I.ws.close(4000,"absolutejs-voice-reconnect-proof")},N=(C)=>{return A.add(C),()=>{A.delete(C)}};return h(),{callControl:M,close:$,endTurn:E,send:b,sendAudio:W,simulateDisconnect:d,start:R,subscribe:N,getReadyState:()=>I.ws?.readyState??3,getScenarioId:()=>I.scenarioId??"",getSessionId:()=>I.sessionId}};var xc=()=>({attempts:0,maxAttempts:0,status:"idle"}),Gc=()=>({assistantAudio:[],assistantStreamingText:"",assistantTexts:[],call:null,error:null,isConnected:!1,partial:"",reconnect:xc(),scenarioId:null,sessionId:null,sessionMetadata:null,status:"idle",turns:[]}),f=()=>{let c=Gc(),g=new Set,A=()=>{g.forEach((T)=>T())};return{dispatch:(T)=>{switch(T.type){case"audio":c={...c,assistantAudio:[...c.assistantAudio,{chunk:T.chunk,format:T.format,receivedAt:T.receivedAt,turnId:T.turnId}]};break;case"assistant":c={...c,assistantStreamingText:"",assistantTexts:[...c.assistantTexts,T.text]};break;case"assistant_delta":c={...c,assistantStreamingText:`${c.assistantStreamingText}${T.delta}`};break;case"complete":c={...c,sessionId:T.sessionId,status:"completed"};break;case"call_lifecycle":c={...c,call:{...c.call,disposition:T.event.type==="end"?T.event.disposition:c.call?.disposition,endedAt:T.event.type==="end"?T.event.at:c.call?.endedAt,events:[...c.call?.events??[],T.event],lastEventAt:T.event.at,startedAt:c.call?.startedAt??T.event.at},sessionId:T.sessionId};break;case"connected":c={...c,isConnected:!0,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect};break;case"connection":c={...c,reconnect:T.reconnect};break;case"disconnected":c={...c,isConnected:!1};break;case"error":c={...c,error:T.message};break;case"final":c={...c,partial:T.transcript.text,turns:c.turns.map((V)=>V)};break;case"partial":c={...c,partial:T.transcript.text};break;case"replay":c={...c,assistantStreamingText:"",assistantTexts:[...T.assistantTexts],call:T.call??null,error:null,isConnected:T.status==="active",partial:T.partial,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect,scenarioId:T.scenarioId??c.scenarioId,sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??c.sessionMetadata,status:T.status,turns:[...T.turns]};break;case"session":c={...c,error:null,scenarioId:T.scenarioId??c.scenarioId,isConnected:T.status==="active",sessionId:T.sessionId,sessionMetadata:T.sessionMetadata??c.sessionMetadata,status:T.status};break;case"turn":c={...c,partial:"",turns:[...c.turns,T.turn]};break}A()},getServerSnapshot:()=>c,getSnapshot:()=>c,subscribe:(T)=>{return g.add(T),()=>{g.delete(T)}}}};var F=(c,g={})=>{let A=k(c,g),n=f(),T=g.browserMedia&&typeof window<"u"?s({...g.browserMedia,getScenarioId:()=>g.browserMedia?g.browserMedia.getScenarioId?.()??A.getScenarioId():A.getScenarioId(),getSessionId:()=>g.browserMedia?g.browserMedia.getSessionId?.()??A.getSessionId():A.getSessionId()}):null,V=new Set,I=(S)=>Promise.resolve().then(()=>{if(!S?.sessionId&&!S?.scenarioId)return;A.start(S),T?.start()}),y=()=>{V.forEach((S)=>S())},_=()=>{if(!g.reconnectReportPath||typeof fetch>"u")return;let S=n.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:S.reconnect,scenarioId:S.scenarioId,sessionId:A.getSessionId(),turnIds:S.turns.map((l)=>l.id)});fetch(g.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},L=A.subscribe((S)=>{let h=z(S);if(h){if(n.dispatch(h),S.type==="connection")_();y()}});return{start:I,get assistantAudio(){return n.getSnapshot().assistantAudio},get assistantTexts(){return n.getSnapshot().assistantTexts},get assistantStreamingText(){return n.getSnapshot().assistantStreamingText},get call(){return n.getSnapshot().call},callControl(S){A.callControl(S)},close(){L(),T?.close(),A.close(),n.dispatch({type:"disconnected"}),y()},endTurn(){A.endTurn()},get error(){return n.getSnapshot().error},getServerSnapshot(){return n.getServerSnapshot()},getSnapshot(){return n.getSnapshot()},get isConnected(){return n.getSnapshot().isConnected},get partial(){return n.getSnapshot().partial},get reconnect(){return n.getSnapshot().reconnect},get scenarioId(){return n.getSnapshot().scenarioId},sendAudio(S){A.sendAudio(S)},get sessionId(){return A.getSessionId()},get sessionMetadata(){return n.getSnapshot().sessionMetadata},simulateDisconnect(){A.simulateDisconnect()},get status(){return n.getSnapshot().status},subscribe(S){return V.add(S),()=>{V.delete(S)}},get turns(){return n.getSnapshot().turns}}};var e=(c)=>{if(!c||c.enabled===!1)return;return{enabled:!0,maxGain:c.maxGain??3,noiseGateAttenuation:c.noiseGateAttenuation??0.15,noiseGateThreshold:c.noiseGateThreshold??0.006,targetLevel:c.targetLevel??0.08}};var Xc={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}},Yc={"accent-heavy":{silenceMs:1200,speechThreshold:0.01,transcriptStabilityMs:1200},general:{},"noisy-room":{silenceMs:2000,speechThreshold:0.02,transcriptStabilityMs:1600},"short-command":{silenceMs:500,speechThreshold:0.016,transcriptStabilityMs:420}};var t=(c)=>{let g=c?.profile??"fast",A=c?.qualityProfile??"general",n=Xc[g],T=Yc[A];return{profile:g,qualityProfile:A,silenceMs:c?.silenceMs??T.silenceMs??n.silenceMs,speechThreshold:c?.speechThreshold??T.speechThreshold??n.speechThreshold,transcriptStabilityMs:c?.transcriptStabilityMs??T.transcriptStabilityMs??n.transcriptStabilityMs}};var Qc={chat:{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"balanced",qualityProfile:"short-command"}},default:{capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:10,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"fast",qualityProfile:"general"}},dictation:{audioConditioning:{enabled:!0,maxGain:2.25,noiseGateAttenuation:0.05,noiseGateThreshold:0.003,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"guided-intake":{audioConditioning:{enabled:!0,maxGain:2.5,noiseGateAttenuation:0,noiseGateThreshold:0.004,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:12,pingInterval:30000,reconnect:!0},sttLifecycle:"turn-scoped",turnDetection:{profile:"long-form",qualityProfile:"accent-heavy"}},"noisy-room":{audioConditioning:{enabled:!0,maxGain:3,noiseGateAttenuation:0.12,noiseGateThreshold:0.006,targetLevel:0.085},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:2100,speechThreshold:0.02,transcriptStabilityMs:1650}},"pstn-balanced":{audioConditioning:{enabled:!0,maxGain:2.8,noiseGateAttenuation:0.07,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:660,speechThreshold:0.012,transcriptStabilityMs:300}},"pstn-fast":{audioConditioning:{enabled:!0,maxGain:2.75,noiseGateAttenuation:0.06,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room",silenceMs:620,speechThreshold:0.012,transcriptStabilityMs:280}},reliability:{audioConditioning:{enabled:!0,maxGain:2.9,noiseGateAttenuation:0.08,noiseGateThreshold:0.005,targetLevel:0.08},capture:{channelCount:1,sampleRateHz:16000},connection:{maxReconnectAttempts:14,pingInterval:45000,reconnect:!0},sttLifecycle:"continuous",turnDetection:{profile:"long-form",qualityProfile:"noisy-room"}}},r=(c="default")=>{let g=Qc[c];return{audioConditioning:e(g.audioConditioning),capture:{channelCount:g.capture?.channelCount??1,sampleRateHz:g.capture?.sampleRateHz??16000},connection:{...g.connection},name:c,sttLifecycle:g.sttLifecycle??"continuous",turnDetection:t(g.turnDetection)}};var Jc=(c)=>({assistantAudio:[...c.assistantAudio],assistantStreamingText:c.assistantStreamingText,assistantTexts:[...c.assistantTexts],call:c.call,error:c.error,isConnected:c.isConnected,isRecording:!1,partial:c.partial,reconnect:c.reconnect,recordingError:null,sessionId:c.sessionId,sessionMetadata:c.sessionMetadata,scenarioId:c.scenarioId,status:c.status,turns:[...c.turns]}),a=(c,g={})=>{let A=r(g.preset),n=F(c,{...A.connection,...g.connection}),T=null,V=Jc(n),I=new Set,y=()=>{for(let R of I)R()},_=()=>{if(V={...V,assistantAudio:[...n.assistantAudio],assistantStreamingText:n.assistantStreamingText,assistantTexts:[...n.assistantTexts],call:n.call,error:n.error,isConnected:n.isConnected,partial:n.partial,reconnect:n.reconnect,sessionId:n.sessionId,sessionMetadata:n.sessionMetadata,scenarioId:n.scenarioId,status:n.status,turns:[...n.turns]},g.autoStopOnComplete!==!1&&V.status==="completed"&&V.isRecording)T?.stop(),T=null,V={...V,isRecording:!1};y()},L=n.subscribe(_);_();let S=()=>{if(T)return T;return T=q({channelCount:g.capture?.channelCount??A.capture.channelCount,onLevel:g.capture?.onLevel,onAudio:(R)=>{if(g.capture?.onAudio){g.capture.onAudio(R,n.sendAudio);return}n.sendAudio(R)},sampleRateHz:g.capture?.sampleRateHz??A.capture.sampleRateHz,...g.capture?.stream?{stream:g.capture.stream}:{}}),T},h=()=>{T?.stop(),T=null,V={...V,isRecording:!1},y()},l=async()=>{if(V.isRecording)return;try{V={...V,recordingError:null},y(),await S().start(),V={...V,isRecording:!0},y()}catch(R){throw T=null,V={...V,isRecording:!1,recordingError:R instanceof Error?R.message:String(R)},y(),R}};return{close:()=>{L(),h(),n.close()},startRecording:l,stopRecording:h,get assistantAudio(){return V.assistantAudio},get assistantTexts(){return V.assistantTexts},get assistantStreamingText(){return V.assistantStreamingText},bindHTMX(R){return Z(n,R)},get call(){return V.call},callControl:(R)=>n.callControl(R),endTurn:()=>n.endTurn(),get error(){return V.error},getServerSnapshot:()=>V,getSnapshot:()=>V,get isConnected(){return V.isConnected},get isRecording(){return V.isRecording},get partial(){return V.partial},get reconnect(){return V.reconnect},get recordingError(){return V.recordingError},get scenarioId(){return V.scenarioId},sendAudio:(R)=>n.sendAudio(R),get sessionId(){return V.sessionId},get sessionMetadata(){return V.sessionMetadata},simulateDisconnect:()=>n.simulateDisconnect(),get status(){return V.status},subscribe:(R)=>{return I.add(R),()=>{I.delete(R)}},toggleRecording:async()=>{if(V.isRecording){h();return}await l()},get turns(){return V.turns}}};var i=(c)=>String(c).replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'");var v=(c)=>{if(!c.isConnected)return"idle";if(c.isPlaying)return"speaking";if(c.isRecording&&c.hasActivePartial)return"listening";if(c.isRecording)return"listening";if(c.lastTranscriptAt&&!c.lastAssistantAt)return"thinking";if(c.lastTranscriptAt&&c.lastAssistantAt&&c.lastTranscriptAt>c.lastAssistantAt)return"thinking";return"idle"};var Zc={accent:"#3b82f6",background:"#0f172a",errorAccent:"#ef4444",fontFamily:'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',foreground:"#f8fafc",radius:16},qc={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},zc=(c,g)=>{switch(c){case"listening":return g.listening;case"speaking":return g.speaking;case"thinking":return g.thinking;case"idle":return g.idle}},m=(c)=>{let g={...Zc,...c.theme},A={...qc,...c.labels},n=c.state.assistantAudio.at(-1)?.receivedAt,T=c.state.turns.at(-1)?.committedAt,V=v({hasActivePartial:c.state.partial.length>0,isConnected:c.state.isConnected,isPlaying:!1,isRecording:c.state.isRecording,lastAssistantAt:n,lastTranscriptAt:T}),I=!c.state.isConnected&&c.state.status!=="idle"&&!c.state.error,y=c.state.error?"Error":I?A.connecting:c.state.status==="completed"?A.callEnded:zc(V,A);return{agentState:V,classes:{container:`absolute-voice-widget absolute-voice-widget--${V}`,dot:`absolute-voice-widget__dot${c.state.error?" absolute-voice-widget__dot--error":""}`},controls:{canEnd:c.state.isConnected,canMute:c.state.isRecording,canStart:!c.state.isRecording&&c.state.status!=="completed"},errorMessage:c.state.error??void 0,labels:A,partial:c.state.partial||void 0,statusLabel:y,theme:g,title:c.title??"Voice"}},Kc=(c)=>typeof c==="number"?`${c}px`:c,u=(c)=>{let g=c.theme,A=`background:${g.background};border-radius:${Kc(g.radius)};color:${g.foreground};font-family:${g.fontFamily};min-width:240px;padding:20px 22px;`,n=`background:${c.errorMessage?g.errorAccent:c.agentState==="idle"?"rgba(148,163,184,0.6)":g.accent};border-radius:50%;height:10px;width:10px;`,T=[];if(c.controls.canStart)T.push(`<button type="button" data-action="start" style="background:${g.accent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${i(c.labels.startCall)}</button>`);if(c.controls.canMute)T.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${i(c.labels.mute)}</button>`);if(c.controls.canEnd)T.push(`<button type="button" data-action="end" style="background:${g.errorAccent};border:none;border-radius:12px;color:${g.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${i(c.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${c.agentState}" class="${i(c.classes.container)}" style="${A}">
|
|
2
2
|
<div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
|
|
3
|
-
<span aria-hidden="true" class="${
|
|
4
|
-
<strong style="font-size:15px;">${
|
|
5
|
-
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${
|
|
3
|
+
<span aria-hidden="true" class="${i(c.classes.dot)}" style="${n}"></span>
|
|
4
|
+
<strong style="font-size:15px;">${i(c.title)}</strong>
|
|
5
|
+
<span style="font-size:13px;margin-left:auto;opacity:0.7;">${i(c.statusLabel)}</span>
|
|
6
6
|
</div>
|
|
7
|
-
${c.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${
|
|
7
|
+
${c.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${i(c.partial)}”</p>`:""}
|
|
8
8
|
<div style="display:flex;gap:10px;">${T.join("")}</div>
|
|
9
|
-
${c.errorMessage?`<p style="color:${g.errorAccent};font-size:12px;margin-top:12px;">${
|
|
10
|
-
</div>`};var
|
|
9
|
+
${c.errorMessage?`<p style="color:${g.errorAccent};font-size:12px;margin-top:12px;">${i(c.errorMessage)}</p>`:""}
|
|
10
|
+
</div>`};var Bc=(c)=>{if(typeof c!=="string")return c;let g=document.querySelector(c);if(!g)throw Error(`AbsoluteVoice.mount: no element matches "${c}"`);return g},p=(c,g={})=>{let A=Bc(c),n=a(g.path??"/voice",g.controllerOptions),T=null,V=null,I=()=>{let _=m({...g.labels!==void 0?{labels:g.labels}:{},state:{assistantAudio:n.assistantAudio,error:n.error,isConnected:n.isConnected,isRecording:n.isRecording,partial:n.partial,status:n.status,turns:n.turns},...g.theme!==void 0?{theme:g.theme}:{},...g.title!==void 0?{title:g.title}:{}});A.innerHTML=u(_);for(let L of A.querySelectorAll("button[data-action]")){let{action:S}=L.dataset;L.addEventListener("click",()=>{if(S==="start")n.startRecording();else if(S==="mute")n.stopRecording();else if(S==="end")n.close()})}if(n.error&&n.error!==T)T=n.error,g.onError?.(n.error);if(n.status!==V)V=n.status,g.onStatusChange?.(n.status)},y=n.subscribe(I);if(I(),g.autoStart)n.startRecording();return{controller:n,async end(){await n.close()},mute(){n.stopRecording()},async start(){await n.startRecording()},unmount(){y(),n.close(),A.innerHTML=""}}},cc="0.0.22-beta.516",gc={mount:p,version:cc};if(typeof globalThis<"u")globalThis.AbsoluteVoice=gc;var oc=gc;})();
|
package/dist/react/index.js
CHANGED
|
@@ -12143,14 +12143,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
12143
12143
|
let processorNode = null;
|
|
12144
12144
|
let mediaStream = null;
|
|
12145
12145
|
const start = async () => {
|
|
12146
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
12146
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
12147
12147
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
12148
12148
|
}
|
|
12149
12149
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
12150
12150
|
if (!AudioContextCtor) {
|
|
12151
12151
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
12152
12152
|
}
|
|
12153
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
12153
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
12154
12154
|
audio: {
|
|
12155
12155
|
autoGainControl: true,
|
|
12156
12156
|
channelCount: options.channelCount ?? 1,
|
|
@@ -12579,7 +12579,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12579
12579
|
}
|
|
12580
12580
|
stream.sendAudio(audio);
|
|
12581
12581
|
},
|
|
12582
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
12582
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
12583
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
12583
12584
|
});
|
|
12584
12585
|
return capture;
|
|
12585
12586
|
};
|
package/dist/svelte/index.js
CHANGED
|
@@ -518,14 +518,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
518
518
|
let processorNode = null;
|
|
519
519
|
let mediaStream = null;
|
|
520
520
|
const start = async () => {
|
|
521
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
521
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
522
522
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
523
523
|
}
|
|
524
524
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
525
525
|
if (!AudioContextCtor) {
|
|
526
526
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
527
527
|
}
|
|
528
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
528
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
529
529
|
audio: {
|
|
530
530
|
autoGainControl: true,
|
|
531
531
|
channelCount: options.channelCount ?? 1,
|
|
@@ -1716,7 +1716,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1716
1716
|
}
|
|
1717
1717
|
stream.sendAudio(audio);
|
|
1718
1718
|
},
|
|
1719
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
1719
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
1720
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
1720
1721
|
});
|
|
1721
1722
|
return capture;
|
|
1722
1723
|
};
|
package/dist/testing/index.js
CHANGED
|
@@ -2242,14 +2242,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
2242
2242
|
let processorNode = null;
|
|
2243
2243
|
let mediaStream = null;
|
|
2244
2244
|
const start = async () => {
|
|
2245
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
2245
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
2246
2246
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
2247
2247
|
}
|
|
2248
2248
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
2249
2249
|
if (!AudioContextCtor) {
|
|
2250
2250
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
2251
2251
|
}
|
|
2252
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
2252
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
2253
2253
|
audio: {
|
|
2254
2254
|
autoGainControl: true,
|
|
2255
2255
|
channelCount: options.channelCount ?? 1,
|
|
@@ -3440,7 +3440,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
3440
3440
|
}
|
|
3441
3441
|
stream.sendAudio(audio);
|
|
3442
3442
|
},
|
|
3443
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
3443
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
3444
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
3444
3445
|
});
|
|
3445
3446
|
return capture;
|
|
3446
3447
|
};
|
package/dist/vue/index.js
CHANGED
|
@@ -11560,14 +11560,14 @@ var createMicrophoneCapture = (options) => {
|
|
|
11560
11560
|
let processorNode = null;
|
|
11561
11561
|
let mediaStream = null;
|
|
11562
11562
|
const start = async () => {
|
|
11563
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
11563
|
+
if (!options.stream && (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)) {
|
|
11564
11564
|
throw new Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");
|
|
11565
11565
|
}
|
|
11566
11566
|
const AudioContextCtor = (typeof window !== "undefined" ? window.AudioContext ?? window.webkitAudioContext : undefined) ?? AudioContext;
|
|
11567
11567
|
if (!AudioContextCtor) {
|
|
11568
11568
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
11569
11569
|
}
|
|
11570
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
11570
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
11571
11571
|
audio: {
|
|
11572
11572
|
autoGainControl: true,
|
|
11573
11573
|
channelCount: options.channelCount ?? 1,
|
|
@@ -11996,7 +11996,8 @@ var createVoiceController = (path, options = {}) => {
|
|
|
11996
11996
|
}
|
|
11997
11997
|
stream.sendAudio(audio);
|
|
11998
11998
|
},
|
|
11999
|
-
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz
|
|
11999
|
+
sampleRateHz: options.capture?.sampleRateHz ?? preset.capture.sampleRateHz,
|
|
12000
|
+
...options.capture?.stream ? { stream: options.capture.stream } : {}
|
|
12000
12001
|
});
|
|
12001
12002
|
return capture;
|
|
12002
12003
|
};
|