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