@streamoji/aitwin 0.3.0 → 0.3.1
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/aitwin.cjs +3 -3
- package/dist/aitwin.js +1517 -1375
- package/dist/index.d.ts +51 -0
- package/package.json +1 -1
package/dist/aitwin.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const pt=require("react/jsx-runtime"),p=require("react"),Nn=require("@pipecat-ai/client-js"),Mt=require("@pipecat-ai/websocket-transport");var yt=typeof document<"u"?document.currentScript:null;const Un="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",cn={publicBase:Un},Vn="0.3.0",$n={version:Vn},Wn={},Ge="https://ai.aitwin.me",xt=`${cn.publicBase}/custom-faces`,Hn=`${cn.publicBase}/aitwin-workers/v${$n.version}/visemeDiffPreview.worker.js`;function qn(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:yt&&yt.tagName.toUpperCase()==="SCRIPT"&&yt.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Wn?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Hn}const Kn="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Pt="eng_a7f2b9c1",ct="eng_d4e8f3a2",xe="eng_c9b1e6d4",Ce=xe,un=new Set([ct,xe]),ln={[Pt]:"oculus_direct",[xe]:"oculus_direct",[ct]:"inworld_word"},qt={google:Pt,inworld:ct,cartesia:xe};function jn(e){return ln[e]}function Gn(e){return e===xe}function zn(e){if(e.ttsEngineId&&e.ttsEngineId in ln)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in qt?qt[t]:Ce}class st extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function fn(e,t=Kn){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new st;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const s=await r.json();if(!s.success)throw new st(s.error??"AI twin not found");const{tts:i,token:o,...a}=s.data,u=String(a.authToken??o??"").trim()||void 0;return{...a,ttsEngineId:zn(s.data),authToken:u}}const Yn="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Jn="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Qn="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Xn="6TNvp3SCs4Og0a1ijm9TommXLql1",Zn="Swaraj Mali";async function rt(){const e=await fetch(Yn,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Jn,"Client-Secret":Qn},body:JSON.stringify({userId:Xn,userName:Zn})});if(!e.ok)throw new Error(`getAuthToken failed (${e.status})`);const t=await e.json(),n=t.authToken??t.token??"";if(!n.trim())throw new Error("getAuthToken returned no token");return n}async function er(e,t=Ge){const n=await fetch(`${t.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${e}`}});if(!n.ok)throw new Error(`/api/session-value failed (${n.status})`);const r=await n.json();if(!r.value)throw new Error("Session value response missing value");return r}function tr(e){const t=e.trim();if(t.length%2!==0)throw new Error("Invalid hex key");const n=new Uint8Array(t.length/2);for(let r=0;r<t.length;r+=2)n[r/2]=Number.parseInt(t.slice(r,r+2),16);return n}function Ze(e){return Uint8Array.from(e)}function nr(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function rr(e,t){if(!t)throw new Error("Asset key is required for encrypted assets");if(e.byteLength<28)throw new Error("Encrypted payload too small");const n=new Uint8Array(e),r=Ze(n.subarray(0,12)),s=Ze(n.subarray(12,28)),i=Ze(n.subarray(28)),o=Ze(nr(i,s)),a=await crypto.subtle.importKey("raw",tr(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let vt=null;const Tt=new Set;function et(e){return e.includes("/custom-faces/")}function it(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||et(t)||et(n)))return{twinBase:n,binBase:t,encrypted:!1};const s=et(t)?t:et(n)?n:t;return{twinBase:s,binBase:s,encrypted:!0}}function Fe(e){return it(e).encrypted}function bt(e,t=xt){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function dn(e,t){return(e??t)?.trim()||void 0}function mn(e){vt=it(e);for(const t of Tt)t()}function sr(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return it(e);const r=s=>{try{return new URL(s,n).href.replace(/\/$/,"")}catch{return s}};return it({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function Pe(){if(!vt)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return vt}function ir(e){return Tt.add(e),()=>Tt.delete(e)}function Kt(){const e=Pe();return Fe(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function ar(){const e=Pe();return Fe(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function or(){const e=Pe();return Fe(e)?e.binBase:e.twinBase}function ut(){return Fe(Pe())}function cr(){const e=Pe();return Fe(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function ur(){const e=Pe();return Fe(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function hn(e){const t=e.split(/\r?\n/);let n="",r="";for(const i of t)i.startsWith("event:")?n=i.slice(6).trim():i.startsWith("data:")&&(r=i.slice(5).trim());if(!n)return null;let s={};if(r)try{s=JSON.parse(r)}catch{s={raw:r}}return{event:n,data:s}}const wn=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],lr=new Map(wn.map(e=>[e.toLowerCase(),e]));function _n(e){const t=(e??"").trim();return t?lr.get(t.toLowerCase())??"sil":"sil"}const fr={aei:["aa","E","I"],o:["O","U"],ee:["I"],bmp:["PP"],fv:["FF"],l:["nn"],r:["RR"],th:["TH"],qw:["U","O"],cdgknstxyz:["DD","SS","kk","CH"]};function dr(e){if(!e)return["sil"];const t=e.toLowerCase();return fr[t]??["sil"]}function mr(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(s*n))}function lt(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function hr(e,t){const n=e.toLowerCase(),r=lt(n,t),s=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":s.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function wr(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";const s=lt(n,t);return s==="u"||s==="w"?"U":"O"}function _r(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const s=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(s)||lt(n,t)==="o"?"O":"U"}const tt={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function gr(e,t){const n=e.toLowerCase(),r=lt(n,t);if(tt[r])return tt[r];for(let s=0;s<n.length;s++){const i=n[s];if(tt[i])return tt[i]}return"DD"}function pr(e,t,n){const r=dr(e);if(r.length===1)return r[0];const s=t.trim();if(!s)return r[0];const i=(e??"").toLowerCase(),o=Math.max(0,n);switch(i){case"aei":return hr(s,o);case"o":return wr(s,o);case"qw":return _r(s,o);case"cdgknstxyz":return gr(s,o);default:return r[0]}}const Bt=16e3;function gn(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Bt}function yr(e){let t=e.trim();const n=t.indexOf(",");t.startsWith("data:")&&n>=0&&(t=t.slice(n+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const r=t.length%4;return r!==0&&(t+="=".repeat(4-r)),t}function Sr(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function jt(e,t,n=Bt){const r=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),i=new Float32Array(s.length);for(let a=0;a<s.length;a++)i[a]=s[a]>=32768?-(65536-s[a])/32768:s[a]/32767;const o=e.createBuffer(1,i.length,n);return o.copyToChannel(i,0),o}function Er(e){const t=yr(e),n=window.atob(t),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);return r}async function kr(e,t,n=Bt){const r=Er(t),s=gn(n);if(Sr(r)){const i=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(i)}if(r.length>=2&&r.length%2===0)return jt(e,r,s);try{const i=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(i)}catch{return jt(e,r,s)}}function We(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function vr(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function pn(e,t){const n=[],r=[];let s=null,i=!1,o=!1,a=!1,u=!1,l=0,h=0,S=0,_=0,b=null,k=1,f=t,g=!1,d=null,E=0;const v=()=>{b!=null&&(clearTimeout(b),b=null)},N=()=>{for(const m of r){try{m.onended=null,m.stop(0)}catch{}try{m.disconnect()}catch{}}r.length=0},J=()=>{for(const m of r)m.playbackRate.value=k},P=()=>{if(!(g||!u||i||r.length>0||n.length>0)){if(a&&s&&h>0){const m=(s.currentTime-h)*1e3;if(m<E){v();const C=k>0?(E-m)/k:E-m;b=setTimeout(()=>{g||(o=!1,b=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,C));return}}o=!1,v(),e.onSpeakingDone(),e.onNotify()}},z=m=>{const C=We(m);if(C<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,l=performance.now(),e.onSpeakingStart(),e.onNotify(),v();const M=k>0?C/k:C;b=setTimeout(()=>{g||(o=!1,b=null,e.onSpeakingDone(),e.onNotify())},M)},H=(m,C,M,V)=>{C.length!==0&&(V&&(S=M),C.forEach(A=>{const Y=String(A.word??"").trim();if(!Y)return;const Q=Math.round((A.start??0)*1e3),W=A.duration!=null?Math.round(A.duration*1e3):A.end!=null?Math.max(1,Math.round((A.end-(A.start??0))*1e3)):0;m.push({word:Y,wtime:S+Q,wduration:W,queueIndex:m.length,gesture:A.gesture??null,emphasis:A.emphasis===!0})}))},T=(m,C,M,V,A,q)=>{M.length!==0&&(A&&(S=V),M.forEach(Y=>{const Q=String(Y.symbol??Y.viseme??"").trim();if(!Q)return;const W=Math.round((Y.start??0)*1e3),K=Math.max(1,Math.round((Y.duration??0)*1e3)),Z=S+W;let fe;if(jn(q)==="oculus_direct")fe=_n(Q);else{const oe=vr(C,Z),ee=oe?mr(oe,Z):0;fe=pr(Q,oe?.word??"",ee)}m.push({viseme:fe,weight:1,vtime:Z,vduration:K})}),e.onNotify())},I=(m,C,M,V,A,q,Y)=>{H(C,V,A,q),T(m,C,M,A,q,Y)},R=async(m,C,M,V,A,q,Y)=>{if(g||!M?.trim())return;const Q=gn(Y?.sampleRate),W=Y?.newStream===!0;if(i){n.push({audio:M,visemes:V,words:A,isNewSegment:q,sampleRate:Q,newStream:W});return}i=!0;try{const K=window.AudioContext||window.webkitAudioContext;s||(s=new K);const Z=s;Z.state==="suspended"&&await Z.resume(),d||(d=Z.createMediaStreamDestination());const fe=await kr(Z,M,Q);a=!0;const oe=Z.currentTime;let ee=_;const de=!o;ee<oe&&(ee=oe+.1),_=ee+fe.duration;const ce=Z.createBufferSource();if(ce.buffer=fe,ce.playbackRate.value=k,ce.connect(Z.destination),d&&ce.connect(d),r.push(ce),g){r.pop();return}if(de){o=!0,e.onSpeakingStart(),W?(h=ee,S=0,E=0,m.length=0,C.length=0,Y?.onNewStream?.()):h<=0&&(h=ee);const _e=(ee-oe)*1e3;l=performance.now()+_e}ce.onended=()=>{const _e=r.indexOf(ce);_e>=0&&r.splice(_e,1),P(),e.onNotify()},ce.start(ee);const Ne=(ee-h)*1e3;I(m,C,V,A,Ne,q,f),E=Math.max(E,We(m))}catch(K){console.error("[avatarChunkPlayback] audio chunk failed:",K)}finally{if(i=!1,g)return;const K=n.shift();K?await R(m,C,K.audio,K.visemes,K.words,K.isNewSegment,{sampleRate:K.sampleRate,newStream:K.newStream,onNewStream:Y?.onNewStream}):P()}};return{setStreamTtsEngineId:m=>{f=m},setPlaybackSpeed:m=>{k=Math.max(.1,Math.min(1,m)),J()},getPlaybackSpeed:()=>k,resetForNewStream:m=>{g=!1,u=!1,f=m,E=0},resumeBotStream:()=>{u=!1},primeAudioContext:async()=>{const m=window.AudioContext||window.webkitAudioContext;s||(s=new m),s.state==="suspended"&&await s.resume(),s&&!d&&(d=s.createMediaStreamDestination())},stop:()=>{g=!0,v(),N(),n.length=0,i=!1,o=!1,a=!1,u=!1,S=0,_=0,h=0,l=0,E=0},markStreamComplete:m=>{if(E=Math.max(E,We(m)),u=!0,!a&&m.length>0){z(m);return}P()},playAudioChunk:R,queueTimingsOnly:(m,C,M,V,A)=>{if(g)return;let q=S;A&&m.length>0&&(q=We(m)),I(m,C,M,V,q,A,f),E=Math.max(E,We(m))},getPlaybackElapsedMs:()=>a&&s&&h>0?Math.max(0,(s.currentTime-h)*1e3):o?Math.max(0,(performance.now()-l)*k):0,isSpeaking:()=>o?!0:!a||!s||h<=0?!1:(s.currentTime-h)*1e3<E,getVoiceStream:()=>d?d.stream:null,getPlaybackStartPerf:()=>l,bargeIn:()=>{g=!0,u=!1,v(),N(),n.length=0,i=!1,o=!1,a=!1,S=0,_=0,h=0,l=0,E=0},interrupt:()=>{g=!0,u=!1,v(),N(),n.length=0,i=!1,o=!1,a=!1,S=0,_=0,h=0,l=0,E=0}}}function ze(e,t){let n=null;for(const r of e)t<r.vtime||t>=r.vtime+r.vduration||(!n||r.vtime>=n.vtime)&&(n=r);return n?n.viseme:"sil"}function Tr(e,t,n=120){const r=ze(e,t);if(r!=="sil")return r;let s=null;for(const i of e){if(i.vtime>t)break;const o=i.vtime+i.vduration;o<=t&&t-o<=n&&(s=i)}return s?.viseme??"sil"}function br(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}const ft=.5,dt=1.5,Lt="Olivia",Ot="f786b574-daa5-4673-aa0c-cbe3e8534c02",Ye=.85;function At(e,t=Ge){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],i=[];let o="neutral",a="",u=Ce;const l=new Set,h=()=>l.forEach(k=>k()),S=pn({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:h},Ce),_=()=>{S.stop(),r.length=0,s.length=0,i.length=0,o="neutral",e("idle"),h()};return{setDeveloperToken:k=>{a=k},setTtsEngineId:k=>{u=k},getTtsEngineId:()=>u,speak:async(k,f)=>{_(),e("loading");const g=a.trim();if(!g)throw new Error("Developer token required for avatar_ttsWithPoses");const d=f?.ttsEngineId??u??Ce;S.resetForNewStream(d),S.setStreamTtsEngineId(d);const E=f?.voiceId??Lt,v=f?.speakingRate??Ye,N=Math.max(ft,Math.min(dt,v)),J={user_query:k,ttsEngineId:d,speakingRate:N,tenant:"aiTwin"};un.has(d)&&(J.voice_id=E);try{const P=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${g}`},body:JSON.stringify(J)});if(!P.ok)throw new Error(`avatar_ttsWithPoses failed (${P.status})`);const z=P.body;if(!z)throw new Error("No response body");const H=z.getReader(),T=new TextDecoder;let I="";const R=async x=>{const m=hn(x);if(m){if(m.event==="audio"){const C=m.data.chunk,M=m.data.visemes??[],V=m.data.words??[],A=m.data.is_new_segment??!1,q=m.data.sample_rate;C?await S.playAudioChunk(r,s,C,M,V,A,{sampleRate:q}):(M.length>0||V.length>0)&&S.queueTimingsOnly(r,s,M,V,A)}else if(m.event==="metadata"){const C=m.data.mood;typeof C=="string"&&C.trim()&&(o=C.trim());const M=m.data.sentence_emotions;if(Array.isArray(M)){i.length=0;for(const V of M){if(!V||typeof V!="object")continue;const A=V;i.push({sentence_index:Number(A.sentence_index??0),text:String(A.text??""),sentiment:typeof A.sentiment=="string"?A.sentiment:void 0,emotion:String(A.emotion??o),start_word:Number(A.start_word??0),end_word:Number(A.end_word??0)})}}h()}else if(m.event==="error")throw new Error(String(m.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:x,value:m}=await H.read();m&&(I+=T.decode(m,{stream:!0}));const C=I.split(`
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const vt=require("react/jsx-runtime"),y=require("react"),Jn=require("@pipecat-ai/client-js"),Lt=require("@pipecat-ai/websocket-transport");var Tt=typeof document<"u"?document.currentScript:null;const Xn="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",Sn={publicBase:Xn},Zn="0.3.1",er={version:Zn},tr={},Je="https://ai.aitwin.me",Ot=`${Sn.publicBase}/custom-faces`,nr=`${Sn.publicBase}/aitwin-workers/v${er.version}/visemeDiffPreview.worker.js`;function rr(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Tt&&Tt.tagName.toUpperCase()==="SCRIPT"&&Tt.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?tr?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():nr}const sr="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Nt="eng_a7f2b9c1",mt="eng_d4e8f3a2",xe="eng_c9b1e6d4",Me=xe,kn=new Set([mt,xe]),En={[Nt]:"oculus_direct",[xe]:"oculus_direct",[mt]:"inworld_word"},en={google:Nt,inworld:mt,cartesia:xe};function ir(e){return En[e]}function ar(e){return e===xe}function or(e){if(e.ttsEngineId&&e.ttsEngineId in En)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in en?en[t]:Me}class ct extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function vn(e,t=sr){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new ct;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const s=await r.json();if(!s.success)throw new ct(s.error??"AI twin not found");const{tts:i,token:o,...a}=s.data,l=String(a.authToken??o??"").trim()||void 0;return{...a,ttsEngineId:or(s.data),authToken:l}}const cr="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",ur="client_6TNvp3SCs4Og0a1ijm9TommXLql1",lr="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",fr="6TNvp3SCs4Og0a1ijm9TommXLql1",dr="Swaraj Mali";async function ot(){const e=await fetch(cr,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":ur,"Client-Secret":lr},body:JSON.stringify({userId:fr,userName:dr})});if(!e.ok)throw new Error(`getAuthToken failed (${e.status})`);const t=await e.json(),n=t.authToken??t.token??"";if(!n.trim())throw new Error("getAuthToken returned no token");return n}async function mr(e,t=Je){const n=await fetch(`${t.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${e}`}});if(!n.ok)throw new Error(`/api/session-value failed (${n.status})`);const r=await n.json();if(!r.value)throw new Error("Session value response missing value");return r}function hr(e){const t=e.trim();if(t.length%2!==0)throw new Error("Invalid hex key");const n=new Uint8Array(t.length/2);for(let r=0;r<t.length;r+=2)n[r/2]=Number.parseInt(t.slice(r,r+2),16);return n}function rt(e){return Uint8Array.from(e)}function wr(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function gr(e,t){if(!t)throw new Error("Asset key is required for encrypted assets");if(e.byteLength<28)throw new Error("Encrypted payload too small");const n=new Uint8Array(e),r=rt(n.subarray(0,12)),s=rt(n.subarray(12,28)),i=rt(n.subarray(28)),o=rt(wr(i,s)),a=await crypto.subtle.importKey("raw",hr(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let Rt=null;const Dt=new Set;function st(e){return e.includes("/custom-faces/")}function ut(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||st(t)||st(n)))return{twinBase:n,binBase:t,encrypted:!1};const s=st(t)?t:st(n)?n:t;return{twinBase:s,binBase:s,encrypted:!0}}function Oe(e){return ut(e).encrypted}function Mt(e,t=Ot){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Tn(e,t){return(e??t)?.trim()||void 0}function bn(e){Rt=ut(e);for(const t of Dt)t()}function pr(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return ut(e);const r=s=>{try{return new URL(s,n).href.replace(/\/$/,"")}catch{return s}};return ut({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function Pe(){if(!Rt)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Rt}function _r(e){return Dt.add(e),()=>Dt.delete(e)}function tn(){const e=Pe();return Oe(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function yr(){const e=Pe();return Oe(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Sr(){const e=Pe();return Oe(e)?e.binBase:e.twinBase}function ht(){return Oe(Pe())}function kr(){const e=Pe();return Oe(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function Er(){const e=Pe();return Oe(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function An(e){const t=e.split(/\r?\n/);let n="",r="";for(const i of t)i.startsWith("event:")?n=i.slice(6).trim():i.startsWith("data:")&&(r=i.slice(5).trim());if(!n)return null;let s={};if(r)try{s=JSON.parse(r)}catch{s={raw:r}}return{event:n,data:s}}const In=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],vr=new Map(In.map(e=>[e.toLowerCase(),e]));function Rn(e){const t=(e??"").trim();return t?vr.get(t.toLowerCase())??"sil":"sil"}const Tr={aei:["aa","E","I"],o:["O","U"],ee:["I"],bmp:["PP"],fv:["FF"],l:["nn"],r:["RR"],th:["TH"],qw:["U","O"],cdgknstxyz:["DD","SS","kk","CH"]};function br(e){if(!e)return["sil"];const t=e.toLowerCase();return Tr[t]??["sil"]}function Ar(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(s*n))}function wt(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function Ir(e,t){const n=e.toLowerCase(),r=wt(n,t),s=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":s.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function Rr(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";const s=wt(n,t);return s==="u"||s==="w"?"U":"O"}function Dr(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const s=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(s)||wt(n,t)==="o"?"O":"U"}const it={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function Mr(e,t){const n=e.toLowerCase(),r=wt(n,t);if(it[r])return it[r];for(let s=0;s<n.length;s++){const i=n[s];if(it[i])return it[i]}return"DD"}function Cr(e,t,n){const r=br(e);if(r.length===1)return r[0];const s=t.trim();if(!s)return r[0];const i=(e??"").toLowerCase(),o=Math.max(0,n);switch(i){case"aei":return Ir(s,o);case"o":return Rr(s,o);case"qw":return Dr(s,o);case"cdgknstxyz":return Mr(s,o);default:return r[0]}}const Ut=16e3;function Dn(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Ut}function xr(e){let t=e.trim();const n=t.indexOf(",");t.startsWith("data:")&&n>=0&&(t=t.slice(n+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const r=t.length%4;return r!==0&&(t+="=".repeat(4-r)),t}function Pr(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function nn(e,t,n=Ut){const r=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),i=new Float32Array(s.length);for(let a=0;a<s.length;a++)i[a]=s[a]>=32768?-(65536-s[a])/32768:s[a]/32767;const o=e.createBuffer(1,i.length,n);return o.copyToChannel(i,0),o}function Fr(e){const t=xr(e),n=window.atob(t),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);return r}async function Br(e,t,n=Ut){const r=Fr(t),s=Dn(n);if(Pr(r)){const i=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(i)}if(r.length>=2&&r.length%2===0)return nn(e,r,s);try{const i=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(i)}catch{return nn(e,r,s)}}function Ge(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function Lr(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Mn(e,t){const n=[],r=[];let s=null,i=!1,o=!1,a=!1,l=!1,f=0,u=0,_=0,m=0,p=null,v=1,d=t,S=!1,h=null,T=0;const b=()=>{p!=null&&(clearTimeout(p),p=null)},V=()=>{for(const g of r){try{g.onended=null,g.stop(0)}catch{}try{g.disconnect()}catch{}}r.length=0},Q=()=>{for(const g of r)g.playbackRate.value=v},U=()=>{if(!(S||!l||i||r.length>0||n.length>0)){if(a&&s&&u>0){const g=(s.currentTime-u)*1e3;if(g<T){b();const M=v>0?(T-g)/v:T-g;p=setTimeout(()=>{S||(o=!1,p=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,M));return}}o=!1,b(),e.onSpeakingDone(),e.onNotify()}},j=g=>{const M=Ge(g);if(M<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,f=performance.now(),e.onSpeakingStart(),e.onNotify(),b();const O=v>0?M/v:M;p=setTimeout(()=>{S||(o=!1,p=null,e.onSpeakingDone(),e.onNotify())},O)},X=(g,M,O,F)=>{M.length!==0&&(F&&(_=O),M.forEach(A=>{const z=String(A.word??"").trim();if(!z)return;const Z=Math.round((A.start??0)*1e3),re=A.duration!=null?Math.round(A.duration*1e3):A.end!=null?Math.max(1,Math.round((A.end-(A.start??0))*1e3)):0;g.push({word:z,wtime:_+Z,wduration:re,queueIndex:g.length,gesture:A.gesture??null,emphasis:A.emphasis===!0})}))},k=(g,M,O,F,A,$)=>{O.length!==0&&(A&&(_=F),O.forEach(z=>{const Z=String(z.symbol??z.viseme??"").trim();if(!Z)return;const re=Math.round((z.start??0)*1e3),L=Math.max(1,Math.round((z.duration??0)*1e3)),K=_+re;let le;if(ir($)==="oculus_direct")le=Rn(Z);else{const fe=Lr(M,K),ie=fe?Ar(fe,K):0;le=Cr(Z,fe?.word??"",ie)}g.push({viseme:le,weight:1,vtime:K,vduration:L})}),e.onNotify())},I=(g,M,O,F,A,$,z)=>{X(M,F,A,$),k(g,M,O,A,$,z)},C=async(g,M,O,F,A,$,z)=>{if(S||!O?.trim())return;const Z=Dn(z?.sampleRate),re=z?.newStream===!0;if(i){n.push({audio:O,visemes:F,words:A,isNewSegment:$,sampleRate:Z,newStream:re});return}i=!0;try{const L=window.AudioContext||window.webkitAudioContext;s||(s=new L);const K=s;K.state==="suspended"&&await K.resume(),h||(h=K.createMediaStreamDestination());const le=await Br(K,O,Z);a=!0;const fe=K.currentTime;let ie=m;const we=!o;ie<fe&&(ie=fe+.1),m=ie+le.duration;const ee=K.createBufferSource();if(ee.buffer=le,ee.playbackRate.value=v,ee.connect(K.destination),h&&ee.connect(h),r.push(ee),S){r.pop();return}if(we){o=!0,e.onSpeakingStart(),re?(u=ie,_=0,T=0,g.length=0,M.length=0,z?.onNewStream?.()):u<=0&&(u=ie);const _e=(ie-fe)*1e3;f=performance.now()+_e}ee.onended=()=>{const _e=r.indexOf(ee);_e>=0&&r.splice(_e,1),U(),e.onNotify()},ee.start(ie);const Fe=(ie-u)*1e3;I(g,M,F,A,Fe,$,d),T=Math.max(T,Ge(g))}catch(L){console.error("[avatarChunkPlayback] audio chunk failed:",L)}finally{if(i=!1,S)return;const L=n.shift();L?await C(g,M,L.audio,L.visemes,L.words,L.isNewSegment,{sampleRate:L.sampleRate,newStream:L.newStream,onNewStream:z?.onNewStream}):U()}};return{setStreamTtsEngineId:g=>{d=g},setPlaybackSpeed:g=>{v=Math.max(.1,Math.min(1,g)),Q()},getPlaybackSpeed:()=>v,resetForNewStream:g=>{S=!1,l=!1,d=g,T=0},resumeBotStream:()=>{l=!1},primeAudioContext:async()=>{const g=window.AudioContext||window.webkitAudioContext;s||(s=new g),s.state==="suspended"&&await s.resume(),s&&!h&&(h=s.createMediaStreamDestination())},stop:()=>{S=!0,b(),V(),n.length=0,i=!1,o=!1,a=!1,l=!1,_=0,m=0,u=0,f=0,T=0},markStreamComplete:g=>{if(T=Math.max(T,Ge(g)),l=!0,!a&&g.length>0){j(g);return}U()},playAudioChunk:C,queueTimingsOnly:(g,M,O,F,A)=>{if(S)return;let $=_;A&&g.length>0&&($=Ge(g)),I(g,M,O,F,$,A,d),T=Math.max(T,Ge(g))},getPlaybackElapsedMs:()=>a&&s&&u>0?Math.max(0,(s.currentTime-u)*1e3):o?Math.max(0,(performance.now()-f)*v):0,isSpeaking:()=>o?!0:!a||!s||u<=0?!1:(s.currentTime-u)*1e3<T,getVoiceStream:()=>h?h.stream:null,getPlaybackStartPerf:()=>f,bargeIn:()=>{S=!0,l=!1,b(),V(),n.length=0,i=!1,o=!1,a=!1,_=0,m=0,u=0,f=0,T=0},interrupt:()=>{S=!0,l=!1,b(),V(),n.length=0,i=!1,o=!1,a=!1,_=0,m=0,u=0,f=0,T=0}}}function Xe(e,t){let n=null;for(const r of e)t<r.vtime||t>=r.vtime+r.vduration||(!n||r.vtime>=n.vtime)&&(n=r);return n?n.viseme:"sil"}function Or(e,t,n=120){const r=Xe(e,t);if(r!=="sil")return r;let s=null;for(const i of e){if(i.vtime>t)break;const o=i.vtime+i.vduration;o<=t&&t-o<=n&&(s=i)}return s?.viseme??"sil"}function Nr(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}const gt=.5,pt=1.5,Vt="Olivia",$t="f786b574-daa5-4673-aa0c-cbe3e8534c02",Ze=.85;function Ct(e,t=Je){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],i=[];let o="neutral",a="",l=Me;const f=new Set,u=()=>f.forEach(v=>v()),_=Mn({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:u},Me),m=()=>{_.stop(),r.length=0,s.length=0,i.length=0,o="neutral",e("idle"),u()};return{setDeveloperToken:v=>{a=v},setTtsEngineId:v=>{l=v},getTtsEngineId:()=>l,speak:async(v,d)=>{m(),e("loading");const S=a.trim();if(!S)throw new Error("Developer token required for avatar_ttsWithPoses");const h=d?.ttsEngineId??l??Me;_.resetForNewStream(h),_.setStreamTtsEngineId(h);const T=d?.voiceId??Vt,b=d?.speakingRate??Ze,V=Math.max(gt,Math.min(pt,b)),Q={user_query:v,ttsEngineId:h,speakingRate:V,tenant:"aiTwin"};kn.has(h)&&(Q.voice_id=T);try{const U=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${S}`},body:JSON.stringify(Q)});if(!U.ok)throw new Error(`avatar_ttsWithPoses failed (${U.status})`);const j=U.body;if(!j)throw new Error("No response body");const X=j.getReader(),k=new TextDecoder;let I="";const C=async R=>{const g=An(R);if(g){if(g.event==="audio"){const M=g.data.chunk,O=g.data.visemes??[],F=g.data.words??[],A=g.data.is_new_segment??!1,$=g.data.sample_rate;M?await _.playAudioChunk(r,s,M,O,F,A,{sampleRate:$}):(O.length>0||F.length>0)&&_.queueTimingsOnly(r,s,O,F,A)}else if(g.event==="metadata"){const M=g.data.mood;typeof M=="string"&&M.trim()&&(o=M.trim());const O=g.data.sentence_emotions;if(Array.isArray(O)){i.length=0;for(const F of O){if(!F||typeof F!="object")continue;const A=F;i.push({sentence_index:Number(A.sentence_index??0),text:String(A.text??""),sentiment:typeof A.sentiment=="string"?A.sentiment:void 0,emotion:String(A.emotion??o),start_word:Number(A.start_word??0),end_word:Number(A.end_word??0)})}}u()}else if(g.event==="error")throw new Error(String(g.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:R,value:g}=await X.read();g&&(I+=k.decode(g,{stream:!0}));const M=I.split(`
|
|
2
2
|
|
|
3
|
-
`);I=
|
|
3
|
+
`);I=M.pop()??"";for(const O of M)await C(O);if(R){I.trim()&&await C(I.trim()),_.markStreamComplete(r);break}}}catch(U){throw console.error("[avatarTtsLipsync]",U),m(),e("error"),U}},stop:m,getVisemeQueue:()=>r,getWordQueue:()=>s,getSentenceEmotions:()=>i,getStreamMood:()=>o,getPlaybackElapsedMs:()=>_.getPlaybackElapsedMs(),isSpeaking:()=>_.isSpeaking(),getVoiceStream:()=>_.getVoiceStream(),setPlaybackSpeed:v=>{_.setPlaybackSpeed(v)},getPlaybackSpeed:()=>_.getPlaybackSpeed(),subscribe:v=>(f.add(v),()=>f.delete(v))}}const Wt=16e3,qt=16e3;class Ur extends Lt.ProtobufFrameSerializer{async deserialize(t){try{return await super.deserialize(t)}catch(n){if(n instanceof Error&&n.message==="Unknown frame kind")return{type:"raw",message:null};throw n}}}class Vr extends Lt.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,Wt,qt)}bufferBotAudio(t,n){}}const $r=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Wr(e){return $r.test(e.trim())}function qr(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function Cn(e){if(e.wsUrl?.trim())return e.wsUrl.trim();const t=e.authToken?.trim();if(!t)throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");const n=e.apiBase??Je,r=new URL(`${qr(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const s=e.voiceId?.trim();s&&Wr(s)&&r.searchParams.set("voiceId",s);const i=e.personaId?.trim();i&&r.searchParams.set("personaId",i);const o=e.speakingRate??Ze;return r.searchParams.set("speaking_rate",String(Math.max(gt,Math.min(pt,o)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),r.toString()}function bt(e,t){if(!Array.isArray(e))return[];const n=[];for(const r of e)!r||typeof r!="object"||n.push({sentence_index:Number(r.sentence_index??0),text:String(r.text??""),sentiment:typeof r.sentiment=="string"?r.sentiment:void 0,emotion:String(r.emotion??t),start_word:Number(r.start_word??0),end_word:Number(r.end_word??0)});return n}function Hr(e){if(!e||typeof e!="object")return null;const t=e,r=(t.data&&typeof t.data=="object"&&!Array.isArray(t.data)?t.data:null)||t;return{...r,type:String(r.type??t.type??"server-message")}}function At(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function Kr(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function xn(e,t={}){const n=[],r=[],s=[],i=[];let o="",a="neutral",l=xe,f=!1,u=null,_=null,m={...t},p=0,v=null;const d=new Set,S=[];let h=!1,T=null,b=!0,V="default";const Q=new Set;let U=null,j=0,X=!1,k=null;const I=()=>{k!=null&&(clearTimeout(k),k=null)},C=()=>d.forEach(c=>c()),R=Mn({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:C},l),g=()=>{if(T)return T;const c=new MessageChannel;return c.port1.onmessage=()=>{const E=S.shift();E!==void 0&&Ne(E),S.length>0?c.port2.postMessage(null):h=!1},T=c,c},M=c=>{S.push(c),!h&&(h=!0,g().port2.postMessage(null))},O=()=>R.getPlaybackElapsedMs(),F=(c,E=o)=>{if(!m.onLipsyncDebug)return;const P=O(),G=n;m.onLipsyncDebug({event:c,spokenText:E,mood:a,playbackAnchorPerf:R.getPlaybackStartPerf(),playbackElapsedMs:P,queueLength:G.length,activeViseme:Xe(G,P),segments:i.map(te=>({...te,visemes:[...te.visemes]}))})},A=(c,E)=>{m.onLipsyncDebug&&(v={event:c,spokenText:E},p===0&&(p=requestAnimationFrame(()=>{p=0;const P=v;v=null,P&&F(P.event,P.spokenText)})))},$=()=>{b=!0,Q.clear()},z=()=>{const c=Kr(u);if(c){V=`bot-${Date.now()}`,c.interruptedTrackIds={[V]:!0};try{c.interrupt?.()}catch{}}const E=_;try{E?.interrupt?.()}catch{}},Z=c=>{const E=c.context_id?.trim();return E&&Q.has(E)?!0:b?!1:!(c.type==="avatar_metadata"||At(c))},re=c=>{b=!1;const E=c.context_id?.trim();E&&Q.add(E),I(),X=!1,S.length=0,h=!1,U?.abort(),U=null,j+=1,z(),R.bargeIn(),L(),e("idle"),A("interrupt"),C()},L=()=>{n.length=0,r.length=0,i.length=0,o="",a="neutral",s.length=0},K=()=>{R.stop(),L(),A("reset"),C()},le=()=>{K(),e("idle"),C()},fe=(c,E)=>{typeof c.mood=="string"&&c.mood.trim()&&(a=c.mood.trim()),Array.isArray(c.sentence_emotions)&&c.sentence_emotions.length>0&&(E&&(s.length=0),s.push(...bt(c.sentence_emotions,a)))},ie=c=>{if(Z({...c,type:"avatar_metadata"}))return;$(),X=!0;const E=String(c.spoken_text??c.text??"").trim();E&&(o=E),R.resetForNewStream(l),typeof c.mood=="string"&&c.mood.trim()&&(a=c.mood.trim()),s.length=0,s.push(...bt(c.sentence_emotions,a)),Array.isArray(c.gestures)&&c.gestures,A("metadata",E),C()},we=(c,E,P,G)=>{if(!m.onLipsyncDebug)return;const te=n.slice(P),Se=G.filter(se=>String(se.symbol??se.viseme??"").trim());i.push({spokenText:E,audioOffsetMs:te[0]?.vtime??0,isNewSegment:!!c.is_new_segment,chunkDurationMs:c.chunk_duration_ms!=null?Number(c.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:te.map((se,Y)=>{const ge=Se[Y];return{rawSymbol:String(ge?.symbol??ge?.viseme??se.viseme).trim(),viseme:se.viseme,startSec:Number(ge?.start??0),durationSec:Number(ge?.duration??0),vtimeMs:se.vtime,vdurationMs:se.vduration}})})},ee=c=>{if(Z(c))return;I(),At(c)&&$();const E=String(c.spoken_text??c.text??"").trim(),P=At(c),G=c.visemes??[],te=c.words??[],Se=String(c.chunk??"").trim(),se=X;se&&(X=!1),E&&(o=E),fe(c,P),se?R.resetForNewStream(l):P&&R.resumeBotStream();const Y=n.length;R.playAudioChunk(n,r,Se,G,te,P,{sampleRate:c.sample_rate,newStream:se,onNewStream:()=>{i.length=0}}).then(()=>{we(c,E,Y,G),A("audio_chunk",E)})},Fe=c=>{if(Z(c))return;(c.is_new_segment||Number(c.audio_offset_ms??-1)===0)&&$(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const E=String(c.spoken_text??c.text??"").trim();E&&(o=E),fe(c,!!c.is_new_segment);const P=n.length;R.queueTimingsOnly(n,r,c.visemes??[],c.words??[],!!c.is_new_segment),we(c,E,P,c.visemes??[]),A("lipsync",E),C()},_e=async c=>{const E=String(c.text??"").trim();if(!E)return;const P=m.authToken?.trim();if(!P){console.error("[realtimeVoice] avatar_speak requires authToken");return}U?.abort();const G=new AbortController;U=G;const te=++j;$(),R.resetForNewStream(l),o=E;const se=`${(m.apiBase??Je).replace(/\/$/,"")}/avatar_ttsWithPoses`,Y=m.voiceId?.trim()||$t,ge=m.speakingRate??Ze,tt=Math.max(gt,Math.min(pt,ge)),Ve={user_query:E,ttsEngineId:l,speakingRate:tt,tenant:"aiTwin"};kn.has(l)&&(Ve.voice_id=Y);try{const ke=await fetch(se,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${P}`},body:JSON.stringify(Ve),signal:G.signal});if(!ke.ok)throw new Error(`avatar_ttsWithPoses failed (${ke.status})`);const $e=ke.body;if(!$e)throw new Error("No response body");const Ae=$e.getReader(),nt=new TextDecoder;let ae="";const Ee=async q=>{if(te!==j||G.signal.aborted||!b)return;const x=An(q);if(x){if(x.event==="audio"){const de=x.data.chunk,J=x.data.visemes??[],ue=x.data.words??[],We=x.data.is_new_segment??!1,Ie=x.data.sample_rate;de?await R.playAudioChunk(n,r,de,J,ue,We,{sampleRate:Ie}):(J.length>0||ue.length>0)&&R.queueTimingsOnly(n,r,J,ue,We)}else if(x.event==="metadata"){const de=x.data.mood;typeof de=="string"&&de.trim()&&(a=de.trim());const J=x.data.sentence_emotions;Array.isArray(J)&&(s.length=0,s.push(...bt(J,a))),C()}else if(x.event==="error")throw new Error(String(x.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(te!==j||G.signal.aborted||!b);){const{done:q,value:x}=await Ae.read();x&&(ae+=nt.decode(x,{stream:!0}));const de=ae.split(`
|
|
4
4
|
|
|
5
|
-
`);re=se.pop()??"";for(const me of se)await Ve(me);if(Se){re.trim()&&await Ve(re.trim()),te===z&&!L.signal.aborted&&v&&x.markStreamComplete(n);break}}}catch($){if(L.signal.aborted||!v)return;console.error("[realtimeVoice] avatar_speak failed:",$),e("error"),R()}finally{P===L&&(P=null)}},Je=c=>{const y=Mr(c);if(!y){console.warn("[realtimeVoice] server message with no payload",c);return}const B=String(y.type??"unknown");switch(B!=="avatar_metadata"&&B!=="avatar_audio_chunk"&&B!=="avatar_lipsync"&&B!=="avatar_interrupt"&&B!=="error"&&console.debug("[realtimeVoice] server message",B,y),B){case"avatar_metadata":ee(y);break;case"avatar_audio_chunk":ce(y);break;case"avatar_lipsync":Ne(y);break;case"avatar_interrupt":W(y);break;case"error":{const L=String(y.message??"Voice session error");console.error("[realtimeVoice] server error:",L),e("error"),R();break}case"avatar_speak":_e(y);break}},ht=()=>h||(S=new Ir,h=new Nn.PipecatClient({transport:new Mt.WebSocketTransport({mediaManager:S,serializer:new Ar,recorderSampleRate:Ft,playerSampleRate:Nt}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{l=!0,e("idle"),R()},onDisconnected:()=>{l=!1,fe()},onError:c=>{const y=typeof c=="object"&&c!==null&&"data"in c?String(c.data??c):String(c);console.error("[realtimeVoice]",y,c),e("error"),R()},onTransportStateChanged:c=>{c==="error"&&(e("error"),R())},onServerMessage:c=>{C(c)},onUserStartedSpeaking:()=>{W({})},onBotStartedSpeaking:()=>{A("bot_started")},onBotStoppedSpeaking:()=>{v&&(I(),T=setTimeout(()=>{T=null,v&&(x.markStreamComplete(n),A("bot_stopped"))},450))},onUserTranscript:c=>{_.onUserTranscript?.(c.text,!!c.final)},onBotOutput:c=>{_.onBotOutput?.(c.text)}}}),h);return{setDeveloperToken:c=>{},setTtsEngineId:c=>{u=c,x.setStreamTtsEngineId(c)},getTtsEngineId:()=>u,speak:async(c,y)=>{const B=c.trim();if(B){if(!h||!l)throw new Error("Realtime voice is not connected. Call connect() first.");Z(),await h.sendText(B)}},stop:()=>{P?.abort(),P=null,z+=1,q(),Z(),e("idle"),R()},connect:async c=>{if(c&&(_={..._,...c}),!_.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const y=ht();await y.initDevices();const B=yn(_);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",B);try{await y.connect({wsUrl:B})}catch(L){l=!1,e("error"),R();const te=L instanceof Error?L.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${te} — ${B}`)}l=!0,e("idle"),R()},disconnect:async()=>{if(I(),H=!1,g.length=0,d=!1,P?.abort(),P=null,z+=1,q(),h)try{await h.disconnect()}catch(c){console.error("[realtimeVoice] disconnect failed:",c)}l=!1,fe()},isConnected:()=>l,unlockAudio:async()=>{await x.primeAudioContext()},getVisemeQueue:()=>n,getWordQueue:()=>r,getSentenceEmotions:()=>s,getStreamMood:()=>a,getPlaybackElapsedMs:M,isSpeaking:()=>x.isSpeaking(),getVoiceStream:()=>x.getVoiceStream(),setPlaybackSpeed:c=>{x.setPlaybackSpeed(c)},getPlaybackSpeed:()=>x.getPlaybackSpeed(),subscribe:c=>(f.add(c),()=>f.delete(c))}}function Pr(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function Br(e,t){const n=e.crop;return{x:t?.source_x??n?.x??0,y:t?.source_y??n?.y??0,width:t?.source_w??n?.width??e.frame_width??0,height:t?.source_h??n?.height??e.frame_height??0}}function Lr(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function mt(e,t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const r=await n.arrayBuffer();return rr(r,t)}async function Or(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await mt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function Fr(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(n),r(i)},i.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted image"))},i.src=n})}async function Nr(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(n),r(i)},i.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted PNG"))},i.src=n})}function Ur(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Vr(e){const t=ar();if(!ut())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await mt(t,e);return Ur(n)}function Ut(e,t){return`${e}/${t}_minus_sil.png`}const En=5;function kn(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const n=e?.crop?.content_threshold;return typeof n=="number"&&n>0?n:En}const $r=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],It=["t01_0.25","t02_0.50","t03_0.75"],Wr=It.length,Gt=new Set(["aa__kk","aa__nn","aa__sil","CH__aa","CH__DD","CH__E","CH__FF","CH__I","CH__kk","CH__nn","CH__O","CH__PP","CH__RR","CH__sil","CH__SS","CH__TH","CH__U","DD__aa","DD__E","DD__FF","DD__I","DD__kk","DD__nn","DD__O","DD__PP","DD__RR","DD__sil","DD__SS","DD__TH","DD__U","E__aa","E__FF","E__I","E__kk","E__nn","E__O","E__PP","E__RR","E__sil","E__SS","E__TH","E__U","FF__aa","FF__I","FF__kk","FF__nn","FF__O","FF__PP","FF__RR","FF__sil","FF__SS","FF__TH","FF__U","I__aa","I__kk","I__nn","I__O","I__PP","I__RR","I__sil","I__SS","I__TH","I__U","kk__nn","kk__sil","nn__sil","O__aa","O__kk","O__nn","O__PP","O__RR","O__sil","O__SS","O__TH","O__U","PP__aa","PP__kk","PP__nn","PP__RR","PP__sil","PP__SS","PP__TH","PP__U","RR__aa","RR__kk","RR__nn","RR__sil","RR__SS","RR__TH","RR__U","SS__aa","SS__kk","SS__nn","SS__sil","SS__TH","SS__U","TH__aa","TH__kk","TH__nn","TH__sil","TH__U","U__aa","U__kk","U__nn","U__sil"]);function zt(e,t){return`${e}__${t}`}function Yt(e,t){return`pairs/${e}/${t}_minus_sil.png`}function at(e){return`${e}_minus_sil.png`}function Hr(e,t){if(t.has(e))return e;const n=/^pairs\/([^/]+)\//.exec(e);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const s=at(r);return t.has(s)?s:null}function vn(e,t){return e.filter(n=>t.has(n))}function qr(e,t,n){const r=Vt(e,t);return vn(r,n).length>0}function Vt(e,t){if(e===t)return[];const n=[],r=zt(e,t);if(Gt.has(r)){for(const i of It)n.push(Yt(r,i));return n}const s=zt(t,e);if(Gt.has(s)){for(let i=Wr-1;i>=0;i--)n.push(Yt(s,It[i]));return n}return[]}function Kr(e){return e<16?[]:e<35?[1]:e<51?[0,2]:[0,1,2]}function jr(e,t){return Kr(t).map(r=>e[r]).filter(r=>r!=null)}function Gr(e,t,n,r){if(r<=0)return 0;const i=Math.max(1,n-t)/r,o=e-t,a=Math.floor(o/i);return Math.min(r-1,Math.max(0,a))}function zr(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,s=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${s}.bin`}const Yr=[.32,.24,.16,.08,0],Jr=Yr.map(e=>`eyes_${e.toFixed(2)}`),Qr=["eyes_0.32","eyes_0.16","eyes_0.00"],Xr=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Jt=2,Zr=-30,Rt=20,es={fear:-30,anger:-20,sad:-10,neutral:0,love:10,happy:0,disgust:20};function $t(e){return`brow_${e}`}function Wt(e){return es[e]}function Me(e){return Math.max(Zr,Math.min(Rt,e))}function ts(e,t){if(e===t)return[];const n=e<t?Jt:-Jt,r=[];let s=e;for(;s!==t;)s+=n,r.push(s);return r}const ns={fear:"fear",afraid:"fear",anxiety:"fear",anger:"anger",angry:"anger",mad:"anger",sad:"sad",sadness:"sad",sorrow:"sad",neutral:"neutral",calm:"neutral",love:"love",loving:"love",affection:"love",happy:"happy",happiness:"happy",joy:"happy",joyful:"happy",excited:"happy",disgust:"disgust",disgusted:"disgust"};function Oe(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?ns[n]??t:t}function Tn(e){return e===0?null:Ut($t(e),"eyes_standard")}function bn(e){return Tn(Wt(e))}function Qt(e,t){const n=$t(Wt(e));return!t||t==="eyes_standard"?bn(e):e==="neutral"&&t==="eyes_standard"?null:Ut(n,t)}function rs(e,t){const n=[];for(const r of t)n.push(Qt(e,r));for(let r=t.length-2;r>=0;r--)n.push(Qt(e,t[r]));return n.push(bn(e)),n}function ss(e){return e===0?null:Ut($t(e),"eyes_standard")}function is(e,t){return ts(e,t).map(ss).filter(n=>n!=null)}const as=6;function os(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function cs(e){const t=Me(e);return t>=Rt?Rt:Me(t+as)}function us(e,t,n){const r=Me(n);return os(t,e)?.emphasis?cs(r):r}function Xt(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const n=Number.parseInt(t[1],10);return Number.isFinite(n)?Me(n):null}function qe(e,t){return e+Math.random()*(t-e)}function nt(){return qe(14,32)}function ls(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:u=380,minDwellMs:l=550}=e;let h="neutral",S="neutral",_=0,b=0,k=0,f={kind:"idle",nextBlinkAt:performance.now()+t},g=null,d="__eyes_open__|neutral|brow:0";function E(T=h){d=`${g??"__eyes_open__"}|${T}|brow:${b}`}function v(T,I=h){g=T;const R=Xt(T);R!=null?b=R:T==null&&(b=0),E(I)}function N(T){return Tn(T)}function J(T,I,R){const x=Me(I),m=Me(R);if(_=m,x===m){v(N(m));return}const C=[...is(x,m),N(m)];f={kind:"browBlend",paths:C,index:0,holdUntil:T+nt(),targetBrow:m},v(C[0]??null)}function P(T,I){f={kind:"idle",nextBlinkAt:T+qe(n,r)},S=I,v(N(_),I)}function z(T,I,R){const x=R?Qr:Math.random()<a?Jr:Xr;f={kind:"playing",paths:rs(I,x),index:0,holdUntil:T+nt(),after:"idle",blinkEmotion:I},S=I,v(f.paths[0]??null,I)}function H(T){if(f.kind==="browBlend"){for(;T>=f.holdUntil&&f.index<f.paths.length-1;)f.index+=1,f.holdUntil=T+nt();const I=f.paths[f.index]??null;v(I),T>=f.holdUntil&&f.index>=f.paths.length-1&&(b=f.targetBrow,_=f.targetBrow,v(N(f.targetBrow)),f={kind:"idle",nextBlinkAt:T+u});return}if(f.kind==="idle"){v(N(_),S),T>=f.nextBlinkAt&&z(T,S,!1);return}if(f.kind==="doublePause"){v(N(_),f.blinkEmotion),T>=f.resumeAt&&z(T,f.blinkEmotion,!0);return}if(f.kind==="playing"){for(;T>=f.holdUntil&&f.index<f.paths.length-1;)f.index+=1,f.holdUntil=T+nt();if(v(f.paths[f.index]??null,f.blinkEmotion),T>=f.holdUntil&&f.index>=f.paths.length-1){if(f.after==="resumeIdle"){P(T+u,h);return}if(f.after==="doublePause"){f={kind:"doublePause",resumeAt:T+qe(i,o),blinkEmotion:f.blinkEmotion},v(N(_),f.blinkEmotion);return}if(f.after==="idle"&&Math.random()<s){f={kind:"doublePause",resumeAt:T+qe(i,o),blinkEmotion:f.blinkEmotion},v(N(_),f.blinkEmotion);return}P(T,f.blinkEmotion)}}}return{advance:H,setTargetEmotion(T){const I=Oe(T,h);if(I===h)return;const R=performance.now();l>0&&I!==h&&!(h==="neutral"&&I!=="neutral")&&R-k<l||(h=I,S=I,k=R)},setTargetEyebrow(T){const I=Me(T);if(I===_&&f.kind!=="browBlend")return;const R=performance.now(),x=f.kind==="browBlend"?Xt(g)??b:b;_=I,!(I===x&&f.kind!=="browBlend")&&(f.kind==="playing"||f.kind==="doublePause"||J(R,x,I))},getTargetEmotion:()=>h,getTargetEyebrow:()=>_,getExpressionPath:()=>g,getDrawKey:()=>d,reset(){h="neutral",S="neutral",_=0,b=0,k=0,P(performance.now()+qe(n,r),"neutral")}}}function fs(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const s=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(i){t&&r===i||(s(),t=!1,r=i,i.startsWith("blob:")&&(n=i),await new Promise((o,a)=>{const u=()=>{const l=e.duration;if(!Number.isFinite(l)||l<=0){a(new Error(`Idle video has invalid duration: ${i}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",u,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${i}`)),{once:!0}),e.src=i,e.load()}))},isReady(){return t},getVideo(){return e},setActive(i){t&&(i?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),s(),t=!1,r=""}}}const ds=50,An=400;function ms(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function hs(e,t){const n=[];for(const r of e){const s=ms(t,r.start_word,r.end_word);if(s.length===0)continue;const i=s[0],o=s[s.length-1];n.push({sentence:r,startMs:Math.max(0,i.wtime-ds),endMs:o.wtime+o.wduration+An})}return n.sort((r,s)=>r.startMs-s.startMs)}function ws(e,t,n,r="neutral"){const s=Oe(r);if(t.length===0)return s;if(n.length===0||e<n[0].wtime)return Oe(t[0]?.emotion,s);const i=hs(t,n);let o=null;for(const l of i)e>=l.startMs&&e<=l.endMs&&(o=l);if(o)return Oe(o.sentence.emotion,s);const a=n[n.length-1],u=a.wtime+a.wduration;return e>u+An?Oe(t[t.length-1]?.emotion,s):s}function In(e,t,n,r,s=En){const i=new OffscreenCanvas(n,r),o=i.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const a=o.getImageData(0,0,n,r),u=o.createImageData(n,r);u.data.set(a.data);const h=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const S of t){h.clearRect(0,0,n,r),h.drawImage(S,0,0,n,r);const _=h.getImageData(0,0,n,r);for(let b=0;b<u.data.length;b+=4){const k=_.data[b],f=_.data[b+1],g=_.data[b+2];Math.max(k,f,g)>s&&(u.data[b]=k,u.data[b+1]=f,u.data[b+2]=g,u.data[b+3]=255)}}return o.putImageData(u,0,0),i}let De=null,Ke=null;const ot=new Map;function _s(){De=null,Ke=null,ot.clear()}ir(_s);function gs(e){return e??Ke??void 0}function Ht(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function ps(e){return ut()?Nr(await mt(Kt(),e??"")):Ht(Kt())}async function Zt(e,t,n,r){const s=n?await Or(e,r):await fetch(e).then(l=>{if(!l.ok)throw new Error(`Failed to load ${e}`);return l.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await Fr(await mt(zr(t,i.path,n),r??"")):await Ht(`${t}/${i.path}`),a=new Map;for(const l of s.cells??[])l.path&&a.set(l.path,l);const u=new Map;for(const l of s.sheets??[])u.set(l.index,l);return{atlas:o,atlasMeta:s,cellByPath:a,sheetByIndex:u,diffBase:t}}async function Dt(e){const t=gs(e),n=ut();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(De&&(!n||Ke===(t??null))){const i=await De;return{...je(i),visemePaths:[...i.viseme.cellByPath.keys()]}}Ke=t??null,ot.clear();const r=or();De=(async()=>{const i=await ps(t),o=await Zt(cr(),r,n,t);let a=null;try{a=await Zt(ur(),r,n,t)}catch{a=null}return{sil:i,viseme:o,expression:a}})();const s=await De;return{...je(s),visemePaths:[...s.viseme.cellByPath.keys()]}}async function Rn(e){if(await Dt(e),!De)throw new Error("Assets not loaded");return De}function je(e){return Pr(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function ys(e,t){const n=document.createElement("canvas");return n.width=t.w,n.height=t.h,n.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}async function en(e,t,n){const r=`${t.diffBase}::${n}`,s=ot.get(r);if(s)return s;const i=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const a=Br(t.atlasMeta,o),u=je(e);if(Lr(o)){const S=ys(t,o),_=document.createElement("canvas");_.width=u.width,_.height=u.height;const b=_.getContext("2d");return b.fillStyle="#000",b.fillRect(0,0,u.width,u.height),b.drawImage(S,a.x,a.y),_}const l=`${t.diffBase}/${n}`,h=await Ht(l);if(h.naturalWidth===u.width&&h.naturalHeight===u.height)return h;throw new Error(`Diff PNG wrong size for ${n}`)})();return ot.set(r,i),i}async function tn(e,t,n,r,s,i){if(s){const{width:b,height:k}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const f=document.createElement("canvas");f.width=b,f.height=k;const g=f.getContext("2d");if(g.clearRect(0,0,b,k),g.drawImage(t,0,0,b,k),i&&!i())return;(e.width!==b||e.height!==k)&&(e.width=b,e.height=k);const d=e.getContext("2d");d.clearRect(0,0,b,k),d.drawImage(f,0,0);return}const o=await Rn(),a=kn(o.viseme.atlasMeta),{width:u,height:l}=je(o);(e.width!==u||e.height!==l)&&(e.width=u,e.height=l);const h=[],S=e.getContext("2d");if(S.clearRect(0,0,u,l),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const b=o.sil;S.drawImage(b,0,0,u,l);return}if(h.length===0){S.drawImage(t,0,0,u,l);return}const _=In(t,h,u,l,a);S.drawImage(_,0,0)}async function Ct(e,t,n){const r=await Rn(Ke??void 0),s=kn(r.viseme.atlasMeta),{width:i,height:o}=je(r);(e.width!==i||e.height!==o)&&(e.width=i,e.height=o);const a=[];if(t.mouthPath){const h=new Set(r.viseme.cellByPath.keys()),S=Hr(t.mouthPath,h)??(h.has(t.mouthPath)?t.mouthPath:null);S&&a.push(await en(r,r.viseme,S))}t.expressionPath&&r.expression&&a.push(await en(r,r.expression,t.expressionPath));const u=e.getContext("2d");if(u.clearRect(0,0,i,o),a.length===0){u.drawImage(r.sil,0,0,i,o);return}const l=In(r.sil,a,i,o,s);u.drawImage(l,0,0)}async function Ss(e){await Ct(e,{mouthPath:null,expressionPath:null})}function Es(e){const t=new Map;for(const n of e)t.has(n.vtime)||t.set(n.vtime,n);return[...t.values()].sort((n,r)=>n.vtime-r.vtime)}function ks(e){const t=Es(e),n=[];for(let r=0;r<t.length-1;r++){const s=t[r].viseme,i=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;s===i||a<=o||n.push({from:s,to:i,fromVtime:o,toVtime:a})}return n}function vs(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function Ts(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const Dn=400,bs=200,As=600,Cn="__sil__";function Is(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===Cn:!1}function Rs(){return{lastDrawnKey:""}}function Ee(e){e.lastDrawnKey="",e.transitionCache=void 0}function Ds(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=ks(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Cs(e,t){let n="sil";for(const r of e)r.viseme!=="sil"&&(t!=null&&r.vtime>t||(n=r.viseme));return n}function Ms(e,t,n,r=120){if(n!=="sil")return n;const s=Tr(e,t,r);return s!=="sil"?s:Cs(e,t)}function xs(e,t){return e==="sil"?!1:t?qr(e,"sil",t):Vt(e,"sil").length>0}function Ps(){return Dn+As}function nn(e){return e??Cn}function Bs(e,t,n,r){if(e.length===0)return{diffPath:null,label:"sil"};const s=Ds(e,r),i=vs(s,t);if(i){const a=i.toVtime-i.fromVtime,u=Ts(i.fromVtime,i.toVtime);if(t>=u.transStart&&t<i.toVtime){let l=Vt(i.from,i.to);n&&(l=vn(l,n));const h=jr(l,a);if(h.length>0){const S=Gr(t,u.transStart,i.toVtime,h.length);return{diffPath:h[S]??h[h.length-1],label:`${i.from}→${i.to}`}}return{diffPath:at(i.to),label:i.to}}}const o=ze(e,t);return o==="sil"?{diffPath:null,label:"sil"}:{diffPath:at(o),label:o}}function Mn(e,t){const n=t??nn(e.expressionPath);return`${nn(e.mouthPath)}|${n}`}function Ls(e,t,n,r,s,i,o,a,u,l){const h=Bs(t,n,u,i),S={mouthPath:h.diffPath,expressionPath:r},_=Mn(S,s);_!==i.lastDrawnKey&&(a(h.label),o(e,S,_,b=>{b===_&&(i.lastDrawnKey=_)}))}function rn(e,t,n,r,s,i,o=null){const a={mouthPath:null,expressionPath:t},u=o!=null?`|idle@${Math.round(o*1e3)}`:"",l=Mn(a,n)+u;!(o!=null)&&l===r.lastDrawnKey||(i(o!=null?"idle":"sil"),s(e,a,l,S=>{S===l&&(r.lastDrawnKey=l)}))}function xn(e){let t=0,n=null,r=!1,s=!1;const i=async()=>{if(!r){r=!0;try{for(;n;){const a=n;n=null;const u=++t,l=await e(a.diffs,u,a);n||l&&u===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n&&i()}}},o=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(a,u,l){n={diffs:a,drawKey:u,onDisplayed:l},o()},reset(){t+=1,n=null},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}const sn=-1,an=new Map;async function Os(e){let t=an.get(e);if(!t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to fetch worker script (${n.status}): ${e}`);const r=await n.blob();t=URL.createObjectURL(r),an.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function Fs(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Ns(e,t){(e.width!==t.width||e.height!==t.height)&&(e.width=t.width,e.height=t.height);const n=e.getContext("2d");n&&n.drawImage(t,0,0)}function on(e,t){let n=0,r=null;const s=xn(async(i,o)=>(await Dt(),await Ct(e,i),s.isLatestSeq(o)));return{usesWorker:!1,async loadAssets(i){const o=await Dt(i);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,s.reset(),await Ss(e)},drawLiveFrame(i,o,a,u){s.enqueue(o,a,u)},async renderViseme(i,o){n+=1;const a=n;t.onStatus?.(o),await Ct(i,{mouthPath:at(o),expressionPath:null})},dispose(){n+=1,s.reset()}}}function Us(e,t,n){let r=null,s=1,i=0,o=!1,a=!1,u=null;const l=new Map,h=xn(async(g,d,E)=>(l.set(d,{drawKey:E.drawKey,onDisplayed:E.onDisplayed}),await k({type:"drawFrame",diffPath:g.mouthPath,expressionDiffPath:g.expressionPath,liveSeq:d},void 0,!0),!1)),S=g=>{if(g===sn){let v=-1,N;for(const[J,P]of l)J>=v&&(v=J,N=P);v>=0&&l.delete(v),N?.onDisplayed?.(N.drawKey);return}const d=-g,E=l.get(d);l.delete(d),E?.onDisplayed?.(E.drawKey)},_=new Map,b=(g,d)=>{a||!r||r.postMessage(g,[])},k=(g,d,E=!1)=>{if(a)return Promise.resolve();const v=s++;return new Promise((N,J)=>{_.set(v,{resolve:P=>N(P),reject:J,generation:typeof g.generation=="number"?g.generation:void 0,expectRenderDone:E}),b({...g,requestId:v})})},f=(async()=>{r=await Os(n),r.onmessage=g=>{if(a)return;const d=g.data;if(d.type==="status"){t.onStatus?.(d.label);return}if(d.type==="frame"){const v=d.generation<0;if(!v&&d.generation!==i){d.bitmap.close();return}if(v&&!(d.generation===sn)){const J=-d.generation;if(!h.isLatestSeq(J)){d.bitmap.close();return}}if(v&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){d.bitmap.close();return}Ns(e,d.bitmap),d.bitmap.close(),v&&S(d.generation);return}const E=_.get(d.requestId);if(E)switch(d.type){case"ready":_.delete(d.requestId),E.resolve();break;case"loadAssetsDone":_.delete(d.requestId),u=d.visemePaths?.length?new Set(d.visemePaths):null,E.resolve({width:d.width,height:d.height,visemePaths:d.visemePaths});break;case"renderDone":if(E.expectRenderDone&&E.generation!=null&&d.generation!==E.generation)return;_.delete(d.requestId),E.resolve();break;case"renderAborted":_.delete(d.requestId),E.resolve();break;case"error":_.delete(d.requestId),t.onError?.(d.message),E.reject(new Error(d.message));break}},r.onerror=g=>{if(a)return;const d=g.message||"Worker error";t.onError?.(d);for(const[,E]of _)E.reject(new Error(d));_.clear()},await k({type:"init"}),o=!0})();return{usesWorker:!0,async loadAssets(g){if(a)return{width:842,height:1264};if(await f,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await k({type:"loadAssets",keyHex:g,urls:sr(Pe())})??{width:842,height:1264}},getVisemeAtlasPaths(){return u},async renderSilOnly(){if(a||(await f,a))return;i+=1,h.reset(),l.clear();const g=i;await k({type:"cancelLiveDraws"}),await k({type:"renderSil",generation:g},void 0,!0)},drawLiveFrame(g,d,E,v){a||f.then(()=>{a||h.enqueue(d,E,v)})},async renderViseme(g,d,E={}){if(a||(await f,a))return;i+=1,h.reset(),l.clear();const v=i;try{await k({type:"cancelLiveDraws"}),await k({type:"renderViseme",generation:v,to:d,from:E.from,transitionDurationMs:E.transitionDurationMs,gapMs:E.gapMs,threshold:E.threshold},void 0,!0)}catch(N){if(N?.name==="AbortError")return;throw N}},dispose(){if(!a){a=!0,i+=1,h.reset(),l.clear();for(const[,g]of _)g.resolve();_.clear(),r?.terminate(),r=null}}}}function Vs(e,t={}){if(!Fs())return on(e,t);const n=qn(t.workerScriptUrl);try{return Us(e,t,n)}catch{return on(e,t)}}class $s extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function kt(e,t,n){return new Promise((r,s)=>{const i=globalThis.setTimeout(()=>{s(new $s(n,t))},t);e.then(o=>{globalThis.clearTimeout(i),r(o)},o=>{globalThis.clearTimeout(i),s(o)})})}const Ws={position:"relative",display:"inline-block",lineHeight:0},Hs={display:"block",maxWidth:"100%",height:"auto"},qs={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",padding:"1rem",background:"rgba(0,0,0,0.55)",color:"#fff",fontSize:"0.875rem",textAlign:"center"};function He(e){return Gn(e)?Ot:Lt}function Ae(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const Ks=p.forwardRef(function({id:t,avatarId:n,faceId:r,assets:s,authToken:i,apiBase:o,ttsEngineId:a=Ce,voiceId:u,speakingRate:l=Ye,className:h,style:S,canvasStyle:_,onStatusChange:b,onDisplayStatus:k,onError:f,onReady:g,showErrorOverlay:d=!0,onUserTranscript:E,onBotOutput:v,onRealtimeLipsyncDebug:N},J){const P=p.useRef(null),z=p.useRef(null),H=p.useRef(Rs()),T=p.useRef(ls()),I=p.useRef(0),R=p.useRef(0),x=p.useRef(0),m=p.useRef(null),C=p.useRef(null),M=p.useRef(!1),V=p.useRef(!1),A=p.useRef(!1),q=p.useRef("sil"),Y=p.useRef(0),Q=p.useRef(!1),W=p.useRef(null),K=p.useRef(!1),[Z,fe]=p.useState("idle"),[oe,ee]=p.useState(null),[de,ce]=p.useState(!1),[Ne,_e]=p.useState(!1),[Je,ht]=p.useState({width:842,height:1264}),ke=p.useRef(i??null),Ie=o?.trim()||Ge,Ue=p.useRef(null),ue=p.useRef(null),Be=p.useRef(!1),c=p.useRef({width:842,height:1264}),y=p.useRef(null),B=p.useRef(g),L=p.useRef(k),te=p.useRef(f),Re=p.useRef(E),ne=p.useRef(v),ve=p.useRef(N);B.current=g,L.current=k,te.current=f,Re.current=E,ne.current=v,ve.current=N;const ye=p.useCallback(w=>{const D=w?.ttsEngineId??a??ue.current?.ttsEngineId??Ce,O=w?.voiceId??u??ue.current?.voiceId??He(D);return{ttsEngineId:D,voiceId:O}},[a,u]),ge=p.useCallback(w=>{ee(w),te.current?.(w)},[]),Te=p.useCallback(w=>{fe(w),b?.(w)},[b]),$=p.useRef(At(Te,Ie)),j=p.useRef(null);p.useEffect(()=>($.current=At(Te,Ie),i&&$.current.setDeveloperToken(i),$.current.setTtsEngineId(a),()=>{$.current.stop();const w=j.current;w&&(w.disconnect(),j.current=null)}),[Te,i,a,Ie]);const Qe=p.useCallback(()=>(j.current||(j.current=Sn(Te,{speakingRate:l,onUserTranscript:(w,D)=>Re.current?.(w,D),onBotOutput:w=>ne.current?.(w),onLipsyncDebug:w=>ve.current?.(w)}),j.current.setTtsEngineId(a)),j.current),[Te,l,a]),le=p.useCallback(()=>{m.current!=null&&(clearTimeout(m.current),m.current=null)},[]),re=p.useCallback(()=>{C.current!=null&&(clearTimeout(C.current),C.current=null),A.current=!1},[]),Ve=p.useCallback(()=>{!K.current||!W.current||(re(),A.current=!0,C.current=setTimeout(()=>{if(C.current=null,Ae($.current,j.current).isSpeaking()){A.current=!1;return}if(M.current){A.current=!1;return}const w=W.current;if(!w){A.current=!1;return}w.restart(),w.setActive(!0);const D=w.getVideo();let O=!1;const U=()=>{O||(O=!0,D.removeEventListener("playing",F),A.current=!1)},F=()=>{U()};if(D.addEventListener("playing",F,{once:!0}),D.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!D.paused){U();return}setTimeout(U,300)},bs))},[re]),Se=p.useCallback(()=>{if(le(),L.current?.("sil"),M.current=!1,!K.current||!W.current){A.current=!1;return}Ve()},[le,Ve]),X=p.useCallback(async w=>{const D=R.current,O=z.current,U=P.current,F=()=>{w?.fallbackOnly||(M.current=!1)};if(!O||!U||!de){F();return}if(Ae($.current,j.current).isSpeaking()){F();return}if(w?.fallbackOnly){if(!M.current||(Ee(H.current),await O.renderSilOnly(),D!==R.current)||Ae($.current,j.current).isSpeaking())return;Se();return}if(Is(H.current)){Ee(H.current),Se();return}const ae=Ms(Ae($.current,j.current).getVisemeQueue(),Y.current,q.current),pe=xs(ae,y.current);if(Ee(H.current),!pe){if(await O.renderSilOnly(),D!==R.current||Ae($.current,j.current).isSpeaking())return;Se();return}try{await O.renderViseme(U,"sil",{from:ae,transitionDurationMs:Dn})}catch(be){if(be?.name!=="AbortError")throw be}if(D!==R.current){F();return}if(Ae($.current,j.current).isSpeaking()){F();return}Se()},[de,Se]),se=p.useCallback(()=>{if(V.current||M.current)return;V.current=!0,M.current=!0,le();const w=R.current;X().finally(()=>{V.current=!1}),m.current=setTimeout(()=>{m.current=null,w===R.current&&X({fallbackOnly:!0})},Ps())},[le,X]),me=p.useCallback(async()=>{const w=Math.floor(Date.now()/1e3);if(Ue.current&&w<Ue.current.expiresAt-60)return Ue.current.key;const D=ke.current??await rt();ke.current=D,$.current.setDeveloperToken(D);const O=await er(D,Ie);return Ue.current={key:O.value,expiresAt:O.expiresAt},O.value},[Ie]);p.useEffect(()=>{i&&(ke.current=i,$.current.setDeveloperToken(i))},[i]),p.useEffect(()=>{$.current.setTtsEngineId(a),j.current?.setTtsEngineId(a),ue.current&&(ue.current.ttsEngineId=a)},[a]),p.useEffect(()=>{const w=u??He(a);ue.current&&(ue.current.voiceId=w)},[u,a]);const he=p.useMemo(()=>dn(n,r),[n,r]),Xe=p.useMemo(()=>s?JSON.stringify(s):he?`face:${he}`:`id:${t??""}`,[s,he,t]);return p.useEffect(()=>{if(!t&&!s&&!he){ge("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let w=!1;Be.current=!1,ce(!1),_e(!1),ee(null),ue.current=null,W.current=null,K.current=!1;const D=P.current;if(!D)return;let O=null;return(async()=>{try{let U,F,ae,pe;if(s)U=s,F=a,ae=u??He(F);else if(he)L.current?.("loadFace"),U=bt(he),F=a,ae=u??He(F);else{L.current?.("getAiTwin");const G=await kt(fn(t),3e4,"getAiTwin");if(w)return;if(!G.faceId?.trim())throw new Error("getAiTwin returned no faceId");F=G.ttsEngineId,ae=u??G.voiceId??He(F),pe=G.knowledgeContextId?.trim()||void 0,U=bt(G.faceId)}ue.current={ttsEngineId:F,voiceId:ae,personaId:pe},mn(U),W.current=fs(),O=Vs(D,{onStatus:G=>{w||L.current?.(G)},onError:G=>{w||ge(G)},shouldAcceptLiveFrame:()=>Ae($.current,j.current).isSpeaking()&&!M.current}),z.current=O,L.current?.("auth");const be=ke.current??i??await kt(rt(),3e4,"getAuthToken");if(w)return;ke.current=be,$.current.setDeveloperToken(be),$.current.setTtsEngineId(F);const $e=ut()?await me():void 0;if(w)return;L.current?.("loadAssets");const ie=await kt(O.loadAssets($e),18e4,"load face assets");if(!w&&ie.width>0&&ie.height>0&&(c.current=ie,ht(ie)),w)return;y.current=O.getVisemeAtlasPaths(),Be.current=!0,ce(!0),B.current?.(),O.renderSilOnly().then(()=>{w||L.current?.("sil")}),(async()=>{try{const G=await Vr($e);if(await W.current.load(G),w)return;K.current=!0,_e(!0),Ee(H.current),W.current.setActive(!0);const we=W.current.getVideo();await tn(D,we,null,void 0,c.current),w||L.current?.("idle")}catch(G){if(w)return;K.current=!1,_e(!1),console.warn("[AiTwin] Idle video unavailable:",G)}})()}catch(U){if(w)return;if(U instanceof st){ge(U.message);return}ge(U instanceof Error?U.message:"Failed to load AI twin")}})(),()=>{w=!0,W.current?.dispose(),O?.dispose(),z.current=null}},[Xe,s,he,t,a,u,i,me,ge]),p.useEffect(()=>{const w={current:!1},D=()=>{const O=P.current,U=z.current,F=Ae($.current,j.current);if(!O||!U||!de){I.current=requestAnimationFrame(D);return}const ae=F.isSpeaking(),pe=ae&&!Q.current,be=Q.current&&!ae;pe&&(le(),re(),M.current=!1,V.current=!1,Ee(H.current),x.current=0,q.current="sil",Y.current=0,W.current?.setActive(!1)),be&&(T.current.reset(),W.current?.setActive(!1),se());const $e=be||M.current||A.current;if(ae){K.current&&W.current?.setActive(!1);const ie=F.getVisemeQueue(),G=F.getPlaybackElapsedMs();Y.current=G;const we=ie.length>0?ze(ie,G):"sil";we!=="sil"&&(q.current=we);const Le=ws(G,F.getSentenceEmotions(),F.getWordQueue(),F.getStreamMood());T.current.setTargetEmotion(Le),T.current.setTargetEyebrow(us(G,F.getWordQueue(),Wt(Le))),T.current.advance(performance.now());const wt=T.current.getExpressionPath(),_t=T.current.getDrawKey();Ls(O,ie,G,wt,_t,H.current,(gt,Ln,On,Fn)=>U.drawLiveFrame(gt,Ln,On,Fn),gt=>L.current?.(gt),y.current)}else if(!$e&&K.current&&W.current){const ie=W.current,G=ie.getVideo();G.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?(ie.setActive(!0),w.current||(w.current=!0,tn(O,G,null,void 0,c.current,()=>!F.isSpeaking()&&!M.current&&!A.current).then(()=>L.current?.("idle")).finally(()=>{w.current=!1}))):rn(O,null,"__sil__",H.current,(we,Le,wt,_t)=>U.drawLiveFrame(we,Le,wt,_t),we=>L.current?.(we))}else $e||rn(O,null,"__sil__",H.current,(ie,G,we,Le)=>U.drawLiveFrame(ie,G,we,Le),ie=>L.current?.(ie));Q.current=ae,I.current=requestAnimationFrame(D)};return I.current=requestAnimationFrame(D),()=>{cancelAnimationFrame(I.current),le(),re(),$.current.stop(),j.current?.stop()}},[de,Ne,se,le,re]),p.useImperativeHandle(J,()=>({speakText:async(w,D)=>{const O=w.trim();if(!O)return;const U=z.current;if(!U||!Be.current&&!de)throw new Error("AI twin is not ready");const{ttsEngineId:F,voiceId:ae}=ye(D);ee(null),R.current+=1,le(),re(),M.current=!1,V.current=!1,q.current="sil",Y.current=0,Ee(H.current),T.current.reset(),Q.current=!1;try{K.current?(W.current?.setActive(!1),W.current?.restart(),Ee(H.current)):await U.renderSilOnly(),await $.current.speak(O,{voiceId:ae,speakingRate:D?.speakingRate??l,ttsEngineId:F})}catch(pe){throw ge(pe instanceof Error?pe.message:"TTS failed"),pe}},stop:()=>{R.current+=1,le(),re(),M.current=!1,V.current=!1,$.current.stop(),j.current?.stop(),Ee(H.current),Q.current=!1,se()},setTtsEngineId:w=>{$.current.setTtsEngineId(w),j.current?.setTtsEngineId(w),ue.current&&(ue.current.ttsEngineId=w)},renderViseme:async(w,D)=>{const O=z.current,U=P.current;if(!O||!U||!Be.current)throw new Error("AI twin is not ready");await O.renderViseme(U,w,{from:D?.from,transitionDurationMs:D?.transitionDurationMs,gapMs:D?.gapMs,onStatus:F=>L.current?.(F)})},isReady:()=>Be.current,getStatus:()=>Z,connect:async(w={})=>{ee(null);try{let D=w.authToken?.trim();D||(D=ke.current??i??await rt(),ke.current=D);const O=w.voiceId?.trim()??u??ue.current?.voiceId,U=w.personaId?.trim()??ue.current?.personaId,F=Qe();await F.unlockAudio(),await F.connect({...w,apiBase:w.apiBase?.trim()||Ie,authToken:D,voiceId:O,personaId:U,speakingRate:w.speakingRate??l})}catch(D){throw ge(D instanceof Error?D.message:"Voice connect failed"),D}},disconnect:async()=>{const w=j.current;w&&(R.current+=1,le(),re(),M.current=!1,V.current=!1,Ee(H.current),Q.current=!1,await w.disconnect(),se())},isConnected:()=>j.current?.isConnected()??!1,getVoiceStream:()=>j.current?.getVoiceStream()??$.current?.getVoiceStream()??null}),[de,l,i,u,le,re,se,ge,ye,Qe,Z]),pt.jsxs("div",{className:h,style:{...Ws,...S},children:[pt.jsx("canvas",{ref:P,width:Je.width,height:Je.height,style:{...Hs,..._},"aria-label":t?`AI twin ${t}`:"AI twin face"}),d&&oe?pt.jsx("div",{style:qs,children:oe}):null]})}),Pn="thumbnail.webp";function js(e,t=xt){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Pn}`}const Gs=new Set([".png",".jpg",".jpeg",".webp"]);function Bn(e=".png"){const t=e.toLowerCase();return Gs.has(t)?`source${t}`:"source.png"}function zs(e,t=xt,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${Bn(n)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Pn;exports.AiTwin=Ks;exports.AiTwinNotFoundError=st;exports.DEFAULT_TTS_ENGINE_ID=Ce;exports.MIC_SAMPLE_RATE=Ft;exports.OCULUS_VISEME_IDS=wn;exports.PLAYBACK_SAMPLE_RATE=Nt;exports.SPEAKING_RATE_MAX=dt;exports.SPEAKING_RATE_MIN=ft;exports.TTS_ENGINE_CARTESIA=xe;exports.TTS_ENGINE_GOOGLE=Pt;exports.TTS_ENGINE_INWORLD=ct;exports.VISEME_IDS=$r;exports.VISEME_TEST_CARTESIA_VOICE_ID=Ot;exports.VISEME_TEST_SPEAKING_RATE=Ye;exports.VISEME_TEST_VOICE_ID=Lt;exports.aiTwinSourceFilename=Bn;exports.buildVoiceWebSocketUrl=yn;exports.createAvatarTtsLipsyncController=At;exports.createRealtimeVoiceLipsyncController=Sn;exports.faceAssetUrls=bt;exports.fetchAiTwin=fn;exports.fetchDevAuthToken=rt;exports.getAiTwinSourceUrl=zs;exports.getAiTwinThumbnailUrl=js;exports.normalizeOculusViseme=_n;exports.resolveDirectFaceId=dn;exports.resolveVisemeAtTime=ze;exports.resolveWordAtTime=br;exports.setActiveTwinAssets=mn;
|
|
5
|
+
`);ae=de.pop()??"";for(const J of de)await Ee(J);if(q){ae.trim()&&await Ee(ae.trim()),te===j&&!G.signal.aborted&&b&&R.markStreamComplete(n);break}}}catch(ke){if(G.signal.aborted||!b)return;console.error("[realtimeVoice] avatar_speak failed:",ke),e("error"),C()}finally{U===G&&(U=null)}},Ne=c=>{const E=Hr(c);if(!E){console.warn("[realtimeVoice] server message with no payload",c);return}const P=String(E.type??"unknown");switch(P!=="avatar_metadata"&&P!=="avatar_audio_chunk"&&P!=="avatar_lipsync"&&P!=="avatar_interrupt"&&P!=="error"&&console.debug("[realtimeVoice] server message",P,E),P){case"avatar_metadata":ie(E);break;case"avatar_audio_chunk":ee(E);break;case"avatar_lipsync":Fe(E);break;case"avatar_interrupt":re(E);break;case"error":{const G=String(E.message??"Voice session error");console.error("[realtimeVoice] server error:",G),e("error"),C();break}case"avatar_speak":_e(E);break}},et=()=>u||(_=new Vr,u=new Jn.PipecatClient({transport:new Lt.WebSocketTransport({mediaManager:_,serializer:new Ur,recorderSampleRate:Wt,playerSampleRate:qt}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{f=!0,e("idle"),C()},onDisconnected:()=>{f=!1,le()},onError:c=>{const E=typeof c=="object"&&c!==null&&"data"in c?String(c.data??c):String(c);console.error("[realtimeVoice]",E,c),e("error"),C()},onTransportStateChanged:c=>{c==="error"&&(e("error"),C())},onServerMessage:c=>{M(c)},onUserStartedSpeaking:()=>{re({})},onBotStartedSpeaking:()=>{A("bot_started")},onBotStoppedSpeaking:()=>{b&&(I(),k=setTimeout(()=>{k=null,b&&(R.markStreamComplete(n),A("bot_stopped"))},450))},onUserTranscript:c=>{m.onUserTranscript?.(c.text,!!c.final)},onBotOutput:c=>{m.onBotOutput?.(c.text)}}}),u);return{setDeveloperToken:c=>{},setTtsEngineId:c=>{l=c,R.setStreamTtsEngineId(c)},getTtsEngineId:()=>l,speak:async(c,E)=>{const P=c.trim();if(P){if(!u||!f)throw new Error("Realtime voice is not connected. Call connect() first.");K(),await u.sendText(P)}},stop:()=>{U?.abort(),U=null,j+=1,$(),K(),e("idle"),C()},connect:async c=>{if(c&&(m={...m,...c}),!m.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const E=et();await E.initDevices();const P=Cn(m);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",P);try{await E.connect({wsUrl:P})}catch(G){f=!1,e("error"),C();const te=G instanceof Error?G.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${te} — ${P}`)}f=!0,e("idle"),C()},disconnect:async()=>{if(I(),X=!1,S.length=0,h=!1,U?.abort(),U=null,j+=1,$(),u)try{await u.disconnect()}catch(c){console.error("[realtimeVoice] disconnect failed:",c)}f=!1,le()},isConnected:()=>f,unlockAudio:async()=>{await R.primeAudioContext()},getVisemeQueue:()=>n,getWordQueue:()=>r,getSentenceEmotions:()=>s,getStreamMood:()=>a,getPlaybackElapsedMs:O,isSpeaking:()=>R.isSpeaking(),getVoiceStream:()=>R.getVoiceStream(),setPlaybackSpeed:c=>{R.setPlaybackSpeed(c)},getPlaybackSpeed:()=>R.getPlaybackSpeed(),subscribe:c=>(d.add(c),()=>d.delete(c))}}function Gr(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function jr(e,t){const n=e.crop;return{x:t?.source_x??n?.x??0,y:t?.source_y??n?.y??0,width:t?.source_w??n?.width??e.frame_width??0,height:t?.source_h??n?.height??e.frame_height??0}}function zr(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function _t(e,t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const r=await n.arrayBuffer();return gr(r,t)}async function Qr(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await _t(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function Yr(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(n),r(i)},i.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted image"))},i.src=n})}async function Jr(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(n),r(i)},i.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted PNG"))},i.src=n})}function Xr(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Zr(e){const t=yr();if(!ht())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await _t(t,e);return Xr(n)}function Ht(e,t){return`${e}/${t}_minus_sil.png`}const Pn=5;function Fn(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const n=e?.crop?.content_threshold;return typeof n=="number"&&n>0?n:Pn}const es=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],xt=["t01_0.25","t02_0.50","t03_0.75"],ts=xt.length,rn=new Set(["aa__kk","aa__nn","aa__sil","CH__aa","CH__DD","CH__E","CH__FF","CH__I","CH__kk","CH__nn","CH__O","CH__PP","CH__RR","CH__sil","CH__SS","CH__TH","CH__U","DD__aa","DD__E","DD__FF","DD__I","DD__kk","DD__nn","DD__O","DD__PP","DD__RR","DD__sil","DD__SS","DD__TH","DD__U","E__aa","E__FF","E__I","E__kk","E__nn","E__O","E__PP","E__RR","E__sil","E__SS","E__TH","E__U","FF__aa","FF__I","FF__kk","FF__nn","FF__O","FF__PP","FF__RR","FF__sil","FF__SS","FF__TH","FF__U","I__aa","I__kk","I__nn","I__O","I__PP","I__RR","I__sil","I__SS","I__TH","I__U","kk__nn","kk__sil","nn__sil","O__aa","O__kk","O__nn","O__PP","O__RR","O__sil","O__SS","O__TH","O__U","PP__aa","PP__kk","PP__nn","PP__RR","PP__sil","PP__SS","PP__TH","PP__U","RR__aa","RR__kk","RR__nn","RR__sil","RR__SS","RR__TH","RR__U","SS__aa","SS__kk","SS__nn","SS__sil","SS__TH","SS__U","TH__aa","TH__kk","TH__nn","TH__sil","TH__U","U__aa","U__kk","U__nn","U__sil"]);function sn(e,t){return`${e}__${t}`}function an(e,t){return`pairs/${e}/${t}_minus_sil.png`}function lt(e){return`${e}_minus_sil.png`}function ns(e,t){if(t.has(e))return e;const n=/^pairs\/([^/]+)\//.exec(e);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const s=lt(r);return t.has(s)?s:null}function Bn(e,t){return e.filter(n=>t.has(n))}function rs(e,t,n){const r=Kt(e,t);return Bn(r,n).length>0}function Kt(e,t){if(e===t)return[];const n=[],r=sn(e,t);if(rn.has(r)){for(const i of xt)n.push(an(r,i));return n}const s=sn(t,e);if(rn.has(s)){for(let i=ts-1;i>=0;i--)n.push(an(s,xt[i]));return n}return[]}function ss(e){return e<16?[]:e<35?[1]:e<51?[0,2]:[0,1,2]}function is(e,t){return ss(t).map(r=>e[r]).filter(r=>r!=null)}function as(e,t,n,r){if(r<=0)return 0;const i=Math.max(1,n-t)/r,o=e-t,a=Math.floor(o/i);return Math.min(r-1,Math.max(0,a))}function os(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,s=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${s}.bin`}const cs=[.32,.24,.16,.08,0],us=cs.map(e=>`eyes_${e.toFixed(2)}`),ls=["eyes_0.32","eyes_0.16","eyes_0.00"],fs=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],on=2,ds=-30,Pt=20,ms={fear:-30,anger:-20,sad:-10,neutral:0,love:10,happy:0,disgust:20};function Gt(e){return`brow_${e}`}function jt(e){return ms[e]}function Ce(e){return Math.max(ds,Math.min(Pt,e))}function hs(e,t){if(e===t)return[];const n=e<t?on:-on,r=[];let s=e;for(;s!==t;)s+=n,r.push(s);return r}const ws={fear:"fear",afraid:"fear",anxiety:"fear",anger:"anger",angry:"anger",mad:"anger",sad:"sad",sadness:"sad",sorrow:"sad",neutral:"neutral",calm:"neutral",love:"love",loving:"love",affection:"love",happy:"happy",happiness:"happy",joy:"happy",joyful:"happy",excited:"happy",disgust:"disgust",disgusted:"disgust"};function Le(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?ws[n]??t:t}function Ln(e){return e===0?null:Ht(Gt(e),"eyes_standard")}function On(e){return Ln(jt(e))}function cn(e,t){const n=Gt(jt(e));return!t||t==="eyes_standard"?On(e):e==="neutral"&&t==="eyes_standard"?null:Ht(n,t)}function gs(e,t){const n=[];for(const r of t)n.push(cn(e,r));for(let r=t.length-2;r>=0;r--)n.push(cn(e,t[r]));return n.push(On(e)),n}function ps(e){return e===0?null:Ht(Gt(e),"eyes_standard")}function _s(e,t){return hs(e,t).map(ps).filter(n=>n!=null)}const ys=6;function Ss(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function ks(e){const t=Ce(e);return t>=Pt?Pt:Ce(t+ys)}function Es(e,t,n){const r=Ce(n);return Ss(t,e)?.emphasis?ks(r):r}function un(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const n=Number.parseInt(t[1],10);return Number.isFinite(n)?Ce(n):null}function ze(e,t){return e+Math.random()*(t-e)}function at(){return ze(14,32)}function vs(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:l=380,minDwellMs:f=550}=e;let u="neutral",_="neutral",m=0,p=0,v=0,d={kind:"idle",nextBlinkAt:performance.now()+t},S=null,h="__eyes_open__|neutral|brow:0";function T(k=u){h=`${S??"__eyes_open__"}|${k}|brow:${p}`}function b(k,I=u){S=k;const C=un(k);C!=null?p=C:k==null&&(p=0),T(I)}function V(k){return Ln(k)}function Q(k,I,C){const R=Ce(I),g=Ce(C);if(m=g,R===g){b(V(g));return}const M=[..._s(R,g),V(g)];d={kind:"browBlend",paths:M,index:0,holdUntil:k+at(),targetBrow:g},b(M[0]??null)}function U(k,I){d={kind:"idle",nextBlinkAt:k+ze(n,r)},_=I,b(V(m),I)}function j(k,I,C){const R=C?ls:Math.random()<a?us:fs;d={kind:"playing",paths:gs(I,R),index:0,holdUntil:k+at(),after:"idle",blinkEmotion:I},_=I,b(d.paths[0]??null,I)}function X(k){if(d.kind==="browBlend"){for(;k>=d.holdUntil&&d.index<d.paths.length-1;)d.index+=1,d.holdUntil=k+at();const I=d.paths[d.index]??null;b(I),k>=d.holdUntil&&d.index>=d.paths.length-1&&(p=d.targetBrow,m=d.targetBrow,b(V(d.targetBrow)),d={kind:"idle",nextBlinkAt:k+l});return}if(d.kind==="idle"){b(V(m),_),k>=d.nextBlinkAt&&j(k,_,!1);return}if(d.kind==="doublePause"){b(V(m),d.blinkEmotion),k>=d.resumeAt&&j(k,d.blinkEmotion,!0);return}if(d.kind==="playing"){for(;k>=d.holdUntil&&d.index<d.paths.length-1;)d.index+=1,d.holdUntil=k+at();if(b(d.paths[d.index]??null,d.blinkEmotion),k>=d.holdUntil&&d.index>=d.paths.length-1){if(d.after==="resumeIdle"){U(k+l,u);return}if(d.after==="doublePause"){d={kind:"doublePause",resumeAt:k+ze(i,o),blinkEmotion:d.blinkEmotion},b(V(m),d.blinkEmotion);return}if(d.after==="idle"&&Math.random()<s){d={kind:"doublePause",resumeAt:k+ze(i,o),blinkEmotion:d.blinkEmotion},b(V(m),d.blinkEmotion);return}U(k,d.blinkEmotion)}}}return{advance:X,setTargetEmotion(k){const I=Le(k,u);if(I===u)return;const C=performance.now();f>0&&I!==u&&!(u==="neutral"&&I!=="neutral")&&C-v<f||(u=I,_=I,v=C)},setTargetEyebrow(k){const I=Ce(k);if(I===m&&d.kind!=="browBlend")return;const C=performance.now(),R=d.kind==="browBlend"?un(S)??p:p;m=I,!(I===R&&d.kind!=="browBlend")&&(d.kind==="playing"||d.kind==="doublePause"||Q(C,R,I))},getTargetEmotion:()=>u,getTargetEyebrow:()=>m,getExpressionPath:()=>S,getDrawKey:()=>h,reset(){u="neutral",_="neutral",m=0,p=0,v=0,U(performance.now()+ze(n,r),"neutral")}}}function Ts(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const s=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(i){t&&r===i||(s(),t=!1,r=i,i.startsWith("blob:")&&(n=i),await new Promise((o,a)=>{const l=()=>{const f=e.duration;if(!Number.isFinite(f)||f<=0){a(new Error(`Idle video has invalid duration: ${i}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",l,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${i}`)),{once:!0}),e.src=i,e.load()}))},isReady(){return t},getVideo(){return e},setActive(i){t&&(i?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),s(),t=!1,r=""}}}const bs=50,Nn=400;function As(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function Is(e,t){const n=[];for(const r of e){const s=As(t,r.start_word,r.end_word);if(s.length===0)continue;const i=s[0],o=s[s.length-1];n.push({sentence:r,startMs:Math.max(0,i.wtime-bs),endMs:o.wtime+o.wduration+Nn})}return n.sort((r,s)=>r.startMs-s.startMs)}function Rs(e,t,n,r="neutral"){const s=Le(r);if(t.length===0)return s;if(n.length===0||e<n[0].wtime)return Le(t[0]?.emotion,s);const i=Is(t,n);let o=null;for(const f of i)e>=f.startMs&&e<=f.endMs&&(o=f);if(o)return Le(o.sentence.emotion,s);const a=n[n.length-1],l=a.wtime+a.wduration;return e>l+Nn?Le(t[t.length-1]?.emotion,s):s}function Un(e,t,n,r,s=Pn){const i=new OffscreenCanvas(n,r),o=i.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const a=o.getImageData(0,0,n,r),l=o.createImageData(n,r);l.data.set(a.data);const u=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const _ of t){u.clearRect(0,0,n,r),u.drawImage(_,0,0,n,r);const m=u.getImageData(0,0,n,r);for(let p=0;p<l.data.length;p+=4){const v=m.data[p],d=m.data[p+1],S=m.data[p+2];Math.max(v,d,S)>s&&(l.data[p]=v,l.data[p+1]=d,l.data[p+2]=S,l.data[p+3]=255)}}return o.putImageData(l,0,0),i}let De=null,Qe=null;const ft=new Map;function Ds(){De=null,Qe=null,ft.clear()}_r(Ds);function Ms(e){return e??Qe??void 0}function zt(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function Cs(e){return ht()?Jr(await _t(tn(),e??"")):zt(tn())}async function ln(e,t,n,r){const s=n?await Qr(e,r):await fetch(e).then(f=>{if(!f.ok)throw new Error(`Failed to load ${e}`);return f.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await Yr(await _t(os(t,i.path,n),r??"")):await zt(`${t}/${i.path}`),a=new Map;for(const f of s.cells??[])f.path&&a.set(f.path,f);const l=new Map;for(const f of s.sheets??[])l.set(f.index,f);return{atlas:o,atlasMeta:s,cellByPath:a,sheetByIndex:l,diffBase:t}}async function Ft(e){const t=Ms(e),n=ht();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(De&&(!n||Qe===(t??null))){const i=await De;return{...Ye(i),visemePaths:[...i.viseme.cellByPath.keys()]}}Qe=t??null,ft.clear();const r=Sr();De=(async()=>{const i=await Cs(t),o=await ln(kr(),r,n,t);let a=null;try{a=await ln(Er(),r,n,t)}catch{a=null}return{sil:i,viseme:o,expression:a}})();const s=await De;return{...Ye(s),visemePaths:[...s.viseme.cellByPath.keys()]}}async function Vn(e){if(await Ft(e),!De)throw new Error("Assets not loaded");return De}function Ye(e){return Gr(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function xs(e,t){const n=document.createElement("canvas");return n.width=t.w,n.height=t.h,n.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}async function fn(e,t,n){const r=`${t.diffBase}::${n}`,s=ft.get(r);if(s)return s;const i=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const a=jr(t.atlasMeta,o),l=Ye(e);if(zr(o)){const _=xs(t,o),m=document.createElement("canvas");m.width=l.width,m.height=l.height;const p=m.getContext("2d");return p.fillStyle="#000",p.fillRect(0,0,l.width,l.height),p.drawImage(_,a.x,a.y),m}const f=`${t.diffBase}/${n}`,u=await zt(f);if(u.naturalWidth===l.width&&u.naturalHeight===l.height)return u;throw new Error(`Diff PNG wrong size for ${n}`)})();return ft.set(r,i),i}async function dn(e,t,n,r,s,i){if(s){const{width:p,height:v}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const d=document.createElement("canvas");d.width=p,d.height=v;const S=d.getContext("2d");if(S.clearRect(0,0,p,v),S.drawImage(t,0,0,p,v),i&&!i())return;(e.width!==p||e.height!==v)&&(e.width=p,e.height=v);const h=e.getContext("2d");h.clearRect(0,0,p,v),h.drawImage(d,0,0);return}const o=await Vn(),a=Fn(o.viseme.atlasMeta),{width:l,height:f}=Ye(o);(e.width!==l||e.height!==f)&&(e.width=l,e.height=f);const u=[],_=e.getContext("2d");if(_.clearRect(0,0,l,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const p=o.sil;_.drawImage(p,0,0,l,f);return}if(u.length===0){_.drawImage(t,0,0,l,f);return}const m=Un(t,u,l,f,a);_.drawImage(m,0,0)}async function Bt(e,t,n){const r=await Vn(Qe??void 0),s=Fn(r.viseme.atlasMeta),{width:i,height:o}=Ye(r);(e.width!==i||e.height!==o)&&(e.width=i,e.height=o);const a=[];if(t.mouthPath){const u=new Set(r.viseme.cellByPath.keys()),_=ns(t.mouthPath,u)??(u.has(t.mouthPath)?t.mouthPath:null);_&&a.push(await fn(r,r.viseme,_))}t.expressionPath&&r.expression&&a.push(await fn(r,r.expression,t.expressionPath));const l=e.getContext("2d");if(l.clearRect(0,0,i,o),a.length===0){l.drawImage(r.sil,0,0,i,o);return}const f=Un(r.sil,a,i,o,s);l.drawImage(f,0,0)}async function Ps(e){await Bt(e,{mouthPath:null,expressionPath:null})}function Fs(e){const t=new Map;for(const n of e)t.has(n.vtime)||t.set(n.vtime,n);return[...t.values()].sort((n,r)=>n.vtime-r.vtime)}function Bs(e){const t=Fs(e),n=[];for(let r=0;r<t.length-1;r++){const s=t[r].viseme,i=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;s===i||a<=o||n.push({from:s,to:i,fromVtime:o,toVtime:a})}return n}function Ls(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function Os(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}let $n=null;function mn(e){$n=e}function dt(){return $n}function Ns(e){return`${e.from}→${e.to}@${e.fromVtime}`}function hn(){return{rafTicksSpeaking:0,rafTicksDeduped:0,drawsRequested:0,drawsDisplayed:0,queueSuperseded:0,workerStale:0,rifeFramesOmittedByGap:0,transitionFramesSampled:0,transitionFramesDisplayed:0,transitionFramesMissed:0}}function Us(){let e=hn();const t=new Set,n=new Set,r=new Set;let s="",i=-1,o="";const a=()=>{e=hn(),t.clear(),n.clear(),r.clear(),s="",i=-1,o=""},l=u=>{t.add(u)},f=u=>{u&&r.add(u)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(u,_){const m=Ns(u);e.transitionFramesSampled+=1,m!==s&&(s=m,i=-1,o!==m&&(o=m,e.rifeFramesOmittedByGap+=u.omittedByGap)),_&&n.add(_),i>=0&&u.frameIdx>i+1&&(e.transitionFramesMissed+=u.frameIdx-i-1),i=u.frameIdx},onDrawDisplayed(u,_){if(e.drawsDisplayed+=1,u.transitionMeta){e.transitionFramesDisplayed+=1;const p=u.transitionMeta;l(p.fromVtime),l(p.toVtime),f(u.mouthPath);return}if(u.label.includes("→")){e.transitionFramesDisplayed+=1;return}const m=u.label.trim();if(!(!m||m==="sil")){for(const p of _)if(p.viseme===m&&u.elapsedMs>=p.vtime&&u.elapsedMs<p.vtime+p.vduration){l(p.vtime);break}}},snapshot(u,_){let m=0,p=0;for(const h of u)if(h.viseme!=="sil"){if(h.vtime>=_)break;m+=1,t.has(h.vtime)&&(p+=1)}const v=m>0?Math.round(p/m*100):100,d=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),S=m-p;return{...e,renderLoss:d,visemeSlotsTotal:m,visemeSlotsCovered:p,visemeCoveragePct:v,transitionFramesUniqueSampled:n.size,transitionFramesUniquePainted:r.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+d,visemesShown:p,visemesSkipped:S,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const Wn=400,Vs=200,$s=600,qn="__sil__";function Ws(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===qn:!1}function qs(){return{lastDrawnKey:""}}function pe(e){e.lastDrawnKey="",e.transitionCache=void 0}function Hs(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=Bs(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Ks(e,t){let n="sil";for(const r of e)r.viseme!=="sil"&&(t!=null&&r.vtime>t||(n=r.viseme));return n}function Gs(e,t,n,r=120){if(n!=="sil")return n;const s=Or(e,t,r);return s!=="sil"?s:Ks(e,t)}function js(e,t){return e==="sil"?!1:t?rs(e,"sil",t):Kt(e,"sil").length>0}function zs(){return Wn+$s}function wn(e){return e??qn}function Qs(e,t,n,r){if(e.length===0)return{diffPath:null,label:"sil"};const s=Hs(e,r),i=Ls(s,t);if(i){const a=i.toVtime-i.fromVtime,l=Os(i.fromVtime,i.toVtime);if(t>=l.transStart&&t<i.toVtime){let f=Kt(i.from,i.to);n&&(f=Bn(f,n));const u=is(f,a);if(u.length>0){const _=as(t,l.transStart,i.toVtime,u.length);return{diffPath:u[_]??u[u.length-1],label:`${i.from}→${i.to}`,transitionMeta:{from:i.from,to:i.to,fromVtime:i.fromVtime,toVtime:i.toVtime,frameIdx:_,frameCount:u.length,fullFrameCount:f.length,omittedByGap:Math.max(0,f.length-u.length)}}}return{diffPath:lt(i.to),label:i.to}}}const o=Xe(e,t);return o==="sil"?{diffPath:null,label:"sil"}:{diffPath:lt(o),label:o}}function Hn(e,t){const n=t??wn(e.expressionPath);return`${wn(e.mouthPath)}|${n}`}function Ys(e,t,n,r,s,i,o,a,l,f){const u=Qs(t,n,l,i),_={mouthPath:u.diffPath,expressionPath:r},m=Hn(_,s),p=dt();if(u.transitionMeta&&p?.onTransitionSample(u.transitionMeta,u.diffPath),m===i.lastDrawnKey){p?.onDrawDeduped();return}p?.onDrawRequested(),a(u),o(e,_,m,v=>{v===m&&(i.lastDrawnKey=m)})}function gn(e,t,n,r,s,i,o=null){const a={mouthPath:null,expressionPath:t},l=o!=null?`|idle@${Math.round(o*1e3)}`:"",f=Hn(a,n)+l;!(o!=null)&&f===r.lastDrawnKey||(i(o!=null?"idle":"sil"),s(e,a,f,_=>{_===f&&(r.lastDrawnKey=f)}))}const Js=3;function Kn(e){let t=0;const n=[];let r=!1,s=!1;const i=async()=>{if(!r){r=!0;try{for(;n.length>0;){const a=n.shift(),l=++t,f=await e(a.diffs,l,a);n.length>0||f&&l===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n.length>0&&i()}}},o=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(a,l,f){const u=n.findIndex(_=>_.drawKey===l);u>=0?n[u]={diffs:a,drawKey:l,onDisplayed:f}:(n.length>=Js&&(n.shift(),dt()?.onQueueSuperseded()),n.push({diffs:a,drawKey:l,onDisplayed:f})),o()},reset(){t+=1,n.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}const pn=-1,_n=new Map;async function Xs(e){let t=_n.get(e);if(!t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to fetch worker script (${n.status}): ${e}`);const r=await n.blob();t=URL.createObjectURL(r),_n.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function Zs(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function ei(e,t){(e.width!==t.width||e.height!==t.height)&&(e.width=t.width,e.height=t.height);const n=e.getContext("2d");n&&n.drawImage(t,0,0)}function yn(e,t){let n=0,r=null;const s=Kn(async(i,o)=>(await Ft(),await Bt(e,i),s.isLatestSeq(o)));return{usesWorker:!1,async loadAssets(i){const o=await Ft(i);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,s.reset(),await Ps(e)},drawLiveFrame(i,o,a,l){s.enqueue(o,a,l)},async renderViseme(i,o){n+=1;const a=n;t.onStatus?.(o),await Bt(i,{mouthPath:lt(o),expressionPath:null})},dispose(){n+=1,s.reset()}}}function ti(e,t,n){let r=null,s=1,i=0,o=!1,a=!1,l=null;const f=new Map,u=Kn(async(S,h,T)=>(f.set(h,{drawKey:T.drawKey,onDisplayed:T.onDisplayed}),await v({type:"drawFrame",diffPath:S.mouthPath,expressionDiffPath:S.expressionPath,liveSeq:h},void 0,!0),!1)),_=S=>{if(S===pn){let b=-1,V;for(const[Q,U]of f)Q>=b&&(b=Q,V=U);b>=0&&f.delete(b),V?.onDisplayed?.(V.drawKey);return}const h=-S,T=f.get(h);f.delete(h),T?.onDisplayed?.(T.drawKey)},m=new Map,p=(S,h)=>{a||!r||r.postMessage(S,[])},v=(S,h,T=!1)=>{if(a)return Promise.resolve();const b=s++;return new Promise((V,Q)=>{m.set(b,{resolve:U=>V(U),reject:Q,generation:typeof S.generation=="number"?S.generation:void 0,expectRenderDone:T}),p({...S,requestId:b})})},d=(async()=>{r=await Xs(n),r.onmessage=S=>{if(a)return;const h=S.data;if(h.type==="status"){t.onStatus?.(h.label);return}if(h.type==="frame"){const b=h.generation<0;if(!b&&h.generation!==i){h.bitmap.close();return}if(b&&!(h.generation===pn)){const Q=-h.generation;if(!u.isLatestSeq(Q)){dt()?.onWorkerStale(),h.bitmap.close();return}}if(b&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){dt()?.onWorkerStale(),h.bitmap.close();return}ei(e,h.bitmap),h.bitmap.close(),b&&_(h.generation);return}const T=m.get(h.requestId);if(T)switch(h.type){case"ready":m.delete(h.requestId),T.resolve();break;case"loadAssetsDone":m.delete(h.requestId),l=h.visemePaths?.length?new Set(h.visemePaths):null,T.resolve({width:h.width,height:h.height,visemePaths:h.visemePaths});break;case"renderDone":if(T.expectRenderDone&&T.generation!=null&&h.generation!==T.generation)return;m.delete(h.requestId),T.resolve();break;case"renderAborted":m.delete(h.requestId),T.resolve();break;case"error":m.delete(h.requestId),t.onError?.(h.message),T.reject(new Error(h.message));break}},r.onerror=S=>{if(a)return;const h=S.message||"Worker error";t.onError?.(h);for(const[,T]of m)T.reject(new Error(h));m.clear()},await v({type:"init"}),o=!0})();return{usesWorker:!0,async loadAssets(S){if(a)return{width:842,height:1264};if(await d,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await v({type:"loadAssets",keyHex:S,urls:pr(Pe())})??{width:842,height:1264}},getVisemeAtlasPaths(){return l},async renderSilOnly(){if(a||(await d,a))return;i+=1,u.reset(),f.clear();const S=i;await v({type:"cancelLiveDraws"}),await v({type:"renderSil",generation:S},void 0,!0)},drawLiveFrame(S,h,T,b){a||d.then(()=>{a||u.enqueue(h,T,b)})},async renderViseme(S,h,T={}){if(a||(await d,a))return;i+=1,u.reset(),f.clear();const b=i;try{await v({type:"cancelLiveDraws"}),await v({type:"renderViseme",generation:b,to:h,from:T.from,transitionDurationMs:T.transitionDurationMs,gapMs:T.gapMs,threshold:T.threshold},void 0,!0)}catch(V){if(V?.name==="AbortError")return;throw V}},dispose(){if(!a){a=!0,i+=1,u.reset(),f.clear();for(const[,S]of m)S.resolve();m.clear(),r?.terminate(),r=null}}}}function ni(e,t={}){if(!Zs())return yn(e,t);const n=rr(t.workerScriptUrl);try{return ti(e,t,n)}catch{return yn(e,t)}}class ri extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function It(e,t,n){return new Promise((r,s)=>{const i=globalThis.setTimeout(()=>{s(new ri(n,t))},t);e.then(o=>{globalThis.clearTimeout(i),r(o)},o=>{globalThis.clearTimeout(i),s(o)})})}const si={position:"relative",display:"inline-block",lineHeight:0},ii={display:"block",maxWidth:"100%",height:"auto"},ai={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",padding:"1rem",background:"rgba(0,0,0,0.55)",color:"#fff",fontSize:"0.875rem",textAlign:"center"};function je(e){return ar(e)?$t:Vt}function Te(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const oi=y.forwardRef(function({id:t,avatarId:n,faceId:r,assets:s,authToken:i,apiBase:o,ttsEngineId:a=Me,voiceId:l,speakingRate:f=Ze,className:u,style:_,canvasStyle:m,onStatusChange:p,onDisplayStatus:v,onError:d,onReady:S,showErrorOverlay:h=!0,onUserTranscript:T,onBotOutput:b,onRealtimeLipsyncDebug:V,onFrameRenderStats:Q},U){const j=y.useRef(null),X=y.useRef(null),k=y.useRef(qs()),I=y.useRef(vs()),C=y.useRef(0),R=y.useRef(0),g=y.useRef(0),M=y.useRef(null),O=y.useRef(null),F=y.useRef(!1),A=y.useRef(!1),$=y.useRef(!1),z=y.useRef("sil"),Z=y.useRef(0),re=y.useRef(!1),L=y.useRef(null),K=y.useRef(!1),[le,fe]=y.useState("idle"),[ie,we]=y.useState(null),[ee,Fe]=y.useState(!1),[_e,Ne]=y.useState(!1),[et,Qt]=y.useState({width:842,height:1264}),ye=y.useRef(i??null),be=o?.trim()||Je,Ue=y.useRef(null),ce=y.useRef(null),c=y.useRef(!1),E=y.useRef({width:842,height:1264}),P=y.useRef(null),G=y.useRef("sil"),te=y.useRef(void 0),Se=y.useRef(new Map),se=y.useRef(S),Y=y.useRef(v),ge=y.useRef(d),tt=y.useRef(T),Ve=y.useRef(b),ke=y.useRef(V),$e=y.useRef(Q),Ae=y.useRef(Us());se.current=S,Y.current=v,ge.current=d,tt.current=T,Ve.current=b,ke.current=V,$e.current=Q,y.useEffect(()=>{const w=Ae.current;return mn(w),()=>mn(null)},[]);const nt=y.useCallback(w=>{const D=w?.ttsEngineId??a??ce.current?.ttsEngineId??Me,B=w?.voiceId??l??ce.current?.voiceId??je(D);return{ttsEngineId:D,voiceId:B}},[a,l]),ae=y.useCallback(w=>{we(w),ge.current?.(w)},[]),Ee=y.useCallback(w=>{fe(w),p?.(w)},[p]),q=y.useRef(Ct(Ee,be)),x=y.useRef(null);y.useEffect(()=>(q.current=Ct(Ee,be),i&&q.current.setDeveloperToken(i),q.current.setTtsEngineId(a),()=>{q.current.stop();const w=x.current;w&&(w.disconnect(),x.current=null)}),[Ee,i,a,be]);const de=y.useCallback(()=>(x.current||(x.current=xn(Ee,{speakingRate:f,onUserTranscript:(w,D)=>tt.current?.(w,D),onBotOutput:w=>Ve.current?.(w),onLipsyncDebug:w=>ke.current?.(w)}),x.current.setTtsEngineId(a)),x.current),[Ee,f,a]),J=y.useCallback(()=>{M.current!=null&&(clearTimeout(M.current),M.current=null)},[]),ue=y.useCallback(()=>{O.current!=null&&(clearTimeout(O.current),O.current=null),$.current=!1},[]),We=y.useCallback(()=>{!K.current||!L.current||(ue(),$.current=!0,O.current=setTimeout(()=>{if(O.current=null,Te(q.current,x.current).isSpeaking()){$.current=!1;return}if(F.current){$.current=!1;return}const w=L.current;if(!w){$.current=!1;return}w.restart(),w.setActive(!0);const D=w.getVideo();let B=!1;const W=()=>{B||(B=!0,D.removeEventListener("playing",N),$.current=!1)},N=()=>{W()};if(D.addEventListener("playing",N,{once:!0}),D.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!D.paused){W();return}setTimeout(W,300)},Vs))},[ue]),Ie=y.useCallback(()=>{if(J(),Y.current?.("sil"),F.current=!1,!K.current||!L.current){$.current=!1;return}We()},[J,We]),yt=y.useCallback(async w=>{const D=R.current,B=X.current,W=j.current,N=()=>{w?.fallbackOnly||(F.current=!1)};if(!B||!W||!ee){N();return}if(Te(q.current,x.current).isSpeaking()){N();return}if(w?.fallbackOnly){if(!F.current||(pe(k.current),await B.renderSilOnly(),D!==R.current)||Te(q.current,x.current).isSpeaking())return;Ie();return}if(Ws(k.current)){pe(k.current),Ie();return}const oe=Gs(Te(q.current,x.current).getVisemeQueue(),Z.current,z.current),he=js(oe,P.current);if(pe(k.current),!he){if(await B.renderSilOnly(),D!==R.current||Te(q.current,x.current).isSpeaking())return;Ie();return}try{await B.renderViseme(W,"sil",{from:oe,transitionDurationMs:Wn})}catch(ve){if(ve?.name!=="AbortError")throw ve}if(D!==R.current){N();return}if(Te(q.current,x.current).isSpeaking()){N();return}Ie()},[ee,Ie]),qe=y.useCallback(()=>{if(A.current||F.current)return;A.current=!0,F.current=!0,J();const w=R.current;yt().finally(()=>{A.current=!1}),M.current=setTimeout(()=>{M.current=null,w===R.current&&yt({fallbackOnly:!0})},zs())},[J,yt]),Yt=y.useCallback(async()=>{const w=Math.floor(Date.now()/1e3);if(Ue.current&&w<Ue.current.expiresAt-60)return Ue.current.key;const D=ye.current??await ot();ye.current=D,q.current.setDeveloperToken(D);const B=await mr(D,be);return Ue.current={key:B.value,expiresAt:B.expiresAt},B.value},[be]);y.useEffect(()=>{i&&(ye.current=i,q.current.setDeveloperToken(i))},[i]),y.useEffect(()=>{q.current.setTtsEngineId(a),x.current?.setTtsEngineId(a),ce.current&&(ce.current.ttsEngineId=a)},[a]),y.useEffect(()=>{const w=l??je(a);ce.current&&(ce.current.voiceId=w)},[l,a]);const Re=y.useMemo(()=>Tn(n,r),[n,r]),zn=y.useMemo(()=>s?JSON.stringify(s):Re?`face:${Re}`:`id:${t??""}`,[s,Re,t]);return y.useEffect(()=>{if(!t&&!s&&!Re){ae("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let w=!1;c.current=!1,Fe(!1),Ne(!1),we(null),ce.current=null,L.current=null,K.current=!1;const D=j.current;if(!D)return;let B=null;return(async()=>{try{let W,N,oe,he;if(s)W=s,N=a,oe=l??je(N);else if(Re)Y.current?.("loadFace"),W=Mt(Re),N=a,oe=l??je(N);else{Y.current?.("getAiTwin");const H=await It(vn(t),3e4,"getAiTwin");if(w)return;if(!H.faceId?.trim())throw new Error("getAiTwin returned no faceId");N=H.ttsEngineId,oe=l??H.voiceId??je(N),he=H.knowledgeContextId?.trim()||void 0,W=Mt(H.faceId)}ce.current={ttsEngineId:N,voiceId:oe,personaId:he},bn(W),L.current=Ts(),B=ni(D,{onStatus:H=>{w||Y.current?.(H)},onError:H=>{w||ae(H)},shouldAcceptLiveFrame:()=>Te(q.current,x.current).isSpeaking()&&!F.current}),X.current=B,Y.current?.("auth");const ve=ye.current??i??await It(ot(),3e4,"getAuthToken");if(w)return;ye.current=ve,q.current.setDeveloperToken(ve),q.current.setTtsEngineId(N);const He=ht()?await Yt():void 0;if(w)return;Y.current?.("loadAssets");const ne=await It(B.loadAssets(He),18e4,"load face assets");if(!w&&ne.width>0&&ne.height>0&&(E.current=ne,Qt(ne)),w)return;P.current=B.getVisemeAtlasPaths(),c.current=!0,Fe(!0),se.current?.(),B.renderSilOnly().then(()=>{w||Y.current?.("sil")}),(async()=>{try{const H=await Zr(He);if(await L.current.load(H),w)return;K.current=!0,Ne(!0),pe(k.current),L.current.setActive(!0);const me=L.current.getVideo();await dn(D,me,null,void 0,E.current),w||Y.current?.("idle")}catch(H){if(w)return;K.current=!1,Ne(!1),console.warn("[AiTwin] Idle video unavailable:",H)}})()}catch(W){if(w)return;if(W instanceof ct){ae(W.message);return}ae(W instanceof Error?W.message:"Failed to load AI twin")}})(),()=>{w=!0,L.current?.dispose(),B?.dispose(),X.current=null}},[zn,s,Re,t,a,l,i,Yt,ae]),y.useEffect(()=>{const w={current:!1},D=()=>{const B=j.current,W=X.current,N=Te(q.current,x.current);if(!B||!W||!ee){C.current=requestAnimationFrame(D);return}const oe=N.isSpeaking(),he=oe&&!re.current,ve=re.current&&!oe;he&&(J(),ue(),F.current=!1,A.current=!1,pe(k.current),Ae.current.reset(),te.current=void 0,g.current=0,z.current="sil",Z.current=0,L.current?.setActive(!1)),ve&&(I.current.reset(),L.current?.setActive(!1),qe());const He=ve||F.current||$.current;if(oe){K.current&&L.current?.setActive(!1);const ne=N.getVisemeQueue(),H=N.getPlaybackElapsedMs();Z.current=H;const me=ne.length>0?Xe(ne,H):"sil";me!=="sil"&&(z.current=me);const Be=Rs(H,N.getSentenceEmotions(),N.getWordQueue(),N.getStreamMood());I.current.setTargetEmotion(Be),I.current.setTargetEyebrow(Es(H,N.getWordQueue(),jt(Be))),I.current.advance(performance.now());const St=I.current.getExpressionPath(),kt=I.current.getDrawKey();Ys(B,ne,H,St,kt,k.current,(Ke,Jt,Xt,Qn)=>{const Zt={label:G.current,elapsedMs:H,mouthPath:Jt.mouthPath,transitionMeta:te.current};Se.current.set(Xt,Zt),W.drawLiveFrame(Ke,Jt,Xt,Et=>{const Yn=Se.current.get(Et)??Zt;Se.current.delete(Et),Ae.current.onDrawDisplayed(Yn,ne),Qn?.(Et)})},Ke=>{G.current=Ke.label,te.current=Ke.transitionMeta,Y.current?.(Ke.label)},P.current),Ae.current.onRafTickSpeaking(),$e.current?.(Ae.current.snapshot(ne,H))}else if(!He&&K.current&&L.current){const ne=L.current,H=ne.getVideo();H.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?(ne.setActive(!0),w.current||(w.current=!0,dn(B,H,null,void 0,E.current,()=>!N.isSpeaking()&&!F.current&&!$.current).then(()=>Y.current?.("idle")).finally(()=>{w.current=!1}))):gn(B,null,"__sil__",k.current,(me,Be,St,kt)=>W.drawLiveFrame(me,Be,St,kt),me=>Y.current?.(me))}else He||gn(B,null,"__sil__",k.current,(ne,H,me,Be)=>W.drawLiveFrame(ne,H,me,Be),ne=>Y.current?.(ne));re.current=oe,C.current=requestAnimationFrame(D)};return C.current=requestAnimationFrame(D),()=>{cancelAnimationFrame(C.current),J(),ue(),q.current.stop(),x.current?.stop()}},[ee,_e,qe,J,ue]),y.useImperativeHandle(U,()=>({speakText:async(w,D)=>{const B=w.trim();if(!B)return;const W=X.current;if(!W||!c.current&&!ee)throw new Error("AI twin is not ready");const{ttsEngineId:N,voiceId:oe}=nt(D);we(null),R.current+=1,J(),ue(),F.current=!1,A.current=!1,z.current="sil",Z.current=0,pe(k.current),I.current.reset(),re.current=!1;try{K.current?(L.current?.setActive(!1),L.current?.restart(),pe(k.current)):await W.renderSilOnly(),await q.current.speak(B,{voiceId:oe,speakingRate:D?.speakingRate??f,ttsEngineId:N})}catch(he){throw ae(he instanceof Error?he.message:"TTS failed"),he}},stop:()=>{R.current+=1,J(),ue(),F.current=!1,A.current=!1,q.current.stop(),x.current?.stop(),pe(k.current),re.current=!1,qe()},setTtsEngineId:w=>{q.current.setTtsEngineId(w),x.current?.setTtsEngineId(w),ce.current&&(ce.current.ttsEngineId=w)},renderViseme:async(w,D)=>{const B=X.current,W=j.current;if(!B||!W||!c.current)throw new Error("AI twin is not ready");await B.renderViseme(W,w,{from:D?.from,transitionDurationMs:D?.transitionDurationMs,gapMs:D?.gapMs,onStatus:N=>Y.current?.(N)})},isReady:()=>c.current,getStatus:()=>le,connect:async(w={})=>{we(null);try{let D=w.authToken?.trim();D||(D=ye.current??i??await ot(),ye.current=D);const B=w.voiceId?.trim()??l??ce.current?.voiceId,W=w.personaId?.trim()??ce.current?.personaId,N=de();await N.unlockAudio(),await N.connect({...w,apiBase:w.apiBase?.trim()||be,authToken:D,voiceId:B,personaId:W,speakingRate:w.speakingRate??f})}catch(D){throw ae(D instanceof Error?D.message:"Voice connect failed"),D}},disconnect:async()=>{const w=x.current;w&&(R.current+=1,J(),ue(),F.current=!1,A.current=!1,pe(k.current),re.current=!1,await w.disconnect(),qe())},isConnected:()=>x.current?.isConnected()??!1,getVoiceStream:()=>x.current?.getVoiceStream()??q.current?.getVoiceStream()??null}),[ee,f,i,l,J,ue,qe,ae,nt,de,le]),vt.jsxs("div",{className:u,style:{...si,..._},children:[vt.jsx("canvas",{ref:j,width:et.width,height:et.height,style:{...ii,...m},"aria-label":t?`AI twin ${t}`:"AI twin face"}),h&&ie?vt.jsx("div",{style:ai,children:ie}):null]})}),Gn="thumbnail.webp";function ci(e,t=Ot){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Gn}`}const ui=new Set([".png",".jpg",".jpeg",".webp"]);function jn(e=".png"){const t=e.toLowerCase();return ui.has(t)?`source${t}`:"source.png"}function li(e,t=Ot,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${jn(n)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Gn;exports.AiTwin=oi;exports.AiTwinNotFoundError=ct;exports.DEFAULT_TTS_ENGINE_ID=Me;exports.MIC_SAMPLE_RATE=Wt;exports.OCULUS_VISEME_IDS=In;exports.PLAYBACK_SAMPLE_RATE=qt;exports.SPEAKING_RATE_MAX=pt;exports.SPEAKING_RATE_MIN=gt;exports.TTS_ENGINE_CARTESIA=xe;exports.TTS_ENGINE_GOOGLE=Nt;exports.TTS_ENGINE_INWORLD=mt;exports.VISEME_IDS=es;exports.VISEME_TEST_CARTESIA_VOICE_ID=$t;exports.VISEME_TEST_SPEAKING_RATE=Ze;exports.VISEME_TEST_VOICE_ID=Vt;exports.aiTwinSourceFilename=jn;exports.buildVoiceWebSocketUrl=Cn;exports.createAvatarTtsLipsyncController=Ct;exports.createRealtimeVoiceLipsyncController=xn;exports.faceAssetUrls=Mt;exports.fetchAiTwin=vn;exports.fetchDevAuthToken=ot;exports.getAiTwinSourceUrl=li;exports.getAiTwinThumbnailUrl=ci;exports.normalizeOculusViseme=Rn;exports.resolveDirectFaceId=Tn;exports.resolveVisemeAtTime=Xe;exports.resolveWordAtTime=Nr;exports.setActiveTwinAssets=bn;
|