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