@streamoji/aitwin 0.5.2 → 0.5.4
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/README.md +64 -0
- package/dist/aitwin.cjs +6 -5
- package/dist/aitwin.js +3152 -2543
- package/dist/index.d.ts +107 -0
- package/package.json +1 -1
package/dist/aitwin.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ur=require("react/jsx-runtime"),T=require("react"),vs=require("@pipecat-ai/client-js"),kr=require("@pipecat-ai/websocket-transport"),ue=require("pixi.js");var cr=typeof document<"u"?document.currentScript:null;const bs="https://aitwin.bubu.social",bn={publicBase:bs},Ts="0.5.2",Es={version:Ts},ks={},kt="https://ai.aitwin.me",Ir=`${bn.publicBase}/custom-faces`,Is=`${bn.publicBase}/aitwin-workers/v${Es.version}/visemeDiffPreview.worker.js`;function As(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:cr&&cr.tagName.toUpperCase()==="SCRIPT"&&cr.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?ks?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Is}const Ps="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",lr=3e3,bt=16,Xr=3e3,xs=4e3,Ms=.85,Rs=8,Ar=400,Pr="eng_a7f2b9c1",Yt="eng_d4e8f3a2",et="eng_c9b1e6d4",Je=et,Tn=new Set([Yt,et]),En={[Pr]:"oculus_direct",[et]:"oculus_direct",[Yt]:"inworld_word"},Jr={google:Pr,inworld:Yt,cartesia:et};function kn(e){return En[e]}function Cs(e){return e===et}function Ds(e){if(e.ttsEngineId&&e.ttsEngineId in En)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Jr?Jr[t]:Je}class $t extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function In(e,t=Ps){const r=new URL(t);r.searchParams.set("id",e);const n=await fetch(r.toString());if(n.status===404)throw new $t;if(!n.ok)throw new Error(`getAiTwin failed (${n.status})`);const s=await n.json();if(!s.success)throw new $t(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:Ds(s.data),authToken:l}}const Fs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Bs="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Ls="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Os="6TNvp3SCs4Og0a1ijm9TommXLql1",Ns="Swaraj Mali";async function Wt(){const e=await fetch(Fs,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Bs,"Client-Secret":Ls},body:JSON.stringify({userId:Os,userName:Ns})});if(!e.ok)throw new Error(`getAuthToken failed (${e.status})`);const t=await e.json(),r=t.authToken??t.token??"";if(!r.trim())throw new Error("getAuthToken returned no token");return r}async function Vs(e,t=kt){const r=await fetch(`${t.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${e}`}});if(!r.ok)throw new Error(`/api/session-value failed (${r.status})`);const n=await r.json();if(!n.value)throw new Error("Session value response missing value");return n}function Us(e){const t=e.trim();if(t.length%2!==0)throw new Error("Invalid hex key");const r=new Uint8Array(t.length/2);for(let n=0;n<t.length;n+=2)r[n/2]=Number.parseInt(t.slice(n,n+2),16);return r}function Lt(e){return Uint8Array.from(e)}function Ws(e,t){const r=new Uint8Array(e.length+t.length);return r.set(e,0),r.set(t,e.length),r}async function $s(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 r=new Uint8Array(e),n=Lt(r.subarray(0,12)),s=Lt(r.subarray(12,28)),i=Lt(r.subarray(28)),o=Lt(Ws(i,s)),a=await crypto.subtle.importKey("raw",Us(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:n,tagLength:128},a,o)}let wr=null;const gr=new Set;function Ot(e){return e.includes("/custom-faces/")}function Ht(e){const t=e.binBase.trim().replace(/\/$/,""),r=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||Ot(t)||Ot(r)))return{twinBase:r,binBase:t,encrypted:!1};const s=Ot(t)?t:Ot(r)?r:t;return{twinBase:s,binBase:s,encrypted:!0}}function tt(e){return Ht(e).encrypted}function yr(e,t=Ir){const r=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:r,binBase:r,encrypted:!0}}function An(e,t){return(e??t)?.trim()||void 0}function Pn(e){wr=Ht(e);for(const t of gr)t()}function Hs(e,t){const r=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!r)return Ht(e);const n=s=>{try{return new URL(s,r).href.replace(/\/$/,"")}catch{return s}};return Ht({twinBase:n(e.twinBase),binBase:n(e.binBase),encrypted:e.encrypted})}function rt(){if(!wr)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return wr}function xn(e){return gr.add(e),()=>gr.delete(e)}function Kt(){const e=rt();return tt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Ks(){const e=rt();return tt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Mn(){const e=rt();return tt(e)?e.binBase:e.twinBase}function It(){return tt(rt())}function Rn(){const e=rt();return tt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function Cn(){const e=rt();return tt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function Dn(e){const t=e.split(/\r?\n/);let r="",n="";for(const i of t)i.startsWith("event:")?r=i.slice(6).trim():i.startsWith("data:")&&(n=i.slice(5).trim());if(!r)return null;let s={};if(n)try{s=JSON.parse(n)}catch{s={raw:n}}return{event:r,data:s}}const Fn=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],qs=new Map(Fn.map(e=>[e.toLowerCase(),e]));function Qt(e){const t=(e??"").trim();return t?qs.get(t.toLowerCase())??"sil":"sil"}const Gs={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 zs(e){if(!e)return["sil"];const t=e.toLowerCase();return Gs[t]??["sil"]}function Bn(e,t){const r=e.word.length;if(r<=0)return 0;const n=e.wduration;if(n<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/n));return Math.min(r-1,Math.floor(s*r))}function ft(e,t){const r=Math.max(0,Math.min(e.length-1,t));return e[r]??""}function Xt(e,t){const r=e.toLowerCase().replace(/[^a-z']/g,"");return!r||ft(r,t)!=="w"||t>0&&ft(r,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(r)}function js(e,t){const r=e.toLowerCase(),n=ft(r,t),s=r.slice(Math.max(0,t-1),t+2);return n==="i"||n==="y"?"I":s.includes("ee")||n==="e"||r.includes("ea")?"E":"aa"}function Ys(e,t){const r=e.toLowerCase(),n=r.slice(Math.max(0,t-1),Math.min(r.length,t+3));if(/oo|ou|uw/.test(n))return"U";if(Xt(r,t))return"FF";const s=ft(r,t);return s==="u"||s==="w"?"U":"O"}function Qs(e,t){const r=e.toLowerCase();if(Xt(r,t))return"FF";const n=r.slice(Math.max(0,t-2),t+1);if(/qu/.test(n))return"U";const s=r.slice(Math.max(0,t-1),Math.min(r.length,t+3));return/wo|wh/.test(s)||ft(r,t)==="o"?"O":"U"}const Nt={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function Xs(e,t){const r=e.toLowerCase(),n=ft(r,t);if(Nt[n])return Nt[n];for(let s=0;s<r.length;s++){const i=r[s];if(Nt[i])return Nt[i]}return"DD"}function Ln(e,t,r){const n=zs(e);if(n.length===1)return n[0];const s=t.trim();if(!s)return n[0];const i=(e??"").toLowerCase(),o=Math.max(0,r);switch(i){case"aei":return js(s,o);case"o":return Ys(s,o);case"qw":return Qs(s,o);case"cdgknstxyz":return Xs(s,o);default:return n[0]}}const xr=16,_r=47,On=new Set(["aa","E","I"]),Nn=new Set(["DD","SS","kk","CH"]),Js=[On,Nn];function Zs(e){for(const t of Js)if(t.has(e))return t;return null}function ei(e){return Zs(e)!=null}function Vn(e,t=xr){return t<=0?e:Math.round(e/t)*t}function Mr(e,t=xr){return e.map(r=>({...r,vtime:Vn(r.vtime,t)}))}function Un(e){const t=new Map;for(const r of e)t.has(r.vtime)||t.set(r.vtime,r);return[...t.values()].sort((r,n)=>r.vtime-n.vtime)}function Rr(e){if(e.length<=2)return[...e];const t=[e[0]];for(let r=1;r<e.length-1;r++){const n=e[r],s=e[r+1],i=t[t.length-1];if(!ei(n.viseme)){t.push(n);continue}const o=n.vtime-i.vtime,a=s.vtime-n.vtime;o<_r||a<_r||t.push(n)}return t.push(e[e.length-1]),t}function Jt(e){return Rr(Un(Mr(e)))}function Wn(e,t){let r="sil";for(const n of e){if(n.vtime>t)break;n.viseme!=="sil"&&(r=n.viseme)}return r}function Zt(e){const t=Un(Mr(e)),r=Rr(t),n=new Set(r.map(i=>i.vtime)),s=[];for(const i of t)n.has(i.vtime)||s.push({viseme:i.viseme,vtime:i.vtime});return s}function ti(e){return Zt(e).map(t=>t.viseme)}const ri=32,Zr=48;function $n(e){let t=0;for(const r of e)t=Math.max(t,r.vtime+r.vduration);return t}function Hn(e){let t=null,r=-1;for(const n of e){if(n.viseme==="sil")continue;const s=n.vtime+n.vduration;s>r&&(t=n,r=s)}return t}function ni(e){return Jt(e).find(r=>r.viseme!=="sil")??null}function Qe(e){const t=$n(e);return Hn(e)?t+Ar:t}function si(e){const t=[],r=ni(e);r&&r.vtime>0&&t.push({from:"sil",to:r.viseme,fromVtime:0,toVtime:r.vtime});const n=Hn(e),s=$n(e);return n&&t.push({from:n.viseme,to:"sil",fromVtime:s,toVtime:s+Ar}),t}function Kn(e){const t=Jt(e),r=[];for(let n=0;n<t.length-1;n++){const s=t[n].viseme,i=t[n+1].viseme,o=t[n].vtime,a=t[n+1].vtime;s===i||a<=o||r.push({from:s,to:i,fromVtime:o,toVtime:a})}return r}function qn(e){return e.length===0?[]:[...si(e),...Kn(e)]}function ii(e,t){let r=null;for(const n of e){const{transStart:s,transEnd:i}=Gn(n.fromVtime,n.toVtime,n.from,n.to);t>=s&&t<i&&(r=n)}return r}function Gn(e,t,r,n){const s=Math.max(0,t-e);if((r==="PP"||n==="PP")&&s>Zr){const f=Zr,c=t,u=c-f;return{gapMs:s,effectiveGapMs:f,holdEnd:u,transStart:u,transEnd:c}}const o=s>0?Math.max(s,ri):0,a=e,l=e+o;return{gapMs:s,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:l}}function zn(e,t,r,n,s,i){n.forEach(o=>{const l=String(o.word??"").trim();if(!l)return;const f=Math.round((o.start??0)*1e3),c=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:l,wtime:s+f,wduration:c,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),r.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const l=Math.round((o.start??0)*1e3),f=Math.max(1,Math.round((o.duration??0)*1e3)),c=s+l,u=Qn(t,c),d=u?Bn(u,c):0;let p;kn(i)==="oculus_direct"?(p=Qt(a),p==="U"&&u&&Xt(u.word,d)&&(p="FF")):p=Ln(a,u?.word??"",d),e.push({viseme:p,weight:1,vtime:c,vduration:f})})}function jn(e,t){let r=t;for(const n of e){const s=Math.round((n.start??0)*1e3),i=Math.max(1,Math.round((n.duration??0)*1e3));r=Math.max(r,t+s+i)}return r}const Cr=16e3;function Yn(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Cr}function oi(e){let t=e.trim();const r=t.indexOf(",");t.startsWith("data:")&&r>=0&&(t=t.slice(r+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const n=t.length%4;return n!==0&&(t+="=".repeat(4-n)),t}function ai(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function en(e,t,r=Cr){const n=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(n.buffer,n.byteOffset,n.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,r);return o.copyToChannel(i,0),o}function ui(e){const t=oi(e),r=window.atob(t),n=new Uint8Array(r.length);for(let s=0;s<r.length;s++)n[s]=r.charCodeAt(s);return n}async function tn(e,t,r=Cr){const n=ui(t),s=Yn(r);if(ai(n)){const i=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return e.decodeAudioData(i)}if(n.length>=2&&n.length%2===0)return en(e,n,s);try{const i=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(i)}catch{return en(e,n,s)}}function Qn(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function Xn(e,t){const r=[],n=[];let s=null,i=!1,o=!1,a=!1,l=!1,f=0,c=0,u=0,d=null,p=1,E=t,m=!1,A=null,x=0,C=!1,w=!1,b=0,O=null,V=null,X=null;const fe=()=>({visemes:[],words:[],segmentOffsetMs:0}),P=()=>{w=!1,b=0},D=()=>{d!=null&&(clearTimeout(d),d=null)},N=()=>{for(const S of n){try{S.onended=null,S.stop(0)}catch{}try{S.disconnect()}catch{}}n.length=0},j=()=>{for(const S of n)S.playbackRate.value=p},F=()=>{if(!(m||!l||i||w||n.length>0||r.length>0)){if(a&&s&&c>0){const S=(s.currentTime-c)*1e3;if(S<x){D();const M=p>0?(x-S)/p:x-S;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,M));return}}o=!1,D(),e.onSpeakingDone(),e.onNotify()}},Y=S=>{const M=Qe(S);if(M<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,f=performance.now(),e.onSpeakingStart(),e.onNotify(),D();const G=p>0?M/p:M;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},G)},$=(S,M,G,z)=>{M.length!==0&&(u=G,M.forEach(I=>{const g=String(I.word??"").trim();if(!g)return;const _=Math.round((I.start??0)*1e3),y=I.duration!=null?Math.round(I.duration*1e3):I.end!=null?Math.max(1,Math.round((I.end-(I.start??0))*1e3)):0;S.push({word:g,wtime:u+_,wduration:y,queueIndex:S.length,gesture:I.gesture??null,emphasis:I.emphasis===!0})}))},q=(S,M,G,z,I,W)=>{G.length!==0&&(u=z,G.forEach(g=>{const _=String(g.symbol??g.viseme??"").trim();if(!_)return;const y=Math.round((g.start??0)*1e3),Z=Math.max(1,Math.round((g.duration??0)*1e3)),oe=u+y,ye=Qn(M,oe),Re=ye?Bn(ye,oe):0;let _e;kn(W)==="oculus_direct"?(_e=Qt(_),_e==="U"&&ye&&Xt(ye.word,Re)&&(_e="FF")):_e=Ln(_,ye?.word??"",Re),S.push({viseme:_e,weight:1,vtime:oe,vduration:Z})}),e.onNotify())},k=(S,M,G,z,I,W,g)=>{$(M,z,I),q(S,M,G,I,W,g)},ee=(S,M,G)=>{X===S&&S.visemes===M||(M.length=0,G.length=0,S.visemes=M,S.words=G,S.segmentOffsetMs=0,X=S,u=0,x=0)},he=async()=>{const S=window.AudioContext||window.webkitAudioContext;return s||(s=new S),s.state==="suspended"&&await s.resume(),A||(A=s.createMediaStreamDestination()),s},ce=(S,M)=>{if(!s)return 0;const G=s,z=G.currentTime,I=z+.02;if(M.isFirstAudio){c<=0&&(c=I);const g=(I-z)*1e3;f=performance.now()+g}M.onBeforeStart?.(I);const W=G.createBufferSource();return W.buffer=S,W.playbackRate.value=p,W.connect(G.destination),A&&W.connect(A),n.push(W),m?(n.pop(),I):(M.isFirstAudio&&(o=!0,e.onSpeakingStart()),W.onended=()=>{const g=n.indexOf(W);g>=0&&n.splice(g,1),e.onNotify(),!m&&(O&&V?te(O,V):F())},W.start(I),I)},te=async(S,M)=>{if(m||i||n.length>0)return;if(r.length===0){F();return}i=!0;let G=!1;try{const z=await he();if(m)return;const I=r[0];if(!I)return;const W=!o;if(C&&(e.shouldHoldForWarmup?.()??!1)&&(w||W&&I.newStream)||w){ee(I.utterance,S,M);for(const y of r){if(m)return;y.audioBuffer||(y.audioBuffer=await tn(z,y.audio,y.sampleRate)),a=!0,w||(w=!0,b=0,y.newStream&&y.onNewStream?.()),y.visemesQueued||(k(S,M,y.visemes,y.words,b,!0,E),y.visemesQueued=!0,b+=Math.round(y.audioBuffer.duration*1e3),x=Math.max(x,Qe(S)))}e.onNotify();return}const _=r.shift();if(!_||(_.audioBuffer||(_.audioBuffer=await tn(z,_.audio,_.sampleRate)),m))return;a=!0,D(),ee(_.utterance,S,M),_.visemesQueued=!1,_.newStream&&_.onNewStream?.(),ce(_.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:y=>{c=y,u=0,f=performance.now()+(y-z.currentTime)*1e3,k(S,M,_.visemes,_.words,0,!0,E),_.visemesQueued=!0,_.utterance.segmentOffsetMs=0}}),G=n.length>0,x=Qe(S),e.onNotify()}catch(z){console.error("[avatarChunkPlayback] audio chunk failed:",z)}finally{if(i=!1,m)return;if(w){r.some(I=>!I.audioBuffer||!I.visemesQueued)&&te(S,M);return}!G&&n.length===0&&r.length>0?te(S,M):n.length===0&&r.length===0&&F()}};return{setStreamTtsEngineId:S=>{E=S},setPlaybackSpeed:S=>{p=Math.max(.1,Math.min(1,S)),j()},getPlaybackSpeed:()=>p,setLipsyncWarmupHoldEnabled:S=>{C=S,S||P()},isWarmingUp:()=>w,releaseWarmupHold:()=>{if(w){w=!1,b=0;for(const S of r)S.newStream=!1;O&&V&&te(O,V),e.onNotify()}},resetForNewStream:S=>{m=!1,l=!1,E=S,x=0},resumeBotStream:()=>{m=!1,l=!1},clearAborted:()=>{m=!1},primeAudioContext:async()=>{const S=window.AudioContext||window.webkitAudioContext;s||(s=new S),s.state==="suspended"&&await s.resume(),s&&!A&&(A=s.createMediaStreamDestination())},stop:()=>{m=!0,D(),N(),r.length=0,i=!1,o=!1,a=!1,l=!1,u=0,c=0,f=0,x=0,O=null,V=null,X=null,P()},markStreamComplete:S=>{if(x=Math.max(x,Qe(S)),l=!0,!a&&S.length>0){Y(S);return}F()},playAudioChunk:async(S,M,G,z,I,W,g)=>{if(m)return;O=S,V=M;const _=Yn(g?.sampleRate),y=g?.newStream===!0,Z=fe();if(!G?.trim()){if(z.length===0&&I.length===0)return;ee(Z,S,M),y&&g?.onNewStream?.(),k(S,M,z,I,0,!0,E),x=Qe(S),!o&&x>0&&Y(S),e.onNotify();return}r.push({audio:G,audioBuffer:null,utterance:Z,visemes:z,words:I,isNewSegment:W,sampleRate:_,newStream:y,onNewStream:g?.onNewStream,visemesQueued:!1}),await te(S,M)},queueTimingsOnly:(S,M,G,z,I)=>{if(m)return;const W=fe();ee(W,S,M),k(S,M,G,z,0,!0,E),W.segmentOffsetMs=0,x=Qe(S)},getPlaybackElapsedMs:()=>a&&s&&c>0?Math.max(0,(s.currentTime-c)*1e3):o?Math.max(0,(performance.now()-f)*p):0,isSpeaking:()=>o?!0:!a||!s||c<=0?!1:(s.currentTime-c)*1e3<x,getVoiceStream:()=>A?A.stream:null,getPlaybackStartPerf:()=>f,bargeIn:()=>{m=!0,l=!1,D(),N(),r.length=0,i=!1,o=!1,a=!1,u=0,c=0,f=0,x=0,O=null,V=null,X=null,P()},interrupt:()=>{m=!0,l=!1,D(),N(),r.length=0,i=!1,o=!1,a=!1,u=0,c=0,f=0,x=0,O=null,V=null,X=null,P()}}}function At(e,t){let r=null;for(const n of e)t<n.vtime||t>=n.vtime+n.vduration||(!r||n.vtime>=r.vtime)&&(r=n);return r?r.viseme:"sil"}function Jn(e,t,r=120){const n=At(e,t);if(n!=="sil")return n;let s=null;for(const i of e){if(i.vtime>t)break;const o=i.vtime+i.vduration;o<=t&&t-o<=r&&(s=i)}return s?.viseme??"sil"}function ci(e,t,r=400){const n=t-r;let s=0;for(const i of e)if(i.vtime+i.vduration<n)s+=1;else break;s>0&&e.splice(0,s)}function li(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function rn(e,t){const r=e.trim();if(!r)return null;try{const n=r.replace(/\s+/g,""),s=atob(n).length,i=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return s/2/i*1e3}catch{return null}}const er=.5,tr=1.5,Dr="Olivia",Fr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Pt=.85;function Sr(e,t=kt,r={}){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,s=[],i=[],o=[],a=[];let l=0;const f=[],c=[];let u="",d="neutral",p="",E=Je;const m=new Set;let A=0,x=null;const C=()=>m.forEach(F=>F());let w=()=>!1;const b=Xn({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:C,shouldHoldForWarmup:()=>w()},Je),O=()=>b.getPlaybackElapsedMs(),V=(F,Y=u)=>{if(!r.onLipsyncDebug)return;const $=O(),q=s,k=Zt(o).map(ee=>({viseme:ee.viseme,vtimeMs:ee.vtime}));r.onLipsyncDebug({event:F,spokenText:Y,mood:d,playbackAnchorPerf:b.getPlaybackStartPerf(),playbackElapsedMs:$,queueLength:q.length,activeViseme:At(q,$),segments:c.map(ee=>({...ee,visemes:[...ee.visemes]})),fullQueueLength:o.length,compactionSkipped:k})},X=(F,Y)=>{r.onLipsyncDebug&&(x={event:F,spokenText:Y},A===0&&(A=requestAnimationFrame(()=>{A=0;const $=x;x=null,$&&V($.event,$.spokenText)})))},fe=(F,Y,$,q,k)=>{if(!r.onLipsyncDebug)return;const ee=s.slice(Y),he=$.filter(ce=>String(ce.symbol??ce.viseme??"").trim());c.push({spokenText:F,audioOffsetMs:ee[0]?.vtime??0,isNewSegment:q,chunkDurationMs:k,receivedAtMs:performance.now(),visemes:ee.map((ce,te)=>{const J=he[te];return{rawSymbol:String(J?.symbol??J?.viseme??ce.viseme).trim(),viseme:ce.viseme,startSec:Number(J?.start??0),durationSec:Number(J?.duration??0),vtimeMs:ce.vtime,vdurationMs:ce.vduration}})})},P=()=>{o.length=0,a.length=0,l=0},D=(F,Y,$,q,k)=>{if(F.length===0&&Y.length===0)return;zn(o,a,F,Y,l,k);const ee=jn(F,l),he=$?rn($,q):null;l=Math.max(ee,he!=null?l+he:l)},N=()=>{b.stop(),s.length=0,i.length=0,P(),f.length=0,d="neutral",c.length=0,u="",e("idle"),X("reset"),C()};return{setDeveloperToken:F=>{p=F},setTtsEngineId:F=>{E=F},getTtsEngineId:()=>E,speak:async(F,Y)=>{N(),e("loading"),u=F,c.length=0,P();const $=p.trim();if(!$)throw new Error("Developer token required for avatar_ttsWithPoses");const q=Y?.ttsEngineId??E??Je;b.resetForNewStream(q),b.setStreamTtsEngineId(q);const k=Y?.voiceId??Dr,ee=Y?.speakingRate??Pt,he=Math.max(er,Math.min(tr,ee)),ce={user_query:F,ttsEngineId:q,speakingRate:he,tenant:"aiTwin"};Tn.has(q)&&(ce.voice_id=k);try{const te=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${$}`},body:JSON.stringify(ce)});if(!te.ok)throw new Error(`avatar_ttsWithPoses failed (${te.status})`);const J=te.body;if(!J)throw new Error("No response body");const ke=J.getReader(),Me=new TextDecoder;let S="",M=!0;const G=async z=>{const I=Dn(z);if(I){if(I.event==="audio"){const W=I.data.chunk,g=I.data.visemes??[],_=I.data.words??[],y=I.data.is_new_segment??!1,Z=I.data.sample_rate,oe=s.length;if(D(g,_,W,Z,q),W){const ye=M;M=!1,await b.playAudioChunk(s,i,W,g,_,y,{sampleRate:Z,newStream:ye}),fe(F,oe,g,y,rn(W,Z)),X("audio_chunk",F)}else(g.length>0||_.length>0)&&(b.queueTimingsOnly(s,i,g,_,y),fe(F,oe,g,y,null),X("audio_chunk",F))}else if(I.event==="metadata"){const W=I.data.mood;typeof W=="string"&&W.trim()&&(d=W.trim());const g=I.data.sentence_emotions;if(Array.isArray(g)){f.length=0;for(const _ of g){if(!_||typeof _!="object")continue;const y=_;f.push({sentence_index:Number(y.sentence_index??0),text:String(y.text??""),sentiment:typeof y.sentiment=="string"?y.sentiment:void 0,emotion:String(y.emotion??d),start_word:Number(y.start_word??0),end_word:Number(y.end_word??0)})}}C(),X("metadata",F)}else if(I.event==="error")throw new Error(String(I.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:z,value:I}=await ke.read();I&&(S+=Me.decode(I,{stream:!0}));const W=S.split(`
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const z=require("react/jsx-runtime"),w=require("react"),Fi=require("@pipecat-ai/client-js"),Rn=require("@pipecat-ai/websocket-transport"),pe=require("pixi.js");var wn=typeof document<"u"?document.currentScript:null;const Li="https://aitwin.bubu.social",Dr={publicBase:Li},Oi="0.5.4",Ni={version:Oi},Vi={},at="https://ai.aitwin.me",Dn=`${Dr.publicBase}/custom-faces`,Ui=`${Dr.publicBase}/aitwin-workers/v${Ni.version}/visemeDiffPreview.worker.js`;function Wi(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:wn&&wn.tagName.toUpperCase()==="SCRIPT"&&wn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Vi?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Ui}const Hi="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",gn=3e3,At=16,ar=3e3,$i=4e3,zi=.85,Ki=8,Bn=400,Fn="eng_a7f2b9c1",nn="eng_d4e8f3a2",ot="eng_c9b1e6d4",it=ot,Br=new Set([nn,ot]),Fr={[Fn]:"oculus_direct",[ot]:"oculus_direct",[nn]:"inworld_word"},or={google:Fn,inworld:nn,cartesia:ot};function Lr(e){return Fr[e]}function ji(e){return e===ot}function qi(e){if(e.ttsEngineId&&e.ttsEngineId in Fr)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in or?or[t]:it}class Yt extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function Or(e,t=Hi){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new Yt;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new Yt(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,l=String(a.authToken??o??"").trim()||void 0;return{...a,ttsEngineId:qi(i.data),authToken:l}}const Gi="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Yi="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Qi="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Xi="6TNvp3SCs4Og0a1ijm9TommXLql1",Ji="Swaraj Mali";async function Pt(){const e=await fetch(Gi,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Yi,"Client-Secret":Qi},body:JSON.stringify({userId:Xi,userName:Ji})});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 Zi(e,t=at){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 es(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 $t(e){return Uint8Array.from(e)}function ts(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function ns(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=$t(n.subarray(0,12)),i=$t(n.subarray(12,28)),s=$t(n.subarray(28)),o=$t(ts(s,i)),a=await crypto.subtle.importKey("raw",es(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let Tn=null;const kn=new Set;function zt(e){return e.includes("/custom-faces/")}function Qt(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||zt(t)||zt(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=zt(t)?t:zt(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function ct(e){return Qt(e).encrypted}function xn(e,t=Dn){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Nr(e,t){return(e??t)?.trim()||void 0}function Vr(e){Tn=Qt(e);for(const t of kn)t()}function rs(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return Qt(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return Qt({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function ut(){if(!Tn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Tn}function Ur(e){return kn.add(e),()=>kn.delete(e)}function Xt(){const e=ut();return ct(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function is(){const e=ut();return ct(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Wr(){const e=ut();return ct(e)?e.binBase:e.twinBase}function Rt(){return ct(ut())}function Hr(){const e=ut();return ct(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function $r(){const e=ut();return ct(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function zr(e){const t=e.split(/\r?\n/);let n="",r="";for(const s of t)s.startsWith("event:")?n=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());if(!n)return null;let i={};if(r)try{i=JSON.parse(r)}catch{i={raw:r}}return{event:n,data:i}}const Kr=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],ss=new Map(Kr.map(e=>[e.toLowerCase(),e]));function rn(e){const t=(e??"").trim();return t?ss.get(t.toLowerCase())??"sil":"sil"}const as={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 os(e){if(!e)return["sil"];const t=e.toLowerCase();return as[t]??["sil"]}function jr(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const i=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(i*n))}function yt(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function sn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||yt(n,t)!=="w"||t>0&&yt(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function cs(e,t){const n=e.toLowerCase(),r=yt(n,t),i=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":i.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function us(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";if(sn(n,t))return"FF";const i=yt(n,t);return i==="u"||i==="w"?"U":"O"}function ls(e,t){const n=e.toLowerCase();if(sn(n,t))return"FF";const r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const i=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(i)||yt(n,t)==="o"?"O":"U"}const Kt={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function fs(e,t){const n=e.toLowerCase(),r=yt(n,t);if(Kt[r])return Kt[r];for(let i=0;i<n.length;i++){const s=n[i];if(Kt[s])return Kt[s]}return"DD"}function qr(e,t,n){const r=os(e);if(r.length===1)return r[0];const i=t.trim();if(!i)return r[0];const s=(e??"").toLowerCase(),o=Math.max(0,n);switch(s){case"aei":return cs(i,o);case"o":return us(i,o);case"qw":return ls(i,o);case"cdgknstxyz":return fs(i,o);default:return r[0]}}const Ln=16,En=47,Gr=new Set(["aa","E","I"]),Yr=new Set(["DD","SS","kk","CH"]),ds=[Gr,Yr];function ms(e){for(const t of ds)if(t.has(e))return t;return null}function hs(e){return ms(e)!=null}function Qr(e,t=Ln){return t<=0?e:Math.round(e/t)*t}function On(e,t=Ln){return e.map(n=>({...n,vtime:Qr(n.vtime,t)}))}function Xr(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 Nn(e){if(e.length<=2)return[...e];const t=[e[0]];for(let n=1;n<e.length-1;n++){const r=e[n],i=e[n+1],s=t[t.length-1];if(!hs(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<En||a<En||t.push(r)}return t.push(e[e.length-1]),t}function an(e){return Nn(Xr(On(e)))}function Jr(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function on(e){const t=Xr(On(e)),n=Nn(t),r=new Set(n.map(s=>s.vtime)),i=[];for(const s of t)r.has(s.vtime)||i.push({viseme:s.viseme,vtime:s.vtime});return i}function ps(e){return on(e).map(t=>t.viseme)}const ws=32,cr=48;function Zr(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function ei(e){let t=null,n=-1;for(const r of e){if(r.viseme==="sil")continue;const i=r.vtime+r.vduration;i>n&&(t=r,n=i)}return t}function gs(e){return an(e).find(n=>n.viseme!=="sil")??null}function nt(e){const t=Zr(e);return ei(e)?t+Bn:t}function ys(e){const t=[],n=gs(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=ei(e),i=Zr(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+Bn}),t}function ti(e){const t=an(e),n=[];for(let r=0;r<t.length-1;r++){const i=t[r].viseme,s=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;i===s||a<=o||n.push({from:i,to:s,fromVtime:o,toVtime:a})}return n}function ni(e){return e.length===0?[]:[...ys(e),...ti(e)]}function _s(e,t){let n=null;for(const r of e){const{transStart:i,transEnd:s}=ri(r.fromVtime,r.toVtime,r.from,r.to);t>=i&&t<s&&(n=r)}return n}function ri(e,t,n,r){const i=Math.max(0,t-e);if((n==="PP"||r==="PP")&&i>cr){const f=cr,u=t,c=u-f;return{gapMs:i,effectiveGapMs:f,holdEnd:c,transStart:c,transEnd:u}}const o=i>0?Math.max(i,ws):0,a=e,l=e+o;return{gapMs:i,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:l}}function ii(e,t,n,r,i,s){r.forEach(o=>{const l=String(o.word??"").trim();if(!l)return;const f=Math.round((o.start??0)*1e3),u=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:l,wtime:i+f,wduration:u,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),n.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const l=Math.round((o.start??0)*1e3),f=Math.max(1,Math.round((o.duration??0)*1e3)),u=i+l,c=oi(t,u),d=c?jr(c,u):0;let p;Lr(s)==="oculus_direct"?(p=rn(a),p==="U"&&c&&sn(c.word,d)&&(p="FF")):p=qr(a,c?.word??"",d),e.push({viseme:p,weight:1,vtime:u,vduration:f})})}function si(e,t){let n=t;for(const r of e){const i=Math.round((r.start??0)*1e3),s=Math.max(1,Math.round((r.duration??0)*1e3));n=Math.max(n,t+i+s)}return n}const Vn=16e3;function ai(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Vn}function vs(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 Ss(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function ur(e,t,n=Vn){const r=t.byteOffset%2===0?t:t.slice(),i=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),s=new Float32Array(i.length);for(let a=0;a<i.length;a++)s[a]=i[a]>=32768?-(65536-i[a])/32768:i[a]/32767;const o=e.createBuffer(1,s.length,n);return o.copyToChannel(s,0),o}function bs(e){const t=vs(e),n=window.atob(t),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return r}async function lr(e,t,n=Vn){const r=bs(t),i=ai(n);if(Ss(r)){const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(s)}if(r.length>=2&&r.length%2===0)return ur(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return ur(e,r,i)}}function oi(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function ci(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,l=!1,f=0,u=0,c=0,d=null,p=1,T=t,m=!1,P=null,C=0,E=!1,g=!1,I=0,N=null,A=null,ee=null;const fe=()=>({visemes:[],words:[],segmentOffsetMs:0}),M=()=>{g=!1,I=0},W=()=>{d!=null&&(clearTimeout(d),d=null)},K=()=>{for(const b of r){try{b.onended=null,b.stop(0)}catch{}try{b.disconnect()}catch{}}r.length=0},Q=()=>{for(const b of r)b.playbackRate.value=p},Y=()=>{if(!(m||!l||s||g||r.length>0||n.length>0)){if(a&&i&&u>0){const b=(i.currentTime-u)*1e3;if(b<C){W();const $=p>0?(C-b)/p:C-b;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,$));return}}o=!1,W(),e.onSpeakingDone(),e.onNotify()}},de=b=>{const $=nt(b);if($<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,f=performance.now(),e.onSpeakingStart(),e.onNotify(),W();const S=p>0?$/p:$;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},S)},F=(b,$,S,O)=>{$.length!==0&&(c=S,$.forEach(D=>{const _=String(D.word??"").trim();if(!_)return;const v=Math.round((D.start??0)*1e3),x=D.duration!=null?Math.round(D.duration*1e3):D.end!=null?Math.max(1,Math.round((D.end-(D.start??0))*1e3)):0;b.push({word:_,wtime:c+v,wduration:x,queueIndex:b.length,gesture:D.gesture??null,emphasis:D.emphasis===!0})}))},Z=(b,$,S,O,D,V)=>{S.length!==0&&(c=O,S.forEach(_=>{const v=String(_.symbol??_.viseme??"").trim();if(!v)return;const x=Math.round((_.start??0)*1e3),H=Math.max(1,Math.round((_.duration??0)*1e3)),X=c+x,se=oi($,X),Ee=se?jr(se,X):0;let _e;Lr(V)==="oculus_direct"?(_e=rn(v),_e==="U"&&se&&sn(se.word,Ee)&&(_e="FF")):_e=qr(v,se?.word??"",Ee),b.push({viseme:_e,weight:1,vtime:X,vduration:H})}),e.onNotify())},k=(b,$,S,O,D,V,_)=>{F($,O,D),Z(b,$,S,D,V,_)},q=(b,$,S)=>{ee===b&&b.visemes===$||($.length=0,S.length=0,b.visemes=$,b.words=S,b.segmentOffsetMs=0,ee=b,c=0,C=0)},re=async()=>{const b=window.AudioContext||window.webkitAudioContext;return i||(i=new b),i.state==="suspended"&&await i.resume(),P||(P=i.createMediaStreamDestination()),i},oe=(b,$)=>{if(!i)return 0;const S=i,O=S.currentTime,D=O+.02;if($.isFirstAudio){u<=0&&(u=D);const _=(D-O)*1e3;f=performance.now()+_}$.onBeforeStart?.(D);const V=S.createBufferSource();return V.buffer=b,V.playbackRate.value=p,V.connect(S.destination),P&&V.connect(P),r.push(V),m?(r.pop(),D):($.isFirstAudio&&(o=!0,e.onSpeakingStart()),V.onended=()=>{const _=r.indexOf(V);_>=0&&r.splice(_,1),e.onNotify(),!m&&(N&&A?ne(N,A):Y())},V.start(D),D)},ne=async(b,$)=>{if(m||s||r.length>0)return;if(n.length===0){Y();return}s=!0;let S=!1;try{const O=await re();if(m)return;const D=n[0];if(!D)return;const V=!o;if(E&&(e.shouldHoldForWarmup?.()??!1)&&(g||V&&D.newStream)||g){q(D.utterance,b,$);for(const x of n){if(m)return;x.audioBuffer||(x.audioBuffer=await lr(O,x.audio,x.sampleRate)),a=!0,g||(g=!0,I=0,x.newStream&&x.onNewStream?.()),x.visemesQueued||(k(b,$,x.visemes,x.words,I,!0,T),x.visemesQueued=!0,I+=Math.round(x.audioBuffer.duration*1e3),C=Math.max(C,nt(b)))}e.onNotify();return}const v=n.shift();if(!v||(v.audioBuffer||(v.audioBuffer=await lr(O,v.audio,v.sampleRate)),m))return;a=!0,W(),q(v.utterance,b,$),v.visemesQueued=!1,v.newStream&&v.onNewStream?.(),oe(v.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:x=>{u=x,c=0,f=performance.now()+(x-O.currentTime)*1e3,b.length=0,$.length=0,k(b,$,v.visemes,v.words,0,!0,T),v.visemesQueued=!0,v.utterance.segmentOffsetMs=0}}),S=r.length>0,C=nt(b),e.onNotify()}catch(O){console.error("[avatarChunkPlayback] audio chunk failed:",O)}finally{if(s=!1,m)return;if(g){n.some(D=>!D.audioBuffer||!D.visemesQueued)&&ne(b,$);return}!S&&r.length===0&&n.length>0?ne(b,$):r.length===0&&n.length===0&&Y()}};return{setStreamTtsEngineId:b=>{T=b},setPlaybackSpeed:b=>{p=Math.max(.1,Math.min(1,b)),Q()},getPlaybackSpeed:()=>p,setLipsyncWarmupHoldEnabled:b=>{E=b,b||M()},isWarmingUp:()=>g,releaseWarmupHold:()=>{if(g){g=!1,I=0;for(const b of n)b.newStream=!1;N&&A&&ne(N,A),e.onNotify()}},resetForNewStream:b=>{m=!1,l=!1,T=b,C=0},resumeBotStream:()=>{m=!1,l=!1},clearAborted:()=>{m=!1},primeAudioContext:async()=>{const b=window.AudioContext||window.webkitAudioContext;i||(i=new b),i.state==="suspended"&&await i.resume(),i&&!P&&(P=i.createMediaStreamDestination())},stop:()=>{m=!0,W(),K(),n.length=0,s=!1,o=!1,a=!1,l=!1,c=0,u=0,f=0,C=0,N=null,A=null,ee=null,M()},markStreamComplete:b=>{if(C=Math.max(C,nt(b)),l=!0,!a&&b.length>0){de(b);return}Y()},playAudioChunk:async(b,$,S,O,D,V,_)=>{if(m)return;N=b,A=$;const v=ai(_?.sampleRate),x=_?.newStream===!0,H=fe();if(!S?.trim()){if(O.length===0&&D.length===0)return;q(H,b,$),x&&_?.onNewStream?.(),k(b,$,O,D,0,!0,T),C=nt(b),!o&&C>0&&de(b),e.onNotify();return}n.push({audio:S,audioBuffer:null,utterance:H,visemes:O,words:D,isNewSegment:V,sampleRate:v,newStream:x,onNewStream:_?.onNewStream,visemesQueued:!1}),await ne(b,$)},queueTimingsOnly:(b,$,S,O,D,V)=>{if(m)return;const _=fe();q(_,b,$),k(b,$,S,O,0,!0,T),_.segmentOffsetMs=0,C=nt(b)},getPlaybackElapsedMs:()=>a&&i&&u>0?Math.max(0,(i.currentTime-u)*1e3*p):o?Math.max(0,(performance.now()-f)*p):0,isSpeaking:()=>o?!0:!a||!i||u<=0?!1:(i.currentTime-u)*1e3<C,getVoiceStream:()=>P?P.stream:null,getPlaybackStartPerf:()=>f,bargeIn:()=>{m=!0,l=!1,W(),K(),n.length=0,s=!1,o=!1,a=!1,c=0,u=0,f=0,C=0,N=null,A=null,ee=null,M()},interrupt:()=>{m=!0,l=!1,W(),K(),n.length=0,s=!1,o=!1,a=!1,c=0,u=0,f=0,C=0,N=null,A=null,ee=null,M()}}}function Dt(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 ui(e,t,n=120){const r=Dt(e,t);if(r!=="sil")return r;let i=null;for(const s of e){if(s.vtime>t)break;const o=s.vtime+s.vduration;o<=t&&t-o<=n&&(i=s)}return i?.viseme??"sil"}function Ts(e,t,n=400){const r=t-n;let i=0;for(const s of e)if(s.vtime+s.vduration<r)i+=1;else break;i>0&&e.splice(0,i)}function ks(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function fr(e,t){const n=e.trim();if(!n)return null;try{const r=n.replace(/\s+/g,""),i=atob(r).length,s=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return i/2/s*1e3}catch{return null}}const cn=.5,un=1.5,Un="Olivia",Wn="f786b574-daa5-4673-aa0c-cbe3e8534c02",Bt=.85;function In(e,t=at,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let l=0;const f=[],u=[];let c="",d="neutral",p="",T=it;const m=new Set;let P=0,C=null,E=0,g=null;const I=()=>m.forEach(F=>F());let N=()=>!1;const A=ci({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:I,shouldHoldForWarmup:()=>N()},it),ee=()=>A.getPlaybackElapsedMs(),fe=(F,Z=c)=>{if(!n.onLipsyncDebug)return;const k=ee(),q=i,re=on(o).map(oe=>({viseme:oe.viseme,vtimeMs:oe.vtime}));n.onLipsyncDebug({event:F,spokenText:Z,mood:d,playbackAnchorPerf:A.getPlaybackStartPerf(),playbackElapsedMs:k,queueLength:q.length,activeViseme:Dt(q,k),segments:u.map(oe=>({...oe,visemes:[...oe.visemes]})),fullQueueLength:o.length,compactionSkipped:re})},M=(F,Z)=>{n.onLipsyncDebug&&(C={event:F,spokenText:Z},P===0&&(P=requestAnimationFrame(()=>{P=0;const k=C;C=null,k&&fe(k.event,k.spokenText)})))},W=(F,Z,k,q,re)=>{if(!n.onLipsyncDebug)return;const oe=i.slice(Z),ne=k.filter(te=>String(te.symbol??te.viseme??"").trim());u.push({spokenText:F,audioOffsetMs:oe[0]?.vtime??0,isNewSegment:q,chunkDurationMs:re,receivedAtMs:performance.now(),visemes:oe.map((te,ie)=>{const we=ne[ie];return{rawSymbol:String(we?.symbol??we?.viseme??te.viseme).trim(),viseme:te.viseme,startSec:Number(we?.start??0),durationSec:Number(we?.duration??0),vtimeMs:te.vtime,vdurationMs:te.vduration}})})},K=()=>{o.length=0,a.length=0,l=0},Q=(F,Z,k,q,re)=>{if(F.length===0&&Z.length===0)return;ii(o,a,F,Z,l,re);const oe=si(F,l),ne=k?fr(k,q):null;l=Math.max(oe,ne!=null?l+ne:l)},Y=()=>{E+=1,g?.abort(),g=null,A.stop(),i.length=0,s.length=0,K(),f.length=0,d="neutral",u.length=0,c="",e("idle"),M("reset"),I()};return{setDeveloperToken:F=>{p=F},setTtsEngineId:F=>{T=F},getTtsEngineId:()=>T,speak:async(F,Z)=>{Y();const k=E;g=new AbortController,e("loading"),c=F,u.length=0,K();const q=p.trim();if(!q)throw new Error("Developer token required for avatar_ttsWithPoses");const re=Z?.ttsEngineId??T??it;A.resetForNewStream(re),A.setStreamTtsEngineId(re);const oe=Z?.voiceId??Un,ne=Z?.speakingRate??Bt,te=Math.max(cn,Math.min(un,ne)),ie={user_query:F,ttsEngineId:re,speakingRate:te,tenant:"aiTwin"};Br.has(re)&&(ie.voice_id=oe);try{const we=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${q}`},body:JSON.stringify(ie),signal:g.signal});if(!we.ok)throw new Error(`avatar_ttsWithPoses failed (${we.status})`);const b=we.body;if(!b)throw new Error("No response body");const $=b.getReader(),S=new TextDecoder;let O="",D=!0;const V=async _=>{if(k!==E)return;const v=zr(_);if(v){if(v.event==="audio"){const x=v.data.chunk,H=v.data.visemes??[],X=v.data.words??[],se=v.data.is_new_segment??!1,Ee=v.data.sample_rate,_e=Number(v.data.audio_offset_ms??0),Ve=i.length;if(Q(H,X,x,Ee,re),x){const Ue=D;D=!1,await A.playAudioChunk(i,s,x,H,X,se,{sampleRate:Ee,newStream:Ue,audioOffsetMs:_e}),W(F,Ve,H,se,fr(x,Ee)),M("audio_chunk",F)}else(H.length>0||X.length>0)&&(A.queueTimingsOnly(i,s,H,X,se,{audioOffsetMs:_e,newStream:D}),W(F,Ve,H,se,null),M("audio_chunk",F))}else if(v.event==="metadata"){const x=v.data.mood;typeof x=="string"&&x.trim()&&(d=x.trim());const H=v.data.sentence_emotions;if(Array.isArray(H)){f.length=0;for(const X of H){if(!X||typeof X!="object")continue;const se=X;f.push({sentence_index:Number(se.sentence_index??0),text:String(se.text??""),sentiment:typeof se.sentiment=="string"?se.sentiment:void 0,emotion:String(se.emotion??d),start_word:Number(se.start_word??0),end_word:Number(se.end_word??0)})}}I(),M("metadata",F)}else if(v.event==="error")throw new Error(String(v.data.message??"avatar_ttsWithPoses stream error"))}};for(;k===E;){const{done:_,value:v}=await $.read();v&&(O+=S.decode(v,{stream:!0}));const x=O.split(`
|
|
2
2
|
|
|
3
|
-
`);
|
|
3
|
+
`);O=x.pop()??"";for(const H of x)await V(H);if(_){O.trim()&&await V(O.trim()),A.markStreamComplete(i),M("bot_stopped",F);break}}}catch(we){if(k!==E||we instanceof DOMException&&we.name==="AbortError")return;throw console.error("[avatarTtsLipsync]",we),Y(),e("error"),we}},stop:Y,getVisemeQueue:()=>i,getWordQueue:()=>s,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>f,getStreamMood:()=>d,getPlaybackElapsedMs:()=>A.getPlaybackElapsedMs(),isSpeaking:()=>A.isSpeaking(),isWarmingUp:()=>A.isWarmingUp(),releaseWarmupHold:()=>A.releaseWarmupHold(),setLipsyncWarmupHold:(F,Z)=>{Z&&(N=Z),A.setLipsyncWarmupHoldEnabled(F)},getVoiceStream:()=>A.getVoiceStream(),setPlaybackSpeed:F=>{A.setPlaybackSpeed(F)},getPlaybackSpeed:()=>A.getPlaybackSpeed(),subscribe:F=>(m.add(F),()=>m.delete(F))}}const Hn=16e3,$n=16e3;class xs extends Rn.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 Es extends Rn.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,Hn,$n)}bufferBotAudio(t,n){}}const Is=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function As(e){return Is.test(e.trim())}function Ps(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function li(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??at,r=new URL(`${Ps(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const i=e.voiceId?.trim();i&&As(i)&&r.searchParams.set("voiceId",i);const s=e.personaId?.trim();s&&r.searchParams.set("personaId",s);const o=e.speakingRate??Bt;return r.searchParams.set("speaking_rate",String(Math.max(cn,Math.min(un,o)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),r.toString()}function yn(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 Ms(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 _n(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function Cs(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function fi(e,t={}){const n=[],r=[],i=[],s=[];let o=0;const a=[],l=[];let f="",u="neutral",c=ot,d=!1,p=null,T=null,m={...t},P=0,C=null;const E=new Set,g=[];let I=!1,N=null,A=!0,ee="default";const fe=new Set;let M=null,W=0,K=!1,Q=null,Y=!1;const de=()=>{Q!=null&&(clearTimeout(Q),Q=null)},F=()=>E.forEach(h=>h());let Z=()=>!1;const k=ci({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{Y=!1,e("done")},onNotify:F,shouldHoldForWarmup:()=>Z()},c),q=()=>{if(N)return N;const h=new MessageChannel;return h.port1.onmessage=()=>{const L=g.shift();L!==void 0&&Ee(L),g.length>0?h.port2.postMessage(null):I=!1},N=h,h},re=h=>{g.push(h),!I&&(I=!0,q().port2.postMessage(null))},oe=()=>k.getPlaybackElapsedMs(),ne=(h,L=f)=>{if(!m.onLipsyncDebug)return;const J=oe(),ce=n,Se=on(i).map(ve=>({viseme:ve.viseme,vtimeMs:ve.vtime}));m.onLipsyncDebug({event:h,spokenText:L,mood:u,playbackAnchorPerf:k.getPlaybackStartPerf(),playbackElapsedMs:J,queueLength:ce.length,activeViseme:Dt(ce,J),segments:l.map(ve=>({...ve,visemes:[...ve.visemes]})),fullQueueLength:i.length,compactionSkipped:Se})},te=(h,L)=>{m.onLipsyncDebug&&(C={event:h,spokenText:L},P===0&&(P=requestAnimationFrame(()=>{P=0;const J=C;C=null,J&&ne(J.event,J.spokenText)})))},ie=()=>{A=!0,fe.clear(),k.clearAborted()},we=()=>{const h=Cs(p);if(h){ee=`bot-${Date.now()}`,h.interruptedTrackIds={[ee]:!0};try{h.interrupt?.()}catch{}}const L=T;try{L?.interrupt?.()}catch{}},b=h=>{if(Y&&k.isSpeaking())return!0;const L=h.context_id?.trim();return L&&fe.has(L)?!0:A?!1:!(h.type==="avatar_metadata"||_n(h))},$=h=>{A=!1,Y=!1;const L=h.context_id?.trim();L&&fe.add(L),de(),K=!1,g.length=0,I=!1,M?.abort(),M=null,W+=1,we(),k.bargeIn(),S(),e("idle"),te("interrupt"),F()},S=()=>{n.length=0,r.length=0,i.length=0,s.length=0,o=0,l.length=0,f="",u="neutral",a.length=0},O=()=>{k.stop(),S(),te("reset"),F()},D=()=>{O(),e("idle"),F()},V=(h,L)=>{typeof h.mood=="string"&&h.mood.trim()&&(u=h.mood.trim()),Array.isArray(h.sentence_emotions)&&h.sentence_emotions.length>0&&(L&&(a.length=0),a.push(...yn(h.sentence_emotions,u)))},_=h=>{if(b({...h,type:"avatar_metadata"}))return;ie(),K=!0;const L=String(h.spoken_text??h.text??"").trim();L&&(f=L),k.resetForNewStream(c),typeof h.mood=="string"&&h.mood.trim()&&(u=h.mood.trim()),a.length=0,a.push(...yn(h.sentence_emotions,u)),Array.isArray(h.gestures)&&h.gestures,te("metadata",L),F()},v=(h,L,J,ce)=>{if(!m.onLipsyncDebug)return;const Se=n.slice(J),ve=ce.filter(ye=>String(ye.symbol??ye.viseme??"").trim());l.push({spokenText:L,audioOffsetMs:Se[0]?.vtime??0,isNewSegment:!!h.is_new_segment,chunkDurationMs:h.chunk_duration_ms!=null?Number(h.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:Se.map((ye,Ie)=>{const Te=ve[Ie];return{rawSymbol:String(Te?.symbol??Te?.viseme??ye.viseme).trim(),viseme:ye.viseme,startSec:Number(Te?.start??0),durationSec:Number(Te?.duration??0),vtimeMs:ye.vtime,vdurationMs:ye.vduration}})})},x=(h,L,J,ce)=>{if(h.length===0&&L.length===0)return;ii(i,s,h,L,o,c);const Se=si(h,o);let ve=null;const ye=J.trim();if(ye)try{const Ie=atob(ye.replace(/\s+/g,"")).length,Te=Number.isFinite(ce)&&(ce??0)>0?Number(ce):16e3;ve=Ie/2/Te*1e3}catch{ve=null}o=Math.max(Se,ve!=null?o+ve:o)},H=h=>{if(b(h))return;de(),_n(h)&&ie();const L=String(h.spoken_text??h.text??"").trim(),J=_n(h),ce=h.visemes??[],Se=h.words??[],ve=String(h.chunk??"").trim(),ye=K;ye&&(K=!1),L&&(f=L),V(h,J),ye?(k.resetForNewStream(c),i.length=0,s.length=0,o=0):J&&k.resumeBotStream(),x(ce,Se,ve,h.sample_rate);const Ie=n.length;k.playAudioChunk(n,r,ve,ce,Se,J,{sampleRate:h.sample_rate,newStream:ye,audioOffsetMs:Number(h.audio_offset_ms??0),onNewStream:()=>{l.length=0}}).then(()=>{v(h,L,Ie,ce),te("audio_chunk",L)})},X=h=>{if(b(h))return;(h.is_new_segment||Number(h.audio_offset_ms??-1)===0)&&ie(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const L=String(h.spoken_text??h.text??"").trim();L&&(f=L),V(h,!!h.is_new_segment),x(h.visemes??[],h.words??[],"",void 0);const J=n.length;k.queueTimingsOnly(n,r,h.visemes??[],h.words??[],!!h.is_new_segment,{audioOffsetMs:Number(h.audio_offset_ms??0)}),v(h,L,J,h.visemes??[]),te("lipsync",L),F()},se=async h=>{const L=String(h.text??"").trim();if(!L)return;const J=m.authToken?.trim();if(!J){console.error("[realtimeVoice] avatar_speak requires authToken");return}M?.abort();const ce=new AbortController;M=ce;const Se=++W;ie(),k.resetForNewStream(c),f=L;const ye=`${(m.apiBase??at).replace(/\/$/,"")}/avatar_ttsWithPoses`,Ie=m.voiceId?.trim()||Wn,Te=m.speakingRate??Bt,lt=Math.max(cn,Math.min(un,Te)),ke={user_query:L,ttsEngineId:c,speakingRate:lt,tenant:"aiTwin"};Br.has(c)&&(ke.voice_id=Ie);try{const Pe=await fetch(ye,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${J}`},body:JSON.stringify(ke),signal:ce.signal});if(!Pe.ok)throw new Error(`avatar_ttsWithPoses failed (${Pe.status})`);const Ze=Pe.body;if(!Ze)throw new Error("No response body");const Ye=Ze.getReader(),Lt=new TextDecoder;let We="",Fe=!0;const Le=async et=>{if(Se!==W||ce.signal.aborted||!A)return;const ge=zr(et);if(ge){if(ge.event==="audio"){const Me=ge.data.chunk,He=ge.data.visemes??[],me=ge.data.words??[],Tt=ge.data.is_new_segment??!1,Ot=ge.data.sample_rate,kt=Number(ge.data.audio_offset_ms??0);if(Me){const ft=Fe;Fe=!1,await k.playAudioChunk(n,r,Me,He,me,Tt,{sampleRate:Ot,newStream:ft,audioOffsetMs:kt})}else(He.length>0||me.length>0)&&k.queueTimingsOnly(n,r,He,me,Tt,{audioOffsetMs:kt,newStream:Fe})}else if(ge.event==="metadata"){const Me=ge.data.mood;typeof Me=="string"&&Me.trim()&&(u=Me.trim());const He=ge.data.sentence_emotions;Array.isArray(He)&&(a.length=0,a.push(...yn(He,u))),F()}else if(ge.event==="error")throw new Error(String(ge.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(Se!==W||ce.signal.aborted||!A);){const{done:et,value:ge}=await Ye.read();ge&&(We+=Lt.decode(ge,{stream:!0}));const Me=We.split(`
|
|
4
4
|
|
|
5
|
-
`);se=Ce.pop()??"";for(const Te of Ce)await _t(Te);if(st){se.trim()&&await _t(se.trim()),me===D&&!re.signal.aborted&&V&&k.markStreamComplete(r);break}}}catch(Ke){if(re.signal.aborted||!V)return;console.error("[realtimeVoice] avatar_speak failed:",Ke),e("error"),$()}finally{P===re&&(P=null)}},Re=h=>{const R=wi(h);if(!R){console.warn("[realtimeVoice] server message with no payload",h);return}const Q=String(R.type??"unknown");switch(Q!=="avatar_metadata"&&Q!=="avatar_audio_chunk"&&Q!=="avatar_lipsync"&&Q!=="avatar_interrupt"&&Q!=="error"&&console.debug("[realtimeVoice] server message",Q,R),Q){case"avatar_metadata":g(R);break;case"avatar_audio_chunk":Z(R);break;case"avatar_lipsync":oe(R);break;case"avatar_interrupt":M(R);break;case"error":{const re=String(R.message??"Voice session error");console.error("[realtimeVoice] server error:",re),e("error"),$();break}case"avatar_speak":ye(R);break}},_e=()=>p||(E=new di,p=new vs.PipecatClient({transport:new kr.WebSocketTransport({mediaManager:E,serializer:new fi,recorderSampleRate:Br,playerSampleRate:Lr}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{d=!0,e("idle"),$()},onDisconnected:()=>{d=!1,I()},onError:h=>{const R=typeof h=="object"&&h!==null&&"data"in h?String(h.data??h):String(h);console.error("[realtimeVoice]",R,h),e("error"),$()},onTransportStateChanged:h=>{h==="error"&&(e("error"),$())},onServerMessage:h=>{he(h)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{ke(),J("bot_started")},onBotStoppedSpeaking:()=>{V&&(Y(),j=setTimeout(()=>{j=null,V&&(k.markStreamComplete(r),J("bot_stopped"))},450))},onUserTranscript:h=>{String(h.text??""),m.onUserTranscript?.(h.text,!!h.final)},onBotOutput:h=>{m.onBotOutput?.(h.text)}}}),p);return{setDeveloperToken:h=>{},setTtsEngineId:h=>{u=h,k.setStreamTtsEngineId(h)},getTtsEngineId:()=>u,speak:async(h,R)=>{const Q=h.trim();if(Q){if(!p||!d)throw new Error("Realtime voice is not connected. Call connect() first.");z(),await p.sendText(Q)}},stop:()=>{P?.abort(),P=null,D+=1,ke(),z(),e("idle"),$()},connect:async h=>{if(h&&(m={...m,...h}),!m.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const R=_e();await R.initDevices();const Q=Zn(m);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",Q);try{await R.connect({wsUrl:Q})}catch(re){d=!1,e("error"),$();const me=re instanceof Error?re.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${me} — ${Q}`)}d=!0,e("idle"),$()},disconnect:async()=>{if(Y(),N=!1,w.length=0,b=!1,P?.abort(),P=null,D+=1,ke(),p)try{await p.disconnect()}catch(h){console.error("[realtimeVoice] disconnect failed:",h)}d=!1,I()},isConnected:()=>d,unlockAudio:async()=>{await k.primeAudioContext()},getVisemeQueue:()=>r,getWordQueue:()=>n,getFullVisemeQueue:()=>s,getFullWordQueue:()=>i,getSentenceEmotions:()=>a,getStreamMood:()=>c,getPlaybackElapsedMs:ce,isSpeaking:()=>k.isSpeaking(),isWarmingUp:()=>k.isWarmingUp(),releaseWarmupHold:()=>k.releaseWarmupHold(),setLipsyncWarmupHold:(h,R)=>{R&&(q=R),k.setLipsyncWarmupHoldEnabled(h)},getVoiceStream:()=>k.getVoiceStream(),setPlaybackSpeed:h=>{k.setPlaybackSpeed(h)},getPlaybackSpeed:()=>k.getPlaybackSpeed(),subscribe:h=>(C.add(h),()=>C.delete(h))}}function ts(e,t,r){return{width:e.crop?.source_width??t,height:e.crop?.source_height??r}}function rs(e,t){const r=e.crop;return{x:t?.source_x??r?.x??0,y:t?.source_y??r?.y??0,width:t?.source_w??r?.width??e.frame_width??0,height:t?.source_h??r?.height??e.frame_height??0}}function ns(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function pt(e,t){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const n=await r.arrayBuffer();return $s(n,t)}async function ss(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const r=await pt(e,t),n=new TextDecoder().decode(r);return JSON.parse(n)}async function yi(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function _i(e){const t=new Blob([e],{type:"image/webp"}),r=URL.createObjectURL(t);return new Promise((n,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(r),n(i)},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("Failed to decode decrypted image"))},i.src=r})}async function Si(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function vi(e){const t=new Blob([e],{type:"image/png"}),r=URL.createObjectURL(t);return new Promise((n,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(r),n(i)},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("Failed to decode decrypted PNG"))},i.src=r})}function bi(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Ti(e){const t=Ks();if(!It())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const r=await pt(t,e);return bi(r)}function lt(e,t){return`${e}/${t}_minus_sil.png`}const is=5;function rr(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const r=e?.crop?.content_threshold;return typeof r=="number"&&r>0?r:is}const Ei=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],vr=["t01_0.25","t02_0.50","t03_0.75"],ki=vr.length,nn=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 on(e,t){return`pairs/${e}/${t}_minus_sil.png`}function dt(e){return`${e}_minus_sil.png`}function Or(e,t){if(t.has(e))return e;const r=/^pairs\/([^/]+)\//.exec(e);if(!r)return null;const n=r[1].split("__")[1];if(!n||n==="sil")return null;const s=dt(n);return t.has(s)?s:null}function os(e,t){return e.filter(r=>t.has(r))}function Ii(e,t,r){const n=Nr(e,t);return os(n,r).length>0}function Nr(e,t){if(e===t)return[];const r=[],n=sn(e,t);if(nn.has(n)){for(const i of vr)r.push(on(n,i));return r}const s=sn(t,e);if(nn.has(s)){for(let i=ki-1;i>=0;i--)r.push(on(s,vr[i]));return r}return[]}function Ai(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function Pi(e,t){return Ai(t).map(n=>e[n]).filter(n=>n!=null)}function xi(e,t,r,n){if(n<=0)return 0;const i=Math.max(1,r-t)/n,o=e-t,a=Math.floor(o/i);return Math.min(n-1,Math.max(0,a))}function as(e,t,r){if(!r)return`${e}/${t}`;const n=t.split("/").pop()??t,s=n.includes(".")?n.slice(0,n.lastIndexOf(".")):n;return`${e}/${s}.bin`}const Mi=[.32,.24,.16,.08,0],Ri=Mi.map(e=>`eyes_${e.toFixed(2)}`),Ci=["eyes_0.32","eyes_0.16","eyes_0.00"],Di=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Le=2,Fi=-20,qt=16,us={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Tt(e){return`brow_${e}`}function Ze(e){return us[e]}function Ue(e){return Math.max(Fi,Math.min(qt,e))}function Bi(e,t){if(e===t)return[];const r=e<t,n=r?Le:-Le,s=[];let i=e;if(i%Le!==0){const o=r?Math.ceil(i/Le)*Le:Math.floor(i/Le)*Le,a=Ue(o);if(r?a>=t:a<=t)return[t];i=a,s.push(i)}for(;;){const o=i+n;if(r?o>=t:o<=t){t!==i&&s.push(t);break}i=o,s.push(i)}return s}function an(e){const t=Ue(e);if(t%Le===0)return[t];const r=Math.floor(t/Le)*Le,n=Math.min(qt,r+Le),s=Ue(r);return t-s<=n-t?s===n?[s]:[s,n]:s===n?[n]:[n,s]}const Li=["fear","anger","sad","neutral","love","happy","disgust"],Oi={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 He(e,t="neutral"){const r=String(e??"").trim().toLowerCase();return r?Oi[r]??t:t}function cs(e){return e===0?null:lt(Tt(e),"eyes_standard")}function ls(e){return cs(Ze(e))}const Ni={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function Vr(e,t){if(!e)return null;if(t(e))return e;const r=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const s=Number(r[1]),i=r[2];for(const a of an(s)){if(a===s)continue;const l=lt(Tt(a),i);if(t(l))return l}const o=Ni[s];if(o){const a=lt(o,i);if(t(a))return a}return null}const n=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const s=n[1],i=n[2],o=Ze(s);for(const a of[o,...an(o)]){const l=lt(Tt(a),i);if(t(l))return l}}return null}function un(e,t){const r=Tt(Ze(e));return!t||t==="eyes_standard"?ls(e):e==="neutral"&&t==="eyes_standard"?null:lt(r,t)}function Vi(e,t){const r=[];for(const n of t)r.push(un(e,n));for(let n=t.length-2;n>=0;n--)r.push(un(e,t[n]));return r.push(ls(e)),r}function Ui(e){return lt(Tt(e),"eyes_standard")}function Wi(e,t){return Bi(e,t).map(Ui)}const $i=6;function Hi(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function Ki(e){const t=Ue(e);return t>=qt?qt:Ue(t+$i)}function qi(e,t,r){const n=Ue(r);return Hi(t,e)?.emphasis?Ki(n):n}function cn(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const r=Number.parseInt(t[1],10);return Number.isFinite(r)?Ue(r):null}function ct(e,t){return e+Math.random()*(t-e)}function Vt(){return ct(14,32)}function Gi(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:r=2200,intervalMaxMs:n=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:l=380,minDwellMs:f=550}=e;let c="neutral",u="neutral",d=0,p=0,E=0,m={kind:"idle",nextBlinkAt:performance.now()+t},A=null,x="__eyes_open__|neutral|brow:0";function C(P=c){x=`${A??"__eyes_open__"}|${P}|brow:${p}`}function w(P,D=c){A=P;const N=cn(P);N!=null?p=N:P==null&&(p=0),C(D)}function b(P){return cs(P)}function O(P,D,N){const j=Ue(D),F=Ue(N);if(d=F,j===F){w(b(F));return}const Y=[...Wi(j,F),b(F)];m={kind:"browBlend",paths:Y,index:0,holdUntil:P+Vt(),targetBrow:F},w(Y[0]??null)}function V(P,D){m={kind:"idle",nextBlinkAt:P+ct(r,n)},u=D,w(b(d),D)}function X(P,D,N){const j=N?Ci:Math.random()<a?Ri:Di;m={kind:"playing",paths:Vi(D,j),index:0,holdUntil:P+Vt(),after:"idle",blinkEmotion:D},u=D,w(m.paths[0]??null,D)}function fe(P){if(m.kind==="browBlend"){for(;P>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=P+Vt();const D=m.paths[m.index]??null;w(D),P>=m.holdUntil&&m.index>=m.paths.length-1&&(p=m.targetBrow,d=m.targetBrow,w(b(m.targetBrow)),m={kind:"idle",nextBlinkAt:P+l});return}if(m.kind==="idle"){w(b(d),u),P>=m.nextBlinkAt&&X(P,u,!1);return}if(m.kind==="doublePause"){w(b(d),m.blinkEmotion),P>=m.resumeAt&&X(P,m.blinkEmotion,!0);return}if(m.kind==="playing"){for(;P>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=P+Vt();if(w(m.paths[m.index]??null,m.blinkEmotion),P>=m.holdUntil&&m.index>=m.paths.length-1){if(m.after==="resumeIdle"){V(P+l,c);return}if(m.after==="doublePause"){m={kind:"doublePause",resumeAt:P+ct(i,o),blinkEmotion:m.blinkEmotion},w(b(d),m.blinkEmotion);return}if(m.after==="idle"&&Math.random()<s){m={kind:"doublePause",resumeAt:P+ct(i,o),blinkEmotion:m.blinkEmotion},w(b(d),m.blinkEmotion);return}V(P,m.blinkEmotion)}}}return{advance:fe,setTargetEmotion(P,D){const N=He(P,c);if(N===c)return;const j=performance.now();!D?.force&&f>0&&!(c==="neutral"&&N!=="neutral")&&j-E<f||(c=N,u=N,E=j)},setTargetEyebrow(P){const D=Ue(P);if(D===d)return;const N=performance.now(),j=m.kind==="browBlend"?cn(A)??p:p;d=D,!(D===j&&m.kind!=="browBlend")&&(m.kind==="playing"||m.kind==="doublePause"||O(N,j,D))},snapToEmotion(P){const D=He(P),N=Ze(D);c=D,u=D,d=N,p=N,E=performance.now(),m={kind:"idle",nextBlinkAt:performance.now()+ct(4e3,7e3)},w(b(N),D)},getTargetEmotion:()=>c,getTargetEyebrow:()=>d,getExpressionPath:()=>A,getDrawKey:()=>x,reset(){c="neutral",u="neutral",d=0,p=0,E=0,V(performance.now()+ct(r,n),"neutral")}}}function zi(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,r=null,n="";const s=()=>{r&&(URL.revokeObjectURL(r),r=null)};return{async load(i){t&&n===i||(s(),t=!1,n=i,i.startsWith("blob:")&&(r=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,n=""}}}const ji=50,fs=400;function Yi(e,t,r){return e.filter(n=>{const s=n.queueIndex??-1;return s>=t&&s<=r})}function Qi(e,t){const r=[];for(const n of e){const s=Yi(t,n.start_word,n.end_word);if(s.length===0)continue;const i=s[0],o=s[s.length-1];r.push({sentence:n,startMs:Math.max(0,i.wtime-ji),endMs:o.wtime+o.wduration+fs})}return r.sort((n,s)=>n.startMs-s.startMs)}function Xi(e,t,r,n="neutral"){const s=He(n);if(t.length===0)return s;if(r.length===0||e<r[0].wtime)return He(t[0]?.emotion,s);const i=Qi(t,r);let o=null;for(const f of i)e>=f.startMs&&e<=f.endMs&&(o=f);if(o)return He(o.sentence.emotion,s);const a=r[r.length-1],l=a.wtime+a.wduration;return e>l+fs?He(t[t.length-1]?.emotion,s):s}function Ur(e,t,r,n,s=is){const i=new OffscreenCanvas(r,n),o=i.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,r,n);const a=o.getImageData(0,0,r,n),l=o.createImageData(r,n);l.data.set(a.data);const c=new OffscreenCanvas(r,n).getContext("2d",{willReadFrequently:!0});for(const u of t){c.clearRect(0,0,r,n),c.drawImage(u,0,0,r,n);const d=c.getImageData(0,0,r,n);for(let p=0;p<l.data.length;p+=4){const E=d.data[p],m=d.data[p+1],A=d.data[p+2];Math.max(E,m,A)>s&&(l.data[p]=E,l.data[p+1]=m,l.data[p+2]=A,l.data[p+3]=255)}}return o.putImageData(l,0,0),i}let Xe=null,mt=null;const Gt=new Map;function Ji(){Xe=null,mt=null,Gt.clear()}xn(Ji);function Zi(e){return e??mt??void 0}function Wr(e){return new Promise((t,r)=>{const n=new Image;n.decoding="async",n.onload=()=>t(n),n.onerror=()=>r(new Error(`Failed to load image: ${e}`)),n.src=e})}async function eo(e){return It()?vi(await pt(Kt(),e??"")):Wr(Kt())}async function ln(e,t,r,n){const s=r?await ss(e,n):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=r?await _i(await pt(as(t,i.path,r),n??"")):await Wr(`${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 br(e){const t=Zi(e),r=It();if(r&&!t)throw new Error("Encrypted assets enabled but no key provided");if(Xe&&(!r||mt===(t??null))){const i=await Xe;return{...ht(i),visemePaths:[...i.viseme.cellByPath.keys()]}}mt=t??null,Gt.clear();const n=Mn();Xe=(async()=>{const i=await eo(t),o=await ln(Rn(),n,r,t);let a=null;try{a=await ln(Cn(),n,r,t)}catch{a=null}return{sil:i,viseme:o,expression:a}})();const s=await Xe;return{...ht(s),visemePaths:[...s.viseme.cellByPath.keys()]}}async function $r(e){if(await br(e),!Xe)throw new Error("Assets not loaded");return Xe}function ht(e){return ts(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function to(e,t){const r=document.createElement("canvas");return r.width=t.w,r.height=t.h,r.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}async function zt(e,t,r){const n=`${t.diffBase}::${r}`,s=Gt.get(n);if(s)return s;const i=(async()=>{const o=t.cellByPath.get(r);if(!o)throw new Error(`No atlas cell for path: ${r}`);const a=rs(t.atlasMeta,o),l=ht(e);if(ns(o)){const u=to(t,o),d=document.createElement("canvas");d.width=l.width,d.height=l.height;const p=d.getContext("2d");return p.fillStyle="#000",p.fillRect(0,0,l.width,l.height),p.drawImage(u,a.x,a.y),d}const f=`${t.diffBase}/${r}`,c=await Wr(f);if(c.naturalWidth===l.width&&c.naturalHeight===l.height)return c;throw new Error(`Diff PNG wrong size for ${r}`)})();return Gt.set(n,i),i}async function mr(e,t,r,n,s,i){if(s){const{width:p,height:E}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const m=document.createElement("canvas");m.width=p,m.height=E;const A=m.getContext("2d");if(A.clearRect(0,0,p,E),A.drawImage(t,0,0,p,E),i&&!i())return;(e.width!==p||e.height!==E)&&(e.width=p,e.height=E);const x=e.getContext("2d");x.clearRect(0,0,p,E),x.drawImage(m,0,0);return}const o=await $r(),a=rr(o.viseme.atlasMeta),{width:l,height:f}=ht(o);(e.width!==l||e.height!==f)&&(e.width=l,e.height=f);const c=[],u=e.getContext("2d");if(u.clearRect(0,0,l,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const p=o.sil;u.drawImage(p,0,0,l,f);return}if(c.length===0){u.drawImage(t,0,0,l,f);return}const d=Ur(t,c,l,f,a);u.drawImage(d,0,0)}async function Tr(e,t,r){const n=await $r(mt??void 0),s=rr(n.viseme.atlasMeta),{width:i,height:o}=ht(n);(e.width!==i||e.height!==o)&&(e.width=i,e.height=o);const a=[];if(t.mouthPath){const c=new Set(n.viseme.cellByPath.keys()),u=Or(t.mouthPath,c)??(c.has(t.mouthPath)?t.mouthPath:null);u&&a.push(await zt(n,n.viseme,u))}if(t.expressionPath&&n.expression){const c=Vr(t.expressionPath,u=>n.expression.cellByPath.has(u));c&&a.push(await zt(n,n.expression,c))}const l=e.getContext("2d");if(l.clearRect(0,0,i,o),a.length===0){l.drawImage(n.sil,0,0,i,o);return}const f=Ur(n.sil,a,i,o,s);l.drawImage(f,0,0)}async function ro(e,t){const r=await $r(mt??void 0),n=rr(r.viseme.atlasMeta),{width:s,height:i}=ht(r),o=[];if(e.mouthPath){const c=new Set(r.viseme.cellByPath.keys()),u=Or(e.mouthPath,c)??(c.has(e.mouthPath)?e.mouthPath:null);u&&o.push(await zt(r,r.viseme,u))}if(e.expressionPath&&r.expression){const c=Vr(e.expressionPath,u=>r.expression.cellByPath.has(u));c&&o.push(await zt(r,r.expression,c))}const a=new OffscreenCanvas(s,i),l=a.getContext("2d");if(o.length===0)return l.drawImage(r.sil,0,0,s,i),a.transferToImageBitmap();const f=Ur(r.sil,o,s,i,n);return l.drawImage(f,0,0),a.transferToImageBitmap()}async function no(e){await Tr(e,{mouthPath:null,expressionPath:null})}let ds=null;function fn(e){ds=e}function Ge(){return ds}function so(e){return`${e.from}→${e.to}@${e.fromVtime}`}function dn(){return{rafTicksSpeaking:0,rafTicksDeduped:0,drawsRequested:0,drawsDisplayed:0,queueSuperseded:0,workerStale:0,rifeFramesOmittedByGap:0,transitionFramesSampled:0,transitionFramesDisplayed:0,transitionFramesMissed:0,bufferTicks:0,bufferHits:0,bufferUnderruns:0,bufferPrefetched:0}}function io(){let e=dn();const t=new Set,r=new Set,n=new Set;let s="",i=-1,o="";const a=()=>{e=dn(),t.clear(),r.clear(),n.clear(),s="",i=-1,o=""},l=c=>{t.add(c)},f=c=>{c&&n.add(c)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(c,u){const d=so(c);e.transitionFramesSampled+=1,d!==s&&(s=d,i=-1,o!==d&&(o=d,e.rifeFramesOmittedByGap+=c.omittedByGap)),u&&r.add(u),i>=0&&c.frameIdx>i+1&&(e.transitionFramesMissed+=c.frameIdx-i-1),i=c.frameIdx},onBufferTick(){e.bufferTicks+=1},onBufferHit(){e.bufferHits+=1},onBufferUnderrun(){e.bufferUnderruns+=1},onBufferPrefetched(){e.bufferPrefetched+=1},onBufferReset(){},onDrawDisplayed(c,u){if(e.drawsDisplayed+=1,c.transitionMeta){e.transitionFramesDisplayed+=1;const p=c.transitionMeta;l(p.fromVtime),l(p.toVtime),f(c.mouthPath);return}if(c.label.includes("→")){e.transitionFramesDisplayed+=1;return}const d=c.label.trim();if(!(!d||d==="sil")){for(const p of u)if(p.viseme===d&&c.elapsedMs>=p.vtime&&c.elapsedMs<p.vtime+p.vduration){l(p.vtime);break}}},snapshot(c,u){let d=0,p=0;for(const C of c)if(C.viseme!=="sil"){if(C.vtime>=u)break;d+=1,t.has(C.vtime)&&(p+=1)}const E=d>0?Math.round(p/d*100):100,m=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),A=d-p,x=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:x,renderLoss:m,visemeSlotsTotal:d,visemeSlotsCovered:p,visemeCoveragePct:E,transitionFramesUniqueSampled:r.size,transitionFramesUniquePainted:n.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+m,visemesShown:p,visemesSkipped:A,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const ms=Ar,oo=200,mn=300,ao=100,uo=600,hs="__sil__";function hn(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===hs:!1}function Hr(){return{lastDrawnKey:""}}function xe(e){e.lastDrawnKey="",e.transitionCache=void 0}function co(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const r=qn(e);return t&&(t.transitionCache={queueLength:e.length,transitions:r}),r}function lo(e,t){let r="sil";for(const n of e)n.viseme!=="sil"&&(t!=null&&n.vtime>t||(r=n.viseme));return r}function fo(e,t,r,n=120){if(r!=="sil")return r;const s=Jn(e,t,n);return s!=="sil"?s:lo(e,t)}function mo(e,t){return e==="sil"?!1:t?Ii(e,"sil",t):Nr(e,"sil").length>0}function ho(){return ms+uo}function jt(e){return e??hs}function Kr(e,t,r,n,s=ao){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=Qe(e))return{diffPath:null,label:"sil"};const i=co(e,n),o=ii(i,t);if(o){const f=Gn(o.fromVtime,o.toVtime,o.from,o.to);if(t>=f.transStart&&t<f.transEnd){let c=Nr(o.from,o.to);r&&(c=os(c,r));const u=Pi(c,f.effectiveGapMs);if(u.length>0){const d=xi(t,f.transStart,f.transEnd,u.length);return{diffPath:u[d]??u[u.length-1],label:`${o.from}→${o.to}`,transitionMeta:{from:o.from,to:o.to,fromVtime:o.fromVtime,toVtime:o.toVtime,frameIdx:d,frameCount:u.length,fullFrameCount:c.length,omittedByGap:Math.max(0,c.length-u.length)}}}return{diffPath:dt(o.to),label:o.to}}}const a=Jt(e);let l=Wn(a,t);return l==="sil"&&(l=Jn(e,t,s)),l==="sil"?{diffPath:null,label:"sil"}:{diffPath:dt(l),label:l}}function Et(e,t){const r=t??jt(e.expressionPath);return`${jt(e.mouthPath)}|${r}`}function pn(e,t,r,n,s,i,o,a,l,f){const c=Kr(t,r,l,i),u={mouthPath:c.diffPath,expressionPath:n},d=Et(u,s),p=Ge();if(c.transitionMeta&&p?.onTransitionSample(c.transitionMeta,c.diffPath),d===i.lastDrawnKey){p?.onDrawDeduped();return}p?.onDrawRequested(),a(c),i.lastDrawnKey=d,o(e,u,d,E=>{E===d&&(i.lastDrawnKey=d)})}function hr(e,t,r,n,s,i,o=null,a=null){const l={mouthPath:a,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",c=Et(l,r)+f;!(o!=null)&&c===n.lastDrawnKey||(i(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),s(e,l,c,d=>{d===c&&(n.lastDrawnKey=c)}))}function ps(e,t,r,n,s=bt,i){if(r<=t||e.length===0)return[];const o=i??Hr(),a=[];let l="";for(let f=t;f<r;f+=s){const c=Kr(e,f,n,o),u=jt(c.diffPath);u!==l&&(l=u,a.push({displayAtMs:f,mouthPath:c.diffPath,mouthKey:u,label:c.label}))}return a}const po=3;function qr(e){let t=0;const r=[];let n=!1,s=!1;const i=async()=>{if(!n){n=!0;try{for(;r.length>0;){const a=r.shift(),l=++t;await e(a.diffs,l,a)&&l===t&&a.onDisplayed?.(a.drawKey)}}finally{n=!1,r.length>0&&i()}}},o=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(a,l,f){const c=r.findIndex(u=>u.drawKey===l);c>=0?r[c]={diffs:a,drawKey:l,onDisplayed:f}:(r.length>=po&&(r.shift(),Ge()?.onQueueSuperseded()),r.push({diffs:a,drawKey:l,onDisplayed:f})),o()},reset(){t+=1,r.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function wo(e,t=2){const r=[],n=new Set;let s=0,i=!1,o=0;const a=(f,c)=>`${f}|${c}`,l=async()=>{if(!i){i=!0;try{for(;s<t&&r.length>0;){const f=r.shift(),c=a(f.displayAtMs,f.drawKey);if(n.has(c))continue;n.add(c),s+=1;const u=o;try{await e(f)}finally{if(n.delete(c),s-=1,u!==o)return}}}finally{i=!1,r.length>0&&s<t&&l()}}};return{enqueue(f){const c=a(f.displayAtMs,f.drawKey);n.has(c)||r.some(u=>a(u.displayAtMs,u.drawKey)===c)||(r.push(f),l())},isQueuedOrInflight(f,c){const u=a(f,c);return n.has(u)?!0:r.some(d=>a(d.displayAtMs,d.drawKey)===u)},reset(){o+=1,r.length=0,n.clear(),s=0},pendingCount(){return r.length+s}}}function go(){const e=new Map,t=r=>{r.bitmap.close()};return{has(r,n){return e.has(n)},markRendered(r,n,s,i,o){const a=e.get(n);a&&t(a),e.set(n,{displayAtMs:r,mouthKey:n,label:s,mouthPath:i,bitmap:o})},findForMouthKey(r){return e.get(r)??null},removeThrough(r){},pruneBefore(r){},reset(){for(const r of e.values())t(r);e.clear()},size(){return e.size}}}function yo(e,t,r,n,s,i){const o=ps(t,r,n,s,bt,i);if(o.length===0)return{ready:0,total:0};let a=0;for(const l of o)e.has(l.displayAtMs,l.mouthKey)&&(a+=1);return{ready:a,total:o.length}}function _o(e){const t=go(),r=Hr(),n=new Set;let s="",i=null;const o=wo(async u=>{try{if(!e.supportsBufferedPlayback)return;const d=await e.compositePrefetchFrame(u.diffs,u.mouthKey);if(!d)return;t.markRendered(u.displayAtMs,u.mouthKey,u.label,u.mouthPath,d),Ge()?.onBufferPrefetched()}finally{n.delete(u.mouthKey)}},Rs),a=u=>{for(const d of u)t.has(d.displayAtMs,d.mouthKey)||n.has(d.mouthKey)||o.isQueuedOrInflight(0,d.mouthKey)||(n.add(d.mouthKey),o.enqueue({...d,displayAtMs:0,drawKey:d.mouthKey,diffs:{mouthPath:d.mouthPath,expressionPath:null}}))},l=(u,d,p,E=lr)=>{if(!e.supportsBufferedPlayback)return;const m=Math.max(0,d-bt*4),A=ps(u,m,d+E,p,bt,r);a(A)},f=(u,d)=>{s=u,i=d},c=(u,d)=>!(s!==u||i!==d);return{reset(){t.reset(),o.reset(),n.clear(),xe(r),s="",i=null,Ge()?.onBufferReset()},markExternallyDisplayed(u,d){f(u.split("|")[0]??u,d)},warmupTick(u){e.supportsBufferedPlayback&&l(u.queue,0,u.availablePaths,Math.max(Xr,lr))},isWarmupReady(u,d=Xr){if(!e.supportsBufferedPlayback)return!0;const{ready:p,total:E}=yo(t,u.queue,0,d,u.availablePaths,r);return E===0?!1:p/E>=Ms},getBufferedFrameCount:()=>t.size(),tick(u){const d=Ge();d?.onBufferTick(),l(u.queue,u.elapsedMs,u.availablePaths),t.pruneBefore(u.elapsedMs-lr);const p=Kr(u.queue,u.elapsedMs,u.availablePaths,r),E=jt(p.diffPath),m=Et({mouthPath:p.diffPath,expressionPath:u.expressionPath},u.expressionDrawKey),A=()=>(f(E,u.expressionPath),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(c(E,u.expressionPath)||u.playbackState.lastDrawnKey===m)return A();const x=t.findForMouthKey(E,u.elapsedMs,bt);return x&&u.expressionPath!=null?(d?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):x?(e.blitBitmap(u.canvas,x.bitmap),f(x.mouthKey,u.expressionPath),u.playbackState.lastDrawnKey=m,u.onStatus({diffPath:x.mouthPath,label:x.label}),u.onDisplayed(m,x.mouthPath,x.label),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(d?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const So=`
|
|
5
|
+
`);We=Me.pop()??"";for(const He of Me)await Le(He);if(et){We.trim()&&await Le(We.trim()),Se===W&&!ce.signal.aborted&&A&&k.markStreamComplete(n);break}}}catch(Pe){if(ce.signal.aborted||!A)return;console.error("[realtimeVoice] avatar_speak failed:",Pe),e("error"),F()}finally{M===ce&&(M=null)}},Ee=h=>{const L=Ms(h);if(!L){console.warn("[realtimeVoice] server message with no payload",h);return}const J=String(L.type??"unknown");switch(J!=="avatar_metadata"&&J!=="avatar_audio_chunk"&&J!=="avatar_lipsync"&&J!=="avatar_interrupt"&&J!=="error"&&console.debug("[realtimeVoice] server message",J,L),J){case"avatar_metadata":_(L);break;case"avatar_audio_chunk":H(L);break;case"avatar_lipsync":X(L);break;case"avatar_interrupt":$(L);break;case"error":{const ce=String(L.message??"Voice session error");console.error("[realtimeVoice] server error:",ce),e("error"),F();break}case"avatar_speak":se(L);break}},_e=()=>p||(T=new Es,p=new Fi.PipecatClient({transport:new Rn.WebSocketTransport({mediaManager:T,serializer:new xs,recorderSampleRate:Hn,playerSampleRate:$n}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{d=!0,e("idle"),F()},onDisconnected:()=>{d=!1,D()},onError:h=>{const L=typeof h=="object"&&h!==null&&"data"in h?String(h.data??h):String(h);console.error("[realtimeVoice]",L,h),e("error"),F()},onTransportStateChanged:h=>{h==="error"&&(e("error"),F())},onServerMessage:h=>{re(h)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{ie(),te("bot_started")},onBotStoppedSpeaking:()=>{A&&(de(),Q=setTimeout(()=>{Q=null,A&&(k.markStreamComplete(n),te("bot_stopped"))},450))},onUserTranscript:h=>{String(h.text??""),m.onUserTranscript?.(h.text,!!h.final)},onBotOutput:h=>{m.onBotOutput?.(h.text)}}}),p);return{setDeveloperToken:h=>{},setTtsEngineId:h=>{c=h,k.setStreamTtsEngineId(h)},getTtsEngineId:()=>c,speak:async(h,L)=>{const J=h.trim();if(J){if(!p||!d)throw new Error("Realtime voice is not connected. Call connect() first.");O(),await p.sendText(J)}},stop:()=>{M?.abort(),M=null,W+=1,ie(),O(),e("idle"),F()},connect:async h=>{if(h&&(m={...m,...h}),!m.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const L=_e();await L.initDevices();const J=li(m);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",J);try{await L.connect({wsUrl:J})}catch(ce){d=!1,e("error"),F();const Se=ce instanceof Error?ce.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${Se} — ${J}`)}d=!0,e("idle"),F()},disconnect:async()=>{if(de(),K=!1,g.length=0,I=!1,M?.abort(),M=null,W+=1,ie(),p)try{await p.disconnect()}catch(h){console.error("[realtimeVoice] disconnect failed:",h)}d=!1,D()},isConnected:()=>d,unlockAudio:async()=>{await k.primeAudioContext()},getVisemeQueue:()=>n,getWordQueue:()=>r,getFullVisemeQueue:()=>i,getFullWordQueue:()=>s,getSentenceEmotions:()=>a,getStreamMood:()=>u,getPlaybackElapsedMs:oe,isSpeaking:()=>k.isSpeaking(),isWarmingUp:()=>k.isWarmingUp(),releaseWarmupHold:()=>k.releaseWarmupHold(),setLipsyncWarmupHold:(h,L)=>{L&&(Z=L),k.setLipsyncWarmupHoldEnabled(h)},getVoiceStream:()=>k.getVoiceStream(),setPlaybackSpeed:h=>{k.setPlaybackSpeed(h)},getPlaybackSpeed:()=>k.getPlaybackSpeed(),subscribe:h=>(E.add(h),()=>E.delete(h))}}function di(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function mi(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 hi(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function bt(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 ns(r,t)}async function pi(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await bt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function Rs(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function Ds(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted image"))},s.src=n})}async function Bs(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function Fs(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted PNG"))},s.src=n})}function Ls(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Os(e){const t=is();if(!Rt())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await bt(t,e);return Ls(n)}function gt(e,t){return`${e}/${t}_minus_sil.png`}const wi=5;function ln(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:wi}const Ns=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],An=["t01_0.25","t02_0.50","t03_0.75"],Vs=An.length,dr=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 mr(e,t){return`${e}__${t}`}function hr(e,t){return`pairs/${e}/${t}_minus_sil.png`}function _t(e){return`${e}_minus_sil.png`}function zn(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 i=_t(r);return t.has(i)?i:null}function gi(e,t){return e.filter(n=>t.has(n))}function Us(e,t,n){const r=Kn(e,t);return gi(r,n).length>0}function Kn(e,t){if(e===t)return[];const n=[],r=mr(e,t);if(dr.has(r)){for(const s of An)n.push(hr(r,s));return n}const i=mr(t,e);if(dr.has(i)){for(let s=Vs-1;s>=0;s--)n.push(hr(i,An[s]));return n}return[]}function Ws(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function Hs(e,t){return Ws(t).map(r=>e[r]).filter(r=>r!=null)}function $s(e,t,n,r){if(r<=0)return 0;const s=Math.max(1,n-t)/r,o=e-t,a=Math.floor(o/s);return Math.min(r-1,Math.max(0,a))}function yi(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,i=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${i}.bin`}const zs=[.32,.24,.16,.08,0],Ks=zs.map(e=>`eyes_${e.toFixed(2)}`),js=["eyes_0.32","eyes_0.16","eyes_0.00"],qs=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],$e=2,Gs=-20,Jt=16,_i={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Mt(e){return`brow_${e}`}function st(e){return _i[e]}function je(e){return Math.max(Gs,Math.min(Jt,e))}function Ys(e,t){if(e===t)return[];const n=e<t,r=n?$e:-$e,i=[];let s=e;if(s%$e!==0){const o=n?Math.ceil(s/$e)*$e:Math.floor(s/$e)*$e,a=je(o);if(n?a>=t:a<=t)return[t];s=a,i.push(s)}for(;;){const o=s+r;if(n?o>=t:o<=t){t!==s&&i.push(t);break}s=o,i.push(s)}return i}function pr(e){const t=je(e);if(t%$e===0)return[t];const n=Math.floor(t/$e)*$e,r=Math.min(Jt,n+$e),i=je(n);return t-i<=r-t?i===r?[i]:[i,r]:i===r?[r]:[r,i]}const Qs=["fear","anger","sad","neutral","love","happy","disgust"],Xs={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 Ge(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?Xs[n]??t:t}function vi(e){return e===0?null:gt(Mt(e),"eyes_standard")}function Si(e){return vi(st(e))}const Js={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function jn(e,t){if(!e)return null;if(t(e))return e;const n=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const i=Number(n[1]),s=n[2];for(const a of pr(i)){if(a===i)continue;const l=gt(Mt(a),s);if(t(l))return l}const o=Js[i];if(o){const a=gt(o,s);if(t(a))return a}return null}const r=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const i=r[1],s=r[2],o=st(i);for(const a of[o,...pr(o)]){const l=gt(Mt(a),s);if(t(l))return l}}return null}function wr(e,t){const n=Mt(st(e));return!t||t==="eyes_standard"?Si(e):e==="neutral"&&t==="eyes_standard"?null:gt(n,t)}function Zs(e,t){const n=[];for(const r of t)n.push(wr(e,r));for(let r=t.length-2;r>=0;r--)n.push(wr(e,t[r]));return n.push(Si(e)),n}function ea(e){return gt(Mt(e),"eyes_standard")}function ta(e,t){return Ys(e,t).map(ea)}const na=6;function ra(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function ia(e){const t=je(e);return t>=Jt?Jt:je(t+na)}function sa(e,t,n){const r=je(n);return ra(t,e)?.emphasis?ia(r):r}function gr(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)?je(n):null}function wt(e,t){return e+Math.random()*(t-e)}function jt(){return wt(14,32)}function aa(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:i=.18,doubleBlinkGapMinMs:s=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:l=380,minDwellMs:f=550}=e;let u="neutral",c="neutral",d=0,p=0,T=0,m={kind:"idle",nextBlinkAt:performance.now()+t},P=null,C="__eyes_open__|neutral|brow:0";function E(M=u){C=`${P??"__eyes_open__"}|${M}|brow:${p}`}function g(M,W=u){P=M;const K=gr(M);K!=null?p=K:M==null&&(p=0),E(W)}function I(M){return vi(M)}function N(M,W,K){const Q=je(W),Y=je(K);if(d=Y,Q===Y){g(I(Y));return}const de=[...ta(Q,Y),I(Y)];m={kind:"browBlend",paths:de,index:0,holdUntil:M+jt(),targetBrow:Y},g(de[0]??null)}function A(M,W){m={kind:"idle",nextBlinkAt:M+wt(n,r)},c=W,g(I(d),W)}function ee(M,W,K){const Q=K?js:Math.random()<a?Ks:qs;m={kind:"playing",paths:Zs(W,Q),index:0,holdUntil:M+jt(),after:"idle",blinkEmotion:W},c=W,g(m.paths[0]??null,W)}function fe(M){if(m.kind==="browBlend"){for(;M>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=M+jt();const W=m.paths[m.index]??null;g(W),M>=m.holdUntil&&m.index>=m.paths.length-1&&(p=m.targetBrow,d=m.targetBrow,g(I(m.targetBrow)),m={kind:"idle",nextBlinkAt:M+l});return}if(m.kind==="idle"){g(I(d),c),M>=m.nextBlinkAt&&ee(M,c,!1);return}if(m.kind==="doublePause"){g(I(d),m.blinkEmotion),M>=m.resumeAt&&ee(M,m.blinkEmotion,!0);return}if(m.kind==="playing"){for(;M>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=M+jt();if(g(m.paths[m.index]??null,m.blinkEmotion),M>=m.holdUntil&&m.index>=m.paths.length-1){if(m.after==="resumeIdle"){A(M+l,u);return}if(m.after==="doublePause"){m={kind:"doublePause",resumeAt:M+wt(s,o),blinkEmotion:m.blinkEmotion},g(I(d),m.blinkEmotion);return}if(m.after==="idle"&&Math.random()<i){m={kind:"doublePause",resumeAt:M+wt(s,o),blinkEmotion:m.blinkEmotion},g(I(d),m.blinkEmotion);return}A(M,m.blinkEmotion)}}}return{advance:fe,setTargetEmotion(M,W){const K=Ge(M,u);if(K===u)return;const Q=performance.now();!W?.force&&f>0&&!(u==="neutral"&&K!=="neutral")&&Q-T<f||(u=K,c=K,T=Q)},setTargetEyebrow(M){const W=je(M);if(W===d)return;const K=performance.now(),Q=m.kind==="browBlend"?gr(P)??p:p;d=W,!(W===Q&&m.kind!=="browBlend")&&(m.kind==="playing"||m.kind==="doublePause"||N(K,Q,W))},snapToEmotion(M){const W=Ge(M),K=st(W);u=W,c=W,d=K,p=K,T=performance.now(),m={kind:"idle",nextBlinkAt:performance.now()+wt(4e3,7e3)},g(I(K),W)},getTargetEmotion:()=>u,getTargetEyebrow:()=>d,getExpressionPath:()=>P,getDrawKey:()=>C,reset(){u="neutral",c="neutral",d=0,p=0,T=0,A(performance.now()+wt(n,r),"neutral")}}}function oa(){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 i=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(s){t&&r===s||(i(),t=!1,r=s,s.startsWith("blob:")&&(n=s),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: ${s}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",l,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${s}`)),{once:!0}),e.src=s,e.load()}))},isReady(){return t},getVideo(){return e},setActive(s){t&&(s?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),i(),t=!1,r=""}}}const ca=50,bi=400;function ua(e,t,n){return e.filter(r=>{const i=r.queueIndex??-1;return i>=t&&i<=n})}function la(e,t){const n=[];for(const r of e){const i=ua(t,r.start_word,r.end_word);if(i.length===0)continue;const s=i[0],o=i[i.length-1];n.push({sentence:r,startMs:Math.max(0,s.wtime-ca),endMs:o.wtime+o.wduration+bi})}return n.sort((r,i)=>r.startMs-i.startMs)}function fa(e,t,n,r="neutral"){const i=Ge(r);if(t.length===0)return i;if(n.length===0||e<n[0].wtime)return Ge(t[0]?.emotion,i);const s=la(t,n);let o=null;for(const f of s)e>=f.startMs&&e<=f.endMs&&(o=f);if(o)return Ge(o.sentence.emotion,i);const a=n[n.length-1],l=a.wtime+a.wduration;return e>l+bi?Ge(t[t.length-1]?.emotion,i):i}function qn(e,t,n,r,i=wi){const s=new OffscreenCanvas(n,r),o=s.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 c of t){u.clearRect(0,0,n,r),u.drawImage(c,0,0,n,r);const d=u.getImageData(0,0,n,r);for(let p=0;p<l.data.length;p+=4){const T=d.data[p],m=d.data[p+1],P=d.data[p+2];Math.max(T,m,P)>i&&(l.data[p]=T,l.data[p+1]=m,l.data[p+2]=P,l.data[p+3]=255)}}return o.putImageData(l,0,0),s}let rt=null,vt=null;const Zt=new Map;function da(){rt=null,vt=null,Zt.clear()}Ur(da);function ma(e){return e??vt??void 0}function Gn(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 ha(e){return Rt()?Fs(await bt(Xt(),e??"")):Gn(Xt())}async function yr(e,t,n,r){const i=n?await pi(e,r):await fetch(e).then(f=>{if(!f.ok)throw new Error(`Failed to load ${e}`);return f.json()}),s=i.sheets?.[0];if(!s?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await Ds(await bt(yi(t,s.path,n),r??"")):await Gn(`${t}/${s.path}`),a=new Map;for(const f of i.cells??[])f.path&&a.set(f.path,f);const l=new Map;for(const f of i.sheets??[])l.set(f.index,f);return{atlas:o,atlasMeta:i,cellByPath:a,sheetByIndex:l,diffBase:t}}async function Pn(e){const t=ma(e),n=Rt();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(rt&&(!n||vt===(t??null))){const s=await rt;return{...St(s),visemePaths:[...s.viseme.cellByPath.keys()]}}vt=t??null,Zt.clear();const r=Wr();rt=(async()=>{const s=await ha(t),o=await yr(Hr(),r,n,t);let a=null;try{a=await yr($r(),r,n,t)}catch{a=null}return{sil:s,viseme:o,expression:a}})();const i=await rt;return{...St(i),visemePaths:[...i.viseme.cellByPath.keys()]}}async function Yn(e){if(await Pn(e),!rt)throw new Error("Assets not loaded");return rt}function St(e){return di(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function pa(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}`,i=Zt.get(r);if(i)return i;const s=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const a=mi(t.atlasMeta,o),l=St(e);if(hi(o)){const c=pa(t,o),d=document.createElement("canvas");d.width=l.width,d.height=l.height;const p=d.getContext("2d");return p.fillStyle="#000",p.fillRect(0,0,l.width,l.height),p.drawImage(c,a.x,a.y),d}const f=`${t.diffBase}/${n}`,u=await Gn(f);if(u.naturalWidth===l.width&&u.naturalHeight===l.height)return u;throw new Error(`Diff PNG wrong size for ${n}`)})();return Zt.set(r,s),s}async function vn(e,t,n,r,i,s){if(i){const{width:p,height:T}=i;if(s&&!s()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const m=document.createElement("canvas");m.width=p,m.height=T;const P=m.getContext("2d");if(P.clearRect(0,0,p,T),P.drawImage(t,0,0,p,T),s&&!s())return;(e.width!==p||e.height!==T)&&(e.width=p,e.height=T);const C=e.getContext("2d");C.clearRect(0,0,p,T),C.drawImage(m,0,0);return}const o=await Yn(),a=ln(o.viseme.atlasMeta),{width:l,height:f}=St(o);(e.width!==l||e.height!==f)&&(e.width=l,e.height=f);const u=[],c=e.getContext("2d");if(c.clearRect(0,0,l,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const p=o.sil;c.drawImage(p,0,0,l,f);return}if(u.length===0){c.drawImage(t,0,0,l,f);return}const d=qn(t,u,l,f,a);c.drawImage(d,0,0)}async function Mn(e,t,n){const r=await Yn(vt??void 0),i=ln(r.viseme.atlasMeta),{width:s,height:o}=St(r);(e.width!==s||e.height!==o)&&(e.width=s,e.height=o);const a=[];if(t.mouthPath){const u=new Set(r.viseme.cellByPath.keys()),c=zn(t.mouthPath,u)??(u.has(t.mouthPath)?t.mouthPath:null);c&&a.push(await en(r,r.viseme,c))}if(t.expressionPath&&r.expression){const u=jn(t.expressionPath,c=>r.expression.cellByPath.has(c));u&&a.push(await en(r,r.expression,u))}const l=e.getContext("2d");if(l.clearRect(0,0,s,o),a.length===0){l.drawImage(r.sil,0,0,s,o);return}const f=qn(r.sil,a,s,o,i);l.drawImage(f,0,0)}async function wa(e,t){const n=await Yn(vt??void 0),r=ln(n.viseme.atlasMeta),{width:i,height:s}=St(n),o=[];if(e.mouthPath){const u=new Set(n.viseme.cellByPath.keys()),c=zn(e.mouthPath,u)??(u.has(e.mouthPath)?e.mouthPath:null);c&&o.push(await en(n,n.viseme,c))}if(e.expressionPath&&n.expression){const u=jn(e.expressionPath,c=>n.expression.cellByPath.has(c));u&&o.push(await en(n,n.expression,u))}const a=new OffscreenCanvas(i,s),l=a.getContext("2d");if(o.length===0)return l.drawImage(n.sil,0,0,i,s),a.transferToImageBitmap();const f=qn(n.sil,o,i,s,r);return l.drawImage(f,0,0),a.transferToImageBitmap()}async function ga(e){await Mn(e,{mouthPath:null,expressionPath:null})}const qt={fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"clamp(0.875rem, 2.5vw, 1.125rem)",color:"rgba(255,255,255,0.85)"};function ya(e){return e.length===0?"":e.map(t=>t.word).join(" ")}function _a(e){if(!e)return{enabled:!1,style:qt};const t=e===!0?{}:e;return{enabled:!0,style:{fontFamily:t.fontFamily??qt.fontFamily,fontSize:t.fontSize??qt.fontSize,color:t.color??qt.color}}}const va={position:"absolute",bottom:0,left:0,right:0,display:"flex",justifyContent:"center",padding:"0.75rem 1rem",pointerEvents:"none"},Sa={display:"inline-block",maxWidth:"100%",padding:"0.45rem 0.85rem",borderRadius:"0.75rem",background:"rgba(0,0,0,0.55)",lineHeight:1.4,textAlign:"center"},ba={display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden",maxWidth:"100%",margin:0};function Ta({text:e,style:t}){return z.jsx("div",{style:va,"aria-live":"polite","aria-atomic":"true",children:z.jsx("div",{style:{...Sa,fontFamily:t.fontFamily,fontSize:t.fontSize,color:t.color},children:z.jsx("p",{style:ba,children:e})})})}let Ti=null;function _r(e){Ti=e}function Je(){return Ti}function ka(e){return`${e.from}→${e.to}@${e.fromVtime}`}function vr(){return{rafTicksSpeaking:0,rafTicksDeduped:0,drawsRequested:0,drawsDisplayed:0,queueSuperseded:0,workerStale:0,rifeFramesOmittedByGap:0,transitionFramesSampled:0,transitionFramesDisplayed:0,transitionFramesMissed:0,bufferTicks:0,bufferHits:0,bufferUnderruns:0,bufferPrefetched:0}}function xa(){let e=vr();const t=new Set,n=new Set,r=new Set;let i="",s=-1,o="";const a=()=>{e=vr(),t.clear(),n.clear(),r.clear(),i="",s=-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,c){const d=ka(u);e.transitionFramesSampled+=1,d!==i&&(i=d,s=-1,o!==d&&(o=d,e.rifeFramesOmittedByGap+=u.omittedByGap)),c&&n.add(c),s>=0&&u.frameIdx>s+1&&(e.transitionFramesMissed+=u.frameIdx-s-1),s=u.frameIdx},onBufferTick(){e.bufferTicks+=1},onBufferHit(){e.bufferHits+=1},onBufferUnderrun(){e.bufferUnderruns+=1},onBufferPrefetched(){e.bufferPrefetched+=1},onBufferReset(){},onDrawDisplayed(u,c){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 d=u.label.trim();if(!(!d||d==="sil")){for(const p of c)if(p.viseme===d&&u.elapsedMs>=p.vtime&&u.elapsedMs<p.vtime+p.vduration){l(p.vtime);break}}},snapshot(u,c){let d=0,p=0;for(const E of u)if(E.viseme!=="sil"){if(E.vtime>=c)break;d+=1,t.has(E.vtime)&&(p+=1)}const T=d>0?Math.round(p/d*100):100,m=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),P=d-p,C=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:C,renderLoss:m,visemeSlotsTotal:d,visemeSlotsCovered:p,visemeCoveragePct:T,transitionFramesUniqueSampled:n.size,transitionFramesUniquePainted:r.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+m,visemesShown:p,visemesSkipped:P,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const ki=Bn,Ea=200,Sr=300,Ia=100,Aa=600,xi="__sil__";function br(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===xi:!1}function Qn(){return{lastDrawnKey:""}}function Be(e){e.lastDrawnKey="",e.transitionCache=void 0}function Pa(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=ni(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Ma(e,t){let n="sil";for(const r of e)r.viseme!=="sil"&&(t!=null&&r.vtime>t||(n=r.viseme));return n}function Ca(e,t,n,r=120){if(n!=="sil")return n;const i=ui(e,t,r);return i!=="sil"?i:Ma(e,t)}function Ra(e,t){return e==="sil"?!1:t?Us(e,"sil",t):Kn(e,"sil").length>0}function Da(){return ki+Aa}function tn(e){return e??xi}function Xn(e,t,n,r,i=Ia){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=nt(e))return{diffPath:null,label:"sil"};const s=Pa(e,r),o=_s(s,t);if(o){const f=ri(o.fromVtime,o.toVtime,o.from,o.to);if(t>=f.transStart&&t<f.transEnd){let u=Kn(o.from,o.to);n&&(u=gi(u,n));const c=Hs(u,f.effectiveGapMs);if(c.length>0){const d=$s(t,f.transStart,f.transEnd,c.length);return{diffPath:c[d]??c[c.length-1],label:`${o.from}→${o.to}`,transitionMeta:{from:o.from,to:o.to,fromVtime:o.fromVtime,toVtime:o.toVtime,frameIdx:d,frameCount:c.length,fullFrameCount:u.length,omittedByGap:Math.max(0,u.length-c.length)}}}return{diffPath:_t(o.to),label:o.to}}}const a=an(e);let l=Jr(a,t);return l==="sil"&&(l=ui(e,t,i)),l==="sil"?{diffPath:null,label:"sil"}:{diffPath:_t(l),label:l}}function Ct(e,t){const n=t??tn(e.expressionPath);return`${tn(e.mouthPath)}|${n}`}function Tr(e,t,n,r,i,s,o,a,l,f){const u=Xn(t,n,l,s),c={mouthPath:u.diffPath,expressionPath:r},d=Ct(c,i),p=Je();if(u.transitionMeta&&p?.onTransitionSample(u.transitionMeta,u.diffPath),d===s.lastDrawnKey){p?.onDrawDeduped();return}p?.onDrawRequested(),a(u),s.lastDrawnKey=d,o(e,c,d,T=>{T===d&&(s.lastDrawnKey=d)})}function Sn(e,t,n,r,i,s,o=null,a=null){const l={mouthPath:a,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",u=Ct(l,n)+f;!(o!=null)&&u===r.lastDrawnKey||(s(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),i(e,l,u,d=>{d===u&&(r.lastDrawnKey=u)}))}function Ei(e,t,n,r,i=At,s){if(n<=t||e.length===0)return[];const o=s??Qn(),a=[];let l="";for(let f=t;f<n;f+=i){const u=Xn(e,f,r,o),c=tn(u.diffPath);c!==l&&(l=c,a.push({displayAtMs:f,mouthPath:u.diffPath,mouthKey:c,label:u.label}))}return a}const Ba=3;function Jn(e){let t=0;const n=[];let r=!1,i=!1;const s=async()=>{if(!r){r=!0;try{for(;n.length>0;){const a=n.shift(),l=++t;await e(a.diffs,l,a)&&l===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n.length>0&&s()}}},o=()=>{i||(i=!0,queueMicrotask(()=>{i=!1,s()}))};return{enqueue(a,l,f){const u=n.findIndex(c=>c.drawKey===l);u>=0?n[u]={diffs:a,drawKey:l,onDisplayed:f}:(n.length>=Ba&&(n.shift(),Je()?.onQueueSuperseded()),n.push({diffs:a,drawKey:l,onDisplayed:f})),o()},reset(){t+=1,n.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function Fa(e,t=2){const n=[],r=new Set;let i=0,s=!1,o=0;const a=(f,u)=>`${f}|${u}`,l=async()=>{if(!s){s=!0;try{for(;i<t&&n.length>0;){const f=n.shift(),u=a(f.displayAtMs,f.drawKey);if(r.has(u))continue;r.add(u),i+=1;const c=o;try{await e(f)}finally{if(r.delete(u),i-=1,c!==o)return}}}finally{s=!1,n.length>0&&i<t&&l()}}};return{enqueue(f){const u=a(f.displayAtMs,f.drawKey);r.has(u)||n.some(c=>a(c.displayAtMs,c.drawKey)===u)||(n.push(f),l())},isQueuedOrInflight(f,u){const c=a(f,u);return r.has(c)?!0:n.some(d=>a(d.displayAtMs,d.drawKey)===c)},reset(){o+=1,n.length=0,r.clear(),i=0},pendingCount(){return n.length+i}}}function La(){const e=new Map,t=n=>{n.bitmap.close()};return{has(n,r){return e.has(r)},markRendered(n,r,i,s,o){const a=e.get(r);a&&t(a),e.set(r,{displayAtMs:n,mouthKey:r,label:i,mouthPath:s,bitmap:o})},findForMouthKey(n){return e.get(n)??null},removeThrough(n){},pruneBefore(n){},reset(){for(const n of e.values())t(n);e.clear()},size(){return e.size}}}function Oa(e,t,n,r,i,s){const o=Ei(t,n,r,i,At,s);if(o.length===0)return{ready:0,total:0};let a=0;for(const l of o)e.has(l.displayAtMs,l.mouthKey)&&(a+=1);return{ready:a,total:o.length}}function Na(e){const t=La(),n=Qn(),r=new Set;let i="",s=null;const o=Fa(async c=>{try{if(!e.supportsBufferedPlayback)return;const d=await e.compositePrefetchFrame(c.diffs,c.mouthKey);if(!d)return;t.markRendered(c.displayAtMs,c.mouthKey,c.label,c.mouthPath,d),Je()?.onBufferPrefetched()}finally{r.delete(c.mouthKey)}},Ki),a=c=>{for(const d of c)t.has(d.displayAtMs,d.mouthKey)||r.has(d.mouthKey)||o.isQueuedOrInflight(0,d.mouthKey)||(r.add(d.mouthKey),o.enqueue({...d,displayAtMs:0,drawKey:d.mouthKey,diffs:{mouthPath:d.mouthPath,expressionPath:null}}))},l=(c,d,p,T=gn)=>{if(!e.supportsBufferedPlayback)return;const m=Math.max(0,d-At*4),P=Ei(c,m,d+T,p,At,n);a(P)},f=(c,d)=>{i=c,s=d},u=(c,d)=>!(i!==c||s!==d);return{reset(){t.reset(),o.reset(),r.clear(),Be(n),i="",s=null,Je()?.onBufferReset()},markExternallyDisplayed(c,d){f(c.split("|")[0]??c,d)},warmupTick(c){e.supportsBufferedPlayback&&l(c.queue,0,c.availablePaths,Math.max(ar,gn))},isWarmupReady(c,d=ar){if(!e.supportsBufferedPlayback)return!0;const{ready:p,total:T}=Oa(t,c.queue,0,d,c.availablePaths,n);return T===0?!1:p/T>=zi},getBufferedFrameCount:()=>t.size(),tick(c){const d=Je();d?.onBufferTick(),l(c.queue,c.elapsedMs,c.availablePaths),t.pruneBefore(c.elapsedMs-gn);const p=Xn(c.queue,c.elapsedMs,c.availablePaths,n),T=tn(p.diffPath),m=Ct({mouthPath:p.diffPath,expressionPath:c.expressionPath},c.expressionDrawKey),P=()=>(f(T,c.expressionPath),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(u(T,c.expressionPath)||c.playbackState.lastDrawnKey===m)return P();const C=t.findForMouthKey(T,c.elapsedMs,At);return C&&c.expressionPath!=null?(d?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):C?(e.blitBitmap(c.canvas,C.bitmap),f(C.mouthKey,c.expressionPath),c.playbackState.lastDrawnKey=m,c.onStatus({diffPath:C.mouthPath,label:C.label}),c.onDisplayed(m,C.mouthPath,C.label),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(d?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const Va=`
|
|
6
6
|
in vec2 aPosition;
|
|
7
7
|
out vec2 vTextureCoord;
|
|
8
8
|
|
|
@@ -30,7 +30,7 @@ void main(void)
|
|
|
30
30
|
gl_Position = filterVertexPosition();
|
|
31
31
|
vTextureCoord = filterTextureCoord();
|
|
32
32
|
}
|
|
33
|
-
`,
|
|
33
|
+
`,Ua=`
|
|
34
34
|
in vec2 vTextureCoord;
|
|
35
35
|
out vec4 finalColor;
|
|
36
36
|
|
|
@@ -44,4 +44,5 @@ void main(void)
|
|
|
44
44
|
float keep = step(uThreshold + 1e-6, peak);
|
|
45
45
|
finalColor = vec4(color.rgb, keep);
|
|
46
46
|
}
|
|
47
|
-
`;function wn(e=5){const t=new ue.Filter({glProgram:ue.GlProgram.from({vertex:So,fragment:vo,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=r=>{t.resources.thresholdUniforms.uniforms.uThreshold=r/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function bo(e,t,r){return e>r||t>r}function To(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function Eo(e,t){return t!=null&&t>0?Math.floor(t):To(e)}function ko(e,t){const r=document.createElement("canvas");r.width=t.w,r.height=t.h;const n=r.getContext("2d");if(!n)throw new Error("Failed to acquire 2d context for atlas cell crop");return n.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}function ws(e){return fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load image: ${e}`);return t.blob()}).then(t=>createImageBitmap(t))}async function gn(e,t,r,n,s){const i=r?await ss(e,s):await fetch(e).then(u=>{if(!u.ok)throw new Error(`Failed to load ${e}`);return u.json()}),o=i.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,l=async(u,d)=>{const p=as(t,d,r),E=r?await yi(await pt(p,s??"")):await ws(p);if(bo(E.width,E.height,n))return console.info(`[PixiVisemeCompositor] Sheet ${d} (${E.width}x${E.height}) exceeds MAX_TEXTURE_SIZE=${n}; using per-cell crops.`),{mode:"cells",bitmap:E};const m=ue.Texture.from(E);return m.source.scaleMode="nearest",{mode:"full",texture:m}};a.set(o.index,await l(o.index,o.path));for(const u of i.sheets??[])u.index!==o.index&&u.path&&a.set(u.index,await l(u.index,u.path));const f=new Map;for(const u of i.cells??[])u.path&&f.set(u.path,u);const c=new Map;for(const u of i.sheets??[])c.set(u.index,u);return{atlasMeta:i,cellByPath:f,sheetByIndex:c,diffBase:t,sheets:a}}async function Io(e,t={}){const r=new ue.Application;try{await r.init({canvas:e,width:842,height:1264,preference:"webgl",autoStart:!1,antialias:!1,resolution:1,autoDensity:!1,backgroundAlpha:1,backgroundColor:0,powerPreference:"high-performance"})}catch(g){throw r.destroy({removeView:!1}),g}if(r.renderer.type!==ue.RendererType.WEBGL)throw r.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const n=Eo(r.renderer.gl,t.maxTextureSize);let s=!1,i=!1,o=!1;const a=r.canvas,l=()=>{s=!0,!i&&!o&&(i=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",l);const f=new ue.Sprite(ue.Texture.EMPTY),c=new ue.Sprite(ue.Texture.EMPTY);c.visible=!1,c.alpha=0;const u=new ue.Sprite(ue.Texture.EMPTY),d=new ue.Sprite(ue.Texture.EMPTY),p=new ue.Sprite(ue.Texture.EMPTY);p.visible=!1;const E=wn(5),m=wn(5);u.filters=[E],d.filters=[m],r.stage.addChild(f),r.stage.addChild(c),r.stage.addChild(u),r.stage.addChild(d),r.stage.addChild(p);let A=null,x=null,C=null,w=null,b=null,O=null,V=null,X=842,fe=1264,P=null,D=5;const N=new Map;let j=null,F=null,Y=null;const $=xn(()=>{N.clear(),O=null,V=null,A=null,P=null}),q=(g,_)=>{X=g,fe=_,r.renderer.resize(g,_),(e.width!==g||e.height!==_)&&(e.width=g,e.height=_)},k=()=>{u.visible=!1,d.visible=!1,u.texture=ue.Texture.EMPTY,d.texture=ue.Texture.EMPTY,j=null,F=null},ee=()=>{b=null,c.visible=!1,c.alpha=0},he=()=>{f.visible=!0,f.width=X,f.height=fe,f.x=0,f.y=0},ce=()=>{c.width=X,c.height=fe,c.x=0,c.y=0},te=()=>{p.visible=!1,ee(),A&&(f.texture=A,he())},J=()=>{!b&&!c.visible||te()},ke=g=>{if(o||s||!A){te();return}const _=Math.max(0,g);if(!x||_<=0){te();return}k(),p.visible=!1,f.texture=x,he(),c.texture=A,ce(),c.alpha=0,c.visible=!0,b={startMs:performance.now(),durationMs:_},W()},Me=(g=performance.now())=>{if(!b)return!1;if(o||s)return J(),!1;const _=(g-b.startMs)/Math.max(1,b.durationMs);if(_>=1)return te(),W(),!1;const y=Math.min(1,Math.max(0,_)),Z=y*y*(3-2*y);return c.alpha=Z,c.visible=!0,W(),!0},S=()=>{if(C){try{C.resource=null}catch{}C.destroy(),C=null}x&&(x.destroy(!1),x=null),w=null},M=(g,_)=>{const y=g.cellByPath.get(_);if(!y||!ns(y))return null;const Z=`${g.diffBase}::${_}`;let oe=N.get(Z);if(!oe){const ye=y.sheet??0,Re=g.sheets.get(ye);if(!Re)return null;let _e,Oe=!1;if(Re.mode==="full")_e=new ue.Texture({source:Re.texture.source,frame:new ue.Rectangle(y.x,y.y,y.w,y.h)});else{const wt=ko(Re.bitmap,y);_e=ue.Texture.from(wt),_e.source.scaleMode="nearest",Oe=!0}oe={texture:_e,ownsSource:Oe},N.set(Z,oe)}return{texture:oe.texture,cell:y}},G=(g,_,y,Z)=>{if(!Z||!y)return g.visible=!1,g.texture=ue.Texture.EMPTY,!1;const oe=M(y,Z);if(!oe)return g.visible=!1,g.texture=ue.Texture.EMPTY,!1;const ye=rs(y.atlasMeta,oe.cell);return _.setThreshold(D),g.texture=oe.texture,g.x=ye.x,g.y=ye.y,g.width=oe.cell.w,g.height=oe.cell.h,g.visible=!0,!0},z=g=>{if(!g||!O)return null;const _=P??new Set(O.cellByPath.keys());return Or(g,_)??(_.has(g)?g:null)},I=g=>{p.visible=!1,te();const _=z(g.mouthPath),y=g.expressionPath&&V?Vr(g.expressionPath,Z=>V.cellByPath.has(Z)):null;_!==j?(G(u,E,O,_),j=_):_?u.visible=!0:u.visible=!1,y!==F?(G(d,m,V,y),F=y):y?d.visible=!0:d.visible=!1},W=()=>{if(!(o||s||document.hidden))try{r.render()}catch{}};return{async loadAssets(g){if(o)return{width:X,height:fe,visemePaths:[]};const _=It();if(_&&!g)throw new Error("Encrypted assets enabled but no key provided");const y=_?await Si(await pt(Kt(),g??"")):await ws(Kt());A&&A.destroy(!0),A=ue.Texture.from(y),A.source.scaleMode="linear";const Z=Mn();O=await gn(Rn(),Z,_,n,g);try{V=await gn(Cn(),Z,_,n,g)}catch(ye){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",ye),V=null}const oe=ts(O.atlasMeta,y.width,y.height);return q(oe.width,oe.height),D=rr(O.atlasMeta),E.setThreshold(D),m.setThreshold(D),P=new Set(O.cellByPath.keys()),N.clear(),te(),k(),W(),{width:oe.width,height:oe.height,visemePaths:[...O.cellByPath.keys()]}},getVisemeAtlasPaths(){return P},drawLiveFrame(g){o||s||!A||(J(),I(g),W())},drawIdleVideo(g,_){o||s||document.hidden||_&&!_()||g.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(ee(),k(),p.visible=!1,!x||w!==g?(S(),C=new ue.VideoSource({resource:g,autoPlay:!1,updateFPS:0}),C.autoUpdate=!1,x=new ue.Texture({source:C}),w=g):x.source.update(),f.texture=x,he(),W())},beginIdleToSilCrossfade:ke,tickIdleToSilCrossfade:Me,finishIdleToSilCrossfade:J,isIdleToSilCrossfading(){return b!=null},renderSilOnly(){o||s||!A||(k(),te(),W())},blitBitmap(g){o||s||(J(),k(),Y&&(Y.destroy(!0),Y=null),Y=ue.Texture.from(g),p.texture=Y,p.visible=!0,p.x=0,p.y=0,p.width=X,p.height=fe,f.visible=!1,W())},async compositePrefetchFrame(g){return null},renderFrame:W,isContextLost(){return s},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",l),$(),S(),Y&&(Y.destroy(!0),Y=null);for(const{texture:_,ownsSource:y}of N.values())_.destroy(y);N.clear(),A&&(A.destroy(!0),A=null);const g=_=>{_.mode==="full"?_.texture.destroy(!0):_.bitmap.close()};if(O)for(const _ of O.sheets.values())g(_);if(V)for(const _ of V.sheets.values())g(_);E.destroy(!0),m.destroy(!0),r.destroy({removeView:!1},{children:!0,texture:!0})}}}const yn=-1,Ut=1e5,_n=new Map;async function Ao(e){let t=_n.get(e);if(!t){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch worker script (${r.status}): ${e}`);const n=await r.blob();t=URL.createObjectURL(n),_n.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function Po(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Er(e,t){(e.width!==t.width||e.height!==t.height)&&(e.width=t.width,e.height=t.height);const r=e.getContext("2d");r&&r.drawImage(t,0,0)}function Sn(e,t){let r=0,n=null;const s=qr(async(i,o)=>(await br(),await Tr(e,i),s.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(i){const o=await br(i);return n=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return n},async renderSilOnly(){r+=1,s.reset(),await no(e)},drawLiveFrame(i,o,a,l){s.enqueue(o,a,l)},async compositePrefetchFrame(i,o){try{return await ro(i)}catch{return null}},blitBitmap(i,o){Er(i,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(i,o){r+=1;const a=r;t.onStatus?.(o),await Tr(i,{mouthPath:dt(o),expressionPath:null})},dispose(){r+=1,s.reset()}}}function xo(e,t,r){let n=null,s=1,i=0,o=!1,a=!1,l=null;const f=new Map,c=new Map;let u=Ut;const d=qr(async(C,w,b)=>(f.set(w,{drawKey:b.drawKey,onDisplayed:b.onDisplayed}),await A({type:"drawFrame",diffPath:C.mouthPath,expressionDiffPath:C.expressionPath,liveSeq:w},void 0,!0),!1)),p=C=>{if(C===yn){let O=-1,V;for(const[X,fe]of f)X>=O&&(O=X,V=fe);O>=0&&f.delete(O),V?.onDisplayed?.(V.drawKey);return}const w=-C,b=f.get(w);f.delete(w),b?.onDisplayed?.(b.drawKey)},E=new Map,m=(C,w)=>{a||!n||n.postMessage(C,[])},A=(C,w,b=!1)=>{if(a)return Promise.resolve();const O=s++;return new Promise((V,X)=>{E.set(O,{resolve:fe=>V(fe),reject:X,generation:typeof C.generation=="number"?C.generation:void 0,expectRenderDone:b}),m({...C,requestId:O})})},x=(async()=>{n=await Ao(r),n.onmessage=C=>{if(a)return;const w=C.data;if(w.type==="status"){t.onStatus?.(w.label);return}if(w.type==="frame"){if(w.generation<=-Ut){const V=-w.generation,X=c.get(V);c.delete(V),X?.resolve(w.bitmap);return}const O=w.generation<0;if(!O&&w.generation!==i){w.bitmap.close();return}if(O&&!(w.generation===yn)){const X=-w.generation;if(!d.isLatestSeq(X)){Ge()?.onWorkerStale(),w.bitmap.close();return}}if(O&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){Ge()?.onWorkerStale(),w.bitmap.close();return}Er(e,w.bitmap),w.bitmap.close(),O&&p(w.generation);return}const b=E.get(w.requestId);if(b)switch(w.type){case"ready":E.delete(w.requestId),b.resolve();break;case"loadAssetsDone":E.delete(w.requestId),l=w.visemePaths?.length?new Set(w.visemePaths):null,b.resolve({width:w.width,height:w.height,visemePaths:w.visemePaths});break;case"renderDone":if(b.expectRenderDone&&b.generation!=null&&w.generation!==b.generation)return;E.delete(w.requestId),b.resolve();break;case"renderAborted":E.delete(w.requestId),b.resolve();break;case"error":E.delete(w.requestId),t.onError?.(w.message),b.reject(new Error(w.message));break}},n.onerror=C=>{if(a)return;const w=C.message||"Worker error";t.onError?.(w);for(const[,b]of E)b.reject(new Error(w));E.clear()},await A({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(C){if(a)return{width:842,height:1264};if(await x,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await A({type:"loadAssets",keyHex:C,urls:Hs(rt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return l},async renderSilOnly(){if(a||(await x,a))return;i+=1,d.reset(),f.clear(),c.forEach(({resolve:w})=>w(null)),c.clear(),u=Ut;const C=i;await A({type:"cancelLiveDraws"}),await A({type:"renderSil",generation:C},void 0,!0)},drawLiveFrame(C,w,b,O){a||x.then(()=>{a||d.enqueue(w,b,O)})},compositePrefetchFrame(C,w){return a?Promise.resolve(null):x.then(()=>{if(a)return null;const b=++u;return new Promise(O=>{c.set(b,{resolve:O}),A({type:"drawFrame",diffPath:C.mouthPath,expressionDiffPath:C.expressionPath,liveSeq:b},void 0,!0).catch(()=>{c.delete(b),O(null)})})})},blitBitmap(C,w){Er(C,w)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(C,w,b={}){if(a||(await x,a))return;i+=1,d.reset(),f.clear();const O=i;try{await A({type:"cancelLiveDraws"}),await A({type:"renderViseme",generation:O,to:w,from:b.from,transitionDurationMs:b.transitionDurationMs,gapMs:b.gapMs,threshold:b.threshold},void 0,!0)}catch(V){if(V?.name==="AbortError")return;throw V}},dispose(){if(!a){a=!0,i+=1,d.reset(),f.clear(),c.forEach(({resolve:C})=>C(null)),c.clear(),u=Ut;for(const[,C]of E)C.resolve();E.clear(),n?.terminate(),n=null}}}}async function Mo(e,t){const r=await Io(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let n=0,s=null,i=!1;const o=qr(async(a,l)=>i?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(Ge()?.onWorkerStale(),!1):(r.drawLiveFrame(a),o.isLatestSeq(l)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(i)return{width:842,height:1264};const l=await r.loadAssets(a);return s=l.visemePaths?.length?new Set(l.visemePaths):null,l},getVisemeAtlasPaths(){return s},async renderSilOnly(){i||(n+=1,o.reset(),r.renderSilOnly())},drawLiveFrame(a,l,f,c){i||o.enqueue(l,f,c)},async compositePrefetchFrame(a,l){if(i)return null;try{return await r.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,l){i||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||r.blitBitmap(l)},drawIdleVideo(a,l){i||r.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){i||r.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return i?!1:r.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){i||r.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return i?!1:r.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,l){if(i)return;n+=1;const f=n;o.reset(),t.onStatus?.(l),r.drawLiveFrame({mouthPath:dt(l),expressionPath:null})},dispose(){i||(i=!0,n+=1,o.reset(),r.dispose())}}}function vn(e,t){if(!Po())return Sn(e,t);const r=As(t.workerScriptUrl);try{return xo(e,t,r)}catch{return Sn(e,t)}}function Ro(e,t={}){if(t.preferLegacyRenderer)return vn(e,t);let r=null,n=!1,s=null,i=!1;const o=()=>r?Promise.resolve(r):(s||(s=(async()=>{try{const a=await Mo(e,t);if(i)throw a.dispose(),new Error("Renderer disposed during Pixi init");return n=!0,r=a,a}catch(a){if(i)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),r=vn(e,t),n=!1,r}})()),s);return{get usesWorker(){return r?.usesWorker??!1},get usesPixi(){return n},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return r?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,l,f,c){o().then(u=>{i||u.drawLiveFrame(a,l,f,c)})},async compositePrefetchFrame(a,l){return(await o()).compositePrefetchFrame(a,l)},blitBitmap(a,l){r&&r.blitBitmap(a,l)},drawIdleVideo(a,l){r?.usesPixi&&r.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){r?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return r?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){r?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return r?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return r?.supportsBufferedPlayback??!1},async renderViseme(a,l,f){return(await o()).renderViseme(a,l,f)},dispose(){i=!0,s=null,r?.dispose(),r=null}}}class Co extends Error{constructor(t,r){super(`${t} timed out after ${Math.round(r/1e3)}s`),this.name="LoadTimeoutError"}}function pr(e,t,r){return new Promise((n,s)=>{const i=globalThis.setTimeout(()=>{s(new Co(r,t))},t);e.then(o=>{globalThis.clearTimeout(i),n(o)},o=>{globalThis.clearTimeout(i),s(o)})})}const Do={position:"relative",display:"inline-block",lineHeight:0},Fo={display:"block",maxWidth:"100%",height:"auto"},Bo={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 vt(e){return Cs(e)?Fr:Dr}function $e(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const Lo=T.forwardRef(function({id:t,avatarId:r,faceId:n,assets:s,authToken:i,apiBase:o,ttsEngineId:a=Je,voiceId:l,speakingRate:f=Pt,className:c,style:u,canvasStyle:d,onStatusChange:p,onDisplayStatus:E,onError:m,onReady:A,showErrorOverlay:x=!0,onUserTranscript:C,onBotOutput:w,onRealtimeLipsyncDebug:b,onFrameRenderStats:O,lipsyncBufferedPlayback:V=!0,lipsyncPlaybackWarmupMs:X=1500,pixiMaxTextureSize:fe},P){const D=T.useRef(null),N=T.useRef(null),j=T.useRef(null),F=T.useRef(V);F.current=V;const Y=T.useRef(X);Y.current=X;const $=T.useRef(0),q=T.useRef(Hr()),k=T.useRef(Gi()),ee=T.useRef(!1),he=T.useRef(null),ce=T.useRef(null),te=T.useRef(0),J=T.useRef(0),ke=T.useRef(0),Me=T.useRef(null),S=T.useRef(null),M=T.useRef(!1),G=T.useRef(!1),z=T.useRef(!1),I=T.useRef(!1),W=T.useRef("sil"),g=T.useRef(0),_=T.useRef(!1),y=T.useRef(null),Z=T.useRef(!1),[oe,ye]=T.useState("idle"),[Re,_e]=T.useState(null),[Oe,wt]=T.useState(!1),[Gr,xt]=T.useState(!1),[nr,h]=T.useState({width:842,height:1264}),[R,Q]=T.useState(0),re=T.useRef(!1),me=T.useRef(i??null),de=o?.trim()||kt,pe=T.useRef(null),we=T.useRef(null),ve=T.useRef(!1),nt=T.useRef({width:842,height:1264}),We=T.useRef(null),Ke=T.useRef("sil"),ze=T.useRef(void 0),gt=T.useRef(new Map),Mt=T.useRef(A),se=T.useRef(E),yt=T.useRef(m),_t=T.useRef(C),st=T.useRef(w),ge=T.useRef(b),Ce=T.useRef(O),Te=T.useRef(io());Mt.current=A,se.current=E,yt.current=m,_t.current=C,st.current=w,ge.current=b,Ce.current=O,T.useEffect(()=>{const v=Te.current;return fn(v),()=>fn(null)},[]);const it=T.useCallback(v=>{const B=v?.ttsEngineId??a??we.current?.ttsEngineId??Je,U=v?.voiceId??l??we.current?.voiceId??vt(B);return{ttsEngineId:B,voiceId:U}},[a,l]),Be=T.useCallback(v=>{_e(v),yt.current?.(v)},[]),je=T.useCallback(v=>{ye(v),p?.(v)},[p]),ie=T.useRef(Sr(je,de,{onLipsyncDebug:v=>ge.current?.(v)})),le=T.useRef(null);T.useEffect(()=>(ie.current=Sr(je,de,{onLipsyncDebug:v=>ge.current?.(v)}),i&&ie.current.setDeveloperToken(i),ie.current.setTtsEngineId(a),()=>{ie.current.stop();const v=le.current;v&&(v.disconnect(),le.current=null)}),[je,i,a,de]);const zr=T.useCallback(()=>(le.current||(le.current=es(je,{speakingRate:f,onUserTranscript:(v,B)=>_t.current?.(v,B),onBotOutput:v=>st.current?.(v),onLipsyncDebug:v=>ge.current?.(v)}),le.current.setTtsEngineId(a)),le.current),[je,f,a]),Ie=T.useCallback(()=>{Me.current!=null&&(clearTimeout(Me.current),Me.current=null)},[]),Ae=T.useCallback(()=>{S.current!=null&&(clearTimeout(S.current),S.current=null),z.current=!1},[]),Rt=T.useCallback(()=>{if(I.current)return;const v=N.current;if(I.current=!0,Ae(),M.current=!1,G.current=!1,!Z.current||!y.current){v?.renderSilOnly();return}y.current.setActive(!1);const B=y.current.getVideo();if(v?.usesPixi){v.drawIdleVideo(B),v.beginIdleToSilCrossfade(mn);return}(async()=>{const U=D.current;U&&await mr(U,B,null,void 0,nt.current).catch(()=>{}),await new Promise(L=>setTimeout(L,mn)),I.current&&await v?.renderSilOnly()})()},[Ae]),jr=T.useCallback(()=>{!Z.current||!y.current||(I.current=!1,N.current?.finishIdleToSilCrossfade(),Ae(),z.current=!0,S.current=setTimeout(()=>{if(S.current=null,$e(ie.current,le.current).isSpeaking()){z.current=!1;return}if(M.current){z.current=!1;return}const v=y.current;if(!v){z.current=!1;return}v.restart(),v.setActive(!0);const B=v.getVideo();let U=!1;const L=()=>{U||(U=!0,B.removeEventListener("playing",H),z.current=!1)},H=()=>{L()};if(B.addEventListener("playing",H,{once:!0}),B.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!B.paused){L();return}setTimeout(L,300)},oo))},[Ae]),ot=T.useCallback(()=>{if(Ie(),se.current?.("sil"),M.current=!1,I.current=!1,!Z.current||!y.current){z.current=!1;return}jr()},[Ie,jr]),sr=T.useCallback(async v=>{const B=J.current,U=N.current,L=D.current,H=()=>{v?.fallbackOnly||(M.current=!1)};if(!U||!L||!Oe){H();return}if($e(ie.current,le.current).isSpeaking()){H();return}if(v?.fallbackOnly){if(!M.current||(xe(q.current),await U.renderSilOnly(),B!==J.current)||$e(ie.current,le.current).isSpeaking())return;ot();return}if(hn(q.current)){xe(q.current),ot();return}if(F.current&&U.supportsBufferedPlayback&&!v?.fallbackOnly){if(xe(q.current),j.current?.reset(),await U.renderSilOnly(),B!==J.current||$e(ie.current,le.current).isSpeaking())return;ot();return}const Ee=fo($e(ie.current,le.current).getVisemeQueue(),g.current,W.current),De=mo(Ee,We.current);if(xe(q.current),!De){if(await U.renderSilOnly(),B!==J.current||$e(ie.current,le.current).isSpeaking())return;ot();return}try{await U.renderViseme(L,"sil",{from:Ee,transitionDurationMs:ms})}catch(Pe){if(Pe?.name!=="AbortError")throw Pe}if(B!==J.current){H();return}if($e(ie.current,le.current).isSpeaking()){H();return}ot()},[Oe,ot]),at=T.useCallback(()=>{if(G.current||M.current)return;G.current=!0,M.current=!0,Ie();const v=J.current;sr().finally(()=>{G.current=!1}),Me.current=setTimeout(()=>{Me.current=null,v===J.current&&sr({fallbackOnly:!0})},ho())},[Ie,sr]),Yr=T.useCallback(async()=>{const v=Math.floor(Date.now()/1e3);if(pe.current&&v<pe.current.expiresAt-60)return pe.current.key;const B=me.current??await Wt();me.current=B,ie.current.setDeveloperToken(B);const U=await Vs(B,de);return pe.current={key:U.value,expiresAt:U.expiresAt},U.value},[de]);T.useEffect(()=>{i&&(me.current=i,ie.current.setDeveloperToken(i))},[i]),T.useEffect(()=>{ie.current.setTtsEngineId(a),le.current?.setTtsEngineId(a),we.current&&(we.current.ttsEngineId=a)},[a]),T.useEffect(()=>{const v=l??vt(a);we.current&&(we.current.voiceId=v)},[l,a]);const Ye=T.useMemo(()=>An(r,n),[r,n]),_s=T.useMemo(()=>s?JSON.stringify(s):Ye?`face:${Ye}`:`id:${t??""}`,[s,Ye,t]);return T.useEffect(()=>{if(!t&&!s&&!Ye){Be("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let v=!1;ve.current=!1,wt(!1),xt(!1),_e(null),we.current=null,y.current=null,Z.current=!1;const B=D.current;if(!B)return;let U=null;return(async()=>{try{let L,H,be,Ee;if(s)L=s,H=a,be=l??vt(H);else if(Ye)se.current?.("loadFace"),L=yr(Ye),H=a,be=l??vt(H);else{se.current?.("getAiTwin");const K=await pr(In(t),3e4,"getAiTwin");if(v)return;if(!K.faceId?.trim())throw new Error("getAiTwin returned no faceId");H=K.ttsEngineId,be=l??K.voiceId??vt(H),Ee=K.knowledgeContextId?.trim()||void 0,L=yr(K.faceId)}we.current={ttsEngineId:H,voiceId:be,personaId:Ee},Pn(L),y.current=zi();const De=!!(s&&!tt(s));U=Ro(B,{preferLegacyRenderer:De,pixiMaxTextureSize:fe,onStatus:K=>{v||se.current?.(K)},onError:K=>{v||Be(K)},shouldAcceptLiveFrame:()=>{if(ee.current)return!0;if(M.current)return!1;const K=$e(ie.current,le.current);return K.isSpeaking()||K.isWarmingUp()},onWebGlContextLost:()=>{v||re.current||(re.current=!0,queueMicrotask(()=>{v||Q(K=>K+1)}))}}),N.current=U,j.current=_o(U),re.current=!1,(K=>{const ne=()=>{if(!K||Y.current<=0)return!1;const Se=N.current;return Se?F.current&&Se.supportsBufferedPlayback?!0:Se.usesPixi:!1};ie.current.setLipsyncWarmupHold(K,ne),le.current?.setLipsyncWarmupHold(K,ne)})(!0),se.current?.("auth");const Ne=me.current??i??await pr(Wt(),3e4,"getAuthToken");if(v)return;me.current=Ne,ie.current.setDeveloperToken(Ne),ie.current.setTtsEngineId(H);const Ct=It()?await Yr():void 0;if(v)return;se.current?.("loadAssets");const ae=await pr(U.loadAssets(Ct),18e4,"load face assets");if(!v&&ae.width>0&&ae.height>0&&(nt.current=ae,h(ae)),v)return;We.current=U.getVisemeAtlasPaths(),ve.current=!0,wt(!0),Mt.current?.(),U.renderSilOnly().then(()=>{v||se.current?.("sil")}),(async()=>{try{const K=await Ti(Ct);if(await y.current.load(K),v)return;Z.current=!0,xt(!0),xe(q.current),y.current.setActive(!0);const ne=y.current.getVideo();U.usesPixi?U.drawIdleVideo(ne):await mr(B,ne,null,void 0,nt.current),v||se.current?.("idle")}catch(K){if(v)return;Z.current=!1,xt(!1),console.warn("[AiTwin] Idle video unavailable:",K)}})()}catch(L){if(v)return;if(L instanceof $t){Be(L.message);return}Be(L instanceof Error?L.message:"Failed to load AI twin")}})(),()=>{v=!0,y.current?.dispose(),U?.dispose(),N.current=null}},[_s,s,Ye,t,a,l,i,fe,Yr,Be,R]),T.useEffect(()=>{const v={current:!1},B=()=>{const U=D.current,L=N.current,H=$e(ie.current,le.current);if(!U||!L||!Oe){te.current=requestAnimationFrame(B);return}if(document.hidden){y.current?.setActive(!1),te.current=requestAnimationFrame(B);return}const be=H.isSpeaking(),Ee=H.isWarmingUp(),De=be&&!_.current,Pe=_.current&&!be;De&&(Ie(),Ae(),M.current=!1,G.current=!1,xe(q.current),j.current?.reset(),Te.current.reset(),ze.current=void 0,ke.current=0,W.current="sil",g.current=0,Rt()),Pe&&(k.current.reset(),y.current?.setActive(!1),j.current?.reset(),L.finishIdleToSilCrossfade(),at());const Ne=Pe||M.current||z.current||I.current,Ct=V&&L.supportsBufferedPlayback;if(Ee){if(Rt(),Z.current&&y.current?.setActive(!1),L.usesPixi&&L.isIdleToSilCrossfading()){L.tickIdleToSilCrossfade(performance.now()),H.getVisemeQueue().length>0&&$.current===0&&($.current=performance.now()),_.current=H.isSpeaking(),te.current=requestAnimationFrame(B);return}const ae=H.getVisemeQueue();ae.length>0&&$.current===0&&($.current=performance.now()),k.current.advance(performance.now());const K=k.current.getExpressionPath(),ne=k.current.getDrawKey(),Se={queue:ae,elapsedMs:0,expressionPath:K,expressionDrawKey:ne,availablePaths:We.current};let Fe=!1;Ct&&j.current?(j.current.warmupTick(Se),Fe=j.current.isWarmupReady(Se,Y.current)):L.usesPixi&&pn(U,ae,0,K,ne,q.current,(ut,Dt,ir,Ft)=>{L.drawLiveFrame(ut,Dt,ir,Ve=>{Ft?.(Ve),H.isWarmingUp()&&Ve!==""&&!hn({lastDrawnKey:Ve})&&($.current=0,H.releaseWarmupHold())})},ut=>{se.current?.(ut.label)},We.current);const qe=$.current>0&&performance.now()-$.current>xs;se.current?.(Fe?"buffer ready":"buffering lipsync…"),(Fe||qe)&&($.current=0,H.releaseWarmupHold()),_.current=H.isSpeaking(),te.current=requestAnimationFrame(B);return}if(be){Rt(),Z.current&&y.current?.setActive(!1),L.usesPixi&&L.isIdleToSilCrossfading()&&L.finishIdleToSilCrossfade();const ae=H.getVisemeQueue(),K=H.getPlaybackElapsedMs();ci(ae,K),g.current=K;const ne=ae.length>0?At(ae,K):"sil";ne!=="sil"&&(W.current=ne);const Se=Xi(K,H.getSentenceEmotions(),H.getWordQueue(),H.getStreamMood());k.current.setTargetEmotion(Se),k.current.setTargetEyebrow(qi(K,H.getWordQueue(),Ze(Se))),k.current.advance(performance.now());const Fe=k.current.getExpressionPath(),qe=k.current.getDrawKey(),ut=(Ve,or,St,ar)=>{const Qr={label:Ke.current,elapsedMs:K,mouthPath:or.mouthPath,transitionMeta:ze.current};gt.current.set(St,Qr),j.current?.markExternallyDisplayed(St,Fe),L.drawLiveFrame(Ve,or,St,Bt=>{const Ss=gt.current.get(Bt)??Qr;gt.current.delete(Bt),Te.current.onDrawDisplayed(Ss,ae),j.current?.markExternallyDisplayed(Bt,Fe),ar?.(Bt)})},Dt=Ve=>{Ke.current=Ve.label,ze.current=Ve.transitionMeta,se.current?.(Ve.label)},ir=V&&L.supportsBufferedPlayback;let Ft=!1;ir&&j.current&&(Ft=j.current.tick({canvas:U,queue:ae,elapsedMs:K,expressionPath:Fe,expressionDrawKey:qe,playbackState:q.current,availablePaths:We.current,onStatus:Dt,onDisplayed:(or,St,ar)=>{Te.current.onDrawDisplayed({label:ar,elapsedMs:K,mouthPath:St,transitionMeta:ze.current},ae)}}).usedBuffer),Ft||pn(U,ae,K,Fe,qe,q.current,ut,Dt,We.current),Te.current.onRafTickSpeaking(),Ce.current?.(Te.current.snapshot(ae,K))}else if(!Ne&&ee.current){y.current?.setActive(!1),k.current.advance(performance.now());const ae=k.current.getExpressionPath(),K=k.current.getDrawKey();hr(U,ae,K,q.current,(ne,Se,Fe,qe)=>L.drawLiveFrame(ne,Se,Fe,qe),ne=>{if(ce.current){se.current?.(ce.current);return}const Se=k.current.getTargetEmotion();se.current?.(ne==="sil"||ne==="blink"?`${Se}${ne==="blink"?" · blink":""}`:ne)},null,he.current)}else if(!Ne&&Z.current&&y.current){const ae=y.current,K=ae.getVideo();if(K.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){ae.setActive(!0);const ne=()=>!H.isSpeaking()&&!M.current&&!z.current&&!ee.current;L.usesPixi?(L.drawIdleVideo(K,ne),ne()&&se.current?.("idle")):v.current||(v.current=!0,mr(U,K,null,void 0,nt.current,ne).then(()=>se.current?.("idle")).finally(()=>{v.current=!1}))}else hr(U,null,"__sil__",q.current,(ne,Se,Fe,qe)=>L.drawLiveFrame(ne,Se,Fe,qe),ne=>se.current?.(ne))}else Ne||hr(U,null,"__sil__",q.current,(ae,K,ne,Se)=>L.drawLiveFrame(ae,K,ne,Se),ae=>se.current?.(ae));_.current=be,te.current=requestAnimationFrame(B)};return te.current=requestAnimationFrame(B),()=>{cancelAnimationFrame(te.current),Ie(),Ae(),ie.current.stop(),le.current?.stop()}},[Oe,Gr,at,Ie,Ae,Rt]),T.useImperativeHandle(P,()=>({speakText:async(v,B)=>{const U=v.trim();if(!U)return;const L=N.current;if(!L||!ve.current&&!Oe)throw new Error("AI twin is not ready");const{ttsEngineId:H,voiceId:be}=it(B);_e(null),J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,W.current="sil",g.current=0,xe(q.current),ee.current=!1,he.current=null,ce.current=null,k.current.reset(),_.current=!1,I.current=!1,L.finishIdleToSilCrossfade();try{await ie.current.speak(U,{voiceId:be,speakingRate:B?.speakingRate??f,ttsEngineId:H})}catch(Ee){throw I.current=!1,L.finishIdleToSilCrossfade(),at(),Be(Ee instanceof Error?Ee.message:"TTS failed"),Ee}},stop:()=>{J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,I.current=!1,N.current?.finishIdleToSilCrossfade(),ie.current.stop(),le.current?.stop(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,at()},setTtsEngineId:v=>{ie.current.setTtsEngineId(v),le.current?.setTtsEngineId(v),we.current&&(we.current.ttsEngineId=v)},renderViseme:async(v,B)=>{const U=N.current,L=D.current;if(!U||!L||!ve.current)throw new Error("AI twin is not ready");await U.renderViseme(L,v,{from:B?.from,transitionDurationMs:B?.transitionDurationMs,gapMs:B?.gapMs,onStatus:H=>se.current?.(H)})},setEmotion:v=>{if(!ve.current)throw new Error("AI twin is not ready");const B=N.current,U=D.current;if(!B||!U)throw new Error("AI twin is not ready");J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,z.current=!1,I.current=!1,ie.current.stop(),le.current?.stop(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,B.finishIdleToSilCrossfade(),y.current?.setActive(!1);const L=He(v);ee.current=!0,he.current=null,ce.current=null,k.current.snapToEmotion(L);const H=k.current.getExpressionPath(),be=k.current.getDrawKey(),Ee={mouthPath:null,expressionPath:H},De=Et(Ee,be);q.current.lastDrawnKey="",B.drawLiveFrame(U,Ee,De,Ne=>{Ne===De&&(q.current.lastDrawnKey=De)});const Pe=Ze(L);se.current?.(H?`${L} · brow ${Pe>0?"+":""}${Pe}`:`${L} · brow 0 (sil base)`)},getEmotion:()=>ee.current?k.current.getTargetEmotion():null,clearEmotionPreview:()=>{ee.current=!1,he.current=null,ce.current=null,k.current.reset(),xe(q.current),se.current?.("idle")},setViseme:v=>{if(!ve.current)throw new Error("AI twin is not ready");const B=N.current,U=D.current;if(!B||!U)throw new Error("AI twin is not ready");J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,z.current=!1,I.current=!1,ie.current.stop(),le.current?.stop(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,B.finishIdleToSilCrossfade(),y.current?.setActive(!1);const L=Qt(v);ee.current=!0,ce.current=L,he.current=L==="sil"?null:dt(L),k.current.snapToEmotion("neutral");const H=k.current.getExpressionPath(),be=k.current.getDrawKey(),De={mouthPath:he.current,expressionPath:H},Pe=Et(De,be);q.current.lastDrawnKey="",B.drawLiveFrame(U,De,Pe,Ne=>{Ne===Pe&&(q.current.lastDrawnKey=Pe)}),se.current?.(L)},getViseme:()=>ee.current?ce.current:null,isReady:()=>ve.current,getStatus:()=>oe,connect:async(v={})=>{_e(null);try{let B=v.authToken?.trim();B||(B=me.current??i??await Wt(),me.current=B);const U=v.voiceId?.trim()??l??we.current?.voiceId,L=v.personaId?.trim()??we.current?.personaId,H=zr();await H.unlockAudio(),await H.connect({...v,apiBase:v.apiBase?.trim()||de,authToken:B,voiceId:U,personaId:L,speakingRate:v.speakingRate??f})}catch(B){throw Be(B instanceof Error?B.message:"Voice connect failed"),B}},disconnect:async()=>{const v=le.current;v&&(J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,I.current=!1,N.current?.finishIdleToSilCrossfade(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,await v.disconnect(),at())},isConnected:()=>le.current?.isConnected()??!1,getVoiceStream:()=>le.current?.getVoiceStream()??ie.current?.getVoiceStream()??null}),[Oe,f,i,l,Ie,Ae,at,Be,it,zr,oe,de]),ur.jsxs("div",{className:c,style:{...Do,...u},children:[ur.jsx("canvas",{ref:D,width:nr.width,height:nr.height,style:{...Fo,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),x&&Re?ur.jsx("div",{style:Bo,children:Re}):null]})}),gs="thumbnail.webp";function Oo(e,t=Ir){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${gs}`}const No=new Set([".png",".jpg",".jpeg",".webp"]);function ys(e=".png"){const t=e.toLowerCase();return No.has(t)?`source${t}`:"source.png"}function Vo(e,t=Ir,r=".png"){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${ys(r)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=gs;exports.AiTwin=Lo;exports.AiTwinNotFoundError=$t;exports.CONSONANT_SKIP_GROUP=Nn;exports.DEFAULT_TTS_ENGINE_ID=Je;exports.EMOTION_TO_EYEBROW=us;exports.EXPRESSION_ATLAS_EMOTIONS=Li;exports.MIC_SAMPLE_RATE=Br;exports.OCULUS_VISEME_IDS=Fn;exports.PLAYBACK_SAMPLE_RATE=Lr;exports.SPEAKING_RATE_MAX=tr;exports.SPEAKING_RATE_MIN=er;exports.TTS_ENGINE_CARTESIA=et;exports.TTS_ENGINE_GOOGLE=Pr;exports.TTS_ENGINE_INWORLD=Yt;exports.VISEME_IDS=Ei;exports.VISEME_SKIP_GAP_MS=_r;exports.VISEME_TEST_CARTESIA_VOICE_ID=Fr;exports.VISEME_TEST_SPEAKING_RATE=Pt;exports.VISEME_TEST_VOICE_ID=Dr;exports.VISEME_VTIME_GRID_MS=xr;exports.VOWEL_SKIP_GROUP=On;exports.aiTwinSourceFilename=ys;exports.buildPlaybackTransitions=qn;exports.buildPlaybackVisemeSeries=Jt;exports.buildRawVisemeTransitions=Kn;exports.buildVoiceWebSocketUrl=Zn;exports.compactSkippableVisemes=Rr;exports.createAvatarTtsLipsyncController=Sr;exports.createRealtimeVoiceLipsyncController=es;exports.emotionToEyebrow=Ze;exports.faceAssetUrls=yr;exports.fetchAiTwin=In;exports.fetchDevAuthToken=Wt;exports.getAiTwinSourceUrl=Vo;exports.getAiTwinThumbnailUrl=Oo;exports.listSkippedVisemeEntries=Zt;exports.listSkippedVisemes=ti;exports.normalizeOculusViseme=Qt;exports.normalizeStreamEmotion=He;exports.resolveDirectFaceId=An;exports.resolveVisemeAtTime=At;exports.resolveVisemeFromPlaybackSeries=Wn;exports.resolveWordAtTime=li;exports.setActiveTwinAssets=Pn;exports.snapVisemeQueueToGrid=Mr;exports.snapVisemeVtimeToGrid=Vn;
|
|
47
|
+
`;function kr(e=5){const t=new pe.Filter({glProgram:pe.GlProgram.from({vertex:Va,fragment:Ua,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=n=>{t.resources.thresholdUniforms.uniforms.uThreshold=n/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function Wa(e,t,n){return e>n||t>n}function Ha(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function $a(e,t){return t!=null&&t>0?Math.floor(t):Ha(e)}function za(e,t){const n=document.createElement("canvas");n.width=t.w,n.height=t.h;const r=n.getContext("2d");if(!r)throw new Error("Failed to acquire 2d context for atlas cell crop");return r.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}function Ii(e){return fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load image: ${e}`);return t.blob()}).then(t=>createImageBitmap(t))}async function xr(e,t,n,r,i){const s=n?await pi(e,i):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),o=s.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,l=async(c,d)=>{const p=yi(t,d,n),T=n?await Rs(await bt(p,i??"")):await Ii(p);if(Wa(T.width,T.height,r))return console.info(`[PixiVisemeCompositor] Sheet ${d} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${r}; using per-cell crops.`),{mode:"cells",bitmap:T};const m=pe.Texture.from(T);return m.source.scaleMode="nearest",{mode:"full",texture:m}};a.set(o.index,await l(o.index,o.path));for(const c of s.sheets??[])c.index!==o.index&&c.path&&a.set(c.index,await l(c.index,c.path));const f=new Map;for(const c of s.cells??[])c.path&&f.set(c.path,c);const u=new Map;for(const c of s.sheets??[])u.set(c.index,c);return{atlasMeta:s,cellByPath:f,sheetByIndex:u,diffBase:t,sheets:a}}async function Ka(e,t={}){const n=new pe.Application;try{await n.init({canvas:e,width:842,height:1264,preference:"webgl",autoStart:!1,antialias:!1,resolution:1,autoDensity:!1,backgroundAlpha:1,backgroundColor:0,powerPreference:"high-performance"})}catch(_){throw n.destroy({removeView:!1}),_}if(n.renderer.type!==pe.RendererType.WEBGL)throw n.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const r=$a(n.renderer.gl,t.maxTextureSize);let i=!1,s=!1,o=!1;const a=n.canvas,l=()=>{i=!0,!s&&!o&&(s=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",l);const f=new pe.Sprite(pe.Texture.EMPTY),u=new pe.Sprite(pe.Texture.EMPTY);u.visible=!1,u.alpha=0;const c=new pe.Sprite(pe.Texture.EMPTY),d=new pe.Sprite(pe.Texture.EMPTY),p=new pe.Sprite(pe.Texture.EMPTY);p.visible=!1;const T=kr(5),m=kr(5);c.filters=[T],d.filters=[m],n.stage.addChild(f),n.stage.addChild(u),n.stage.addChild(c),n.stage.addChild(d),n.stage.addChild(p);let P=null,C=null,E=null,g=null,I=null,N=null,A=null,ee=842,fe=1264,M=null,W=5;const K=new Map;let Q=null,Y=null,de=null;const F=Ur(()=>{K.clear(),N=null,A=null,P=null,M=null}),Z=(_,v)=>{ee=_,fe=v,n.renderer.resize(_,v),(e.width!==_||e.height!==v)&&(e.width=_,e.height=v)},k=()=>{c.visible=!1,d.visible=!1,c.texture=pe.Texture.EMPTY,d.texture=pe.Texture.EMPTY,Q=null,Y=null},q=()=>{I=null,u.visible=!1,u.alpha=0},re=()=>{f.visible=!0,f.width=ee,f.height=fe,f.x=0,f.y=0},oe=()=>{u.width=ee,u.height=fe,u.x=0,u.y=0},ne=()=>{p.visible=!1,q(),P&&(f.texture=P,re())},te=()=>{!I&&!u.visible||ne()},ie=_=>{if(o||i||!P){ne();return}const v=Math.max(0,_);if(!C||v<=0){ne();return}k(),p.visible=!1,f.texture=C,re(),u.texture=P,oe(),u.alpha=0,u.visible=!0,I={startMs:performance.now(),durationMs:v},V()},we=(_=performance.now())=>{if(!I)return!1;if(o||i)return te(),!1;const v=(_-I.startMs)/Math.max(1,I.durationMs);if(v>=1)return ne(),V(),!1;const x=Math.min(1,Math.max(0,v)),H=x*x*(3-2*x);return u.alpha=H,u.visible=!0,V(),!0},b=()=>{if(E){try{E.resource=null}catch{}E.destroy(),E=null}C&&(C.destroy(!1),C=null),g=null},$=(_,v)=>{const x=_.cellByPath.get(v);if(!x||!hi(x))return null;const H=`${_.diffBase}::${v}`;let X=K.get(H);if(!X){const se=x.sheet??0,Ee=_.sheets.get(se);if(!Ee)return null;let _e,Ve=!1;if(Ee.mode==="full")_e=new pe.Texture({source:Ee.texture.source,frame:new pe.Rectangle(x.x,x.y,x.w,x.h)});else{const Ue=za(Ee.bitmap,x);_e=pe.Texture.from(Ue),_e.source.scaleMode="nearest",Ve=!0}X={texture:_e,ownsSource:Ve},K.set(H,X)}return{texture:X.texture,cell:x}},S=(_,v,x,H)=>{if(!H||!x)return _.visible=!1,_.texture=pe.Texture.EMPTY,!1;const X=$(x,H);if(!X)return _.visible=!1,_.texture=pe.Texture.EMPTY,!1;const se=mi(x.atlasMeta,X.cell);return v.setThreshold(W),_.texture=X.texture,_.x=se.x,_.y=se.y,_.width=X.cell.w,_.height=X.cell.h,_.visible=!0,!0},O=_=>{if(!_||!N)return null;const v=M??new Set(N.cellByPath.keys());return zn(_,v)??(v.has(_)?_:null)},D=_=>{p.visible=!1,ne();const v=O(_.mouthPath),x=_.expressionPath&&A?jn(_.expressionPath,H=>A.cellByPath.has(H)):null;v!==Q?(S(c,T,N,v),Q=v):v?c.visible=!0:c.visible=!1,x!==Y?(S(d,m,A,x),Y=x):x?d.visible=!0:d.visible=!1},V=()=>{if(!(o||i||document.hidden))try{n.render()}catch{}};return{async loadAssets(_){if(o)return{width:ee,height:fe,visemePaths:[]};const v=Rt();if(v&&!_)throw new Error("Encrypted assets enabled but no key provided");const x=v?await Bs(await bt(Xt(),_??"")):await Ii(Xt());P&&P.destroy(!0),P=pe.Texture.from(x),P.source.scaleMode="linear";const H=Wr();N=await xr(Hr(),H,v,r,_);try{A=await xr($r(),H,v,r,_)}catch(se){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",se),A=null}const X=di(N.atlasMeta,x.width,x.height);return Z(X.width,X.height),W=ln(N.atlasMeta),T.setThreshold(W),m.setThreshold(W),M=new Set(N.cellByPath.keys()),K.clear(),ne(),k(),V(),{width:X.width,height:X.height,visemePaths:[...N.cellByPath.keys()]}},getVisemeAtlasPaths(){return M},drawLiveFrame(_){o||i||!P||(te(),D(_),V())},drawIdleVideo(_,v){o||i||document.hidden||v&&!v()||_.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(q(),k(),p.visible=!1,!C||g!==_?(b(),E=new pe.VideoSource({resource:_,autoPlay:!1,updateFPS:0}),E.autoUpdate=!1,C=new pe.Texture({source:E}),g=_):C.source.update(),f.texture=C,re(),V())},beginIdleToSilCrossfade:ie,tickIdleToSilCrossfade:we,finishIdleToSilCrossfade:te,isIdleToSilCrossfading(){return I!=null},renderSilOnly(){o||i||!P||(k(),ne(),V())},blitBitmap(_){o||i||(te(),k(),de&&(de.destroy(!0),de=null),de=pe.Texture.from(_),p.texture=de,p.visible=!0,p.x=0,p.y=0,p.width=ee,p.height=fe,f.visible=!1,V())},async compositePrefetchFrame(_){return null},renderFrame:V,isContextLost(){return i},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",l),F(),b(),de&&(de.destroy(!0),de=null);for(const{texture:v,ownsSource:x}of K.values())v.destroy(x);K.clear(),P&&(P.destroy(!0),P=null);const _=v=>{v.mode==="full"?v.texture.destroy(!0):v.bitmap.close()};if(N)for(const v of N.sheets.values())_(v);if(A)for(const v of A.sheets.values())_(v);T.destroy(!0),m.destroy(!0),n.destroy({removeView:!1},{children:!0,texture:!0})}}}const Er=-1,Gt=1e5,Ir=new Map;async function ja(e){let t=Ir.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),Ir.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function qa(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Cn(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 Ar(e,t){let n=0,r=null;const i=Jn(async(s,o)=>(await Pn(),await Mn(e,s),i.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(s){const o=await Pn(s);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,i.reset(),await ga(e)},drawLiveFrame(s,o,a,l){i.enqueue(o,a,l)},async compositePrefetchFrame(s,o){try{return await wa(s)}catch{return null}},blitBitmap(s,o){Cn(s,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(s,o){n+=1;const a=n;t.onStatus?.(o),await Mn(s,{mouthPath:_t(o),expressionPath:null})},dispose(){n+=1,i.reset()}}}function Ga(e,t,n){let r=null,i=1,s=0,o=!1,a=!1,l=null;const f=new Map,u=new Map;let c=Gt;const d=Jn(async(E,g,I)=>(f.set(g,{drawKey:I.drawKey,onDisplayed:I.onDisplayed}),await P({type:"drawFrame",diffPath:E.mouthPath,expressionDiffPath:E.expressionPath,liveSeq:g},void 0,!0),!1)),p=E=>{if(E===Er){let N=-1,A;for(const[ee,fe]of f)ee>=N&&(N=ee,A=fe);N>=0&&f.delete(N),A?.onDisplayed?.(A.drawKey);return}const g=-E,I=f.get(g);f.delete(g),I?.onDisplayed?.(I.drawKey)},T=new Map,m=(E,g)=>{a||!r||r.postMessage(E,[])},P=(E,g,I=!1)=>{if(a)return Promise.resolve();const N=i++;return new Promise((A,ee)=>{T.set(N,{resolve:fe=>A(fe),reject:ee,generation:typeof E.generation=="number"?E.generation:void 0,expectRenderDone:I}),m({...E,requestId:N})})},C=(async()=>{r=await ja(n),r.onmessage=E=>{if(a)return;const g=E.data;if(g.type==="status"){t.onStatus?.(g.label);return}if(g.type==="frame"){if(g.generation<=-Gt){const A=-g.generation,ee=u.get(A);u.delete(A),ee?.resolve(g.bitmap);return}const N=g.generation<0;if(!N&&g.generation!==s){g.bitmap.close();return}if(N&&!(g.generation===Er)){const ee=-g.generation;if(!d.isLatestSeq(ee)){Je()?.onWorkerStale(),g.bitmap.close();return}}if(N&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){Je()?.onWorkerStale(),g.bitmap.close();return}Cn(e,g.bitmap),g.bitmap.close(),N&&p(g.generation);return}const I=T.get(g.requestId);if(I)switch(g.type){case"ready":T.delete(g.requestId),I.resolve();break;case"loadAssetsDone":T.delete(g.requestId),l=g.visemePaths?.length?new Set(g.visemePaths):null,I.resolve({width:g.width,height:g.height,visemePaths:g.visemePaths});break;case"renderDone":if(I.expectRenderDone&&I.generation!=null&&g.generation!==I.generation)return;T.delete(g.requestId),I.resolve();break;case"renderAborted":T.delete(g.requestId),I.resolve();break;case"error":T.delete(g.requestId),t.onError?.(g.message),I.reject(new Error(g.message));break}},r.onerror=E=>{if(a)return;const g=E.message||"Worker error";t.onError?.(g);for(const[,I]of T)I.reject(new Error(g));T.clear()},await P({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(E){if(a)return{width:842,height:1264};if(await C,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await P({type:"loadAssets",keyHex:E,urls:rs(ut())})??{width:842,height:1264}},getVisemeAtlasPaths(){return l},async renderSilOnly(){if(a||(await C,a))return;s+=1,d.reset(),f.clear(),u.forEach(({resolve:g})=>g(null)),u.clear(),c=Gt;const E=s;await P({type:"cancelLiveDraws"}),await P({type:"renderSil",generation:E},void 0,!0)},drawLiveFrame(E,g,I,N){a||C.then(()=>{a||d.enqueue(g,I,N)})},compositePrefetchFrame(E,g){return a?Promise.resolve(null):C.then(()=>{if(a)return null;const I=++c;return new Promise(N=>{u.set(I,{resolve:N}),P({type:"drawFrame",diffPath:E.mouthPath,expressionDiffPath:E.expressionPath,liveSeq:I},void 0,!0).catch(()=>{u.delete(I),N(null)})})})},blitBitmap(E,g){Cn(E,g)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(E,g,I={}){if(a||(await C,a))return;s+=1,d.reset(),f.clear();const N=s;try{await P({type:"cancelLiveDraws"}),await P({type:"renderViseme",generation:N,to:g,from:I.from,transitionDurationMs:I.transitionDurationMs,gapMs:I.gapMs,threshold:I.threshold},void 0,!0)}catch(A){if(A?.name==="AbortError")return;throw A}},dispose(){if(!a){a=!0,s+=1,d.reset(),f.clear(),u.forEach(({resolve:E})=>E(null)),u.clear(),c=Gt;for(const[,E]of T)E.resolve();T.clear(),r?.terminate(),r=null}}}}async function Ya(e,t){const n=await Ka(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let r=0,i=null,s=!1;const o=Jn(async(a,l)=>s?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(Je()?.onWorkerStale(),!1):(n.drawLiveFrame(a),o.isLatestSeq(l)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(s)return{width:842,height:1264};const l=await n.loadAssets(a);return i=l.visemePaths?.length?new Set(l.visemePaths):null,l},getVisemeAtlasPaths(){return i},async renderSilOnly(){s||(r+=1,o.reset(),n.renderSilOnly())},drawLiveFrame(a,l,f,u){s||o.enqueue(l,f,u)},async compositePrefetchFrame(a,l){if(s)return null;try{return await n.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,l){s||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||n.blitBitmap(l)},drawIdleVideo(a,l){s||n.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){s||n.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return s?!1:n.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){s||n.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return s?!1:n.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,l){if(s)return;r+=1;const f=r;o.reset(),t.onStatus?.(l),n.drawLiveFrame({mouthPath:_t(l),expressionPath:null})},dispose(){s||(s=!0,r+=1,o.reset(),n.dispose())}}}function Pr(e,t){if(!qa())return Ar(e,t);const n=Wi(t.workerScriptUrl);try{return Ga(e,t,n)}catch{return Ar(e,t)}}function Qa(e,t={}){if(t.preferLegacyRenderer)return Pr(e,t);let n=null,r=!1,i=null,s=!1;const o=()=>n?Promise.resolve(n):(i||(i=(async()=>{try{const a=await Ya(e,t);if(s)throw a.dispose(),new Error("Renderer disposed during Pixi init");return r=!0,n=a,a}catch(a){if(s)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),n=Pr(e,t),r=!1,n}})()),i);return{get usesWorker(){return n?.usesWorker??!1},get usesPixi(){return r},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return n?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,l,f,u){o().then(c=>{s||c.drawLiveFrame(a,l,f,u)})},async compositePrefetchFrame(a,l){return(await o()).compositePrefetchFrame(a,l)},blitBitmap(a,l){n&&n.blitBitmap(a,l)},drawIdleVideo(a,l){n?.usesPixi&&n.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){n?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return n?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){n?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return n?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return n?.supportsBufferedPlayback??!1},async renderViseme(a,l,f){return(await o()).renderViseme(a,l,f)},dispose(){s=!0,i=null,n?.dispose(),n=null}}}class Xa extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function bn(e,t,n){return new Promise((r,i)=>{const s=globalThis.setTimeout(()=>{i(new Xa(n,t))},t);e.then(o=>{globalThis.clearTimeout(s),r(o)},o=>{globalThis.clearTimeout(s),i(o)})})}const Ja={position:"relative",display:"inline-block",lineHeight:0},Za={display:"block",maxWidth:"100%",height:"auto"},eo={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 It(e){return ji(e)?Wn:Un}function qe(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const Ai=w.forwardRef(function({id:t,avatarId:n,faceId:r,assets:i,authToken:s,apiBase:o,ttsEngineId:a=it,voiceId:l,speakingRate:f=Bt,className:u,style:c,canvasStyle:d,onStatusChange:p,onDisplayStatus:T,onError:m,onReady:P,showErrorOverlay:C=!0,onUserTranscript:E,onBotOutput:g,onRealtimeLipsyncDebug:I,onFrameRenderStats:N,lipsyncBufferedPlayback:A=!0,lipsyncPlaybackWarmupMs:ee=1500,pixiMaxTextureSize:fe,captions:M},W){const K=w.useRef(null),Q=w.useRef(null),Y=w.useRef(null),de=w.useRef(A);de.current=A;const F=w.useRef(ee);F.current=ee;const Z=w.useRef(0),k=w.useRef(Qn()),q=w.useRef(aa()),re=w.useRef(!1),oe=w.useRef(null),ne=w.useRef(null),te=w.useRef(0),ie=w.useRef(0),we=w.useRef(0),b=w.useRef(null),$=w.useRef(null),S=w.useRef(!1),O=w.useRef(!1),D=w.useRef(!1),V=w.useRef(!1),_=w.useRef("sil"),v=w.useRef(0),x=w.useRef(!1),H=w.useRef(null),X=w.useRef(!1),[se,Ee]=w.useState("idle"),[_e,Ve]=w.useState(null),[Ue,fn]=w.useState(!1),[Zn,Ft]=w.useState(!1),[h,L]=w.useState({width:842,height:1264}),[J,ce]=w.useState(null),[Se,ve]=w.useState(0),ye=w.useRef(!1),Ie=w.useRef(s??null),Te=o?.trim()||at,lt=w.useRef(null),ke=w.useRef(null),Pe=w.useRef(!1),Ze=w.useRef({width:842,height:1264}),Ye=w.useRef(null),Lt=w.useRef("sil"),We=w.useRef(""),Fe=w.useMemo(()=>_a(M),[M]),Le=w.useCallback(()=>{We.current="",ce(null)},[]);w.useEffect(()=>{Fe.enabled||Le()},[Fe.enabled,Le]);const et=w.useCallback(y=>{if(!Fe.enabled)return;const R=y.isSpeaking(),U=y.isWarmingUp();if(!R||U){We.current&&Le();return}const B=ya(y.getWordQueue());if(!B){We.current&&Le();return}B!==We.current&&(We.current=B,ce(B))},[Fe.enabled,Le]),ge=w.useRef(void 0),Me=w.useRef(new Map),He=w.useRef(P),me=w.useRef(T),Tt=w.useRef(m),Ot=w.useRef(E),kt=w.useRef(g),ft=w.useRef(I),er=w.useRef(N),dt=w.useRef(xa());He.current=P,me.current=T,Tt.current=m,Ot.current=E,kt.current=g,ft.current=I,er.current=N,w.useEffect(()=>{const y=dt.current;return _r(y),()=>_r(null)},[]);const tr=w.useCallback(y=>{const R=y?.ttsEngineId??a??ke.current?.ttsEngineId??it,U=y?.voiceId??l??ke.current?.voiceId??It(R);return{ttsEngineId:R,voiceId:U}},[a,l]),Qe=w.useCallback(y=>{Ve(y),Tt.current?.(y)},[]),xt=w.useCallback(y=>{Ee(y),p?.(y)},[p]),ue=w.useRef(In(xt,Te,{onLipsyncDebug:y=>ft.current?.(y)})),le=w.useRef(null);w.useEffect(()=>(ue.current=In(xt,Te,{onLipsyncDebug:y=>ft.current?.(y)}),s&&ue.current.setDeveloperToken(s),ue.current.setTtsEngineId(a),()=>{ue.current.stop();const y=le.current;y&&(y.disconnect(),le.current=null)}),[xt,s,a,Te]);const nr=w.useCallback(()=>(le.current||(le.current=fi(xt,{speakingRate:f,onUserTranscript:(y,R)=>Ot.current?.(y,R),onBotOutput:y=>kt.current?.(y),onLipsyncDebug:y=>ft.current?.(y)}),le.current.setTtsEngineId(a)),le.current),[xt,f,a]),Ce=w.useCallback(()=>{b.current!=null&&(clearTimeout(b.current),b.current=null)},[]),Re=w.useCallback(()=>{$.current!=null&&(clearTimeout($.current),$.current=null),D.current=!1},[]),Nt=w.useCallback(()=>{if(V.current)return;const y=Q.current;if(V.current=!0,Re(),S.current=!1,O.current=!1,!X.current||!H.current){y?.renderSilOnly();return}H.current.setActive(!1);const R=H.current.getVideo();if(y?.usesPixi){y.drawIdleVideo(R),y.beginIdleToSilCrossfade(Sr);return}(async()=>{const U=K.current;U&&await vn(U,R,null,void 0,Ze.current).catch(()=>{}),await new Promise(B=>setTimeout(B,Sr)),V.current&&await y?.renderSilOnly()})()},[Re]),rr=w.useCallback(()=>{!X.current||!H.current||(V.current=!1,Q.current?.finishIdleToSilCrossfade(),Re(),D.current=!0,$.current=setTimeout(()=>{if($.current=null,qe(ue.current,le.current).isSpeaking()){D.current=!1;return}if(S.current){D.current=!1;return}const y=H.current;if(!y){D.current=!1;return}y.restart(),y.setActive(!0);const R=y.getVideo();let U=!1;const B=()=>{U||(U=!0,R.removeEventListener("playing",j),D.current=!1)},j=()=>{B()};if(R.addEventListener("playing",j,{once:!0}),R.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!R.paused){B();return}setTimeout(B,300)},Ea))},[Re]),mt=w.useCallback(()=>{if(Ce(),me.current?.("sil"),S.current=!1,V.current=!1,!X.current||!H.current){D.current=!1;return}rr()},[Ce,rr]),dn=w.useCallback(async y=>{const R=ie.current,U=Q.current,B=K.current,j=()=>{y?.fallbackOnly||(S.current=!1)};if(!U||!B||!Ue){j();return}if(qe(ue.current,le.current).isSpeaking()){j();return}if(y?.fallbackOnly){if(!S.current||(Be(k.current),await U.renderSilOnly(),R!==ie.current)||qe(ue.current,le.current).isSpeaking())return;mt();return}if(br(k.current)){Be(k.current),mt();return}if(de.current&&U.supportsBufferedPlayback&&!y?.fallbackOnly){if(Be(k.current),Y.current?.reset(),await U.renderSilOnly(),R!==ie.current||qe(ue.current,le.current).isSpeaking())return;mt();return}const Ae=Ca(qe(ue.current,le.current).getVisemeQueue(),v.current,_.current),Oe=Ra(Ae,Ye.current);if(Be(k.current),!Oe){if(await U.renderSilOnly(),R!==ie.current||qe(ue.current,le.current).isSpeaking())return;mt();return}try{await U.renderViseme(B,"sil",{from:Ae,transitionDurationMs:ki})}catch(De){if(De?.name!=="AbortError")throw De}if(R!==ie.current){j();return}if(qe(ue.current,le.current).isSpeaking()){j();return}mt()},[Ue,mt]),ht=w.useCallback(()=>{if(O.current||S.current)return;O.current=!0,S.current=!0,Ce();const y=ie.current;dn().finally(()=>{O.current=!1}),b.current=setTimeout(()=>{b.current=null,y===ie.current&&dn({fallbackOnly:!0})},Da())},[Ce,dn]),ir=w.useCallback(async()=>{const y=Math.floor(Date.now()/1e3);if(lt.current&&y<lt.current.expiresAt-60)return lt.current.key;const R=Ie.current??await Pt();Ie.current=R,ue.current.setDeveloperToken(R);const U=await Zi(R,Te);return lt.current={key:U.value,expiresAt:U.expiresAt},U.value},[Te]);w.useEffect(()=>{s&&(Ie.current=s,ue.current.setDeveloperToken(s))},[s]),w.useEffect(()=>{ue.current.setTtsEngineId(a),le.current?.setTtsEngineId(a),ke.current&&(ke.current.ttsEngineId=a)},[a]),w.useEffect(()=>{const y=l??It(a);ke.current&&(ke.current.voiceId=y)},[l,a]);const tt=w.useMemo(()=>Nr(n,r),[n,r]),Di=w.useMemo(()=>i?JSON.stringify(i):tt?`face:${tt}`:`id:${t??""}`,[i,tt,t]);return w.useEffect(()=>{if(!t&&!i&&!tt){Qe("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let y=!1;Pe.current=!1,fn(!1),Ft(!1),Ve(null),ke.current=null,H.current=null,X.current=!1;const R=K.current;if(!R)return;let U=null;return(async()=>{try{let B,j,xe,Ae;if(i)B=i,j=a,xe=l??It(j);else if(tt)me.current?.("loadFace"),B=xn(tt),j=a,xe=l??It(j);else{me.current?.("getAiTwin");const G=await bn(Or(t),3e4,"getAiTwin");if(y)return;if(!G.faceId?.trim())throw new Error("getAiTwin returned no faceId");j=G.ttsEngineId,xe=l??G.voiceId??It(j),Ae=G.knowledgeContextId?.trim()||void 0,B=xn(G.faceId)}ke.current={ttsEngineId:j,voiceId:xe,personaId:Ae},Vr(B),H.current=oa();const Oe=!!(i&&!ct(i));U=Qa(R,{preferLegacyRenderer:Oe,pixiMaxTextureSize:fe,onStatus:G=>{y||me.current?.(G)},onError:G=>{y||Qe(G)},shouldAcceptLiveFrame:()=>{if(re.current)return!0;if(S.current)return!1;const G=qe(ue.current,le.current);return G.isSpeaking()||G.isWarmingUp()},onWebGlContextLost:()=>{y||ye.current||(ye.current=!0,queueMicrotask(()=>{y||ve(G=>G+1)}))}}),Q.current=U,Y.current=Na(U),ye.current=!1,(G=>{const ae=()=>{if(!G||F.current<=0)return!1;const be=Q.current;return be?de.current&&be.supportsBufferedPlayback?!0:be.usesPixi:!1};ue.current.setLipsyncWarmupHold(G,ae),le.current?.setLipsyncWarmupHold(G,ae)})(!0),me.current?.("auth");const ze=Ie.current??s??await bn(Pt(),3e4,"getAuthToken");if(y)return;Ie.current=ze,ue.current.setDeveloperToken(ze),ue.current.setTtsEngineId(j);const Vt=Rt()?await ir():void 0;if(y)return;me.current?.("loadAssets");const he=await bn(U.loadAssets(Vt),18e4,"load face assets");if(!y&&he.width>0&&he.height>0&&(Ze.current=he,L(he)),y)return;Ye.current=U.getVisemeAtlasPaths(),Pe.current=!0,fn(!0),He.current?.(),U.renderSilOnly().then(()=>{y||me.current?.("sil")}),(async()=>{try{const G=await Os(Vt);if(await H.current.load(G),y)return;X.current=!0,Ft(!0),Be(k.current),H.current.setActive(!0);const ae=H.current.getVideo();U.usesPixi?U.drawIdleVideo(ae):await vn(R,ae,null,void 0,Ze.current),y||me.current?.("idle")}catch(G){if(y)return;X.current=!1,Ft(!1),console.warn("[AiTwin] Idle video unavailable:",G)}})()}catch(B){if(y)return;if(B instanceof Yt){Qe(B.message);return}Qe(B instanceof Error?B.message:"Failed to load AI twin")}})(),()=>{y=!0,H.current?.dispose(),U?.dispose(),Q.current=null}},[Di,i,tt,t,a,l,s,fe,ir,Qe,Se]),w.useEffect(()=>{const y={current:!1},R=()=>{const U=K.current,B=Q.current,j=qe(ue.current,le.current);if(!U||!B||!Ue){te.current=requestAnimationFrame(R);return}if(document.hidden){H.current?.setActive(!1),te.current=requestAnimationFrame(R);return}const xe=j.isSpeaking(),Ae=j.isWarmingUp(),Oe=xe&&!x.current,De=x.current&&!xe;Oe&&(Ce(),Re(),S.current=!1,O.current=!1,Be(k.current),Y.current?.reset(),dt.current.reset(),ge.current=void 0,we.current=0,_.current="sil",v.current=0,Nt()),De&&(q.current.reset(),H.current?.setActive(!1),Y.current?.reset(),B.finishIdleToSilCrossfade(),Le(),ht());const ze=De||S.current||D.current||V.current,Vt=A&&B.supportsBufferedPlayback;if(Ae){if(Nt(),X.current&&H.current?.setActive(!1),B.usesPixi&&B.isIdleToSilCrossfading()){B.tickIdleToSilCrossfade(performance.now()),j.getVisemeQueue().length>0&&Z.current===0&&(Z.current=performance.now()),x.current=j.isSpeaking(),te.current=requestAnimationFrame(R);return}const he=j.getVisemeQueue();he.length>0&&Z.current===0&&(Z.current=performance.now()),q.current.advance(performance.now());const G=q.current.getExpressionPath(),ae=q.current.getDrawKey(),be={queue:he,elapsedMs:0,expressionPath:G,expressionDrawKey:ae,availablePaths:Ye.current};let Ne=!1;Vt&&Y.current?(Y.current.warmupTick(be),Ne=Y.current.isWarmupReady(be,F.current)):B.usesPixi&&Tr(U,he,0,G,ae,k.current,(pt,Ut,mn,Wt)=>{B.drawLiveFrame(pt,Ut,mn,Ke=>{Wt?.(Ke),j.isWarmingUp()&&Ke!==""&&!br({lastDrawnKey:Ke})&&(Z.current=0,j.releaseWarmupHold())})},pt=>{me.current?.(pt.label)},Ye.current);const Xe=Z.current>0&&performance.now()-Z.current>$i;me.current?.(Ne?"buffer ready":"buffering lipsync…"),(Ne||Xe)&&(Z.current=0,j.releaseWarmupHold()),et(j),x.current=j.isSpeaking(),te.current=requestAnimationFrame(R);return}if(xe){Nt(),X.current&&H.current?.setActive(!1),B.usesPixi&&B.isIdleToSilCrossfading()&&B.finishIdleToSilCrossfade();const he=j.getVisemeQueue(),G=j.getPlaybackElapsedMs();Ts(he,G),v.current=G;const ae=he.length>0?Dt(he,G):"sil";ae!=="sil"&&(_.current=ae);const be=fa(G,j.getSentenceEmotions(),j.getWordQueue(),j.getStreamMood());q.current.setTargetEmotion(be),q.current.setTargetEyebrow(sa(G,j.getWordQueue(),st(be))),q.current.advance(performance.now());const Ne=q.current.getExpressionPath(),Xe=q.current.getDrawKey(),pt=(Ke,hn,Et,pn)=>{const sr={label:Lt.current,elapsedMs:G,mouthPath:hn.mouthPath,transitionMeta:ge.current};Me.current.set(Et,sr),Y.current?.markExternallyDisplayed(Et,Ne),B.drawLiveFrame(Ke,hn,Et,Ht=>{const Bi=Me.current.get(Ht)??sr;Me.current.delete(Ht),dt.current.onDrawDisplayed(Bi,he),Y.current?.markExternallyDisplayed(Ht,Ne),pn?.(Ht)})},Ut=Ke=>{Lt.current=Ke.label,ge.current=Ke.transitionMeta,me.current?.(Ke.label)},mn=A&&B.supportsBufferedPlayback;let Wt=!1;mn&&Y.current&&(Wt=Y.current.tick({canvas:U,queue:he,elapsedMs:G,expressionPath:Ne,expressionDrawKey:Xe,playbackState:k.current,availablePaths:Ye.current,onStatus:Ut,onDisplayed:(hn,Et,pn)=>{dt.current.onDrawDisplayed({label:pn,elapsedMs:G,mouthPath:Et,transitionMeta:ge.current},he)}}).usedBuffer),Wt||Tr(U,he,G,Ne,Xe,k.current,pt,Ut,Ye.current),dt.current.onRafTickSpeaking(),er.current?.(dt.current.snapshot(he,G))}else if(!ze&&re.current){H.current?.setActive(!1),q.current.advance(performance.now());const he=q.current.getExpressionPath(),G=q.current.getDrawKey();Sn(U,he,G,k.current,(ae,be,Ne,Xe)=>B.drawLiveFrame(ae,be,Ne,Xe),ae=>{if(ne.current){me.current?.(ne.current);return}const be=q.current.getTargetEmotion();me.current?.(ae==="sil"||ae==="blink"?`${be}${ae==="blink"?" · blink":""}`:ae)},null,oe.current)}else if(!ze&&X.current&&H.current){const he=H.current,G=he.getVideo();if(G.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){he.setActive(!0);const ae=()=>!j.isSpeaking()&&!S.current&&!D.current&&!re.current;B.usesPixi?(B.drawIdleVideo(G,ae),ae()&&me.current?.("idle")):y.current||(y.current=!0,vn(U,G,null,void 0,Ze.current,ae).then(()=>me.current?.("idle")).finally(()=>{y.current=!1}))}else Sn(U,null,"__sil__",k.current,(ae,be,Ne,Xe)=>B.drawLiveFrame(ae,be,Ne,Xe),ae=>me.current?.(ae))}else ze||Sn(U,null,"__sil__",k.current,(he,G,ae,be)=>B.drawLiveFrame(he,G,ae,be),he=>me.current?.(he));Fe.enabled&&et(j),x.current=xe,te.current=requestAnimationFrame(R)};return te.current=requestAnimationFrame(R),()=>{cancelAnimationFrame(te.current),Ce(),Re(),ue.current.stop(),le.current?.stop()}},[Ue,Zn,ht,Ce,Re,Nt,et,Le,Fe.enabled]),w.useImperativeHandle(W,()=>({speakText:async(y,R)=>{const U=y.trim();if(!U)return;const B=Q.current;if(!B||!Pe.current&&!Ue)throw new Error("AI twin is not ready");const{ttsEngineId:j,voiceId:xe}=tr(R);Ve(null),Le(),ie.current+=1,Ce(),Re(),S.current=!1,O.current=!1,_.current="sil",v.current=0,Be(k.current),re.current=!1,oe.current=null,ne.current=null,q.current.reset(),x.current=!1,V.current=!1,B.finishIdleToSilCrossfade();try{await ue.current.speak(U,{voiceId:xe,speakingRate:R?.speakingRate??f,ttsEngineId:j})}catch(Ae){throw V.current=!1,B.finishIdleToSilCrossfade(),ht(),Qe(Ae instanceof Error?Ae.message:"TTS failed"),Ae}},stop:()=>{ie.current+=1,Ce(),Re(),S.current=!1,O.current=!1,V.current=!1,Q.current?.finishIdleToSilCrossfade(),ue.current.stop(),le.current?.stop(),Be(k.current),Y.current?.reset(),Z.current=0,x.current=!1,Le(),ht()},setTtsEngineId:y=>{ue.current.setTtsEngineId(y),le.current?.setTtsEngineId(y),ke.current&&(ke.current.ttsEngineId=y)},renderViseme:async(y,R)=>{const U=Q.current,B=K.current;if(!U||!B||!Pe.current)throw new Error("AI twin is not ready");await U.renderViseme(B,y,{from:R?.from,transitionDurationMs:R?.transitionDurationMs,gapMs:R?.gapMs,onStatus:j=>me.current?.(j)})},setEmotion:y=>{if(!Pe.current)throw new Error("AI twin is not ready");const R=Q.current,U=K.current;if(!R||!U)throw new Error("AI twin is not ready");ie.current+=1,Ce(),Re(),S.current=!1,O.current=!1,D.current=!1,V.current=!1,ue.current.stop(),le.current?.stop(),Be(k.current),Y.current?.reset(),Z.current=0,x.current=!1,R.finishIdleToSilCrossfade(),H.current?.setActive(!1);const B=Ge(y);re.current=!0,oe.current=null,ne.current=null,q.current.snapToEmotion(B);const j=q.current.getExpressionPath(),xe=q.current.getDrawKey(),Ae={mouthPath:null,expressionPath:j},Oe=Ct(Ae,xe);k.current.lastDrawnKey="",R.drawLiveFrame(U,Ae,Oe,ze=>{ze===Oe&&(k.current.lastDrawnKey=Oe)});const De=st(B);me.current?.(j?`${B} · brow ${De>0?"+":""}${De}`:`${B} · brow 0 (sil base)`)},getEmotion:()=>re.current?q.current.getTargetEmotion():null,clearEmotionPreview:()=>{re.current=!1,oe.current=null,ne.current=null,q.current.reset(),Be(k.current),me.current?.("idle")},setViseme:y=>{if(!Pe.current)throw new Error("AI twin is not ready");const R=Q.current,U=K.current;if(!R||!U)throw new Error("AI twin is not ready");ie.current+=1,Ce(),Re(),S.current=!1,O.current=!1,D.current=!1,V.current=!1,ue.current.stop(),le.current?.stop(),Be(k.current),Y.current?.reset(),Z.current=0,x.current=!1,R.finishIdleToSilCrossfade(),H.current?.setActive(!1);const B=rn(y);re.current=!0,ne.current=B,oe.current=B==="sil"?null:_t(B),q.current.snapToEmotion("neutral");const j=q.current.getExpressionPath(),xe=q.current.getDrawKey(),Oe={mouthPath:oe.current,expressionPath:j},De=Ct(Oe,xe);k.current.lastDrawnKey="",R.drawLiveFrame(U,Oe,De,ze=>{ze===De&&(k.current.lastDrawnKey=De)}),me.current?.(B)},getViseme:()=>re.current?ne.current:null,isReady:()=>Pe.current,getStatus:()=>se,connect:async(y={})=>{Ve(null);try{let R=y.authToken?.trim();R||(R=Ie.current??s??await Pt(),Ie.current=R);const U=y.voiceId?.trim()??l??ke.current?.voiceId,B=y.personaId?.trim()??ke.current?.personaId,j=nr();await j.unlockAudio(),await j.connect({...y,apiBase:y.apiBase?.trim()||Te,authToken:R,voiceId:U,personaId:B,speakingRate:y.speakingRate??f})}catch(R){throw Qe(R instanceof Error?R.message:"Voice connect failed"),R}},disconnect:async()=>{const y=le.current;y&&(ie.current+=1,Ce(),Re(),S.current=!1,O.current=!1,V.current=!1,Q.current?.finishIdleToSilCrossfade(),Be(k.current),Y.current?.reset(),Z.current=0,x.current=!1,await y.disconnect(),ht())},isConnected:()=>le.current?.isConnected()??!1,getVoiceStream:()=>le.current?.getVoiceStream()??ue.current?.getVoiceStream()??null,setMuted:y=>{const R=ue.current,U=le.current;R?.setMuted?.(y),U?.setMuted?.(y)},isMuted:()=>{const y=le.current,R=ue.current;return y?.isMuted?.()??R?.isMuted?.()??!1},getPersonaId:()=>ke.current?.personaId?.trim()||null}),[Ue,f,s,l,Ce,Re,ht,Qe,tr,nr,se,Te]),z.jsxs("div",{className:u,style:{...Ja,...c},children:[z.jsx("canvas",{ref:K,width:h.width,height:h.height,style:{...Za,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),C&&_e?z.jsx("div",{style:eo,children:_e}):null,Fe.enabled&&J?z.jsx(Ta,{text:J,style:Fe.style},J):null]})});async function to(e){try{const t=await e.json();if(typeof t.detail=="string"&&t.detail.trim())return t.detail;if(typeof t.error=="string"&&t.error.trim())return t.error}catch{}return`avatarReply failed (${e.status})`}async function Pi(e){const t=e.message.trim();if(!t)throw new Error("Message is required");const n=e.authToken.trim();if(!n)throw new Error("Auth token is required");const r=(e.apiBase?.trim()||at).replace(/\/$/,""),i=await fetch(`${r}/avatarReply`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`,Accept:"text/event-stream"},body:JSON.stringify({message:t,history:e.history??[],persona_id:e.personaId?.trim()||""})});if(!i.ok)throw new Error(await to(i));if(!i.body)throw new Error("avatarReply response body is empty");const s=i.body.getReader(),o=new TextDecoder;let a="",l="",f="",u="";for(;;){const{done:c,value:d}=await s.read();if(c)break;a+=o.decode(d,{stream:!0});const p=a.split(`
|
|
48
|
+
`);a=p.pop()||"";for(const T of p){if(T.startsWith("event: ")){u=T.slice(7).trim();continue}if(!T.startsWith("data: "))continue;const m=T.slice(6).trim();if(!m)continue;let P;try{P=JSON.parse(m)}catch{continue}if(u==="spokenText")l=P.text||"",e.onSpokenText?.(l);else if(u==="displayText")f=P.text||"";else if(u==="error")throw new Error(P.error||"avatarReply stream error")}}if(!l.trim()||!f.trim())throw new Error("avatarReply stream missing displayText or spokenText");return{displayText:f.trim(),spokenText:l.trim()}}function no({muted:e}){return e?z.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[z.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),z.jsx("path",{d:"m16 9.5 5 5m0-5-5 5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]}):z.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[z.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),z.jsx("path",{d:"M15.5 8.5a4.5 4.5 0 0 1 0 7M18.5 6a8 8 0 0 1 0 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]})}function ro(){return z.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:z.jsx("path",{d:"M8 5.5v13l11-6.5L8 5.5Z"})})}function io(){return z.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:z.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"1.5"})})}function so(){return z.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:z.jsx("path",{d:"M5 6.5A2.5 2.5 0 0 1 7.5 4h9A2.5 2.5 0 0 1 19 6.5v7A2.5 2.5 0 0 1 16.5 16H10l-4 3.5V16H7.5A2.5 2.5 0 0 1 5 13.5v-7Z",stroke:"currentColor",strokeWidth:"2",strokeLinejoin:"round"})})}function Mi({className:e}){return z.jsx("span",{className:e??"aitwin-widget__spinner","aria-hidden":!0,children:z.jsx("svg",{viewBox:"0 0 24 24",fill:"none",children:z.jsx("circle",{cx:"12",cy:"12",r:"9",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeDasharray:"40 20"})})})}function ao({muted:e,onToggle:t}){return z.jsx("button",{type:"button",className:"aitwin-widget__mute",onClick:t,"aria-label":e?"Unmute":"Mute","aria-pressed":e,children:z.jsx(no,{muted:e})})}function oo(){return z.jsxs("div",{className:"aitwin-widget__connecting",role:"status","aria-live":"polite",children:[z.jsx(Mi,{className:"aitwin-widget__spinner aitwin-widget__spinner--accent"}),z.jsx("span",{children:"Connecting..."})]})}function co(e){const t=e.connecting||e.textSending||e.status==="loading"||e.status==="speaking",n=e.connecting?"Connecting...":e.connected?"End Talk":"Talk",r=["aitwin-widget__action",e.textMode&&!e.connecting?"":"aitwin-widget__action--primary",e.connecting?"aitwin-widget__action--connecting":""].filter(Boolean).join(" ");return z.jsxs("div",{className:"aitwin-widget__controls",children:[z.jsxs("div",{className:"aitwin-widget__actions",children:[z.jsxs("button",{type:"button",className:r,onClick:e.onTalk,disabled:!e.ready||e.connecting||e.textSending,"aria-busy":e.connecting,children:[e.connecting?z.jsx(Mi,{className:"aitwin-widget__spinner aitwin-widget__spinner--on-accent"}):e.connected?z.jsx(io,{}):z.jsx(ro,{}),z.jsx("span",{children:n})]}),z.jsxs("button",{type:"button",className:e.textMode?"aitwin-widget__action aitwin-widget__action--primary":"aitwin-widget__action",onClick:e.onTextMode,disabled:!e.ready||e.connecting||e.textSending,"aria-pressed":e.textMode,children:[z.jsx(so,{}),z.jsx("span",{children:"Text"})]})]}),e.textMode?z.jsxs("form",{className:"aitwin-widget__composer",onSubmit:i=>{i.preventDefault(),e.onSendText()},children:[z.jsx("input",{type:"text",className:"aitwin-widget__composer-input",value:e.textDraft,onChange:i=>e.onTextDraftChange(i.target.value),placeholder:e.textSending?"Getting reply...":"Type a message…",autoComplete:"off",disabled:!e.ready||t}),z.jsx("button",{type:"submit",className:"aitwin-widget__composer-send",disabled:!e.ready||t||!e.textDraft.trim()&&!e.textSending,"aria-busy":e.textSending,children:e.textSending?"…":"Send"})]}):null,e.error?z.jsx("p",{className:"aitwin-widget__controls-error",role:"alert",children:e.error}):null]})}function Mr(e){const t=e.id?.trim()||void 0,n=e.faceId?.trim()||e.avatarId?.trim()||void 0;return{id:n?void 0:t,faceId:n,authToken:e.authToken?.trim()||void 0,apiBase:e.apiBase?.trim()||void 0,voiceId:e.voiceId?.trim()||void 0,speakingRate:e.speakingRate}}function uo(e){return[e.id??"",e.faceId??"",e.authToken?.slice(0,16)??"",e.voiceId??"",e.apiBase??"",String(e.speakingRate??"")].join("|")}const Cr={display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",lineHeight:0},lo={display:"block",height:"100%",width:"100%",objectFit:"cover",objectPosition:"top"},fo=w.forwardRef(function({options:t},n){const r=w.useRef(null),i=w.useRef(t);i.current={...i.current,onReady:t.onReady,onStatusChange:t.onStatusChange,onError:t.onError,onUserTranscript:t.onUserTranscript,onBotOutput:t.onBotOutput};const[s,o]=w.useState(!!t.showControls),[a,l]=w.useState(()=>Mr(t)),[f,u]=w.useState(!1),[c,d]=w.useState(!1),[p,T]=w.useState(!1),[m,P]=w.useState("idle"),[C,E]=w.useState(null),[g,I]=w.useState(!1),[N,A]=w.useState(!1),[ee,fe]=w.useState(""),[M,W]=w.useState(!1),[K,Q]=w.useState([]),[Y,de]=w.useState(t.personaId?.trim()||void 0),F=w.useCallback(S=>{i.current={...i.current,...S},S.showControls!==void 0&&o(!!S.showControls),S.personaId!==void 0&&de(S.personaId.trim()||void 0),l(O=>Mr({id:S.id??O.id,faceId:S.faceId??S.avatarId??O.faceId,authToken:S.authToken??O.authToken,apiBase:S.apiBase??O.apiBase,voiceId:S.voiceId??O.voiceId,speakingRate:S.speakingRate??O.speakingRate}))},[]);w.useImperativeHandle(n,()=>({getTwin:()=>r.current,applyOptions:F}),[F]),w.useEffect(()=>{F(t)},[F,t.id,t.faceId,t.avatarId,t.authToken,t.apiBase,t.voiceId,t.speakingRate,t.showControls,t.personaId]);const Z=w.useCallback(()=>{u(!0),E(null),i.current.onReady?.()},[]),k=w.useCallback(S=>{P(S),i.current.onStatusChange?.(S)},[]),q=w.useCallback(S=>{E(S),T(!1),i.current.onError?.(S)},[]),re=w.useCallback((S,O)=>{i.current.onUserTranscript?.(S,O)},[]),oe=w.useCallback(S=>{i.current.onBotOutput?.(S)},[]);w.useEffect(()=>{if(!s)return;const S=window.setInterval(()=>{d(!!r.current?.isConnected())},400);return()=>window.clearInterval(S)},[s,a]),w.useEffect(()=>{f&&r.current?.setMuted(g)},[f,g,a]),w.useEffect(()=>{Q([])},[a.id,a.faceId]);const ne=()=>{const S=r.current;if(!S?.isReady())return;if(E(null),A(!1),S.isConnected()){T(!1),S.disconnect().finally(()=>{d(!1)});return}T(!0);const O={authToken:a.authToken,voiceId:a.voiceId,speakingRate:a.speakingRate,apiBase:a.apiBase};S.connect(O).then(()=>{d(!!S.isConnected())}).catch(D=>{const V=D instanceof Error?D.message:"Failed to connect voice.";E(V),i.current.onError?.(V)}).finally(()=>{T(!1)})},te=()=>{A(S=>!S),E(null)},ie=()=>{const S=ee.trim(),O=r.current;!S||!O?.isReady()||M||(E(null),fe(""),W(!0),i.current.onUserTranscript?.(S,!0),(async()=>{try{const D=a.authToken?.trim()||await Pt(),V=Y||O.getPersonaId()?.trim()||void 0,_=await Pi({message:S,authToken:D,apiBase:a.apiBase||at,personaId:V,history:K});Q(v=>[...v,{role:"user",content:S},{role:"assistant",content:_.displayText}]),i.current.onBotOutput?.(_.displayText),await O.speakText(_.spokenText,{voiceId:a.voiceId,speakingRate:a.speakingRate})}catch(D){const V=D instanceof Error?D.message:"Failed to get reply.";E(V),i.current.onError?.(V)}finally{W(!1)}})())},we=()=>{const S=!g;I(S),r.current?.setMuted(S)},b=uo(a),$=!!(a.id||a.faceId);return z.jsxs("div",{className:"aitwin-widget__layout",children:[z.jsxs("div",{className:"aitwin-widget__stage",children:[$?z.jsx("div",{style:Cr,children:z.jsx(Ai,{ref:r,id:a.id,faceId:a.faceId,authToken:a.authToken,apiBase:a.apiBase,voiceId:a.voiceId,speakingRate:a.speakingRate,style:Cr,canvasStyle:lo,onReady:Z,onStatusChange:k,onError:q,onUserTranscript:re,onBotOutput:oe},b)}):z.jsx("p",{className:"aitwin-widget__hint",style:{padding:16},children:"Pass id or faceId to load a twin."}),s?z.jsx(ao,{muted:g,onToggle:we}):null,s&&p?z.jsx(oo,{}):null]}),s?z.jsx(co,{ready:f,connected:c,connecting:p,status:m,textMode:N,textDraft:ee,textSending:M,error:C,onTalk:ne,onTextMode:te,onTextDraftChange:fe,onSendText:ie}):null]})}),mo=".aitwin-widget{--aitwin-border: rgba(255, 255, 255, .12);--aitwin-text: #f4f4f5;--aitwin-muted: #a1a1aa;--aitwin-accent: #f97316;--aitwin-accent-hover: #fb923c;--aitwin-font: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;--aitwin-size: 1;--aitwin-stage-width: calc(200px * var(--aitwin-size));--aitwin-stage-height: calc(267px * var(--aitwin-size));--aitwin-action-height: calc(40px * var(--aitwin-size));--aitwin-action-font: calc(13px * var(--aitwin-size));--aitwin-action-radius: calc(10px * var(--aitwin-size));--aitwin-action-gap: calc(6px * var(--aitwin-size));--aitwin-mute-size: calc(28px * var(--aitwin-size));--aitwin-layout-gap: calc(8px * var(--aitwin-size));box-sizing:border-box;color:var(--aitwin-text);font-family:var(--aitwin-font);font-size:calc(12px * var(--aitwin-size));line-height:1.45;width:fit-content;max-width:100%}.aitwin-widget *,.aitwin-widget *:before,.aitwin-widget *:after{box-sizing:border-box}.aitwin-widget__layout{display:flex;flex-direction:column;gap:var(--aitwin-layout-gap);width:fit-content;max-width:100%}.aitwin-widget__stage{align-items:center;background:#0a0a0b;border:1px solid var(--aitwin-border);border-radius:calc(10px * var(--aitwin-size));display:flex;flex-shrink:0;height:var(--aitwin-stage-height);justify-content:center;line-height:0;overflow:hidden;position:relative;width:var(--aitwin-stage-width)}.aitwin-widget__stage .aitwin-root,.aitwin-widget__stage canvas{display:block;height:100%;object-fit:cover;object-position:top;width:100%}.aitwin-widget__hint{color:var(--aitwin-muted);font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget__mute{align-items:center;background:#28282cb8;border:none;border-radius:999px;color:#fff;cursor:pointer;display:inline-flex;height:var(--aitwin-mute-size);justify-content:center;padding:0;position:absolute;right:calc(8px * var(--aitwin-size));top:calc(8px * var(--aitwin-size));width:var(--aitwin-mute-size);z-index:2}.aitwin-widget__mute:hover{background:#37373cd9}.aitwin-widget__mute svg{height:calc(15px * var(--aitwin-size));width:calc(15px * var(--aitwin-size))}.aitwin-widget__controls{display:flex;flex-direction:column;gap:var(--aitwin-action-gap);width:var(--aitwin-stage-width)}.aitwin-widget__actions{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr 1fr;width:100%}.aitwin-widget__action{align-items:center;background:transparent;border:1.5px solid var(--aitwin-accent);border-radius:999px;color:var(--aitwin-accent);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--aitwin-action-font);font-weight:600;gap:calc(6px * var(--aitwin-size));height:var(--aitwin-action-height);justify-content:center;padding:0 calc(10px * var(--aitwin-size))}.aitwin-widget__action svg{flex-shrink:0;height:calc(12px * var(--aitwin-size));width:calc(12px * var(--aitwin-size))}.aitwin-widget__action:hover:not(:disabled){background:#f973161a}.aitwin-widget__action:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__action--primary{background:var(--aitwin-accent);border-color:transparent;color:#fff}.aitwin-widget__action--primary:hover:not(:disabled){background:var(--aitwin-accent-hover)}.aitwin-widget__action--connecting:disabled{cursor:progress;opacity:1}.aitwin-widget__spinner{display:inline-flex;flex-shrink:0;height:calc(14px * var(--aitwin-size));width:calc(14px * var(--aitwin-size))}.aitwin-widget__spinner svg{animation:aitwin-widget-spin .8s linear infinite;display:block;height:100%;width:100%}.aitwin-widget__spinner--accent{color:var(--aitwin-accent);height:calc(16px * var(--aitwin-size));width:calc(16px * var(--aitwin-size))}.aitwin-widget__spinner--on-accent{color:#fff}@keyframes aitwin-widget-spin{to{transform:rotate(360deg)}}.aitwin-widget__connecting{align-items:center;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);background:#ffffffe0;border-radius:999px;bottom:calc(14px * var(--aitwin-size));box-shadow:0 4px 16px #0000001f;color:#3f3f46;display:inline-flex;font-size:calc(12px * var(--aitwin-size));font-weight:600;gap:calc(8px * var(--aitwin-size));left:50%;line-height:1;padding:calc(8px * var(--aitwin-size)) calc(14px * var(--aitwin-size));pointer-events:none;position:absolute;transform:translate(-50%);z-index:3}.aitwin-widget__composer{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr auto;width:100%}.aitwin-widget__composer-input{background:#ffffff0a;border:1px solid var(--aitwin-border);border-radius:var(--aitwin-action-radius);color:var(--aitwin-text);font-family:inherit;font-size:calc(12px * var(--aitwin-size));min-width:0;outline:none;padding:calc(8px * var(--aitwin-size)) calc(10px * var(--aitwin-size))}.aitwin-widget__composer-input:focus{border-color:#f973168c}.aitwin-widget__composer-send{background:var(--aitwin-accent);border:none;border-radius:var(--aitwin-action-radius);color:#fff;cursor:pointer;font-family:inherit;font-size:calc(12px * var(--aitwin-size));font-weight:600;padding:0 calc(12px * var(--aitwin-size))}.aitwin-widget__composer-send:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__controls-error{color:#fecaca;font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget--float{bottom:20px;filter:drop-shadow(0 12px 32px rgba(0,0,0,.45));height:fit-content;margin:0;max-width:calc(100vw - 40px);position:fixed;right:20px;width:fit-content;z-index:2147483000}",Rr="data-aitwin-widget-style";function ho(){if(typeof document>"u"||document.querySelector(`style[${Rr}]`))return;const e=document.createElement("style");e.setAttribute(Rr,"1"),e.textContent=mo,document.head.appendChild(e)}const po=w.forwardRef(function(t,n){const r=w.useRef(null);w.useEffect(()=>{ho()},[]),w.useImperativeHandle(n,()=>({speakText:async(s,o)=>{const a=r.current?.getTwin();if(!a)throw new Error("AiTwinWidget: twin is not mounted");return a.speakText(s,o)},connect:async s=>{const o=r.current?.getTwin();if(!o)throw new Error("AiTwinWidget: twin is not mounted");return o.connect(s)},disconnect:async()=>{const s=r.current?.getTwin();if(s)return s.disconnect()},stop:()=>{r.current?.getTwin()?.stop()},isReady:()=>!!r.current?.getTwin()?.isReady(),isConnected:()=>!!r.current?.getTwin()?.isConnected(),getTwin:()=>r.current?.getTwin()??null}),[]);const i=!!t.float;return z.jsx("div",{className:i?"aitwin-widget aitwin-widget--float":"aitwin-widget",children:z.jsx(fo,{ref:r,options:t})})}),Ci="thumbnail.webp";function wo(e,t=Dn){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Ci}`}const go=new Set([".png",".jpg",".jpeg",".webp"]);function Ri(e=".png"){const t=e.toLowerCase();return go.has(t)?`source${t}`:"source.png"}function yo(e,t=Dn,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${Ri(n)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Ci;exports.AiTwin=Ai;exports.AiTwinNotFoundError=Yt;exports.AiTwinWidget=po;exports.CONSONANT_SKIP_GROUP=Yr;exports.DEFAULT_TTS_ENGINE_ID=it;exports.EMOTION_TO_EYEBROW=_i;exports.EXPRESSION_ATLAS_EMOTIONS=Qs;exports.MIC_SAMPLE_RATE=Hn;exports.OCULUS_VISEME_IDS=Kr;exports.PLAYBACK_SAMPLE_RATE=$n;exports.SPEAKING_RATE_MAX=un;exports.SPEAKING_RATE_MIN=cn;exports.TTS_ENGINE_CARTESIA=ot;exports.TTS_ENGINE_GOOGLE=Fn;exports.TTS_ENGINE_INWORLD=nn;exports.VISEME_IDS=Ns;exports.VISEME_SKIP_GAP_MS=En;exports.VISEME_TEST_CARTESIA_VOICE_ID=Wn;exports.VISEME_TEST_SPEAKING_RATE=Bt;exports.VISEME_TEST_VOICE_ID=Un;exports.VISEME_VTIME_GRID_MS=Ln;exports.VOWEL_SKIP_GROUP=Gr;exports.aiTwinSourceFilename=Ri;exports.buildPlaybackTransitions=ni;exports.buildPlaybackVisemeSeries=an;exports.buildRawVisemeTransitions=ti;exports.buildVoiceWebSocketUrl=li;exports.compactSkippableVisemes=Nn;exports.createAvatarTtsLipsyncController=In;exports.createRealtimeVoiceLipsyncController=fi;exports.emotionToEyebrow=st;exports.faceAssetUrls=xn;exports.fetchAiTwin=Or;exports.fetchAvatarReply=Pi;exports.fetchDevAuthToken=Pt;exports.getAiTwinSourceUrl=yo;exports.getAiTwinThumbnailUrl=wo;exports.listSkippedVisemeEntries=on;exports.listSkippedVisemes=ps;exports.normalizeOculusViseme=rn;exports.normalizeStreamEmotion=Ge;exports.resolveDirectFaceId=Nr;exports.resolveVisemeAtTime=Dt;exports.resolveVisemeFromPlaybackSeries=Jr;exports.resolveWordAtTime=ks;exports.setActiveTwinAssets=Vr;exports.snapVisemeQueueToGrid=On;exports.snapVisemeVtimeToGrid=Qr;
|