@absolutejs/voice 0.0.22-beta.515 → 0.0.22-beta.516

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.
@@ -0,0 +1,10 @@
1
+ (()=>{var{defineProperty:a,getOwnPropertyNames:lc,getOwnPropertyDescriptor:ic}=Object,gc=Object.prototype.hasOwnProperty;function sc(c){return this[c]}var ec=(c)=>{var n=(W??=new WeakMap).get(c),l;if(n)return n;if(n=a({},"__esModule",{value:!0}),c&&typeof c==="object"||typeof c==="function"){for(var o of lc(c))if(!gc.call(n,o))a(n,o,{get:sc.bind(c,o),enumerable:!(l=ic(c,o))||l.enumerable})}return W.set(c,n),n},W;var Ac=(c)=>c;function dc(c,n){this[c]=Ac.bind(null,n)}var Cc=(c,n)=>{for(var l in n)a(c,l,{get:n[l],enumerable:!0,configurable:!0,set:dc.bind(n,l)})};var Yc={};Cc(Yc,{mount:()=>p,default:()=>qc,VOICE_EMBED_VERSION:()=>cc});var Tc=(c)=>{if(typeof c!=="string")return c;return document.querySelector(c)},tc=(c,n,l,o)=>{let i=n??c.getAttribute("hx-get")??"";if(!i)return"";let e=new URL(i,window.location.origin);if(o)e.searchParams.set(l,o);else e.searchParams.delete(l);return`${e.pathname}${e.search}${e.hash}`},$=(c,n)=>{if(typeof window>"u"||typeof document>"u")return()=>{};let l=Tc(n.element);if(!l)return()=>{};let o=n.eventName??"voice-refresh",i=n.sessionQueryParam??"sessionId",e=()=>{let C=window,T=tc(l,n.route,i,c.sessionId);if(T)l.setAttribute("hx-get",T);C.htmx?.process?.(l),C.htmx?.trigger?.(l,o)},s=c.subscribe(e);return e(),()=>{s()}};var hc=(c)=>Math.max(-1,Math.min(1,c)),Sc=(c)=>{let n=new Int16Array(c.length);for(let l=0;l<c.length;l+=1){let o=hc(c[l]??0);n[l]=o<0?o*32768:o*32767}return new Uint8Array(n.buffer)},yc=(c)=>{let n=c instanceof Uint8Array?c:new Uint8Array(c);if(n.byteLength<2)return 0;let l=new Int16Array(n.buffer,n.byteOffset,Math.floor(n.byteLength/2));if(l.length===0)return 0;let o=0;for(let i of l){let e=i/32768;o+=e*e}return Math.min(1,Math.max(0,Math.sqrt(o/l.length)*5.5))},Rc=(c,n,l)=>{if(n===l)return c;let o=n/l,i=Math.round(c.length/o),e=new Float32Array(i),s=0,C=0;while(s<e.length){let T=Math.round((s+1)*o),S=0,d=0;for(let h=C;h<T&&h<c.length;h+=1)S+=c[h]??0,d+=1;e[s]=d>0?S/d:0,s+=1,C=T}return e},H=(c)=>{let n=null,l=null,o=null,i=null;return{start:async()=>{if(typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw Error("Browser microphone capture requires navigator.mediaDevices.getUserMedia.");let C=(typeof window<"u"?window.AudioContext??window.webkitAudioContext:void 0)??AudioContext;if(!C)throw Error("Browser microphone capture requires AudioContext support.");i=await navigator.mediaDevices.getUserMedia({audio:{channelCount:c.channelCount??1}}),n=new C,l=n.createMediaStreamSource(i),o=n.createScriptProcessor(4096,1,1),o.onaudioprocess=(T)=>{let S=T.inputBuffer.getChannelData(0),d=Rc(S,n?.sampleRate??48000,c.sampleRateHz??16000),h=Sc(d);c.onLevel?.(yc(h)),c.onAudio(h)},l.connect(o),o.connect(n.destination)},stop:()=>{o?.disconnect(),l?.disconnect(),i?.getTracks().forEach((C)=>C.stop()),n?.close(),c.onLevel?.(0),n=null,i=null,o=null,l=null}}};var P=(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 n=c;for(let l of["message","reason","description"]){let o=n[l];if(typeof o==="string"&&o.trim())return o}if("error"in n)return P(n.error);if("cause"in n)return P(n.cause);try{return JSON.stringify(c)}catch{}}return"Unexpected error"},G=(c)=>{switch(c.type){case"audio":return{chunk:Uint8Array.from(atob(c.chunkBase64),(n)=>n.charCodeAt(0)),format:c.format,receivedAt:c.receivedAt,turnId:c.turnId,type:"audio"};case"assistant":return{text:c.text,type:"assistant"};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:P(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 M=(c,n,l,o)=>{c.push({code:l,message:o,severity:n})};var Vc=(c)=>c.length===0?void 0:c.reduce((n,l)=>n+l,0)/c.length,E=(c)=>c.length===0?void 0:Math.max(...c);var R=(c,n)=>{let l=c[n];return typeof l==="number"&&Number.isFinite(l)?l:void 0},O=(c,n)=>{let l=c[n];return typeof l==="boolean"?l:void 0},V=(c,n)=>{let l=c[n];return typeof l==="string"?l:void 0},N=(c)=>String(c.id??V(c,"ssrc")??R(c,"ssrc")??V(c,"trackIdentifier")??V(c,"mid")??"unknown"),z=(c)=>c===void 0?void 0:c*1000;var Ic=(c)=>{let n={};for(let[l,o]of Object.entries(c))if(o===null||typeof o==="boolean"||typeof o==="number"||typeof o==="string")n[l]=o;return n};var X=(c={})=>{let n=c.stats??[],l=[],o=n.filter((g)=>g.type==="inbound-rtp"&&V(g,"kind")!=="video"),i=n.filter((g)=>g.type==="outbound-rtp"&&V(g,"kind")!=="video"),e=n.filter((g)=>g.type==="candidate-pair"),s=n.filter((g)=>(g.type==="track"||g.type==="media-source")&&V(g,"kind")==="audio"),C=e.filter((g)=>O(g,"selected")===!0||O(g,"nominated")===!0||V(g,"state")==="succeeded").length,T=s.filter((g)=>V(g,"readyState")!=="ended"&&V(g,"trackState")!=="ended"&&O(g,"ended")!==!0).length,S=s.filter((g)=>V(g,"readyState")==="ended"||V(g,"trackState")==="ended"||O(g,"ended")===!0).length,d=o.reduce((g,y)=>g+(R(y,"packetsReceived")??0),0),h=i.reduce((g,y)=>g+(R(y,"packetsSent")??0),0),A=[...o,...i].reduce((g,y)=>g+Math.max(0,R(y,"packetsLost")??0),0),I=d+A,t=I===0?0:A/I,x=o.reduce((g,y)=>g+(R(y,"bytesReceived")??0),0),w=i.reduce((g,y)=>g+(R(y,"bytesSent")??0),0),b=E(e.map((g)=>z(R(g,"currentRoundTripTime")??R(g,"roundTripTime"))).filter((g)=>g!==void 0)),f=E([...o,...i].map((g)=>z(R(g,"jitter"))).filter((g)=>g!==void 0)),D=E(o.map((g)=>{let y=R(g,"jitterBufferDelay"),_=R(g,"jitterBufferEmittedCount");return y!==void 0&&_!==void 0&&_>0?y/_*1000:void 0}).filter((g)=>g!==void 0)),r=s.map((g)=>R(g,"audioLevel")).filter((g)=>g!==void 0);if(c.requireConnectedCandidatePair&&e.length>0&&C===0)M(l,"error","media.webrtc_candidate_pair_missing","No active WebRTC candidate pair was observed.");if(c.requireLiveAudioTrack&&T===0)M(l,"error","media.webrtc_audio_track_missing","No live WebRTC audio track was observed.");if(c.maxPacketLossRatio!==void 0&&t>c.maxPacketLossRatio)M(l,"warning","media.webrtc_packet_loss",`Observed WebRTC packet loss ratio ${String(t)} above ${String(c.maxPacketLossRatio)}.`);if(c.maxRoundTripTimeMs!==void 0&&b!==void 0&&b>c.maxRoundTripTimeMs)M(l,"warning","media.webrtc_round_trip_time",`Observed WebRTC RTT ${String(b)}ms above ${String(c.maxRoundTripTimeMs)}ms.`);if(c.maxJitterMs!==void 0&&f!==void 0&&f>c.maxJitterMs)M(l,"warning","media.webrtc_jitter",`Observed WebRTC jitter ${String(f)}ms above ${String(c.maxJitterMs)}ms.`);return{activeCandidatePairs:C,audioLevelAverage:Vc(r),bytesReceived:x,bytesSent:w,checkedAt:Date.now(),endedAudioTracks:S,inboundPackets:d,issues:l,jitterBufferDelayMs:D,jitterMs:f,liveAudioTracks:T,outboundPackets:h,packetLossRatio:t,packetsLost:A,roundTripTimeMs:b,status:l.some((g)=>g.severity==="error")?"fail":l.length>0?"warn":"pass",totalStats:n.length}},Y=async(c)=>{return[...(await c.peerConnection.getStats(c.selector??null)).values()].map(Ic)};var q=(c={})=>{let n=c.stats??[],l=c.previousStats??[],o=[],i=new Map(l.map((A)=>[N(A),A])),s=n.filter((A)=>(A.type==="inbound-rtp"||A.type==="outbound-rtp")&&V(A,"kind")!=="video"&&V(A,"mediaType")!=="video").map((A)=>{let I=A.type==="outbound-rtp"?"outbound":"inbound",t=I==="outbound"?"packetsSent":"packetsReceived",x=I==="outbound"?"bytesSent":"bytesReceived",w=i.get(N(A)),b=R(A,t),f=w?R(w,t):void 0,D=R(A,x),r=w?R(w,x):void 0,g=A.timestamp!==void 0&&w?.timestamp!==void 0?A.timestamp-w.timestamp:void 0;return{bytesDelta:D!==void 0&&r!==void 0?D-r:void 0,currentPackets:b,direction:I,id:N(A),packetDelta:b!==void 0&&f!==void 0?b-f:void 0,previousPackets:f,timeDeltaMs:g}}),C=s.filter((A)=>A.direction==="inbound"),T=s.filter((A)=>A.direction==="outbound"),S=E(s.map((A)=>A.timeDeltaMs).filter((A)=>A!==void 0)),d=C.filter((A)=>c.maxInboundPacketStallMs!==void 0&&A.timeDeltaMs!==void 0&&A.timeDeltaMs>=c.maxInboundPacketStallMs&&A.packetDelta!==void 0&&A.packetDelta<=0).length,h=T.filter((A)=>c.maxOutboundPacketStallMs!==void 0&&A.timeDeltaMs!==void 0&&A.timeDeltaMs>=c.maxOutboundPacketStallMs&&A.packetDelta!==void 0&&A.packetDelta<=0).length;if(c.requireInboundAudio&&C.length===0)M(o,"error","media.webrtc_inbound_audio_missing","No inbound WebRTC audio RTP stream was observed.");if(c.requireOutboundAudio&&T.length===0)M(o,"error","media.webrtc_outbound_audio_missing","No outbound WebRTC audio RTP stream was observed.");if(c.maxGapMs!==void 0&&S!==void 0&&S>c.maxGapMs)M(o,"warning","media.webrtc_stream_gap",`Observed WebRTC stream sample gap ${String(S)}ms above ${String(c.maxGapMs)}ms.`);if(d>0)M(o,"error","media.webrtc_inbound_stalled",`${String(d)} inbound WebRTC audio stream(s) stopped receiving packets.`);if(h>0)M(o,"error","media.webrtc_outbound_stalled",`${String(h)} outbound WebRTC audio stream(s) stopped sending packets.`);return{checkedAt:Date.now(),inboundAudioStreams:C.length,issues:o,maxObservedGapMs:S,outboundAudioStreams:T.length,stalledInboundStreams:d,stalledOutboundStreams:h,status:o.some((A)=>A.severity==="error")?"fail":o.length>0?"warn":"pass",streams:s,totalStats:n.length}};var _c="/api/voice/browser-media",wc=5000,bc=async(c)=>c.peerConnection??await c.getPeerConnection?.()??null,fc=async(c,n)=>{let l=n.fetch??globalThis.fetch;if(!l)return;await l(n.path??_c,{body:JSON.stringify(c),headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"})},Q=(c)=>{let n=null,l=[],o=async()=>{let s=await bc(c);if(!s)return;let C=await Y({peerConnection:s}),T=X({...c,stats:C}),S=c.continuity===!1?void 0:q({...c.continuity,previousStats:l,stats:C}),d={at:Date.now(),continuity:S,report:T,scenarioId:c.getScenarioId?.()??null,sessionId:c.getSessionId?.()??null};return l=C,c.onReport?.(d),await fc(d,c),d},i=()=>{o().catch((s)=>{c.onError?.(s)})},e=()=>{if(n)clearInterval(n),n=null};return{close:e,reportOnce:o,start:()=>{if(n)return;i(),n=setInterval(i,c.intervalMs??wc)},stop:e}};var U=()=>{},Mc=()=>U,Lc={callControl:U,close:U,endTurn:U,getReadyState:()=>3,getScenarioId:()=>"",getSessionId:()=>"",send:U,sendAudio:U,simulateDisconnect:U,start:()=>{},subscribe:Mc},Uc=()=>crypto.randomUUID(),xc=(c,n,l)=>{let{hostname:o,port:i,protocol:e}=window.location,s=e==="https:"?"wss:":"ws:",C=i?`:${i}`:"",T=new URL(`${s}//${o}${C}${c}`);if(T.searchParams.set("sessionId",n),l)T.searchParams.set("scenarioId",l);return T.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}},rc=(c)=>{if(typeof c.data!=="string")return null;try{let n=JSON.parse(c.data);return Dc(n)?n:null}catch{return null}},J=(c,n={})=>{if(typeof window>"u")return Lc;let l=new Set,o=n.reconnect!==!1,i=n.maxReconnectAttempts??10,e=n.pingInterval??30000,s={isConnected:!1,pendingMessages:[],scenarioId:n.scenarioId??null,pingInterval:null,reconnectAttempts:0,reconnectTimeout:null,sessionId:n.sessionId??Uc(),ws:null},C=(g)=>{l.forEach((y)=>y(g))},T=()=>{if(s.pingInterval)clearInterval(s.pingInterval),s.pingInterval=null;if(s.reconnectTimeout)clearTimeout(s.reconnectTimeout),s.reconnectTimeout=null},S=()=>{if(s.ws?.readyState!==1)return;while(s.pendingMessages.length>0){let g=s.pendingMessages.shift();if(g!==void 0)s.ws.send(g)}},d=()=>{let g=Date.now()+500;s.reconnectAttempts+=1,C({reconnect:{attempts:s.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:i,nextAttemptAt:g,status:"reconnecting"},type:"connection"}),s.reconnectTimeout=setTimeout(()=>{if(s.reconnectAttempts>i){C({reconnect:{attempts:s.reconnectAttempts,maxAttempts:i,status:"exhausted"},type:"connection"});return}h()},500)},h=()=>{let g=new WebSocket(xc(c,s.sessionId,s.scenarioId));g.binaryType="arraybuffer",g.onopen=()=>{let y=s.reconnectAttempts>0;if(s.isConnected=!0,S(),y)C({reconnect:{attempts:s.reconnectAttempts,lastResumedAt:Date.now(),maxAttempts:i,status:"resumed"},type:"connection"}),s.reconnectAttempts=0;l.forEach((_)=>_({scenarioId:s.scenarioId??void 0,sessionId:s.sessionId,status:"active",type:"session"})),s.pingInterval=setInterval(()=>{if(g.readyState===1)g.send(JSON.stringify({type:"ping"}))},e)},g.onmessage=(y)=>{let _=rc(y);if(!_)return;if(_.type==="session")s.sessionId=_.sessionId,s.scenarioId=_.scenarioId??s.scenarioId;l.forEach((oc)=>oc(_))},g.onclose=(y)=>{if(s.isConnected=!1,T(),o&&y.code!==1000&&s.reconnectAttempts<i)d();else if(o&&y.code!==1000)C({reconnect:{attempts:s.reconnectAttempts,lastDisconnectAt:Date.now(),maxAttempts:i,status:"exhausted"},type:"connection"})},s.ws=g},A=(g)=>{if(s.ws?.readyState===1){s.ws.send(g);return}s.pendingMessages.push(g)},I=(g)=>{A(JSON.stringify(g))},t=(g={})=>{if(g.sessionId)s.sessionId=g.sessionId;if(g.scenarioId)s.scenarioId=g.scenarioId;I({type:"start",sessionId:s.sessionId,scenarioId:s.scenarioId??void 0})},x=(g)=>{A(g)},w=()=>{I({type:"end_turn"})},b=(g)=>{I({...g,type:"call_control"})},f=()=>{if(T(),s.ws)s.ws.close(1000),s.ws=null;s.isConnected=!1,l.clear()},D=()=>{if(s.ws?.readyState===1)s.ws.close(4000,"absolutejs-voice-reconnect-proof")},r=(g)=>{return l.add(g),()=>{l.delete(g)}};return h(),{callControl:b,close:f,endTurn:w,getReadyState:()=>s.ws?.readyState??3,getScenarioId:()=>s.scenarioId??"",getSessionId:()=>s.sessionId,send:I,sendAudio:x,simulateDisconnect:D,start:t,subscribe:r}};var Oc=()=>({attempts:0,maxAttempts:0,status:"idle"}),Ec=()=>({assistantAudio:[],assistantTexts:[],call:null,error:null,isConnected:!1,sessionMetadata:null,scenarioId:null,partial:"",reconnect:Oc(),sessionId:null,status:"idle",turns:[]}),Z=()=>{let c=Ec(),n=new Set,l=()=>{n.forEach((i)=>i())};return{dispatch:(i)=>{switch(i.type){case"audio":c={...c,assistantAudio:[...c.assistantAudio,{chunk:i.chunk,format:i.format,receivedAt:i.receivedAt,turnId:i.turnId}]};break;case"assistant":c={...c,assistantTexts:[...c.assistantTexts,i.text]};break;case"complete":c={...c,sessionId:i.sessionId,status:"completed"};break;case"call_lifecycle":c={...c,call:{...c.call,disposition:i.event.type==="end"?i.event.disposition:c.call?.disposition,endedAt:i.event.type==="end"?i.event.at:c.call?.endedAt,events:[...c.call?.events??[],i.event],lastEventAt:i.event.at,startedAt:c.call?.startedAt??i.event.at},sessionId:i.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:i.reconnect};break;case"disconnected":c={...c,isConnected:!1};break;case"error":c={...c,error:i.message};break;case"final":c={...c,partial:i.transcript.text,turns:c.turns.map((e)=>e)};break;case"partial":c={...c,partial:i.transcript.text};break;case"replay":c={...c,assistantTexts:[...i.assistantTexts],call:i.call??null,error:null,isConnected:i.status==="active",partial:i.partial,reconnect:c.reconnect.status==="reconnecting"?{...c.reconnect,lastResumedAt:Date.now(),nextAttemptAt:void 0,status:"resumed"}:c.reconnect,scenarioId:i.scenarioId??c.scenarioId,sessionId:i.sessionId,sessionMetadata:i.sessionMetadata??c.sessionMetadata,status:i.status,turns:[...i.turns]};break;case"session":c={...c,error:null,scenarioId:i.scenarioId??c.scenarioId,isConnected:i.status==="active",sessionId:i.sessionId,sessionMetadata:i.sessionMetadata??c.sessionMetadata,status:i.status};break;case"turn":c={...c,partial:"",turns:[...c.turns,i.turn]};break}l()},getServerSnapshot:()=>c,getSnapshot:()=>c,subscribe:(i)=>{return n.add(i),()=>{n.delete(i)}}}};var B=(c,n={})=>{let l=J(c,n),o=Z(),i=n.browserMedia&&typeof window<"u"?Q({...n.browserMedia,getScenarioId:()=>n.browserMedia?n.browserMedia.getScenarioId?.()??l.getScenarioId():l.getScenarioId(),getSessionId:()=>n.browserMedia?n.browserMedia.getSessionId?.()??l.getSessionId():l.getSessionId()}):null,e=new Set,s=(d)=>Promise.resolve().then(()=>{if(!d?.sessionId&&!d?.scenarioId)return;l.start(d),i?.start()}),C=()=>{e.forEach((d)=>d())},T=()=>{if(!n.reconnectReportPath||typeof fetch>"u")return;let d=o.getSnapshot(),h=JSON.stringify({at:Date.now(),reconnect:d.reconnect,scenarioId:d.scenarioId,sessionId:l.getSessionId(),turnIds:d.turns.map((A)=>A.id)});fetch(n.reconnectReportPath,{body:h,headers:{"Content-Type":"application/json"},keepalive:!0,method:"POST"}).catch(()=>{})},S=l.subscribe((d)=>{let h=G(d);if(h){if(o.dispatch(h),d.type==="connection")T();C()}});return{callControl(d){l.callControl(d)},close(){S(),i?.close(),l.close(),o.dispatch({type:"disconnected"}),C()},endTurn(){l.endTurn()},get error(){return o.getSnapshot().error},getServerSnapshot(){return o.getServerSnapshot()},getSnapshot(){return o.getSnapshot()},get isConnected(){return o.getSnapshot().isConnected},get scenarioId(){return o.getSnapshot().scenarioId},get sessionMetadata(){return o.getSnapshot().sessionMetadata},start:s,get partial(){return o.getSnapshot().partial},get reconnect(){return o.getSnapshot().reconnect},get sessionId(){return l.getSessionId()},get status(){return o.getSnapshot().status},get turns(){return o.getSnapshot().turns},get assistantTexts(){return o.getSnapshot().assistantTexts},get assistantAudio(){return o.getSnapshot().assistantAudio},get call(){return o.getSnapshot().call},sendAudio(d){l.sendAudio(d)},simulateDisconnect(){l.simulateDisconnect()},subscribe(d){return e.add(d),()=>{e.delete(d)}}}};var K=(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 ac={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}},Pc={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 j=(c)=>{let n=c?.profile??"fast",l=c?.qualityProfile??"general",o=ac[n],i=Pc[l];return{profile:n,qualityProfile:l,silenceMs:c?.silenceMs??i.silenceMs??o.silenceMs,speechThreshold:c?.speechThreshold??i.speechThreshold??o.speechThreshold,transcriptStabilityMs:c?.transcriptStabilityMs??i.transcriptStabilityMs??o.transcriptStabilityMs}};var Nc={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"}}},k=(c="default")=>{let n=Nc[c];return{audioConditioning:K(n.audioConditioning),capture:{channelCount:n.capture?.channelCount??1,sampleRateHz:n.capture?.sampleRateHz??16000},connection:{...n.connection},name:c,sttLifecycle:n.sttLifecycle??"continuous",turnDetection:j(n.turnDetection)}};var Wc=(c)=>({assistantAudio:[...c.assistantAudio],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]}),F=(c,n={})=>{let l=k(n.preset),o=B(c,{...l.connection,...n.connection}),i=null,e=Wc(o),s=new Set,C=()=>{for(let t of s)t()},T=()=>{if(e={...e,assistantAudio:[...o.assistantAudio],assistantTexts:[...o.assistantTexts],call:o.call,error:o.error,isConnected:o.isConnected,partial:o.partial,reconnect:o.reconnect,sessionId:o.sessionId,sessionMetadata:o.sessionMetadata,scenarioId:o.scenarioId,status:o.status,turns:[...o.turns]},n.autoStopOnComplete!==!1&&e.status==="completed"&&e.isRecording)i?.stop(),i=null,e={...e,isRecording:!1};C()},S=o.subscribe(T);T();let d=()=>{if(i)return i;return i=H({channelCount:n.capture?.channelCount??l.capture.channelCount,onLevel:n.capture?.onLevel,onAudio:(t)=>{if(n.capture?.onAudio){n.capture.onAudio(t,o.sendAudio);return}o.sendAudio(t)},sampleRateHz:n.capture?.sampleRateHz??l.capture.sampleRateHz}),i},h=()=>{i?.stop(),i=null,e={...e,isRecording:!1},C()},A=async()=>{if(e.isRecording)return;try{e={...e,recordingError:null},C(),await d().start(),e={...e,isRecording:!0},C()}catch(t){throw i=null,e={...e,isRecording:!1,recordingError:t instanceof Error?t.message:String(t)},C(),t}};return{bindHTMX(t){return $(o,t)},callControl:(t)=>o.callControl(t),close:()=>{S(),h(),o.close()},endTurn:()=>o.endTurn(),get error(){return e.error},getServerSnapshot:()=>e,getSnapshot:()=>e,get isConnected(){return e.isConnected},get isRecording(){return e.isRecording},get partial(){return e.partial},get recordingError(){return e.recordingError},get reconnect(){return e.reconnect},sendAudio:(t)=>o.sendAudio(t),simulateDisconnect:()=>o.simulateDisconnect(),get sessionId(){return e.sessionId},get sessionMetadata(){return e.sessionMetadata},get scenarioId(){return e.scenarioId},startRecording:A,get status(){return e.status},stopRecording:h,subscribe:(t)=>{return s.add(t),()=>{s.delete(t)}},toggleRecording:async()=>{if(e.isRecording){h();return}await A()},get turns(){return e.turns},get assistantTexts(){return e.assistantTexts},get assistantAudio(){return e.assistantAudio},get call(){return e.call}}};var m=(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 $c={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},Hc={callEnded:"Call ended",connecting:"Connecting…",endCall:"End call",idle:"Idle",listening:"Listening",mute:"Mute",speaking:"Speaking",startCall:"Start call",thinking:"Thinking",unmute:"Unmute"},Gc=(c,n)=>{switch(c){case"listening":return n.listening;case"speaking":return n.speaking;case"thinking":return n.thinking;case"idle":return n.idle}},v=(c)=>{let n={...$c,...c.theme},l={...Hc,...c.labels},o=c.state.assistantAudio.at(-1)?.receivedAt,i=c.state.turns.at(-1)?.committedAt,e=m({hasActivePartial:c.state.partial.length>0,isConnected:c.state.isConnected,isPlaying:!1,isRecording:c.state.isRecording,lastAssistantAt:o,lastTranscriptAt:i}),s=!c.state.isConnected&&c.state.status!=="idle"&&!c.state.error,C=c.state.error?"Error":s?l.connecting:c.state.status==="completed"?l.callEnded:Gc(e,l);return{agentState:e,classes:{container:`absolute-voice-widget absolute-voice-widget--${e}`,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:l,partial:c.state.partial||void 0,statusLabel:C,theme:n,title:c.title??"Voice"}},L=(c)=>c.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;"),zc=(c)=>typeof c==="number"?`${c}px`:c,u=(c)=>{let n=c.theme,l=`background:${n.background};border-radius:${zc(n.radius)};color:${n.foreground};font-family:${n.fontFamily};min-width:240px;padding:20px 22px;`,o=`background:${c.errorMessage?n.errorAccent:c.agentState==="idle"?"rgba(148,163,184,0.6)":n.accent};border-radius:50%;height:10px;width:10px;`,i=[];if(c.controls.canStart)i.push(`<button type="button" data-action="start" style="background:${n.accent};border:none;border-radius:12px;color:${n.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${L(c.labels.startCall)}</button>`);if(c.controls.canMute)i.push(`<button type="button" data-action="mute" style="background:transparent;border:1px solid rgba(255,255,255,0.18);border-radius:12px;color:${n.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${L(c.labels.mute)}</button>`);if(c.controls.canEnd)i.push(`<button type="button" data-action="end" style="background:${n.errorAccent};border:none;border-radius:12px;color:${n.foreground};cursor:pointer;font-size:14px;font-weight:500;padding:10px 14px;">${L(c.labels.endCall)}</button>`);return`<div role="region" aria-live="polite" data-agent-state="${c.agentState}" class="${L(c.classes.container)}" style="${l}">
2
+ <div style="align-items:center;display:flex;gap:10px;margin-bottom:12px;">
3
+ <span aria-hidden="true" class="${L(c.classes.dot)}" style="${o}"></span>
4
+ <strong style="font-size:15px;">${L(c.title)}</strong>
5
+ <span style="font-size:13px;margin-left:auto;opacity:0.7;">${L(c.statusLabel)}</span>
6
+ </div>
7
+ ${c.partial?`<p style="font-size:13px;margin:8px 0 12px;opacity:0.85;word-break:break-word;">“${L(c.partial)}”</p>`:""}
8
+ <div style="display:flex;gap:10px;">${i.join("")}</div>
9
+ ${c.errorMessage?`<p style="color:${n.errorAccent};font-size:12px;margin-top:12px;">${L(c.errorMessage)}</p>`:""}
10
+ </div>`};var Xc=(c)=>{if(typeof c!=="string")return c;let n=document.querySelector(c);if(!n)throw Error(`AbsoluteVoice.mount: no element matches "${c}"`);return n},p=(c,n={})=>{let l=Xc(c),o=F(n.path??"/voice",n.controllerOptions),i=null,e=null,s=()=>{let T=v({...n.labels!==void 0?{labels:n.labels}:{},state:{assistantAudio:o.assistantAudio,error:o.error,isConnected:o.isConnected,isRecording:o.isRecording,partial:o.partial,status:o.status,turns:o.turns},...n.theme!==void 0?{theme:n.theme}:{},...n.title!==void 0?{title:n.title}:{}});l.innerHTML=u(T);for(let S of l.querySelectorAll("button[data-action]")){let d=S.dataset.action;S.addEventListener("click",()=>{if(d==="start")o.startRecording();else if(d==="mute")o.stopRecording();else if(d==="end")o.close()})}if(o.error&&o.error!==i)i=o.error,n.onError?.(o.error);if(o.status!==e)e=o.status,n.onStatusChange?.(o.status)},C=o.subscribe(s);if(s(),n.autoStart)o.startRecording();return{controller:o,async end(){await o.close()},mute(){o.stopRecording()},async start(){await o.startRecording()},unmount(){C(),o.close(),l.innerHTML=""}}},cc="0.0.22-beta.516",nc={mount:p,version:cc};if(typeof globalThis<"u")globalThis.AbsoluteVoice=nc;var qc=nc;})();
@@ -71,7 +71,7 @@ export declare const VoiceWidget: import("vue").DefineComponent<import("vue").Ex
71
71
  }>, {
72
72
  title: string;
73
73
  path: string;
74
+ labels: VoiceWidgetLabels;
74
75
  theme: VoiceWidgetTheme;
75
76
  controllerOptions: VoiceControllerOptions;
76
- labels: VoiceWidgetLabels;
77
77
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.515",
3
+ "version": "0.0.22-beta.516",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -160,7 +160,7 @@
160
160
  "bench:stt": "bun run ./scripts/benchmark-stt.ts all",
161
161
  "bench:assemblyai:sessions": "bun run ./scripts/benchmark-session.ts assemblyai",
162
162
  "bench:openai:sessions": "bun run ./scripts/benchmark-session.ts openai",
163
- "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 && tsc --emitDeclarationOnly --project tsconfig.json",
163
+ "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",
164
164
  "format": "prettier --write \"./**/*.{js,jsx,ts,tsx,json,md}\"",
165
165
  "lint": "eslint ./src",
166
166
  "release": "bun run format && bun run build && bun publish",
@@ -203,7 +203,13 @@
203
203
  "./testing": {
204
204
  "import": "./dist/testing/index.js",
205
205
  "types": "./dist/testing/index.d.ts"
206
- }
206
+ },
207
+ "./embed": {
208
+ "browser": "./dist/embed/index.js",
209
+ "import": "./dist/embed/index.js",
210
+ "types": "./dist/embed/index.d.ts"
211
+ },
212
+ "./embed/voice-widget.js": "./dist/embed/voice-widget.js"
207
213
  },
208
214
  "typesVersions": {
209
215
  "*": {
@@ -224,6 +230,9 @@
224
230
  ],
225
231
  "angular": [
226
232
  "dist/angular/index.d.ts"
233
+ ],
234
+ "embed": [
235
+ "dist/embed/index.d.ts"
227
236
  ]
228
237
  }
229
238
  },