@streamoji/aitwin 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/aitwin.cjs CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const nt=require("react/jsx-runtime"),w=require("react"),Rn=require("@pipecat-ai/client-js"),Xt=require("@pipecat-ai/websocket-transport");var rt=typeof document<"u"?document.currentScript:null;const Dn="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",Zt={publicBase:Dn},Cn="0.2.2",Mn={version:Cn},xn={},ve="https://ai.streamoji.com",en=`${Zt.publicBase}/custom-faces`,Pn=`${Zt.publicBase}/aitwin-workers/v${Mn.version}/visemeDiffPreview.worker.js`;function Ln(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"?xn?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Pn}const On="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",ht="eng_a7f2b9c1",je="eng_d4e8f3a2",Ee="eng_c9b1e6d4",pe=Ee,Bn=new Set([je,Ee]),tn={[ht]:"oculus_direct",[Ee]:"oculus_direct",[je]:"inworld_word"},Pt={google:ht,inworld:je,cartesia:Ee};function Fn(e){return tn[e]}function Un(e){return e===Ee}function Nn(e){if(e.ttsEngineId&&e.ttsEngineId in tn)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Pt?Pt[t]:pe}class We extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function nn(e,t=On){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:Nn(s.data)}}const Vn="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",$n="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Wn="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Hn="6TNvp3SCs4Og0a1ijm9TommXLql1",qn="Swaraj Mali";async function $e(){const e=await fetch(Vn,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":$n,"Client-Secret":Wn},body:JSON.stringify({userId:Hn,userName:qn})});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 Kn(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 jn(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 Gn(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=Fe(n.subarray(0,12)),s=Fe(n.subarray(12,28)),i=Fe(n.subarray(28)),o=Fe(Gn(i,s)),a=await crypto.subtle.importKey("raw",jn(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=en){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 Yn(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 Jn(e){return ot.add(e),()=>ot.delete(e)}function Lt(){const e=Se();return be(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Qn(){const e=Se();return be(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Xn(){const e=Se();return be(e)?e.binBase:e.twinBase}function Ge(){return be(Se())}function Zn(){const e=Se();return be(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function er(){const e=Se();return be(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function tr(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"],nr=new Map(on.map(e=>[e.toLowerCase(),e]));function an(e){const t=(e??"").trim();return t?nr.get(t.toLowerCase())??"sil":"sil"}const rr={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 sr(e){if(!e)return["sil"];const t=e.toLowerCase();return rr[t]??["sil"]}function ir(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(s*n))}function ze(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function or(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 ar(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 cr(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 ur(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 lr(e,t,n){const r=sr(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 or(s,o);case"o":return ar(s,o);case"qw":return cr(s,o);case"cdgknstxyz":return ur(s,o);default:return r[0]}}const fr=24e3;function dr(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 hr(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Ot(e,t,n=fr){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 mr(e){const t=dr(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 _r(e,t){const n=mr(t);if(hr(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 Ot(e,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(r)}catch{return Ot(e,n)}}function Bt(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function wr(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=Bt(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 $=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+$,wduration:U,queueIndex:g.length,gesture:I.gesture??null,emphasis:I.emphasis===!0})}))},W=(g,x,b,C,I,L)=>{b.length!==0&&(I&&(p=C),b.forEach(O=>{const $=String(O.symbol??O.viseme??"").trim();if(!$)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(Fn(L)==="oculus_direct")Z=an($);else{const ae=wr(x,se),J=ae?ir(ae,se):0;Z=lr($,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),W(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 $=window.AudioContext||window.webkitAudioContext;s||(s=new $);const U=s;U.state==="suspended"&&await U.resume();const X=await _r(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($){console.error("[avatarChunkPlayback] audio chunk failed:",$)}finally{i=!1;const $=n.shift();$?await E(g,x,$.audio,$.visemes,$.words,$.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=Bt(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 gr(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}const mt=.5,_t=1.5,wt="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??wt,S=u?.speakingRate??Je,D=Math.max(mt,Math.min(_t,S)),H={user_query:k,ttsEngineId:d,speakingRate:D,tenant:"aiTwin"};Bn.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 W=V.body;if(!W)throw new Error("No response body");const j=W.getReader(),E=new TextDecoder;let A="";const g=async x=>{const b=tr(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 nt=require("react/jsx-runtime"),w=require("react"),Rn=require("@pipecat-ai/client-js"),Xt=require("@pipecat-ai/websocket-transport");var rt=typeof document<"u"?document.currentScript:null;const Dn="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",Zt={publicBase:Dn},Cn="0.2.4",Mn={version:Cn},xn={},ve="https://ai.streamoji.com",en=`${Zt.publicBase}/custom-faces`,Pn=`${Zt.publicBase}/aitwin-workers/v${Mn.version}/visemeDiffPreview.worker.js`;function Ln(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"?xn?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Pn}const On="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",ht="eng_a7f2b9c1",je="eng_d4e8f3a2",Ee="eng_c9b1e6d4",pe=Ee,Bn=new Set([je,Ee]),tn={[ht]:"oculus_direct",[Ee]:"oculus_direct",[je]:"inworld_word"},Pt={google:ht,inworld:je,cartesia:Ee};function Fn(e){return tn[e]}function Un(e){return e===Ee}function Nn(e){if(e.ttsEngineId&&e.ttsEngineId in tn)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Pt?Pt[t]:pe}class We extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function nn(e,t=On){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:Nn(s.data)}}const Vn="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",$n="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Wn="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Hn="6TNvp3SCs4Og0a1ijm9TommXLql1",qn="Swaraj Mali";async function $e(){const e=await fetch(Vn,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":$n,"Client-Secret":Wn},body:JSON.stringify({userId:Hn,userName:qn})});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 Kn(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 jn(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 Gn(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=Fe(n.subarray(0,12)),s=Fe(n.subarray(12,28)),i=Fe(n.subarray(28)),o=Fe(Gn(i,s)),a=await crypto.subtle.importKey("raw",jn(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=en){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 Yn(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 Jn(e){return ot.add(e),()=>ot.delete(e)}function Lt(){const e=Se();return be(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Qn(){const e=Se();return be(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Xn(){const e=Se();return be(e)?e.binBase:e.twinBase}function Ge(){return be(Se())}function Zn(){const e=Se();return be(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function er(){const e=Se();return be(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function tr(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"],nr=new Map(on.map(e=>[e.toLowerCase(),e]));function an(e){const t=(e??"").trim();return t?nr.get(t.toLowerCase())??"sil":"sil"}const rr={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 sr(e){if(!e)return["sil"];const t=e.toLowerCase();return rr[t]??["sil"]}function ir(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(s*n))}function ze(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function or(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 ar(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 cr(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 ur(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 lr(e,t,n){const r=sr(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 or(s,o);case"o":return ar(s,o);case"qw":return cr(s,o);case"cdgknstxyz":return ur(s,o);default:return r[0]}}const fr=24e3;function dr(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 hr(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Ot(e,t,n=fr){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 mr(e){const t=dr(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 _r(e,t){const n=mr(t);if(hr(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 Ot(e,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(r)}catch{return Ot(e,n)}}function Bt(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function wr(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=Bt(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 $=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+$,wduration:U,queueIndex:g.length,gesture:I.gesture??null,emphasis:I.emphasis===!0})}))},W=(g,x,b,C,I,L)=>{b.length!==0&&(I&&(p=C),b.forEach(O=>{const $=String(O.symbol??O.viseme??"").trim();if(!$)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(Fn(L)==="oculus_direct")Z=an($);else{const ae=wr(x,se),J=ae?ir(ae,se):0;Z=lr($,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),W(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 $=window.AudioContext||window.webkitAudioContext;s||(s=new $);const U=s;U.state==="suspended"&&await U.resume();const X=await _r(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($){console.error("[avatarChunkPlayback] audio chunk failed:",$)}finally{i=!1;const $=n.shift();$?await E(g,x,$.audio,$.visemes,$.words,$.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=Bt(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 gr(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}const mt=.5,_t=1.5,wt="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??wt,S=u?.speakingRate??Je,D=Math.max(mt,Math.min(_t,S)),H={user_query:k,ttsEngineId:d,speakingRate:D,tenant:"aiTwin"};Bn.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 W=V.body;if(!W)throw new Error("No response body");const j=W.getReader(),E=new TextDecoder;let A="";const g=async x=>{const b=tr(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(`
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 gt=16e3,pt=24e3;class pr extends Xt.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,gt,pt)}bufferBotAudio(t,n){}}const yr=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Er(e){return yr.test(e.trim())}function Sr(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(`${Sr(n)}/ws/voice`);r.searchParams.set("authToken",t);const s=e.voiceId?.trim();s&&Er(s)&&r.searchParams.set("voiceId",s);const i=e.speakingRate??Je;return r.searchParams.set("speaking_rate",String(Math.max(mt,Math.min(_t,i)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),r.toString()}function Ft(e,t){if(!Array.isArray(e))return[];const n=[];for(const r of e)!r||typeof r!="object"||n.push({sentence_index:Number(r.sentence_index??0),text:String(r.text??""),sentiment:typeof r.sentiment=="string"?r.sentiment:void 0,emotion:String(r.emotion??t),start_word:Number(r.start_word??0),end_word:Number(r.end_word??0)});return n}function kr(e){if(!e||typeof e!="object")return null;const t=e,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&&$(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))},W=()=>D.getPlaybackElapsedMs(),j=(c,v=o)=>{if(!m.onLipsyncDebug)return;const B=W(),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(...Ft(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(...Ft(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()},$=c=>{const v=kr(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 pr,_=new Rn.PipecatClient({transport:new Xt.WebSocketTransport({mediaManager:p,recorderSampleRate:gt,playerSampleRate:pt}),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:W,isSpeaking:()=>D.isSpeaking(),setPlaybackSpeed:c=>{D.setPlaybackSpeed(c)},getPlaybackSpeed:()=>D.getPlaybackSpeed(),subscribe:c=>(u.add(c),()=>u.delete(c))}}function Tr(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function vr(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 br(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 zn(r,t)}async function Ar(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 Ir(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 Rr(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 Dr(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Cr(e){const t=Qn();if(!Ge())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await Qe(t,e);return Dr(n)}function yt(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 Mr=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],ut=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],xr=ut.length,Ut=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 Nt(e,t){return`${e}__${t}`}function Vt(e,t){return`pairs/${e}/${t}_minus_sil.png`}function qe(e){return`${e}_minus_sil.png`}function Pr(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 Lr(e,t,n){const r=Et(e,t);return mn(r,n).length>0}function Et(e,t){if(e===t)return[];const n=[],r=Nt(e,t);if(Ut.has(r)){for(const i of ut)n.push(Vt(r,i));return n}const s=Nt(t,e);if(Ut.has(s)){for(let i=xr-1;i>=0;i--)n.push(Vt(s,ut[i]));return n}return[]}function Or(e){return e<16?[]:e<35?[2]:e<51?[0,4]:e<67?[0,2,4]:e<83?[0,1,2,3]:[0,1,2,3,4]}function Br(e,t){return Or(t).map(r=>e[r]).filter(r=>r!=null)}function Fr(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 Ur(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 Nr=[.32,.24,.16,.08,0],Vr=Nr.map(e=>`eyes_${e.toFixed(2)}`),$r=["eyes_0.32","eyes_0.16","eyes_0.00"],Wr=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],$t=2,Hr=-30,lt=20,qr={fear:-30,anger:-20,sad:-10,neutral:0,love:10,happy:0,disgust:20};function St(e){return`brow_${e}`}function kt(e){return qr[e]}function ye(e){return Math.max(Hr,Math.min(lt,e))}function Kr(e,t){if(e===t)return[];const n=e<t?$t:-$t,r=[];let s=e;for(;s!==t;)s+=n,r.push(s);return r}const jr={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?jr[n]??t:t}function _n(e){return e===0?null:yt(St(e),"eyes_standard")}function wn(e){return _n(kt(e))}function Wt(e,t){const n=St(kt(e));return!t||t==="eyes_standard"?wn(e):e==="neutral"&&t==="eyes_standard"?null:yt(n,t)}function Gr(e,t){const n=[];for(const r of t)n.push(Wt(e,r));for(let r=t.length-2;r>=0;r--)n.push(Wt(e,t[r]));return n.push(wn(e)),n}function zr(e){return yt(St(e),"eyes_standard")}function Yr(e,t){return Kr(e,t).map(zr)}const Jr=6;function Qr(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Xr(e){const t=ye(e);return t>=lt?lt:ye(t+Jr)}function Zr(e,t,n){const r=ye(n);return Qr(t,e)?.emphasis?Xr(r):r}function Ht(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 Pe(e,t){return e+Math.random()*(t-e)}function Ve(){return Pe(14,32)}function es(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=Ht(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=[...Yr(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+Pe(n,r)},p=A,S(D(m),A)}function W(E,A,g){const x=g?$r:Math.random()<a?Vr:Wr;u={kind:"playing",paths:Gr(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&&W(E,p,!1);return}if(u.kind==="doublePause"){S(D(m),u.blinkEmotion),E>=u.resumeAt&&W(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+Pe(i,o),blinkEmotion:u.blinkEmotion},S(D(m),u.blinkEmotion);return}if(u.after==="idle"&&Math.random()<s){u={kind:"doublePause",resumeAt:E+Pe(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"?Ht(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()+Pe(n,r),"neutral")}}}function ts(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const s=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(i){t&&r===i||(s(),t=!1,r=i,i.startsWith("blob:")&&(n=i),await new Promise((o,a)=>{const 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 ns=50,gn=400;function rs(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function ss(e,t){const n=[];for(const r of e){const s=rs(t,r.start_word,r.end_word);if(s.length===0)continue;const i=s[0],o=s[s.length-1];n.push({sentence:r,startMs:Math.max(0,i.wtime-ns),endMs:o.wtime+o.wduration+gn})}return n.sort((r,s)=>r.startMs-s.startMs)}function is(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=ss(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,Le=null;const Ke=new Map;function os(){ge=null,Le=null,Ke.clear()}Jn(os);function as(e){return e??Le??void 0}function Tt(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function cs(e){return Ge()?Rr(await Qe(Lt(),e??"")):Tt(Lt())}async function qt(e,t,n,r){const s=n?await Ar(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 Ir(await Qe(Ur(t,i.path,n),r??"")):await Tt(`${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=as(e),n=Ge();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(ge&&(!n||Le===(t??null))){const i=await ge;return{...Oe(i),visemePaths:[...i.viseme.cellByPath.keys()]}}Le=t??null,Ke.clear();const r=Xn();ge=(async()=>{const i=await cs(t),o=await qt(Zn(),r,n,t);let a=null;try{a=await qt(er(),r,n,t)}catch{a=null}return{sil:i,viseme:o,expression:a}})();const s=await ge;return{...Oe(s),visemePaths:[...s.viseme.cellByPath.keys()]}}async function yn(e){if(await ft(e),!ge)throw new Error("Assets not loaded");return ge}function Oe(e){return Tr(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function us(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 Kt(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=vr(t.atlasMeta,o),f=Oe(e);if(br(o)){const p=us(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 Tt(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 jt(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}=Oe(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(Le??void 0),s=hn(r.viseme.atlasMeta),{width:i,height:o}=Oe(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=Pr(t.mouthPath,_)??(_.has(t.mouthPath)?t.mouthPath:null);p&&a.push(await Kt(r,r.viseme,p))}t.expressionPath&&r.expression&&a.push(await Kt(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 ls(e){await dt(e,{mouthPath:null,expressionPath:null})}function fs(e){const t=new Map;for(const n of e)t.has(n.vtime)||t.set(n.vtime,n);return[...t.values()].sort((n,r)=>n.vtime-r.vtime)}function ds(e){const t=fs(e),n=[];for(let r=0;r<t.length-1;r++){const s=t[r].viseme,i=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;s===i||a<=o||n.push({from:s,to:i,fromVtime:o,toVtime:a})}return n}function hs(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function ms(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const En=400,_s=200,ws=600,gs="__sil__";function ps(){return{lastDrawnKey:""}}function he(e){e.lastDrawnKey="",e.transitionCache=void 0}function ys(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=ds(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Es(e){let t="sil";for(const n of e)n.viseme!=="sil"&&(t=n.viseme);return t}function Ss(e,t){return e==="sil"?!1:t?Lr(e,"sil",t):Et(e,"sil").length>0}function ks(){return En+ws}function Gt(e){return e??gs}function Ts(e,t,n,r){if(e.length===0)return{diffPath:null,label:"sil"};const s=ys(e,r),i=hs(s,t);if(i){const a=i.toVtime-i.fromVtime,f=ms(i.fromVtime,i.toVtime);if(t>=f.transStart&&t<i.toVtime){let l=Et(i.from,i.to);n&&(l=mn(l,n));const _=Br(l,a);if(_.length>0){const p=Fr(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 Sn(e,t){const n=t??Gt(e.expressionPath);return`${Gt(e.mouthPath)}|${n}`}function vs(e,t,n,r,s,i,o,a,f,l){const _=Ts(t,n,f,i),p={mouthPath:_.diffPath,expressionPath:r},m=Sn(p,s);m!==i.lastDrawnKey&&(a(_.label),o(e,p,m,T=>{T===m&&(i.lastDrawnKey=m)}))}function zt(e,t,n,r,s,i,o=null){const a={mouthPath:null,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",l=Sn(a,n)+f;!(o!=null)&&l===r.lastDrawnKey||(i(o!=null?"idle":"sil"),s(e,a,l,p=>{p===l&&(r.lastDrawnKey=l)}))}function kn(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 Yt=-1,Jt=new Map;async function bs(e){let t=Jt.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),Jt.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function As(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Is(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 Qt(e,t){let n=0,r=null;const s=kn(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 ls(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 Rs(e,t,n){let r=null,s=1,i=0,o=!1,a=!1,f=null;const l=new Map,_=kn(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===Yt){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 bs(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===Yt)){const H=-d.generation;if(!_.isLatestSeq(H)){d.bitmap.close();return}}if(S&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){d.bitmap.close();return}Is(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:Yn(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 Ds(e,t={}){if(!As())return Qt(e,t);const n=Ln(t.workerScriptUrl);try{return Rs(e,t,n)}catch{return Qt(e,t)}}class Cs 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 Cs(n,t))},t);e.then(o=>{globalThis.clearTimeout(i),r(o)},o=>{globalThis.clearTimeout(i),s(o)})})}const Ms={position:"relative",display:"inline-block",lineHeight:0},xs={display:"block",maxWidth:"100%",height:"auto"},Ps={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 xe(e){return Un(e)?un:wt}function me(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const Ls=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=w.useRef(ps()),j=w.useRef(es()),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.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),vt=w.useRef(u),ee=w.useRef(T),bt=w.useRef(k),At=w.useRef(d),It=w.useRef(R),Rt=w.useRef(S);vt.current=u,ee.current=T,bt.current=k,At.current=d,It.current=R,Rt.current=S;const Dt=w.useCallback(h=>{const M=h?.ttsEngineId??o??Y.current?.ttsEngineId??pe,P=h?.voiceId??a??Y.current?.voiceId??xe(M);return{ttsEngineId:M,voiceId:P}},[o,a]),le=w.useCallback(h=>{J(h),bt.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 Ct=w.useCallback(()=>(K.current||(K.current=fn(Re,{speakingRate:f,onUserTranscript:(h,M)=>At.current?.(h,M),onBotOutput:h=>It.current?.(h),onLipsyncDebug:h=>Rt.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},[]),Mt=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)},_s))},[ce]),Be=w.useCallback(()=>{if(ie(),ee.current?.("sil"),C.current=!1,!X.current||!U.current){L.current=!1;return}Mt()},[ie,Mt]),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||(he(W.current),await P.renderSilOnly(),M!==A.current)||me(q.current,K.current).isSpeaking())return;Be();return}const te=O.current!=="sil"?O.current:Es(me(q.current,K.current).getVisemeQueue()),oe=Ss(te,Ze.current);if(he(W.current),!oe){if(await P.renderSilOnly(),M!==A.current||me(q.current,K.current).isSpeaking())return;Be();return}try{await P.renderViseme(F,"sil",{from:te,transitionDurationMs:En})}catch(fe){if(fe?.name!=="AbortError")throw fe}if(M!==A.current){N();return}if(me(q.current,K.current).isSpeaking()){N();return}Be()},[c,Be]),De=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})},ks())},[ie,et]),xt=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 Kn(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??xe(o);Y.current&&(Y.current.voiceId=h)},[a,o]);const _e=w.useMemo(()=>rn(n,r),[n,r]),vn=w.useMemo(()=>s?JSON.stringify(s):_e?`face:${_e}`:`id:${t??""}`,[s,_e,t]);return w.useEffect(()=>{if(!t&&!s&&!_e){le("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??xe(N);else if(_e)ee.current?.("loadFace"),F=at(_e),N=o,te=a??xe(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??xe(N),F=at(Q.faceId)}Y.current={ttsEngineId:N,voiceId:te},sn(F),U.current=ts(),P=Ds(M,{onStatus:Q=>{h||ee.current?.(Q)},onError:Q=>{h||le(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 fe=Ge()?await xt():void 0;if(h)return;ee.current?.("loadAssets");const ue=await st(P.loadAssets(fe),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),vt.current?.(),P.renderSilOnly().then(()=>{h||ee.current?.("sil")}),(async()=>{try{const Q=await Cr(fe);if(await U.current.load(Q),h)return;X.current=!0,z(!0),he(W.current),U.current.setActive(!0);const re=U.current.getVideo();await jt(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){le(F.message);return}le(F instanceof Error?F.message:"Failed to load AI twin")}})(),()=>{h=!0,U.current?.dispose(),P?.dispose(),V.current=null}},[vn,s,_e,t,o,a,i,xt,le]),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&&!$.current,fe=$.current&&!te;oe&&(ie(),ce(),C.current=!1,I.current=!1,he(W.current),g.current=0,O.current="sil",U.current?.setActive(!1)),fe&&(j.current.reset(),U.current?.setActive(!1),De());const ue=N.getPlaybackElapsedMs(),Q=fe||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 de=is(ue,N.getSentenceEmotions(),N.getWordQueue(),N.getStreamMood());j.current.setTargetEmotion(de),j.current.setTargetEyebrow(Zr(ue,N.getWordQueue(),kt(de))),j.current.advance(performance.now());const Ce=j.current.getExpressionPath(),tt=j.current.getDrawKey();vs(P,re,ue,Ce,tt,W.current,(Me,bn,An,In)=>F.drawLiveFrame(Me,bn,An,In),Me=>ee.current?.(Me),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,jt(P,we,null,void 0,Xe.current,()=>!N.isSpeaking()&&!C.current&&!L.current).then(()=>ee.current?.("idle")).finally(()=>{h.current=!1}))):zt(P,null,"__sil__",W.current,(de,Ce,tt,Me)=>F.drawLiveFrame(de,Ce,tt,Me),de=>ee.current?.(de))}else Q||zt(P,null,"__sil__",W.current,(re,we,de,Ce)=>F.drawLiveFrame(re,we,de,Ce),re=>ee.current?.(re));$.current=te,E.current=requestAnimationFrame(M)};return E.current=requestAnimationFrame(M),()=>{cancelAnimationFrame(E.current),ie(),ce(),q.current.stop(),K.current?.stop()}},[c,B,De,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}=Dt(M);J(null),A.current+=1,ie(),ce(),C.current=!1,I.current=!1,O.current="sil",he(W.current),j.current.reset(),$.current=!1;try{X.current?(U.current?.setActive(!1),U.current?.restart(),he(W.current)):await F.renderSilOnly(),await q.current.speak(P,{voiceId:te,speakingRate:M?.speakingRate??f,ttsEngineId:N})}catch(oe){throw le(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(),he(W.current),$.current=!1,De()},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=Ct();await F.unlockAudio(),await F.connect({...h,authToken:M,voiceId:P,speakingRate:h.speakingRate??f})}catch(M){throw le(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,he(W.current),$.current=!1,await h.disconnect(),De())},isConnected:()=>K.current?.isConnected()??!1}),[c,f,i,a,ie,ce,De,le,Dt,Ct,se]),nt.jsxs("div",{className:l,style:{...Ms,..._},children:[nt.jsx("canvas",{ref:H,width:ne.width,height:ne.height,style:{...xs,...p},"aria-label":t?`AI twin ${t}`:"AI twin face"}),y&&ae?nt.jsx("div",{style:Ps,children:ae}):null]})}),Tn="thumbnail.webp";function Os(e,t=en){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Tn}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Tn;exports.AiTwin=Ls;exports.AiTwinNotFoundError=We;exports.DEFAULT_TTS_ENGINE_ID=pe;exports.MIC_SAMPLE_RATE=gt;exports.OCULUS_VISEME_IDS=on;exports.PLAYBACK_SAMPLE_RATE=pt;exports.SPEAKING_RATE_MAX=_t;exports.SPEAKING_RATE_MIN=mt;exports.TTS_ENGINE_CARTESIA=Ee;exports.TTS_ENGINE_GOOGLE=ht;exports.TTS_ENGINE_INWORLD=je;exports.VISEME_IDS=Mr;exports.VISEME_TEST_CARTESIA_VOICE_ID=un;exports.VISEME_TEST_SPEAKING_RATE=Je;exports.VISEME_TEST_VOICE_ID=wt;exports.buildVoiceWebSocketUrl=ln;exports.createAvatarTtsLipsyncController=ct;exports.createRealtimeVoiceLipsyncController=fn;exports.faceAssetUrls=at;exports.fetchAiTwin=nn;exports.fetchDevAuthToken=$e;exports.getAiTwinThumbnailUrl=Os;exports.normalizeOculusViseme=an;exports.resolveDirectFaceId=rn;exports.resolveVisemeAtTime=Ye;exports.resolveWordAtTime=gr;exports.setActiveTwinAssets=sn;
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 gt=16e3,pt=24e3;class pr extends Xt.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,gt,pt)}bufferBotAudio(t,n){}}const yr=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Er(e){return yr.test(e.trim())}function Sr(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(`${Sr(n)}/ws/voice`);r.searchParams.set("authToken",t);const s=e.voiceId?.trim();s&&Er(s)&&r.searchParams.set("voiceId",s);const i=e.speakingRate??Je;return r.searchParams.set("speaking_rate",String(Math.max(mt,Math.min(_t,i)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),r.toString()}function Ft(e,t){if(!Array.isArray(e))return[];const n=[];for(const r of e)!r||typeof r!="object"||n.push({sentence_index:Number(r.sentence_index??0),text:String(r.text??""),sentiment:typeof r.sentiment=="string"?r.sentiment:void 0,emotion:String(r.emotion??t),start_word:Number(r.start_word??0),end_word:Number(r.end_word??0)});return n}function kr(e){if(!e||typeof e!="object")return null;const t=e,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&&$(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))},W=()=>D.getPlaybackElapsedMs(),j=(c,v=o)=>{if(!m.onLipsyncDebug)return;const B=W(),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(...Ft(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(...Ft(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()},$=c=>{const v=kr(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 pr,_=new Rn.PipecatClient({transport:new Xt.WebSocketTransport({mediaManager:p,recorderSampleRate:gt,playerSampleRate:pt}),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:W,isSpeaking:()=>D.isSpeaking(),setPlaybackSpeed:c=>{D.setPlaybackSpeed(c)},getPlaybackSpeed:()=>D.getPlaybackSpeed(),subscribe:c=>(u.add(c),()=>u.delete(c))}}function Tr(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function vr(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 br(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 zn(r,t)}async function Ar(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 Ir(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 Rr(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 Dr(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Cr(e){const t=Qn();if(!Ge())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await Qe(t,e);return Dr(n)}function yt(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 Mr=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],ut=["t01_0.25","t02_0.50","t03_0.75"],xr=ut.length,Ut=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 Nt(e,t){return`${e}__${t}`}function Vt(e,t){return`pairs/${e}/${t}_minus_sil.png`}function qe(e){return`${e}_minus_sil.png`}function Pr(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 Lr(e,t,n){const r=Et(e,t);return mn(r,n).length>0}function Et(e,t){if(e===t)return[];const n=[],r=Nt(e,t);if(Ut.has(r)){for(const i of ut)n.push(Vt(r,i));return n}const s=Nt(t,e);if(Ut.has(s)){for(let i=xr-1;i>=0;i--)n.push(Vt(s,ut[i]));return n}return[]}function Or(e){return e<16?[]:e<35?[1]:e<51?[0,2]:[0,1,2]}function Br(e,t){return Or(t).map(r=>e[r]).filter(r=>r!=null)}function Fr(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 Ur(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 Nr=[.32,.24,.16,.08,0],Vr=Nr.map(e=>`eyes_${e.toFixed(2)}`),$r=["eyes_0.32","eyes_0.16","eyes_0.00"],Wr=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],$t=2,Hr=-30,lt=20,qr={fear:-30,anger:-20,sad:-10,neutral:0,love:10,happy:0,disgust:20};function St(e){return`brow_${e}`}function kt(e){return qr[e]}function ye(e){return Math.max(Hr,Math.min(lt,e))}function Kr(e,t){if(e===t)return[];const n=e<t?$t:-$t,r=[];let s=e;for(;s!==t;)s+=n,r.push(s);return r}const jr={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?jr[n]??t:t}function _n(e){return e===0?null:yt(St(e),"eyes_standard")}function wn(e){return _n(kt(e))}function Wt(e,t){const n=St(kt(e));return!t||t==="eyes_standard"?wn(e):e==="neutral"&&t==="eyes_standard"?null:yt(n,t)}function Gr(e,t){const n=[];for(const r of t)n.push(Wt(e,r));for(let r=t.length-2;r>=0;r--)n.push(Wt(e,t[r]));return n.push(wn(e)),n}function zr(e){return e===0?null:yt(St(e),"eyes_standard")}function Yr(e,t){return Kr(e,t).map(zr).filter(n=>n!=null)}const Jr=6;function Qr(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Xr(e){const t=ye(e);return t>=lt?lt:ye(t+Jr)}function Zr(e,t,n){const r=ye(n);return Qr(t,e)?.emphasis?Xr(r):r}function Ht(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 Pe(e,t){return e+Math.random()*(t-e)}function Ve(){return Pe(14,32)}function es(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=Ht(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=[...Yr(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+Pe(n,r)},p=A,S(D(m),A)}function W(E,A,g){const x=g?$r:Math.random()<a?Vr:Wr;u={kind:"playing",paths:Gr(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&&W(E,p,!1);return}if(u.kind==="doublePause"){S(D(m),u.blinkEmotion),E>=u.resumeAt&&W(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+Pe(i,o),blinkEmotion:u.blinkEmotion},S(D(m),u.blinkEmotion);return}if(u.after==="idle"&&Math.random()<s){u={kind:"doublePause",resumeAt:E+Pe(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"?Ht(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()+Pe(n,r),"neutral")}}}function ts(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const s=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(i){t&&r===i||(s(),t=!1,r=i,i.startsWith("blob:")&&(n=i),await new Promise((o,a)=>{const 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 ns=50,gn=400;function rs(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function ss(e,t){const n=[];for(const r of e){const s=rs(t,r.start_word,r.end_word);if(s.length===0)continue;const i=s[0],o=s[s.length-1];n.push({sentence:r,startMs:Math.max(0,i.wtime-ns),endMs:o.wtime+o.wduration+gn})}return n.sort((r,s)=>r.startMs-s.startMs)}function is(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=ss(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,Le=null;const Ke=new Map;function os(){ge=null,Le=null,Ke.clear()}Jn(os);function as(e){return e??Le??void 0}function Tt(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function cs(e){return Ge()?Rr(await Qe(Lt(),e??"")):Tt(Lt())}async function qt(e,t,n,r){const s=n?await Ar(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 Ir(await Qe(Ur(t,i.path,n),r??"")):await Tt(`${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=as(e),n=Ge();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(ge&&(!n||Le===(t??null))){const i=await ge;return{...Oe(i),visemePaths:[...i.viseme.cellByPath.keys()]}}Le=t??null,Ke.clear();const r=Xn();ge=(async()=>{const i=await cs(t),o=await qt(Zn(),r,n,t);let a=null;try{a=await qt(er(),r,n,t)}catch{a=null}return{sil:i,viseme:o,expression:a}})();const s=await ge;return{...Oe(s),visemePaths:[...s.viseme.cellByPath.keys()]}}async function yn(e){if(await ft(e),!ge)throw new Error("Assets not loaded");return ge}function Oe(e){return Tr(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function us(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 Kt(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=vr(t.atlasMeta,o),f=Oe(e);if(br(o)){const p=us(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 Tt(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 jt(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}=Oe(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(Le??void 0),s=hn(r.viseme.atlasMeta),{width:i,height:o}=Oe(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=Pr(t.mouthPath,_)??(_.has(t.mouthPath)?t.mouthPath:null);p&&a.push(await Kt(r,r.viseme,p))}t.expressionPath&&r.expression&&a.push(await Kt(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 ls(e){await dt(e,{mouthPath:null,expressionPath:null})}function fs(e){const t=new Map;for(const n of e)t.has(n.vtime)||t.set(n.vtime,n);return[...t.values()].sort((n,r)=>n.vtime-r.vtime)}function ds(e){const t=fs(e),n=[];for(let r=0;r<t.length-1;r++){const s=t[r].viseme,i=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;s===i||a<=o||n.push({from:s,to:i,fromVtime:o,toVtime:a})}return n}function hs(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function ms(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const En=400,_s=200,ws=600,gs="__sil__";function ps(){return{lastDrawnKey:""}}function he(e){e.lastDrawnKey="",e.transitionCache=void 0}function ys(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=ds(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Es(e){let t="sil";for(const n of e)n.viseme!=="sil"&&(t=n.viseme);return t}function Ss(e,t){return e==="sil"?!1:t?Lr(e,"sil",t):Et(e,"sil").length>0}function ks(){return En+ws}function Gt(e){return e??gs}function Ts(e,t,n,r){if(e.length===0)return{diffPath:null,label:"sil"};const s=ys(e,r),i=hs(s,t);if(i){const a=i.toVtime-i.fromVtime,f=ms(i.fromVtime,i.toVtime);if(t>=f.transStart&&t<i.toVtime){let l=Et(i.from,i.to);n&&(l=mn(l,n));const _=Br(l,a);if(_.length>0){const p=Fr(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 Sn(e,t){const n=t??Gt(e.expressionPath);return`${Gt(e.mouthPath)}|${n}`}function vs(e,t,n,r,s,i,o,a,f,l){const _=Ts(t,n,f,i),p={mouthPath:_.diffPath,expressionPath:r},m=Sn(p,s);m!==i.lastDrawnKey&&(a(_.label),o(e,p,m,T=>{T===m&&(i.lastDrawnKey=m)}))}function zt(e,t,n,r,s,i,o=null){const a={mouthPath:null,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",l=Sn(a,n)+f;!(o!=null)&&l===r.lastDrawnKey||(i(o!=null?"idle":"sil"),s(e,a,l,p=>{p===l&&(r.lastDrawnKey=l)}))}function kn(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 Yt=-1,Jt=new Map;async function bs(e){let t=Jt.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),Jt.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function As(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Is(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 Qt(e,t){let n=0,r=null;const s=kn(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 ls(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 Rs(e,t,n){let r=null,s=1,i=0,o=!1,a=!1,f=null;const l=new Map,_=kn(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===Yt){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 bs(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===Yt)){const H=-d.generation;if(!_.isLatestSeq(H)){d.bitmap.close();return}}if(S&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){d.bitmap.close();return}Is(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:Yn(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 Ds(e,t={}){if(!As())return Qt(e,t);const n=Ln(t.workerScriptUrl);try{return Rs(e,t,n)}catch{return Qt(e,t)}}class Cs 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 Cs(n,t))},t);e.then(o=>{globalThis.clearTimeout(i),r(o)},o=>{globalThis.clearTimeout(i),s(o)})})}const Ms={position:"relative",display:"inline-block",lineHeight:0},xs={display:"block",maxWidth:"100%",height:"auto"},Ps={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 xe(e){return Un(e)?un:wt}function me(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const Ls=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=w.useRef(ps()),j=w.useRef(es()),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.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),vt=w.useRef(u),ee=w.useRef(T),bt=w.useRef(k),At=w.useRef(d),It=w.useRef(R),Rt=w.useRef(S);vt.current=u,ee.current=T,bt.current=k,At.current=d,It.current=R,Rt.current=S;const Dt=w.useCallback(h=>{const M=h?.ttsEngineId??o??Y.current?.ttsEngineId??pe,P=h?.voiceId??a??Y.current?.voiceId??xe(M);return{ttsEngineId:M,voiceId:P}},[o,a]),le=w.useCallback(h=>{J(h),bt.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 Ct=w.useCallback(()=>(K.current||(K.current=fn(Re,{speakingRate:f,onUserTranscript:(h,M)=>At.current?.(h,M),onBotOutput:h=>It.current?.(h),onLipsyncDebug:h=>Rt.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},[]),Mt=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)},_s))},[ce]),Be=w.useCallback(()=>{if(ie(),ee.current?.("sil"),C.current=!1,!X.current||!U.current){L.current=!1;return}Mt()},[ie,Mt]),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||(he(W.current),await P.renderSilOnly(),M!==A.current)||me(q.current,K.current).isSpeaking())return;Be();return}const te=O.current!=="sil"?O.current:Es(me(q.current,K.current).getVisemeQueue()),oe=Ss(te,Ze.current);if(he(W.current),!oe){if(await P.renderSilOnly(),M!==A.current||me(q.current,K.current).isSpeaking())return;Be();return}try{await P.renderViseme(F,"sil",{from:te,transitionDurationMs:En})}catch(fe){if(fe?.name!=="AbortError")throw fe}if(M!==A.current){N();return}if(me(q.current,K.current).isSpeaking()){N();return}Be()},[c,Be]),De=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})},ks())},[ie,et]),xt=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 Kn(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??xe(o);Y.current&&(Y.current.voiceId=h)},[a,o]);const _e=w.useMemo(()=>rn(n,r),[n,r]),vn=w.useMemo(()=>s?JSON.stringify(s):_e?`face:${_e}`:`id:${t??""}`,[s,_e,t]);return w.useEffect(()=>{if(!t&&!s&&!_e){le("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??xe(N);else if(_e)ee.current?.("loadFace"),F=at(_e),N=o,te=a??xe(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??xe(N),F=at(Q.faceId)}Y.current={ttsEngineId:N,voiceId:te},sn(F),U.current=ts(),P=Ds(M,{onStatus:Q=>{h||ee.current?.(Q)},onError:Q=>{h||le(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 fe=Ge()?await xt():void 0;if(h)return;ee.current?.("loadAssets");const ue=await st(P.loadAssets(fe),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),vt.current?.(),P.renderSilOnly().then(()=>{h||ee.current?.("sil")}),(async()=>{try{const Q=await Cr(fe);if(await U.current.load(Q),h)return;X.current=!0,z(!0),he(W.current),U.current.setActive(!0);const re=U.current.getVideo();await jt(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){le(F.message);return}le(F instanceof Error?F.message:"Failed to load AI twin")}})(),()=>{h=!0,U.current?.dispose(),P?.dispose(),V.current=null}},[vn,s,_e,t,o,a,i,xt,le]),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&&!$.current,fe=$.current&&!te;oe&&(ie(),ce(),C.current=!1,I.current=!1,he(W.current),g.current=0,O.current="sil",U.current?.setActive(!1)),fe&&(j.current.reset(),U.current?.setActive(!1),De());const ue=N.getPlaybackElapsedMs(),Q=fe||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 de=is(ue,N.getSentenceEmotions(),N.getWordQueue(),N.getStreamMood());j.current.setTargetEmotion(de),j.current.setTargetEyebrow(Zr(ue,N.getWordQueue(),kt(de))),j.current.advance(performance.now());const Ce=j.current.getExpressionPath(),tt=j.current.getDrawKey();vs(P,re,ue,Ce,tt,W.current,(Me,bn,An,In)=>F.drawLiveFrame(Me,bn,An,In),Me=>ee.current?.(Me),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,jt(P,we,null,void 0,Xe.current,()=>!N.isSpeaking()&&!C.current&&!L.current).then(()=>ee.current?.("idle")).finally(()=>{h.current=!1}))):zt(P,null,"__sil__",W.current,(de,Ce,tt,Me)=>F.drawLiveFrame(de,Ce,tt,Me),de=>ee.current?.(de))}else Q||zt(P,null,"__sil__",W.current,(re,we,de,Ce)=>F.drawLiveFrame(re,we,de,Ce),re=>ee.current?.(re));$.current=te,E.current=requestAnimationFrame(M)};return E.current=requestAnimationFrame(M),()=>{cancelAnimationFrame(E.current),ie(),ce(),q.current.stop(),K.current?.stop()}},[c,B,De,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}=Dt(M);J(null),A.current+=1,ie(),ce(),C.current=!1,I.current=!1,O.current="sil",he(W.current),j.current.reset(),$.current=!1;try{X.current?(U.current?.setActive(!1),U.current?.restart(),he(W.current)):await F.renderSilOnly(),await q.current.speak(P,{voiceId:te,speakingRate:M?.speakingRate??f,ttsEngineId:N})}catch(oe){throw le(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(),he(W.current),$.current=!1,De()},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=Ct();await F.unlockAudio(),await F.connect({...h,authToken:M,voiceId:P,speakingRate:h.speakingRate??f})}catch(M){throw le(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,he(W.current),$.current=!1,await h.disconnect(),De())},isConnected:()=>K.current?.isConnected()??!1}),[c,f,i,a,ie,ce,De,le,Dt,Ct,se]),nt.jsxs("div",{className:l,style:{...Ms,..._},children:[nt.jsx("canvas",{ref:H,width:ne.width,height:ne.height,style:{...xs,...p},"aria-label":t?`AI twin ${t}`:"AI twin face"}),y&&ae?nt.jsx("div",{style:Ps,children:ae}):null]})}),Tn="thumbnail.webp";function Os(e,t=en){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Tn}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Tn;exports.AiTwin=Ls;exports.AiTwinNotFoundError=We;exports.DEFAULT_TTS_ENGINE_ID=pe;exports.MIC_SAMPLE_RATE=gt;exports.OCULUS_VISEME_IDS=on;exports.PLAYBACK_SAMPLE_RATE=pt;exports.SPEAKING_RATE_MAX=_t;exports.SPEAKING_RATE_MIN=mt;exports.TTS_ENGINE_CARTESIA=Ee;exports.TTS_ENGINE_GOOGLE=ht;exports.TTS_ENGINE_INWORLD=je;exports.VISEME_IDS=Mr;exports.VISEME_TEST_CARTESIA_VOICE_ID=un;exports.VISEME_TEST_SPEAKING_RATE=Je;exports.VISEME_TEST_VOICE_ID=wt;exports.buildVoiceWebSocketUrl=ln;exports.createAvatarTtsLipsyncController=ct;exports.createRealtimeVoiceLipsyncController=fn;exports.faceAssetUrls=at;exports.fetchAiTwin=nn;exports.fetchDevAuthToken=$e;exports.getAiTwinThumbnailUrl=Os;exports.normalizeOculusViseme=an;exports.resolveDirectFaceId=rn;exports.resolveVisemeAtTime=Ye;exports.resolveWordAtTime=gr;exports.setActiveTwinAssets=sn;
package/dist/aitwin.js CHANGED
@@ -4,7 +4,7 @@ import { PipecatClient as bn } from "@pipecat-ai/client-js";
4
4
  import { WebSocketTransport as Tn, DailyMediaManager as An } from "@pipecat-ai/websocket-transport";
5
5
  const In = "https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev", Yt = {
6
6
  publicBase: In
7
- }, Rn = "0.2.2", Dn = {
7
+ }, Rn = "0.2.4", Dn = {
8
8
  version: Rn
9
9
  }, Mn = {}, be = "https://ai.streamoji.com", Jt = `${Yt.publicBase}/custom-faces`, xn = `${Yt.publicBase}/aitwin-workers/v${Dn.version}/visemeDiffPreview.worker.js`;
10
10
  function Cn(e) {
@@ -331,7 +331,7 @@ function wr(e) {
331
331
  const r = t.length % 4;
332
332
  return r !== 0 && (t += "=".repeat(4 - r)), t;
333
333
  }
334
- function _r(e) {
334
+ function gr(e) {
335
335
  return e.length >= 4 && e[0] === 82 && e[1] === 73 && e[2] === 70 && e[3] === 70;
336
336
  }
337
337
  function xt(e, t, n = mr) {
@@ -345,15 +345,15 @@ function xt(e, t, n = mr) {
345
345
  const o = e.createBuffer(1, i.length, n);
346
346
  return o.copyToChannel(i, 0), o;
347
347
  }
348
- function gr(e) {
348
+ function _r(e) {
349
349
  const t = wr(e), n = window.atob(t), r = new Uint8Array(n.length);
350
350
  for (let s = 0; s < n.length; s++)
351
351
  r[s] = n.charCodeAt(s);
352
352
  return r;
353
353
  }
354
354
  async function pr(e, t) {
355
- const n = gr(t);
356
- if (_r(n)) {
355
+ const n = _r(t);
356
+ if (gr(n)) {
357
357
  const r = n.buffer.slice(
358
358
  n.byteOffset,
359
359
  n.byteOffset + n.byteLength
@@ -386,23 +386,23 @@ function yr(e, t) {
386
386
  }
387
387
  function Zt(e, t) {
388
388
  const n = [], r = [];
389
- let s = null, i = !1, o = !1, a = !1, f = !1, l = 0, w = 0, g = 0, m = 0, S = null, k = 1, u = t, p = !1;
389
+ let s = null, i = !1, o = !1, a = !1, f = !1, l = 0, w = 0, _ = 0, m = 0, S = null, k = 1, u = t, p = !1;
390
390
  const d = () => {
391
391
  S != null && (clearTimeout(S), S = null);
392
392
  }, I = () => {
393
- for (const _ of r)
393
+ for (const g of r)
394
394
  try {
395
- _.stop();
395
+ g.stop();
396
396
  } catch {
397
397
  }
398
398
  r.length = 0;
399
399
  }, E = () => {
400
- for (const _ of r)
401
- _.playbackRate.value = k;
400
+ for (const g of r)
401
+ g.playbackRate.value = k;
402
402
  }, R = () => {
403
403
  !f || i || r.length > 0 || n.length > 0 || (o = !1, d(), e.onSpeakingDone(), e.onNotify());
404
- }, W = (_) => {
405
- const x = Ct(_);
404
+ }, W = (g) => {
405
+ const x = Ct(g);
406
406
  if (x <= 0) {
407
407
  e.onSpeakingDone(), e.onNotify();
408
408
  return;
@@ -412,25 +412,25 @@ function Zt(e, t) {
412
412
  S = setTimeout(() => {
413
413
  p || (o = !1, S = null, e.onSpeakingDone(), e.onNotify());
414
414
  }, b);
415
- }, V = (_, x, b, D) => {
416
- x.length !== 0 && (D && (g = b), x.forEach((A) => {
415
+ }, V = (g, x, b, D) => {
416
+ x.length !== 0 && (D && (_ = b), x.forEach((A) => {
417
417
  const B = String(A.word ?? "").trim();
418
418
  if (!B) return;
419
419
  const $ = Math.round((A.start ?? 0) * 1e3), U = A.duration != null ? Math.round(A.duration * 1e3) : A.end != null ? Math.max(1, Math.round((A.end - (A.start ?? 0)) * 1e3)) : 0;
420
- _.push({
420
+ g.push({
421
421
  word: B,
422
- wtime: g + $,
422
+ wtime: _ + $,
423
423
  wduration: U,
424
- queueIndex: _.length,
424
+ queueIndex: g.length,
425
425
  gesture: A.gesture ?? null,
426
426
  emphasis: A.emphasis === !0
427
427
  });
428
428
  }));
429
- }, H = (_, x, b, D, A, P) => {
430
- b.length !== 0 && (A && (g = D), b.forEach((B) => {
429
+ }, H = (g, x, b, D, A, P) => {
430
+ b.length !== 0 && (A && (_ = D), b.forEach((B) => {
431
431
  const $ = String(B.symbol ?? B.viseme ?? "").trim();
432
432
  if (!$) return;
433
- const U = Math.round((B.start ?? 0) * 1e3), X = Math.max(1, Math.round((B.duration ?? 0) * 1e3)), se = g + U;
433
+ const U = Math.round((B.start ?? 0) * 1e3), X = Math.max(1, Math.round((B.duration ?? 0) * 1e3)), se = _ + U;
434
434
  let Z;
435
435
  if (Ln(P) === "oculus_direct")
436
436
  Z = ir($);
@@ -442,30 +442,30 @@ function Zt(e, t) {
442
442
  J
443
443
  );
444
444
  }
445
- _.push({
445
+ g.push({
446
446
  viseme: Z,
447
447
  weight: 1,
448
448
  vtime: se,
449
449
  vduration: X
450
450
  });
451
451
  }), e.onNotify());
452
- }, j = (_, x, b, D, A, P, B) => {
452
+ }, j = (g, x, b, D, A, P, B) => {
453
453
  V(x, D, A, P), H(
454
- _,
454
+ g,
455
455
  x,
456
456
  b,
457
457
  A,
458
458
  P,
459
459
  B
460
460
  );
461
- }, y = async (_, x, b, D, A, P, B) => {
461
+ }, y = async (g, x, b, D, A, P, B) => {
462
462
  if (p || !b?.trim()) {
463
463
  (D.length > 0 || A.length > 0) && !a && j(
464
- _,
464
+ g,
465
465
  x,
466
466
  D,
467
467
  A,
468
- g,
468
+ _,
469
469
  P,
470
470
  u
471
471
  );
@@ -498,7 +498,7 @@ function Zt(e, t) {
498
498
  return;
499
499
  }
500
500
  if (ce) {
501
- o = !0, e.onSpeakingStart(), w = Z, g = 0, _.length = 0, x.length = 0, B?.();
501
+ o = !0, e.onSpeakingStart(), w = Z, _ = 0, g.length = 0, x.length = 0, B?.();
502
502
  const v = (Z - se) * 1e3;
503
503
  l = performance.now() + v;
504
504
  }
@@ -508,7 +508,7 @@ function Zt(e, t) {
508
508
  }, J.start(Z);
509
509
  const c = (Z - w) * 1e3;
510
510
  j(
511
- _,
511
+ g,
512
512
  x,
513
513
  D,
514
514
  A,
@@ -522,7 +522,7 @@ function Zt(e, t) {
522
522
  i = !1;
523
523
  const $ = n.shift();
524
524
  $ ? await y(
525
- _,
525
+ g,
526
526
  x,
527
527
  $.audio,
528
528
  $.visemes,
@@ -533,36 +533,36 @@ function Zt(e, t) {
533
533
  }
534
534
  };
535
535
  return {
536
- setStreamTtsEngineId: (_) => {
537
- u = _;
536
+ setStreamTtsEngineId: (g) => {
537
+ u = g;
538
538
  },
539
- setPlaybackSpeed: (_) => {
540
- k = Math.max(0.1, Math.min(1, _)), E();
539
+ setPlaybackSpeed: (g) => {
540
+ k = Math.max(0.1, Math.min(1, g)), E();
541
541
  },
542
542
  getPlaybackSpeed: () => k,
543
- resetForNewStream: (_) => {
544
- p = !1, f = !1, u = _;
543
+ resetForNewStream: (g) => {
544
+ p = !1, f = !1, u = g;
545
545
  },
546
546
  /** Call from a user gesture before bot audio (connect / unlock). */
547
547
  primeAudioContext: async () => {
548
- const _ = window.AudioContext || window.webkitAudioContext;
549
- s || (s = new _()), s.state === "suspended" && await s.resume();
548
+ const g = window.AudioContext || window.webkitAudioContext;
549
+ s || (s = new g()), s.state === "suspended" && await s.resume();
550
550
  },
551
551
  stop: () => {
552
- p = !0, d(), I(), n.length = 0, i = !1, o = !1, a = !1, f = !1, g = 0, m = 0, w = 0, l = 0;
552
+ p = !0, d(), I(), n.length = 0, i = !1, o = !1, a = !1, f = !1, _ = 0, m = 0, w = 0, l = 0;
553
553
  },
554
- markStreamComplete: (_) => {
555
- if (f = !0, !a && _.length > 0) {
556
- W(_);
554
+ markStreamComplete: (g) => {
555
+ if (f = !0, !a && g.length > 0) {
556
+ W(g);
557
557
  return;
558
558
  }
559
559
  R();
560
560
  },
561
561
  playAudioChunk: y,
562
- queueTimingsOnly: (_, x, b, D, A) => {
563
- let P = g;
564
- A && _.length > 0 && (P = Ct(_)), j(
565
- _,
562
+ queueTimingsOnly: (g, x, b, D, A) => {
563
+ let P = _;
564
+ A && g.length > 0 && (P = Ct(g)), j(
565
+ g,
566
566
  x,
567
567
  b,
568
568
  D,
@@ -602,7 +602,7 @@ const en = 0.5, tn = 1.5, nn = "Olivia", Er = "f786b574-daa5-4673-aa0c-cbe3e8534
602
602
  function Pt(e, t = be) {
603
603
  const n = `${t.replace(/\/$/, "")}/avatar_ttsWithPoses`, r = [], s = [], i = [];
604
604
  let o = "neutral", a = "", f = Te;
605
- const l = /* @__PURE__ */ new Set(), w = () => l.forEach((k) => k()), g = Zt(
605
+ const l = /* @__PURE__ */ new Set(), w = () => l.forEach((k) => k()), _ = Zt(
606
606
  {
607
607
  onSpeakingStart: () => e("speaking"),
608
608
  onSpeakingDone: () => e("done"),
@@ -610,7 +610,7 @@ function Pt(e, t = be) {
610
610
  },
611
611
  Te
612
612
  ), m = () => {
613
- g.stop(), r.length = 0, s.length = 0, i.length = 0, o = "neutral", e("idle"), w();
613
+ _.stop(), r.length = 0, s.length = 0, i.length = 0, o = "neutral", e("idle"), w();
614
614
  };
615
615
  return {
616
616
  setDeveloperToken: (k) => {
@@ -626,7 +626,7 @@ function Pt(e, t = be) {
626
626
  if (!p)
627
627
  throw new Error("Developer token required for avatar_ttsWithPoses");
628
628
  const d = u?.ttsEngineId ?? f ?? Te;
629
- g.resetForNewStream(d), g.setStreamTtsEngineId(d);
629
+ _.resetForNewStream(d), _.setStreamTtsEngineId(d);
630
630
  const I = u?.voiceId ?? nn, E = u?.speakingRate ?? ft, R = Math.max(
631
631
  en,
632
632
  Math.min(tn, E)
@@ -652,19 +652,19 @@ function Pt(e, t = be) {
652
652
  if (!H) throw new Error("No response body");
653
653
  const j = H.getReader(), y = new TextDecoder();
654
654
  let T = "";
655
- const _ = async (x) => {
655
+ const g = async (x) => {
656
656
  const b = nr(x);
657
657
  if (b) {
658
658
  if (b.event === "audio") {
659
659
  const D = b.data.chunk, A = b.data.visemes ?? [], P = b.data.words ?? [], B = b.data.is_new_segment ?? !1;
660
- D ? await g.playAudioChunk(
660
+ D ? await _.playAudioChunk(
661
661
  r,
662
662
  s,
663
663
  D,
664
664
  A,
665
665
  P,
666
666
  B
667
- ) : (A.length > 0 || P.length > 0) && g.queueTimingsOnly(
667
+ ) : (A.length > 0 || P.length > 0) && _.queueTimingsOnly(
668
668
  r,
669
669
  s,
670
670
  A,
@@ -704,9 +704,9 @@ function Pt(e, t = be) {
704
704
 
705
705
  `);
706
706
  T = D.pop() ?? "";
707
- for (const A of D) await _(A);
707
+ for (const A of D) await g(A);
708
708
  if (x) {
709
- T.trim() && await _(T.trim()), g.markStreamComplete(r);
709
+ T.trim() && await g(T.trim()), _.markStreamComplete(r);
710
710
  break;
711
711
  }
712
712
  }
@@ -719,12 +719,12 @@ function Pt(e, t = be) {
719
719
  getWordQueue: () => s,
720
720
  getSentenceEmotions: () => i,
721
721
  getStreamMood: () => o,
722
- getPlaybackElapsedMs: () => g.getPlaybackElapsedMs(),
723
- isSpeaking: () => g.isSpeaking(),
722
+ getPlaybackElapsedMs: () => _.getPlaybackElapsedMs(),
723
+ isSpeaking: () => _.isSpeaking(),
724
724
  setPlaybackSpeed: (k) => {
725
- g.setPlaybackSpeed(k);
725
+ _.setPlaybackSpeed(k);
726
726
  },
727
- getPlaybackSpeed: () => g.getPlaybackSpeed(),
727
+ getPlaybackSpeed: () => _.getPlaybackSpeed(),
728
728
  subscribe: (k) => (l.add(k), () => l.delete(k))
729
729
  };
730
730
  }
@@ -791,7 +791,7 @@ function Ar(e) {
791
791
  }
792
792
  function Ir(e, t = {}) {
793
793
  const n = [], r = [], s = [], i = [];
794
- let o = "", a = "neutral", f = Ae, l = !1, w = null, g = null, m = { ...t }, S = 0, k = null;
794
+ let o = "", a = "neutral", f = Ae, l = !1, w = null, _ = null, m = { ...t }, S = 0, k = null;
795
795
  const u = /* @__PURE__ */ new Set(), p = [];
796
796
  let d = !1, I = null;
797
797
  const E = () => u.forEach((c) => c()), R = Zt(
@@ -834,10 +834,10 @@ function Ir(e, t = {}) {
834
834
  })));
835
835
  }, T = () => {
836
836
  n.length = 0, r.length = 0, i.length = 0, o = "", a = "neutral", s.length = 0;
837
- }, _ = () => {
837
+ }, g = () => {
838
838
  R.stop(), T(), y("reset"), E();
839
839
  }, x = () => {
840
- _(), e("idle"), E();
840
+ g(), e("idle"), E();
841
841
  }, b = (c, v) => {
842
842
  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(
843
843
  ...Bt(c.sentence_emotions, a)
@@ -935,9 +935,9 @@ function Ir(e, t = {}) {
935
935
  );
936
936
  break;
937
937
  }
938
- }, U = () => w || (g = new kr(), w = new bn({
938
+ }, U = () => w || (_ = new kr(), w = new bn({
939
939
  transport: new Tn({
940
- mediaManager: g,
940
+ mediaManager: _,
941
941
  recorderSampleRate: rn,
942
942
  playerSampleRate: sn
943
943
  }),
@@ -991,11 +991,11 @@ function Ir(e, t = {}) {
991
991
  throw new Error(
992
992
  "Realtime voice is not connected. Call connect() first."
993
993
  );
994
- _(), await w.sendText(L);
994
+ g(), await w.sendText(L);
995
995
  }
996
996
  },
997
997
  stop: () => {
998
- _(), e("idle"), E();
998
+ g(), e("idle"), E();
999
999
  },
1000
1000
  connect: async (c) => {
1001
1001
  if (c && (m = { ...m, ...c }), !m.authToken?.trim())
@@ -1130,11 +1130,9 @@ const qs = [
1130
1130
  "kk",
1131
1131
  "nn"
1132
1132
  ], it = [
1133
- "t01_0.17",
1134
- "t02_0.33",
1135
- "t03_0.50",
1136
- "t04_0.67",
1137
- "t05_0.83"
1133
+ "t01_0.25",
1134
+ "t02_0.50",
1135
+ "t03_0.75"
1138
1136
  ], Or = it.length, Lt = /* @__PURE__ */ new Set([
1139
1137
  "aa__kk",
1140
1138
  "aa__nn",
@@ -1284,7 +1282,7 @@ function ht(e, t) {
1284
1282
  return [];
1285
1283
  }
1286
1284
  function Nr(e) {
1287
- return e < 16 ? [] : e < 35 ? [2] : e < 51 ? [0, 4] : e < 67 ? [0, 2, 4] : e < 83 ? [0, 1, 2, 3] : [0, 1, 2, 3, 4];
1285
+ return e < 16 ? [] : e < 35 ? [1] : e < 51 ? [0, 2] : [0, 1, 2];
1288
1286
  }
1289
1287
  function Vr(e, t) {
1290
1288
  return Nr(t).map((r) => e[r]).filter((r) => r != null);
@@ -1382,10 +1380,10 @@ function Qr(e, t) {
1382
1380
  return n.push(ln(e)), n;
1383
1381
  }
1384
1382
  function Xr(e) {
1385
- return dt(mt(e), "eyes_standard");
1383
+ return e === 0 ? null : dt(mt(e), "eyes_standard");
1386
1384
  }
1387
1385
  function Zr(e, t) {
1388
- return Yr(e, t).map(Xr);
1386
+ return Yr(e, t).map(Xr).filter((n) => n != null);
1389
1387
  }
1390
1388
  const es = 6;
1391
1389
  function ts(e, t) {
@@ -1427,7 +1425,7 @@ function ss(e = {}) {
1427
1425
  postEmotionChangeDelayMs: f = 380,
1428
1426
  minDwellMs: l = 550
1429
1427
  } = e;
1430
- let w = "neutral", g = "neutral", m = 0, S = 0, k = 0, u = {
1428
+ let w = "neutral", _ = "neutral", m = 0, S = 0, k = 0, u = {
1431
1429
  kind: "idle",
1432
1430
  nextBlinkAt: performance.now() + t
1433
1431
  }, p = null, d = "__eyes_open__|neutral|brow:0";
@@ -1436,14 +1434,14 @@ function ss(e = {}) {
1436
1434
  }
1437
1435
  function E(y, T = w) {
1438
1436
  p = y;
1439
- const _ = Vt(y);
1440
- _ != null ? S = _ : y == null && (S = 0), I(T);
1437
+ const g = Vt(y);
1438
+ g != null ? S = g : y == null && (S = 0), I(T);
1441
1439
  }
1442
1440
  function R(y) {
1443
1441
  return un(y);
1444
1442
  }
1445
- function W(y, T, _) {
1446
- const x = ye(T), b = ye(_);
1443
+ function W(y, T, g) {
1444
+ const x = ye(T), b = ye(g);
1447
1445
  if (m = b, x === b) {
1448
1446
  E(R(b));
1449
1447
  return;
@@ -1464,10 +1462,10 @@ function ss(e = {}) {
1464
1462
  u = {
1465
1463
  kind: "idle",
1466
1464
  nextBlinkAt: y + Oe(n, r)
1467
- }, g = T, E(R(m), T);
1465
+ }, _ = T, E(R(m), T);
1468
1466
  }
1469
- function H(y, T, _) {
1470
- const x = _ ? Kr : Math.random() < a ? qr : jr;
1467
+ function H(y, T, g) {
1468
+ const x = g ? Kr : Math.random() < a ? qr : jr;
1471
1469
  u = {
1472
1470
  kind: "playing",
1473
1471
  paths: Qr(T, x),
@@ -1475,7 +1473,7 @@ function ss(e = {}) {
1475
1473
  holdUntil: y + We(),
1476
1474
  after: "idle",
1477
1475
  blinkEmotion: T
1478
- }, g = T, E(u.paths[0] ?? null, T);
1476
+ }, _ = T, E(u.paths[0] ?? null, T);
1479
1477
  }
1480
1478
  function j(y) {
1481
1479
  if (u.kind === "browBlend") {
@@ -1489,7 +1487,7 @@ function ss(e = {}) {
1489
1487
  return;
1490
1488
  }
1491
1489
  if (u.kind === "idle") {
1492
- E(R(m), g), y >= u.nextBlinkAt && H(y, g, !1);
1490
+ E(R(m), _), y >= u.nextBlinkAt && H(y, _, !1);
1493
1491
  return;
1494
1492
  }
1495
1493
  if (u.kind === "doublePause") {
@@ -1529,21 +1527,21 @@ function ss(e = {}) {
1529
1527
  setTargetEmotion(y) {
1530
1528
  const T = ve(y, w);
1531
1529
  if (T === w) return;
1532
- const _ = performance.now();
1533
- l > 0 && T !== w && !(w === "neutral" && T !== "neutral") && _ - k < l || (w = T, g = T, k = _);
1530
+ const g = performance.now();
1531
+ l > 0 && T !== w && !(w === "neutral" && T !== "neutral") && g - k < l || (w = T, _ = T, k = g);
1534
1532
  },
1535
1533
  setTargetEyebrow(y) {
1536
1534
  const T = ye(y);
1537
1535
  if (T === m && u.kind !== "browBlend") return;
1538
- const _ = performance.now(), x = u.kind === "browBlend" ? Vt(p) ?? S : S;
1539
- m = T, !(T === x && u.kind !== "browBlend") && (u.kind === "playing" || u.kind === "doublePause" || W(_, x, T));
1536
+ const g = performance.now(), x = u.kind === "browBlend" ? Vt(p) ?? S : S;
1537
+ m = T, !(T === x && u.kind !== "browBlend") && (u.kind === "playing" || u.kind === "doublePause" || W(g, x, T));
1540
1538
  },
1541
1539
  getTargetEmotion: () => w,
1542
1540
  getTargetEyebrow: () => m,
1543
1541
  getExpressionPath: () => p,
1544
1542
  getDrawKey: () => d,
1545
1543
  reset() {
1546
- w = "neutral", g = "neutral", m = 0, S = 0, k = 0, V(
1544
+ w = "neutral", _ = "neutral", m = 0, S = 0, k = 0, V(
1547
1545
  performance.now() + Oe(n, r),
1548
1546
  "neutral"
1549
1547
  );
@@ -1641,8 +1639,8 @@ function dn(e, t, n, r, s = on) {
1641
1639
  const a = o.getImageData(0, 0, n, r), f = o.createImageData(n, r);
1642
1640
  f.data.set(a.data);
1643
1641
  const w = new OffscreenCanvas(n, r).getContext("2d", { willReadFrequently: !0 });
1644
- for (const g of t) {
1645
- w.clearRect(0, 0, n, r), w.drawImage(g, 0, 0, n, r);
1642
+ for (const _ of t) {
1643
+ w.clearRect(0, 0, n, r), w.drawImage(_, 0, 0, n, r);
1646
1644
  const m = w.getImageData(0, 0, n, r);
1647
1645
  for (let S = 0; S < f.data.length; S += 4) {
1648
1646
  const k = m.data[S], u = m.data[S + 1], p = m.data[S + 2];
@@ -1660,7 +1658,7 @@ Qn(ls);
1660
1658
  function fs(e) {
1661
1659
  return e ?? Fe ?? void 0;
1662
1660
  }
1663
- function _t(e) {
1661
+ function gt(e) {
1664
1662
  return new Promise((t, n) => {
1665
1663
  const r = new Image();
1666
1664
  r.decoding = "async", r.onload = () => t(r), r.onerror = () => n(new Error(`Failed to load image: ${e}`)), r.src = e;
@@ -1669,7 +1667,7 @@ function _t(e) {
1669
1667
  async function ds(e) {
1670
1668
  return Ge() ? Pr(
1671
1669
  await Ye(Mt(), e ?? "")
1672
- ) : _t(Mt());
1670
+ ) : gt(Mt());
1673
1671
  }
1674
1672
  async function $t(e, t, n, r) {
1675
1673
  const s = n ? await xr(e, r) : await fetch(e).then((l) => {
@@ -1682,7 +1680,7 @@ async function $t(e, t, n, r) {
1682
1680
  Hr(t, i.path, n),
1683
1681
  r ?? ""
1684
1682
  )
1685
- ) : await _t(`${t}/${i.path}`), a = /* @__PURE__ */ new Map();
1683
+ ) : await gt(`${t}/${i.path}`), a = /* @__PURE__ */ new Map();
1686
1684
  for (const l of s.cells ?? [])
1687
1685
  l.path && a.set(l.path, l);
1688
1686
  const f = /* @__PURE__ */ new Map();
@@ -1749,12 +1747,12 @@ async function Ht(e, t, n) {
1749
1747
  if (!o) throw new Error(`No atlas cell for path: ${n}`);
1750
1748
  const a = Dr(t.atlasMeta, o), f = Ue(e);
1751
1749
  if (Mr(o)) {
1752
- const g = hs(t, o), m = document.createElement("canvas");
1750
+ const _ = hs(t, o), m = document.createElement("canvas");
1753
1751
  m.width = f.width, m.height = f.height;
1754
1752
  const S = m.getContext("2d");
1755
- return S.fillStyle = "#000", S.fillRect(0, 0, f.width, f.height), S.drawImage(g, a.x, a.y), m;
1753
+ return S.fillStyle = "#000", S.fillRect(0, 0, f.width, f.height), S.drawImage(_, a.x, a.y), m;
1756
1754
  }
1757
- const l = `${t.diffBase}/${n}`, w = await _t(l);
1755
+ const l = `${t.diffBase}/${n}`, w = await gt(l);
1758
1756
  if (w.naturalWidth === f.width && w.naturalHeight === f.height)
1759
1757
  return w;
1760
1758
  throw new Error(`Diff PNG wrong size for ${n}`);
@@ -1777,26 +1775,26 @@ async function Wt(e, t, n, r, s, i) {
1777
1775
  }
1778
1776
  const o = await hn(), a = an(o.viseme.atlasMeta), { width: f, height: l } = Ue(o);
1779
1777
  (e.width !== f || e.height !== l) && (e.width = f, e.height = l);
1780
- const w = [], g = e.getContext("2d");
1781
- if (g.clearRect(0, 0, f, l), t.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
1778
+ const w = [], _ = e.getContext("2d");
1779
+ if (_.clearRect(0, 0, f, l), t.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
1782
1780
  const S = o.sil;
1783
- g.drawImage(S, 0, 0, f, l);
1781
+ _.drawImage(S, 0, 0, f, l);
1784
1782
  return;
1785
1783
  }
1786
1784
  if (w.length === 0) {
1787
- g.drawImage(t, 0, 0, f, l);
1785
+ _.drawImage(t, 0, 0, f, l);
1788
1786
  return;
1789
1787
  }
1790
1788
  const m = dn(t, w, f, l, a);
1791
- g.drawImage(m, 0, 0);
1789
+ _.drawImage(m, 0, 0);
1792
1790
  }
1793
1791
  async function ct(e, t, n) {
1794
1792
  const r = await hn(Fe ?? void 0), s = an(r.viseme.atlasMeta), { width: i, height: o } = Ue(r);
1795
1793
  (e.width !== i || e.height !== o) && (e.width = i, e.height = o);
1796
1794
  const a = [];
1797
1795
  if (t.mouthPath) {
1798
- const w = new Set(r.viseme.cellByPath.keys()), g = Fr(t.mouthPath, w) ?? (w.has(t.mouthPath) ? t.mouthPath : null);
1799
- g && a.push(await Ht(r, r.viseme, g));
1796
+ const w = new Set(r.viseme.cellByPath.keys()), _ = Fr(t.mouthPath, w) ?? (w.has(t.mouthPath) ? t.mouthPath : null);
1797
+ _ && a.push(await Ht(r, r.viseme, _));
1800
1798
  }
1801
1799
  t.expressionPath && r.expression && a.push(
1802
1800
  await Ht(r, r.expression, t.expressionPath)
@@ -1824,7 +1822,7 @@ function ws(e) {
1824
1822
  t.has(n.vtime) || t.set(n.vtime, n);
1825
1823
  return [...t.values()].sort((n, r) => n.vtime - r.vtime);
1826
1824
  }
1827
- function _s(e) {
1825
+ function gs(e) {
1828
1826
  const t = ws(e), n = [];
1829
1827
  for (let r = 0; r < t.length - 1; r++) {
1830
1828
  const s = t[r].viseme, i = t[r + 1].viseme, o = t[r].vtime, a = t[r + 1].vtime;
@@ -1832,7 +1830,7 @@ function _s(e) {
1832
1830
  }
1833
1831
  return n;
1834
1832
  }
1835
- function gs(e, t) {
1833
+ function _s(e, t) {
1836
1834
  let n = null;
1837
1835
  for (const r of e)
1838
1836
  t >= r.fromVtime && t < r.toVtime && (n = r);
@@ -1851,7 +1849,7 @@ function me(e) {
1851
1849
  function vs(e, t) {
1852
1850
  if (t?.transitionCache && t.transitionCache.queueLength === e.length)
1853
1851
  return t.transitionCache.transitions;
1854
- const n = _s(e);
1852
+ const n = gs(e);
1855
1853
  return t && (t.transitionCache = { queueLength: e.length, transitions: n }), n;
1856
1854
  }
1857
1855
  function bs(e) {
@@ -1872,7 +1870,7 @@ function qt(e) {
1872
1870
  function Is(e, t, n, r) {
1873
1871
  if (e.length === 0)
1874
1872
  return { diffPath: null, label: "sil" };
1875
- const s = vs(e, r), i = gs(s, t);
1873
+ const s = vs(e, r), i = _s(s, t);
1876
1874
  if (i) {
1877
1875
  const a = i.toVtime - i.fromVtime, f = ps(i.fromVtime, i.toVtime);
1878
1876
  if (t >= f.transStart && t < i.toVtime) {
@@ -1880,13 +1878,13 @@ function Is(e, t, n, r) {
1880
1878
  n && (l = cn(l, n));
1881
1879
  const w = Vr(l, a);
1882
1880
  if (w.length > 0) {
1883
- const g = $r(
1881
+ const _ = $r(
1884
1882
  t,
1885
1883
  f.transStart,
1886
1884
  i.toVtime,
1887
1885
  w.length
1888
1886
  );
1889
- return { diffPath: w[g] ?? w[w.length - 1], label: `${i.from}→${i.to}` };
1887
+ return { diffPath: w[_] ?? w[w.length - 1], label: `${i.from}→${i.to}` };
1890
1888
  }
1891
1889
  return { diffPath: Ke(i.to), label: i.to };
1892
1890
  }
@@ -1899,11 +1897,11 @@ function wn(e, t) {
1899
1897
  return `${qt(e.mouthPath)}|${n}`;
1900
1898
  }
1901
1899
  function Rs(e, t, n, r, s, i, o, a, f, l) {
1902
- const w = Is(t, n, f, i), g = {
1900
+ const w = Is(t, n, f, i), _ = {
1903
1901
  mouthPath: w.diffPath,
1904
1902
  expressionPath: r
1905
- }, m = wn(g, s);
1906
- m !== i.lastDrawnKey && (a(w.label), o(e, g, m, (S) => {
1903
+ }, m = wn(_, s);
1904
+ m !== i.lastDrawnKey && (a(w.label), o(e, _, m, (S) => {
1907
1905
  S === m && (i.lastDrawnKey = m);
1908
1906
  }));
1909
1907
  }
@@ -1911,11 +1909,11 @@ function Kt(e, t, n, r, s, i, o = null) {
1911
1909
  const a = { mouthPath: null, expressionPath: t }, f = o != null ? `|idle@${Math.round(o * 1e3)}` : "", l = wn(a, n) + f;
1912
1910
  !(o != null) && l === r.lastDrawnKey || (i(
1913
1911
  o != null ? "idle" : "sil"
1914
- ), s(e, a, l, (g) => {
1915
- g === l && (r.lastDrawnKey = l);
1912
+ ), s(e, a, l, (_) => {
1913
+ _ === l && (r.lastDrawnKey = l);
1916
1914
  }));
1917
1915
  }
1918
- function _n(e) {
1916
+ function gn(e) {
1919
1917
  let t = 0, n = null, r = !1, s = !1;
1920
1918
  const i = async () => {
1921
1919
  if (!r) {
@@ -1975,7 +1973,7 @@ function xs(e, t) {
1975
1973
  }
1976
1974
  function zt(e, t) {
1977
1975
  let n = 0, r = null;
1978
- const s = _n(async (i, o) => (await at(), await ct(e, i), s.isLatestSeq(o)));
1976
+ const s = gn(async (i, o) => (await at(), await ct(e, i), s.isLatestSeq(o)));
1979
1977
  return {
1980
1978
  usesWorker: !1,
1981
1979
  async loadAssets(i) {
@@ -2006,7 +2004,7 @@ function zt(e, t) {
2006
2004
  }
2007
2005
  function Cs(e, t, n) {
2008
2006
  let r = null, s = 1, i = 0, o = !1, a = !1, f = null;
2009
- const l = /* @__PURE__ */ new Map(), w = _n(async (p, d, I) => (l.set(d, {
2007
+ const l = /* @__PURE__ */ new Map(), w = gn(async (p, d, I) => (l.set(d, {
2010
2008
  drawKey: I.drawKey,
2011
2009
  onDisplayed: I.onDisplayed
2012
2010
  }), await k(
@@ -2018,7 +2016,7 @@ function Cs(e, t, n) {
2018
2016
  },
2019
2017
  void 0,
2020
2018
  !0
2021
- ), !1)), g = (p) => {
2019
+ ), !1)), _ = (p) => {
2022
2020
  if (p === jt) {
2023
2021
  let E = -1, R;
2024
2022
  for (const [W, V] of l)
@@ -2066,7 +2064,7 @@ function Cs(e, t, n) {
2066
2064
  d.bitmap.close();
2067
2065
  return;
2068
2066
  }
2069
- xs(e, d.bitmap), d.bitmap.close(), E && g(d.generation);
2067
+ xs(e, d.bitmap), d.bitmap.close(), E && _(d.generation);
2070
2068
  return;
2071
2069
  }
2072
2070
  const I = m.get(d.requestId);
@@ -2229,7 +2227,7 @@ const Ks = Sn(function({
2229
2227
  speakingRate: f = ft,
2230
2228
  className: l,
2231
2229
  style: w,
2232
- canvasStyle: g,
2230
+ canvasStyle: _,
2233
2231
  onStatusChange: m,
2234
2232
  onDisplayStatus: S,
2235
2233
  onError: k,
@@ -2239,10 +2237,10 @@ const Ks = Sn(function({
2239
2237
  onBotOutput: I,
2240
2238
  onRealtimeLipsyncDebug: E
2241
2239
  }, R) {
2242
- const W = F(null), V = F(null), H = F(Ss()), j = F(ss()), y = F(0), T = F(0), _ = F(0), x = F(null), b = F(null), D = F(!1), A = F(!1), P = F(!1), B = F("sil"), $ = F(!1), U = F(
2240
+ const W = F(null), V = F(null), H = F(Ss()), j = F(ss()), y = F(0), T = F(0), g = F(0), x = F(null), b = F(null), D = F(!1), A = F(!1), P = F(!1), B = F("sil"), $ = F(!1), U = F(
2243
2241
  null
2244
- ), X = F(!1), [se, Z] = Be("idle"), [ce, J] = Be(null), [c, v] = Be(!1), [L, z] = Be(!1), [ne, Re] = Be({ width: 842, height: 1264 }), G = F(i ?? null), ke = F(null), Y = F(null), De = F(!1), Je = F({ width: 842, height: 1264 }), Qe = F(null), gt = F(u), ee = F(S), pt = F(k), yt = F(d), Et = F(I), kt = F(E);
2245
- gt.current = u, ee.current = S, pt.current = k, yt.current = d, Et.current = I, kt.current = E;
2242
+ ), X = F(!1), [se, Z] = Be("idle"), [ce, J] = Be(null), [c, v] = Be(!1), [L, z] = Be(!1), [ne, Re] = Be({ width: 842, height: 1264 }), G = F(i ?? null), ke = F(null), Y = F(null), De = F(!1), Je = F({ width: 842, height: 1264 }), Qe = F(null), _t = F(u), ee = F(S), pt = F(k), yt = F(d), Et = F(I), kt = F(E);
2243
+ _t.current = u, ee.current = S, pt.current = k, yt.current = d, Et.current = I, kt.current = E;
2246
2244
  const St = oe(
2247
2245
  (h) => {
2248
2246
  const M = h?.ttsEngineId ?? o ?? Y.current?.ttsEngineId ?? Te, C = h?.voiceId ?? a ?? Y.current?.voiceId ?? Le(M);
@@ -2412,12 +2410,12 @@ const Ks = Sn(function({
2412
2410
  const h = a ?? Le(o);
2413
2411
  Y.current && (Y.current.voiceId = h);
2414
2412
  }, [a, o]);
2415
- const _e = It(
2413
+ const ge = It(
2416
2414
  () => zn(n, r),
2417
2415
  [n, r]
2418
- ), gn = It(() => s ? JSON.stringify(s) : _e ? `face:${_e}` : `id:${t ?? ""}`, [s, _e, t]);
2416
+ ), _n = It(() => s ? JSON.stringify(s) : ge ? `face:${ge}` : `id:${t ?? ""}`, [s, ge, t]);
2419
2417
  return Se(() => {
2420
- if (!t && !s && !_e) {
2418
+ if (!t && !s && !ge) {
2421
2419
  fe("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");
2422
2420
  return;
2423
2421
  }
@@ -2431,8 +2429,8 @@ const Ks = Sn(function({
2431
2429
  let O, N, te;
2432
2430
  if (s)
2433
2431
  O = s, N = o, te = a ?? Le(N);
2434
- else if (_e)
2435
- ee.current?.("loadFace"), O = Dt(_e), N = o, te = a ?? Le(N);
2432
+ else if (ge)
2433
+ ee.current?.("loadFace"), O = Dt(ge), N = o, te = a ?? Le(N);
2436
2434
  else {
2437
2435
  ee.current?.("getAiTwin");
2438
2436
  const Q = await tt(
@@ -2469,7 +2467,7 @@ const Ks = Sn(function({
2469
2467
  "load face assets"
2470
2468
  );
2471
2469
  if (!h && le.width > 0 && le.height > 0 && (Je.current = le, Re(le)), h) return;
2472
- Qe.current = C.getVisemeAtlasPaths(), De.current = !0, v(!0), gt.current?.(), C.renderSilOnly().then(() => {
2470
+ Qe.current = C.getVisemeAtlasPaths(), De.current = !0, v(!0), _t.current?.(), C.renderSilOnly().then(() => {
2473
2471
  h || ee.current?.("sil");
2474
2472
  }), (async () => {
2475
2473
  try {
@@ -2500,7 +2498,7 @@ const Ks = Sn(function({
2500
2498
  })(), () => {
2501
2499
  h = !0, U.current?.dispose(), C?.dispose(), V.current = null;
2502
2500
  };
2503
- }, [gn, s, _e, t, o, a, i, Tt, fe]), Se(() => {
2501
+ }, [_n, s, ge, t, o, a, i, Tt, fe]), Se(() => {
2504
2502
  const h = { current: !1 }, M = () => {
2505
2503
  const C = W.current, O = V.current, N = we(
2506
2504
  q.current,
@@ -2511,12 +2509,12 @@ const Ks = Sn(function({
2511
2509
  return;
2512
2510
  }
2513
2511
  const te = N.isSpeaking(), ae = te && !$.current, de = $.current && !te;
2514
- ae && (ie(), ue(), D.current = !1, A.current = !1, me(H.current), _.current = 0, B.current = "sil", U.current?.setActive(!1)), de && (j.current.reset(), U.current?.setActive(!1), xe());
2512
+ ae && (ie(), ue(), D.current = !1, A.current = !1, me(H.current), g.current = 0, B.current = "sil", U.current?.setActive(!1)), de && (j.current.reset(), U.current?.setActive(!1), xe());
2515
2513
  const le = N.getPlaybackElapsedMs(), Q = de || D.current || P.current;
2516
2514
  if (te) {
2517
2515
  X.current && U.current?.setActive(!1);
2518
- const re = N.getVisemeQueue(), ge = re.length > 0 ? lt(re, le) : "sil";
2519
- ge !== "sil" && (B.current = ge);
2516
+ const re = N.getVisemeQueue(), _e = re.length > 0 ? lt(re, le) : "sil";
2517
+ _e !== "sil" && (B.current = _e);
2520
2518
  const he = us(
2521
2519
  le,
2522
2520
  N.getSentenceEmotions(),
@@ -2543,10 +2541,10 @@ const Ks = Sn(function({
2543
2541
  Qe.current
2544
2542
  );
2545
2543
  } else if (!Q && X.current && U.current) {
2546
- const re = U.current, ge = re.getVideo();
2547
- ge.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA ? (re.setActive(!0), h.current || (h.current = !0, Wt(
2544
+ const re = U.current, _e = re.getVideo();
2545
+ _e.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA ? (re.setActive(!0), h.current || (h.current = !0, Wt(
2548
2546
  C,
2549
- ge,
2547
+ _e,
2550
2548
  null,
2551
2549
  void 0,
2552
2550
  Je.current,
@@ -2566,7 +2564,7 @@ const Ks = Sn(function({
2566
2564
  null,
2567
2565
  "__sil__",
2568
2566
  H.current,
2569
- (re, ge, he, Ce) => O.drawLiveFrame(re, ge, he, Ce),
2567
+ (re, _e, he, Ce) => O.drawLiveFrame(re, _e, he, Ce),
2570
2568
  (re) => ee.current?.(re)
2571
2569
  );
2572
2570
  $.current = te, y.current = requestAnimationFrame(M);
@@ -2664,7 +2662,7 @@ const Ks = Sn(function({
2664
2662
  ref: W,
2665
2663
  width: ne.width,
2666
2664
  height: ne.height,
2667
- style: { ...Os, ...g },
2665
+ style: { ...Os, ..._ },
2668
2666
  "aria-label": t ? `AI twin ${t}` : "AI twin face"
2669
2667
  }
2670
2668
  ),
@@ -0,0 +1 @@
1
+ (function(){"use strict";function et(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function nt(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 rt(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}function k(e){return e.includes("/custom-faces/")}function z(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||k(t)||k(n)))return{twinBase:n,binBase:t,encrypted:!1};const s=k(t)?t:k(n)?n:t;return{twinBase:s,binBase:s,encrypted:!0}}function m(e){return z(e).encrypted}function st(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 P(e){return Uint8Array.from(e)}function at(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function ot(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=P(n.subarray(0,12)),s=P(n.subarray(12,28)),a=P(n.subarray(28)),o=P(at(a,s)),l=await crypto.subtle.importKey("raw",st(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},l,o)}async function O(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 ot(r,t)}async function it(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await O(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function ct(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function lt(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}const W=5;function K(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:W}const T=["t01_0.25","t02_0.50","t03_0.75"],_t=T.length,J=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 G(e,t){return`${e}__${t}`}function j(e,t){return`pairs/${e}/${t}_minus_sil.png`}function $(e){return`${e}_minus_sil.png`}function ft(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=$(r);return t.has(s)?s:null}function ut(e,t){return e.filter(n=>t.has(n))}function dt(e,t){if(e===t)return[];const n=[],r=G(e,t);if(J.has(r)){for(const a of T)n.push(j(r,a));return n}const s=G(t,e);if(J.has(s)){for(let a=_t-1;a>=0;a--)n.push(j(s,T[a]));return n}return[]}function wt(e){return e<16?[]:e<35?[1]:e<51?[0,2]:[0,1,2]}function ht(e,t){return wt(t).map(r=>e[r]).filter(r=>r!=null)}function pt(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`}function yt(e,t,n,r,s=W){const a=new OffscreenCanvas(n,r),o=a.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const l=o.getImageData(0,0,n,r),i=o.createImageData(n,r);i.data.set(l.data);const u=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const w of t){u.clearRect(0,0,n,r),u.drawImage(w,0,0,n,r);const _=u.getImageData(0,0,n,r);for(let f=0;f<i.data.length;f+=4){const y=_.data[f],F=_.data[f+1],x=_.data[f+2];Math.max(y,F,x)>s&&(i.data[f]=y,i.data[f+1]=F,i.data[f+2]=x,i.data[f+3]=255)}}return o.putImageData(i,0,0),a}const Q=-1;function mt(e){return e<0}let g=0,X=Promise.resolve(),D=!1;function v(e){const t=X.then(e);return X=t.then(()=>{},()=>{}),t}function I(e,t){const n=t>0?-t:Q,r={type:"renderDone",requestId:e,generation:n};self.postMessage(r)}async function gt(e){const t=typeof e.liveSeq=="number"?e.liveSeq:0;if(D){I(e.requestId,t);return}if(t>0&&(g=t),!d)throw new Error("Worker not initialized");if(t>0&&t!==g){I(e.requestId,t);return}if(await S(p??void 0),t>0&&t!==g){I(e.requestId,t);return}if(await tt(d,e.diffPath,e.expressionDiffPath??null,e.threshold),t>0&&t!==g){I(e.requestId,t);return}const n=t>0?-t:Q;await U(n),I(e.requestId,t)}let d=null,E=null,p=null,q=null,A="sil";const B=new Map;function b(){if(!q)throw new Error("Worker assets not configured");return q}function Y(){const e=b();return m(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Dt(){const e=b();return m(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function It(){const e=b();return m(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function Et(){const e=b();return m(e)?e.binBase:e.twinBase}function M(){return m(b())}async function H(e){const t=await fetch(e);if(!t.ok)throw new Error(`Failed to load image: ${e}`);const n=await t.blob();return createImageBitmap(n)}async function bt(e){return M()?lt(await O(Y(),e??"")):H(Y())}async function Z(e,t,n){const r=M(),s=r?await it(e,n):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),a=s.sheets?.[0];if(!a?.path)throw new Error(`${e} has no sheets[0].path`);const o=r?await ct(await O(pt(t,a.path,r),n??"")):await H(`${t}/${a.path}`),l=new Map;for(const c of s.cells??[])c.path&&l.set(c.path,c);const i=new Map;for(const c of s.sheets??[])i.set(c.index,c);return{atlas:o,atlasMeta:s,cellByPath:l,sheetByIndex:i,diffBase:t}}async function S(e){if(M()&&!e)throw new Error("Encrypted assets enabled but no key provided");if(E&&(!M()||p===(e??null)))return E;p=e??null,B.clear();const t=Et();return E=(async()=>{const n=await bt(e),r=await Z(Dt(),t,e);let s=null;try{s=await Z(It(),t,e)}catch{s=null}return{sil:n,viseme:r,expression:s}})(),E}function R(e){return et(e.viseme.atlasMeta,e.sil.width,e.sil.height)}function St(e,t){if(!e.sheetByIndex.get(t.sheet??0))throw new Error(`Unknown sheet index: ${t.sheet}`);const r=new OffscreenCanvas(t.w,t.h);return r.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}async function Ft(e){return createImageBitmap(e)}async function V(e,t,n){const r=`${t.diffBase}::${n}`,s=B.get(r);if(s)return s;const a=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const l=nt(t.atlasMeta,o),i=R(e);if(rt(o)){const w=St(t,o),_=new OffscreenCanvas(i.width,i.height),f=_.getContext("2d");return f.fillStyle="#000",f.fillRect(0,0,i.width,i.height),f.drawImage(w,l.x,l.y),Ft(_)}const c=`${t.diffBase}/${n}`,u=await H(c);if(u.width===i.width&&u.height===i.height)return u;throw u.close(),new Error(`Diff PNG wrong size for ${n}`)})();return B.set(r,a),a}function C(e,t){const n={type:"status",label:e,generation:t};self.postMessage(n)}function kt(e,t){const n={type:"error",requestId:e,message:t};self.postMessage(n)}async function U(e){if(!d)return;const t=mt(e);if(!t&&e!==h)return;const n=await createImageBitmap(d);if(!t&&e!==h){n.close();return}const r={type:"frame",bitmap:n,generation:e};self.postMessage(r,{transfer:[n]})}function Pt(e,t,n){return new Promise((r,s)=>{setTimeout(()=>{t!==n?s(new DOMException("Aborted","AbortError")):r()},e)})}async function tt(e,t,n,r){const s=await S(p??void 0),a=r??K(s.viseme.atlasMeta),{width:o,height:l}=R(s);(e.width!==o||e.height!==l)&&(e.width=o,e.height=l);const i=[];if(t){const w=new Set(s.viseme.cellByPath.keys()),_=ft(t,w)??(w.has(t)?t:null);_&&i.push(await V(s,s.viseme,_))}n&&s.expression&&s.expression.cellByPath.get(n)&&i.push(await V(s,s.expression,n));const c=e.getContext("2d");if(c.clearRect(0,0,o,l),i.length===0){c.drawImage(s.sil,0,0,o,l);return}const u=yt(s.sil,i,o,l,a);c.drawImage(u,0,0)}async function N(e,t,n,r,s){await tt(e,t,n,s),await U(r)}async function L(e,t,n){A="sil";const r=await S(p??void 0);if(t!==n)throw new DOMException("Aborted","AbortError");const{width:s,height:a}=R(r);e.width=s,e.height=a;const o=e.getContext("2d");o.clearRect(0,0,s,a),o.drawImage(r.sil,0,0,s,a),await U(t)}async function At(e,t,n,r,s={}){const a=s.from??A,o=s.transitionDurationMs??400,l=s.gapMs??o,i=await S(p??void 0),c=s.threshold??K(i.viseme.atlasMeta);if(a===t){if(C(t,n),t==="sil"?await L(e,n,r):await N(e,$(t),null,n,c),n!==r)throw new DOMException("Aborted","AbortError");A=t;return}const u=dt(a,t),w=new Set(i.viseme.cellByPath.keys());let _=ht(u,l);_=ut(_,w);const f=_.length>0?o/_.length:0;_.length===0&&C(`${a} → ${t} (no pair; final only)`,n);for(let y=0;y<_.length;y++){if(n!==r)throw new DOMException("Aborted","AbortError");const F=_[y],x=F.split("/").pop()?.replace("_minus_sil.png","")??`frame ${y}`;if(C(`${a} → ${t} (${x})`,n),await N(e,F,null,n,c),n!==r)throw new DOMException("Aborted","AbortError");f>0&&await Pt(f,n,r)}if(n!==r)throw new DOMException("Aborted","AbortError");if(C(t,n),t==="sil"?await L(e,n,r):await N(e,$(t),null,n,c),n!==r)throw new DOMException("Aborted","AbortError");A=t}let h=0;self.onmessage=e=>{const t=e.data;(async()=>{try{switch(t.type){case"init":{d=new OffscreenCanvas(1,1);const n={type:"ready",requestId:t.requestId};self.postMessage(n);break}case"loadAssets":{q=z(t.urls),E=null,p=null,B.clear();const n=await S(t.keyHex),{width:r,height:s}=R(n),a={type:"loadAssetsDone",requestId:t.requestId,width:r,height:s,visemePaths:[...n.viseme.cellByPath.keys()]};self.postMessage(a);break}case"cancelLiveDraws":{g+=1;const n={type:"renderDone",requestId:t.requestId,generation:h};self.postMessage(n);break}case"drawFrame":{await v(()=>gt(t));break}case"renderSil":{await v(async()=>{D=!0;try{if(h=t.generation,!d)throw new Error("Worker not initialized");await L(d,t.generation,h)}finally{D=!1}});const n={type:"renderDone",requestId:t.requestId,generation:t.generation};self.postMessage(n);break}case"renderViseme":{await v(async()=>{D=!0;try{if(h=t.generation,!d)throw new Error("Worker not initialized");await At(d,t.to,t.generation,h,{from:t.from,transitionDurationMs:t.transitionDurationMs,gapMs:t.gapMs,threshold:t.threshold})}finally{D=!1}});const n={type:"renderDone",requestId:t.requestId,generation:t.generation};self.postMessage(n);break}default:break}}catch(n){if(n instanceof DOMException&&n.name==="AbortError"){const r={type:"renderAborted",requestId:t.requestId,generation:"generation"in t?t.generation:h};self.postMessage(r);return}kt(t.requestId,n instanceof Error?n.message:String(n))}})()}})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoji/aitwin",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Embeddable React AI twin face with TTS lipsync",
5
5
  "type": "module",
6
6
  "main": "./dist/aitwin.cjs",
@@ -1 +0,0 @@
1
- (function(){"use strict";function et(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function nt(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 rt(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}function k(e){return e.includes("/custom-faces/")}function z(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||k(t)||k(n)))return{twinBase:n,binBase:t,encrypted:!1};const s=k(t)?t:k(n)?n:t;return{twinBase:s,binBase:s,encrypted:!0}}function m(e){return z(e).encrypted}function st(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 P(e){return Uint8Array.from(e)}function at(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function ot(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=P(n.subarray(0,12)),s=P(n.subarray(12,28)),a=P(n.subarray(28)),o=P(at(a,s)),l=await crypto.subtle.importKey("raw",st(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},l,o)}async function T(e,t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const r=await n.arrayBuffer();return ot(r,t)}async function it(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await T(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function ct(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function lt(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}const W=5;function K(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:W}const x=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],_t=x.length,J=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 G(e,t){return`${e}__${t}`}function j(e,t){return`pairs/${e}/${t}_minus_sil.png`}function $(e){return`${e}_minus_sil.png`}function ft(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=$(r);return t.has(s)?s:null}function ut(e,t){return e.filter(n=>t.has(n))}function dt(e,t){if(e===t)return[];const n=[],r=G(e,t);if(J.has(r)){for(const a of x)n.push(j(r,a));return n}const s=G(t,e);if(J.has(s)){for(let a=_t-1;a>=0;a--)n.push(j(s,x[a]));return n}return[]}function wt(e){return e<16?[]:e<35?[2]:e<51?[0,4]:e<67?[0,2,4]:e<83?[0,1,2,3]:[0,1,2,3,4]}function ht(e,t){return wt(t).map(r=>e[r]).filter(r=>r!=null)}function pt(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`}function yt(e,t,n,r,s=W){const a=new OffscreenCanvas(n,r),o=a.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const l=o.getImageData(0,0,n,r),i=o.createImageData(n,r);i.data.set(l.data);const u=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const h of t){u.clearRect(0,0,n,r),u.drawImage(h,0,0,n,r);const _=u.getImageData(0,0,n,r);for(let f=0;f<i.data.length;f+=4){const y=_.data[f],F=_.data[f+1],O=_.data[f+2];Math.max(y,F,O)>s&&(i.data[f]=y,i.data[f+1]=F,i.data[f+2]=O,i.data[f+3]=255)}}return o.putImageData(i,0,0),a}const Q=-1;function mt(e){return e<0}let g=0,X=Promise.resolve(),D=!1;function v(e){const t=X.then(e);return X=t.then(()=>{},()=>{}),t}function I(e,t){const n=t>0?-t:Q,r={type:"renderDone",requestId:e,generation:n};self.postMessage(r)}async function gt(e){const t=typeof e.liveSeq=="number"?e.liveSeq:0;if(D){I(e.requestId,t);return}if(t>0&&(g=t),!d)throw new Error("Worker not initialized");if(t>0&&t!==g){I(e.requestId,t);return}if(await S(p??void 0),t>0&&t!==g){I(e.requestId,t);return}if(await tt(d,e.diffPath,e.expressionDiffPath??null,e.threshold),t>0&&t!==g){I(e.requestId,t);return}const n=t>0?-t:Q;await U(n),I(e.requestId,t)}let d=null,E=null,p=null,q=null,A="sil";const B=new Map;function b(){if(!q)throw new Error("Worker assets not configured");return q}function Y(){const e=b();return m(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Dt(){const e=b();return m(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function It(){const e=b();return m(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function Et(){const e=b();return m(e)?e.binBase:e.twinBase}function R(){return m(b())}async function H(e){const t=await fetch(e);if(!t.ok)throw new Error(`Failed to load image: ${e}`);const n=await t.blob();return createImageBitmap(n)}async function bt(e){return R()?lt(await T(Y(),e??"")):H(Y())}async function Z(e,t,n){const r=R(),s=r?await it(e,n):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),a=s.sheets?.[0];if(!a?.path)throw new Error(`${e} has no sheets[0].path`);const o=r?await ct(await T(pt(t,a.path,r),n??"")):await H(`${t}/${a.path}`),l=new Map;for(const c of s.cells??[])c.path&&l.set(c.path,c);const i=new Map;for(const c of s.sheets??[])i.set(c.index,c);return{atlas:o,atlasMeta:s,cellByPath:l,sheetByIndex:i,diffBase:t}}async function S(e){if(R()&&!e)throw new Error("Encrypted assets enabled but no key provided");if(E&&(!R()||p===(e??null)))return E;p=e??null,B.clear();const t=Et();return E=(async()=>{const n=await bt(e),r=await Z(Dt(),t,e);let s=null;try{s=await Z(It(),t,e)}catch{s=null}return{sil:n,viseme:r,expression:s}})(),E}function M(e){return et(e.viseme.atlasMeta,e.sil.width,e.sil.height)}function St(e,t){if(!e.sheetByIndex.get(t.sheet??0))throw new Error(`Unknown sheet index: ${t.sheet}`);const r=new OffscreenCanvas(t.w,t.h);return r.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}async function Ft(e){return createImageBitmap(e)}async function V(e,t,n){const r=`${t.diffBase}::${n}`,s=B.get(r);if(s)return s;const a=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const l=nt(t.atlasMeta,o),i=M(e);if(rt(o)){const h=St(t,o),_=new OffscreenCanvas(i.width,i.height),f=_.getContext("2d");return f.fillStyle="#000",f.fillRect(0,0,i.width,i.height),f.drawImage(h,l.x,l.y),Ft(_)}const c=`${t.diffBase}/${n}`,u=await H(c);if(u.width===i.width&&u.height===i.height)return u;throw u.close(),new Error(`Diff PNG wrong size for ${n}`)})();return B.set(r,a),a}function C(e,t){const n={type:"status",label:e,generation:t};self.postMessage(n)}function kt(e,t){const n={type:"error",requestId:e,message:t};self.postMessage(n)}async function U(e){if(!d)return;const t=mt(e);if(!t&&e!==w)return;const n=await createImageBitmap(d);if(!t&&e!==w){n.close();return}const r={type:"frame",bitmap:n,generation:e};self.postMessage(r,{transfer:[n]})}function Pt(e,t,n){return new Promise((r,s)=>{setTimeout(()=>{t!==n?s(new DOMException("Aborted","AbortError")):r()},e)})}async function tt(e,t,n,r){const s=await S(p??void 0),a=r??K(s.viseme.atlasMeta),{width:o,height:l}=M(s);(e.width!==o||e.height!==l)&&(e.width=o,e.height=l);const i=[];if(t){const h=new Set(s.viseme.cellByPath.keys()),_=ft(t,h)??(h.has(t)?t:null);_&&i.push(await V(s,s.viseme,_))}if(n&&s.expression){if(!s.expression.cellByPath.get(n))throw new Error(`No expression atlas cell for path: ${n}`);i.push(await V(s,s.expression,n))}const c=e.getContext("2d");if(c.clearRect(0,0,o,l),i.length===0){c.drawImage(s.sil,0,0,o,l);return}const u=yt(s.sil,i,o,l,a);c.drawImage(u,0,0)}async function N(e,t,n,r,s){await tt(e,t,n,s),await U(r)}async function L(e,t,n){A="sil";const r=await S(p??void 0);if(t!==n)throw new DOMException("Aborted","AbortError");const{width:s,height:a}=M(r);e.width=s,e.height=a;const o=e.getContext("2d");o.clearRect(0,0,s,a),o.drawImage(r.sil,0,0,s,a),await U(t)}async function At(e,t,n,r,s={}){const a=s.from??A,o=s.transitionDurationMs??400,l=s.gapMs??o,i=await S(p??void 0),c=s.threshold??K(i.viseme.atlasMeta);if(a===t){if(C(t,n),t==="sil"?await L(e,n,r):await N(e,$(t),null,n,c),n!==r)throw new DOMException("Aborted","AbortError");A=t;return}const u=dt(a,t),h=new Set(i.viseme.cellByPath.keys());let _=ht(u,l);_=ut(_,h);const f=_.length>0?o/_.length:0;_.length===0&&C(`${a} → ${t} (no pair; final only)`,n);for(let y=0;y<_.length;y++){if(n!==r)throw new DOMException("Aborted","AbortError");const F=_[y],O=F.split("/").pop()?.replace("_minus_sil.png","")??`frame ${y}`;if(C(`${a} → ${t} (${O})`,n),await N(e,F,null,n,c),n!==r)throw new DOMException("Aborted","AbortError");f>0&&await Pt(f,n,r)}if(n!==r)throw new DOMException("Aborted","AbortError");if(C(t,n),t==="sil"?await L(e,n,r):await N(e,$(t),null,n,c),n!==r)throw new DOMException("Aborted","AbortError");A=t}let w=0;self.onmessage=e=>{const t=e.data;(async()=>{try{switch(t.type){case"init":{d=new OffscreenCanvas(1,1);const n={type:"ready",requestId:t.requestId};self.postMessage(n);break}case"loadAssets":{q=z(t.urls),E=null,p=null,B.clear();const n=await S(t.keyHex),{width:r,height:s}=M(n),a={type:"loadAssetsDone",requestId:t.requestId,width:r,height:s,visemePaths:[...n.viseme.cellByPath.keys()]};self.postMessage(a);break}case"cancelLiveDraws":{g+=1;const n={type:"renderDone",requestId:t.requestId,generation:w};self.postMessage(n);break}case"drawFrame":{await v(()=>gt(t));break}case"renderSil":{await v(async()=>{D=!0;try{if(w=t.generation,!d)throw new Error("Worker not initialized");await L(d,t.generation,w)}finally{D=!1}});const n={type:"renderDone",requestId:t.requestId,generation:t.generation};self.postMessage(n);break}case"renderViseme":{await v(async()=>{D=!0;try{if(w=t.generation,!d)throw new Error("Worker not initialized");await At(d,t.to,t.generation,w,{from:t.from,transitionDurationMs:t.transitionDurationMs,gapMs:t.gapMs,threshold:t.threshold})}finally{D=!1}});const n={type:"renderDone",requestId:t.requestId,generation:t.generation};self.postMessage(n);break}default:break}}catch(n){if(n instanceof DOMException&&n.name==="AbortError"){const r={type:"renderAborted",requestId:t.requestId,generation:"generation"in t?t.generation:w};self.postMessage(r);return}kt(t.requestId,n instanceof Error?n.message:String(n))}})()}})();