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