@streamoji/aitwin 0.2.6 → 0.2.8

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