@streamoji/aitwin 0.2.9 → 0.3.0

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