@streamoji/aitwin 0.6.4 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/aitwin.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("react/jsx-runtime"),h=require("react"),us=require("@pipecat-ai/client-js"),Hn=require("@pipecat-ai/websocket-transport"),we=require("pixi.js");var xn=typeof document<"u"?document.currentScript:null;const ds="https://aitwin.bubu.social",ri={publicBase:ds},fs="0.6.4",ms={version:fs},hs={},ht="https://ai.aitwin.me",$n=`${ri.publicBase}/custom-faces`,gs=`${ri.publicBase}/aitwin-workers/v${ms.version}/visemeDiffPreview.worker.js`;function ws(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:xn&&xn.tagName.toUpperCase()==="SCRIPT"&&xn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?hs?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():gs}const ps="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",In=3e3,Ot=16,Er=3e3,ys=4e3,vs=.85,_s=8,jn=400,Kn="eng_a7f2b9c1",un="eng_d4e8f3a2",tt="eng_c9b1e6d4",nt="visemetts",dt=tt,dn="eve",ii=new Set([un,tt,nt]),Gn={[Kn]:"oculus_direct",[tt]:"oculus_direct",[nt]:"oculus_direct",[un]:"inworld_word"},Dn={google:Kn,inworld:un,cartesia:tt,visemetts:nt};function bs(e){const t=e.trim();if(t)return t in Gn?t:Dn[t.toLowerCase()]}function si(e){const t=e?.trim();if(!t)return{};const n=t.indexOf(":");if(n<=0)return{voiceId:t};const r=bs(t.slice(0,n));if(!r)return{voiceId:t};const i=t.slice(n+1).trim();return{ttsEngineId:r,voiceId:i||void 0}}function et(e,t){const n=si(t);return{ttsEngineId:e??n.ttsEngineId,voiceId:n.voiceId}}function ai(e){return Gn[e]}function Ss(e){return e===tt}function oi(e){return e===nt}function Ts(e){if(e.ttsEngineId&&e.ttsEngineId in Gn)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Dn?Dn[t]:dt}class nn extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}function qn(e,...t){const n=typeof e=="string"?e:e?.brainId?.trim()||e?.knowledgeContextId?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}async function ci(e,t=ps){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new nn;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new nn(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,u=String(a.authToken??o??"").trim()||void 0,d=qn(a);return{...a,ttsEngineId:Ts(i.data),authToken:u,brainId:d,knowledgeContextId:d}}const Yn="thumbnail.webp";function li(e,t=$n){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Yn}`}function xr(e){const t=e?.trim();if(!t)return null;try{return li(t)}catch{return null}}function ks(e){if(!e)return null;const t=(e.binBase||e.twinBase).trim().replace(/\/$/,"");return t?`${t}/${Yn}`:null}const Es="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",xs="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Is="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",As="6TNvp3SCs4Og0a1ijm9TommXLql1",Ms="Swaraj Mali";async function Nt(){const e=await fetch(Es,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":xs,"Client-Secret":Is},body:JSON.stringify({userId:As,userName:Ms})});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 Ps(e,t=ht){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 Cs(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 Xt(e){return Uint8Array.from(e)}function Rs(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Ds(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=Xt(n.subarray(0,12)),i=Xt(n.subarray(12,28)),s=Xt(n.subarray(28)),o=Xt(Rs(s,i)),a=await crypto.subtle.importKey("raw",Cs(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let Bn=null;const Fn=new Set;function Jt(e){return e.includes("/custom-faces/")}function rn(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||Jt(t)||Jt(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=Jt(t)?t:Jt(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function gt(e){return rn(e).encrypted}function Ln(e,t=$n){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function ui(e,t){return(e??t)?.trim()||void 0}function di(e){Bn=rn(e);for(const t of Fn)t()}function Bs(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return rn(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return rn({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function wt(){if(!Bn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Bn}function fi(e){return Fn.add(e),()=>Fn.delete(e)}function sn(){const e=wt();return gt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Fs(){const e=wt();return gt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function mi(){const e=wt();return gt(e)?e.binBase:e.twinBase}function Wt(){return gt(wt())}function hi(){const e=wt();return gt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function gi(){const e=wt();return gt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}const ft=[{code:"en",label:"English",visemetts:!0,cartesia:!0},{code:"es",label:"Spanish",visemetts:!0,cartesia:!0},{code:"es-MX",label:"Spanish (Mexico)",visemetts:!0,cartesia:!0},{code:"es-ES",label:"Spanish (Spain)",visemetts:!0,cartesia:!0},{code:"pt",label:"Portuguese",visemetts:!0,cartesia:!0},{code:"pt-BR",label:"Portuguese (Brazil)",visemetts:!0,cartesia:!0},{code:"pt-PT",label:"Portuguese (Portugal)",visemetts:!0,cartesia:!0},{code:"fr",label:"French",visemetts:!0,cartesia:!0},{code:"de",label:"German",visemetts:!0,cartesia:!0},{code:"it",label:"Italian",visemetts:!0,cartesia:!0},{code:"zh",label:"Chinese",visemetts:!0,cartesia:!0},{code:"ja",label:"Japanese",visemetts:!0,cartesia:!0},{code:"hi",label:"Hindi",visemetts:!0,cartesia:!0},{code:"ko",label:"Korean",visemetts:!0,cartesia:!0},{code:"ru",label:"Russian",visemetts:!0,cartesia:!0},{code:"tr",label:"Turkish",visemetts:!0,cartesia:!0},{code:"id",label:"Indonesian",visemetts:!0,cartesia:!0},{code:"ar",label:"Arabic",visemetts:!0,cartesia:!0},{code:"ar-EG",label:"Arabic (Egypt)",visemetts:!0,cartesia:!0},{code:"ar-AE",label:"Arabic (UAE)",visemetts:!0,cartesia:!0},{code:"vi",label:"Vietnamese",visemetts:!0,cartesia:!0},{code:"bn",label:"Bengali",visemetts:!0,cartesia:!0},{code:"auto",label:"Auto-detect",visemetts:!0,cartesia:!1},{code:"nl",label:"Dutch",visemetts:!1,cartesia:!0},{code:"pl",label:"Polish",visemetts:!1,cartesia:!0},{code:"sv",label:"Swedish",visemetts:!1,cartesia:!0},{code:"tl",label:"Tagalog",visemetts:!1,cartesia:!0},{code:"bg",label:"Bulgarian",visemetts:!1,cartesia:!0},{code:"ro",label:"Romanian",visemetts:!1,cartesia:!0},{code:"cs",label:"Czech",visemetts:!1,cartesia:!0},{code:"el",label:"Greek",visemetts:!1,cartesia:!0},{code:"fi",label:"Finnish",visemetts:!1,cartesia:!0},{code:"hr",label:"Croatian",visemetts:!1,cartesia:!0},{code:"ms",label:"Malay",visemetts:!1,cartesia:!0},{code:"sk",label:"Slovak",visemetts:!1,cartesia:!0},{code:"da",label:"Danish",visemetts:!1,cartesia:!0},{code:"ta",label:"Tamil",visemetts:!1,cartesia:!0},{code:"uk",label:"Ukrainian",visemetts:!1,cartesia:!0},{code:"hu",label:"Hungarian",visemetts:!1,cartesia:!0},{code:"no",label:"Norwegian",visemetts:!1,cartesia:!0},{code:"th",label:"Thai",visemetts:!1,cartesia:!0},{code:"he",label:"Hebrew",visemetts:!1,cartesia:!0},{code:"ka",label:"Georgian",visemetts:!1,cartesia:!0},{code:"te",label:"Telugu",visemetts:!1,cartesia:!0},{code:"gu",label:"Gujarati",visemetts:!1,cartesia:!0},{code:"kn",label:"Kannada",visemetts:!1,cartesia:!0},{code:"ml",label:"Malayalam",visemetts:!1,cartesia:!0},{code:"mr",label:"Marathi",visemetts:!1,cartesia:!0},{code:"pa",label:"Punjabi",visemetts:!1,cartesia:!0}],wi=ft.map(e=>e.code),Ls=new Set(wi),Os=new Set(ft.filter(e=>e.visemetts).map(e=>e.code)),Ns=new Set(ft.filter(e=>e.cartesia).map(e=>e.code)),Vs="en";function pi(e){return Ls.has(e)}function fn(e){const t=e?.trim();if(t)return t}function Us(e){return e===nt?ft.filter(t=>t.visemetts).map(t=>t.code):e===tt?ft.filter(t=>t.cartesia).map(t=>t.code):ft.filter(t=>t.visemetts&&t.cartesia).map(t=>t.code)}function Ws(e,t){const n=t.trim();return n?e===nt?Os.has(n):e===tt?Ns.has(n):pi(n):!1}function yi(e){const t=e.split(/\r?\n/);let n="",r="";for(const s of t)s.startsWith("event:")?n=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());if(!n)return null;let i={};if(r)try{i=JSON.parse(r)}catch{i={raw:r}}return{event:n,data:i}}const vi=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],zs=new Map(vi.map(e=>[e.toLowerCase(),e]));function mn(e){const t=(e??"").trim();return t?zs.get(t.toLowerCase())??"sil":"sil"}const Hs={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 $s(e){if(!e)return["sil"];const t=e.toLowerCase();return Hs[t]??["sil"]}function _i(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const i=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(i*n))}function Et(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function hn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||Et(n,t)!=="w"||t>0&&Et(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function js(e,t){const n=e.toLowerCase(),r=Et(n,t),i=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":i.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function Ks(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";if(hn(n,t))return"FF";const i=Et(n,t);return i==="u"||i==="w"?"U":"O"}function Gs(e,t){const n=e.toLowerCase();if(hn(n,t))return"FF";const r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const i=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(i)||Et(n,t)==="o"?"O":"U"}const Zt={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function qs(e,t){const n=e.toLowerCase(),r=Et(n,t);if(Zt[r])return Zt[r];for(let i=0;i<n.length;i++){const s=n[i];if(Zt[s])return Zt[s]}return"DD"}function bi(e,t,n){const r=$s(e);if(r.length===1)return r[0];const i=t.trim();if(!i)return r[0];const s=(e??"").toLowerCase(),o=Math.max(0,n);switch(s){case"aei":return js(i,o);case"o":return Ks(i,o);case"qw":return Gs(i,o);case"cdgknstxyz":return qs(i,o);default:return r[0]}}const Qn=16,On=47,Si=new Set(["aa","E","I"]),Ti=new Set(["DD","SS","kk","CH"]),Ys=[Si,Ti];function Qs(e){for(const t of Ys)if(t.has(e))return t;return null}function Xs(e){return Qs(e)!=null}function ki(e,t=Qn){return t<=0?e:Math.round(e/t)*t}function Xn(e,t=Qn){return e.map(n=>({...n,vtime:ki(n.vtime,t)}))}function Ei(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 Jn(e){if(e.length<=2)return[...e];const t=[e[0]];for(let n=1;n<e.length-1;n++){const r=e[n],i=e[n+1],s=t[t.length-1];if(!Xs(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<On||a<On||t.push(r)}return t.push(e[e.length-1]),t}function gn(e){return Jn(Ei(Xn(e)))}function xi(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function wn(e){const t=Ei(Xn(e)),n=Jn(t),r=new Set(n.map(s=>s.vtime)),i=[];for(const s of t)r.has(s.vtime)||i.push({viseme:s.viseme,vtime:s.vtime});return i}function Js(e){return wn(e).map(t=>t.viseme)}const Zs=32,Ir=48;function Ii(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function Ai(e){let t=null,n=-1;for(const r of e){if(r.viseme==="sil")continue;const i=r.vtime+r.vduration;i>n&&(t=r,n=i)}return t}function ea(e){return gn(e).find(n=>n.viseme!=="sil")??null}function lt(e){const t=Ii(e);return Ai(e)?t+jn:t}function ta(e){const t=[],n=ea(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=Ai(e),i=Ii(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+jn}),t}function Mi(e){const t=gn(e),n=[];for(let r=0;r<t.length-1;r++){const i=t[r].viseme,s=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;i===s||a<=o||n.push({from:i,to:s,fromVtime:o,toVtime:a})}return n}function Pi(e){return e.length===0?[]:[...ta(e),...Mi(e)]}function na(e,t){let n=null;for(const r of e){const{transStart:i,transEnd:s}=Ci(r.fromVtime,r.toVtime,r.from,r.to);t>=i&&t<s&&(n=r)}return n}function Ci(e,t,n,r){const i=Math.max(0,t-e);if((n==="PP"||r==="PP")&&i>Ir){const d=Ir,l=t,c=l-d;return{gapMs:i,effectiveGapMs:d,holdEnd:c,transStart:c,transEnd:l}}const o=i>0?Math.max(i,Zs):0,a=e,u=e+o;return{gapMs:i,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:u}}function Ri(e,t,n,r,i,s){r.forEach(o=>{const u=String(o.word??"").trim();if(!u)return;const d=Math.round((o.start??0)*1e3),l=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:u,wtime:i+d,wduration:l,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),n.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const u=Math.round((o.start??0)*1e3),d=Math.max(1,Math.round((o.duration??0)*1e3)),l=i+u,c=Fi(t,l),m=c?_i(c,l):0;let w;ai(s)==="oculus_direct"?(w=mn(a),w==="U"&&c&&hn(c.word,m)&&(w="FF")):w=bi(a,c?.word??"",m),e.push({viseme:w,weight:1,vtime:l,vduration:d})})}function Di(e,t){let n=t;for(const r of e){const i=Math.round((r.start??0)*1e3),s=Math.max(1,Math.round((r.duration??0)*1e3));n=Math.max(n,t+i+s)}return n}const Zn=16e3;function Bi(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Zn}function ra(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 ia(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Ar(e,t,n=Zn){const r=t.byteOffset%2===0?t:t.slice(),i=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),s=new Float32Array(i.length);for(let a=0;a<i.length;a++)s[a]=i[a]>=32768?-(65536-i[a])/32768:i[a]/32767;const o=e.createBuffer(1,s.length,n);return o.copyToChannel(s,0),o}function sa(e){const t=ra(e),n=window.atob(t),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return r}async function Mr(e,t,n=Zn){const r=sa(t),i=Bi(n);if(ia(r)){const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(s)}if(r.length>=2&&r.length%2===0)return Ar(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return Ar(e,r,i)}}function Fi(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Li(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,u=!1,d=0,l=0,c=0,m=null,w=1,T=t,f=!1,E=null,D=0,B=!1,v=!1,k=0,L=null,A=null,ie=null;const de=()=>({visemes:[],words:[],segmentOffsetMs:0}),I=()=>{v=!1,k=0},V=()=>{m!=null&&(clearTimeout(m),m=null)},G=()=>{for(const b of r){try{b.onended=null,b.stop(0)}catch{}try{b.disconnect()}catch{}}r.length=0},ae=()=>{for(const b of r)b.playbackRate.value=w},se=()=>{if(!(f||!u||s||v||r.length>0||n.length>0)){if(a&&i&&l>0){const b=(i.currentTime-l)*1e3;if(b<D){V();const P=w>0?(D-b)/w:D-b;m=setTimeout(()=>{f||(o=!1,m=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,P));return}}o=!1,V(),e.onSpeakingDone(),e.onNotify()}},re=b=>{const P=lt(b);if(P<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,d=performance.now(),e.onSpeakingStart(),e.onNotify(),V();const H=w>0?P/w:P;m=setTimeout(()=>{f||(o=!1,m=null,e.onSpeakingDone(),e.onNotify())},H)},O=(b,P,H,le)=>{P.length!==0&&(c=H,P.forEach(j=>{const p=String(j.word??"").trim();if(!p)return;const S=Math.round((j.start??0)*1e3),x=j.duration!=null?Math.round(j.duration*1e3):j.end!=null?Math.max(1,Math.round((j.end-(j.start??0))*1e3)):0;b.push({word:p,wtime:c+S,wduration:x,queueIndex:b.length,gesture:j.gesture??null,emphasis:j.emphasis===!0})}))},J=(b,P,H,le,j,q)=>{H.length!==0&&(c=le,H.forEach(p=>{const S=String(p.symbol??p.viseme??"").trim();if(!S)return;const x=Math.round((p.start??0)*1e3),_=Math.max(1,Math.round((p.duration??0)*1e3)),U=c+x,Z=Fi(P,U),te=Z?_i(Z,U):0;let z;ai(q)==="oculus_direct"?(z=mn(S),z==="U"&&Z&&hn(Z.word,te)&&(z="FF")):z=bi(S,Z?.word??"",te),b.push({viseme:z,weight:1,vtime:U,vduration:_})}),e.onNotify())},W=(b,P,H,le,j,q,p)=>{O(P,le,j),J(b,P,H,j,q,p)},he=(b,P,H)=>{ie===b&&b.visemes===P||(P.length=0,H.length=0,b.visemes=P,b.words=H,b.segmentOffsetMs=0,ie=b,c=0,D=0)},K=async()=>{const b=window.AudioContext||window.webkitAudioContext;return i||(i=new b),i.state==="suspended"&&await i.resume(),E||(E=i.createMediaStreamDestination()),i},ee=(b,P)=>{if(!i)return 0;const H=i,le=H.currentTime,j=le+.02;if(P.isFirstAudio){l<=0&&(l=j);const p=(j-le)*1e3;d=performance.now()+p}P.onBeforeStart?.(j);const q=H.createBufferSource();return q.buffer=b,q.playbackRate.value=w,q.connect(H.destination),E&&q.connect(E),r.push(q),f?(r.pop(),j):(P.isFirstAudio&&(o=!0,e.onSpeakingStart()),q.onended=()=>{const p=r.indexOf(q);p>=0&&r.splice(p,1),e.onNotify(),!f&&(L&&A?$(L,A):se())},q.start(j),j)},$=async(b,P)=>{if(f||s||r.length>0)return;if(n.length===0){se();return}s=!0;let H=!1;try{const le=await K();if(f)return;const j=n[0];if(!j)return;const q=!o;if(B&&(e.shouldHoldForWarmup?.()??!1)&&(v||q&&j.newStream)||v){he(j.utterance,b,P);for(const x of n){if(f)return;x.audioBuffer||(x.audioBuffer=await Mr(le,x.audio,x.sampleRate)),a=!0,v||(v=!0,k=0,x.newStream&&x.onNewStream?.()),x.visemesQueued||(W(b,P,x.visemes,x.words,k,!0,T),x.visemesQueued=!0,k+=Math.round(x.audioBuffer.duration*1e3),D=Math.max(D,lt(b)))}e.onNotify();return}const S=n.shift();if(!S||(S.audioBuffer||(S.audioBuffer=await Mr(le,S.audio,S.sampleRate)),f))return;a=!0,V(),he(S.utterance,b,P),S.visemesQueued=!1,S.newStream&&S.onNewStream?.(),ee(S.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:x=>{l=x,c=0,d=performance.now()+(x-le.currentTime)*1e3,b.length=0,P.length=0,W(b,P,S.visemes,S.words,0,!0,T),S.visemesQueued=!0,S.utterance.segmentOffsetMs=0}}),H=r.length>0,D=lt(b),e.onNotify()}catch(le){console.error("[avatarChunkPlayback] audio chunk failed:",le)}finally{if(s=!1,f)return;if(v){n.some(j=>!j.audioBuffer||!j.visemesQueued)&&$(b,P);return}!H&&r.length===0&&n.length>0?$(b,P):r.length===0&&n.length===0&&se()}};return{setStreamTtsEngineId:b=>{T=b},setPlaybackSpeed:b=>{w=Math.max(.1,Math.min(1,b)),ae()},getPlaybackSpeed:()=>w,setLipsyncWarmupHoldEnabled:b=>{B=b,b||I()},isWarmingUp:()=>v,releaseWarmupHold:()=>{if(v){v=!1,k=0;for(const b of n)b.newStream=!1;L&&A&&$(L,A),e.onNotify()}},resetForNewStream:b=>{f=!1,u=!1,T=b,D=0},resumeBotStream:()=>{f=!1,u=!1},clearAborted:()=>{f=!1},primeAudioContext:async()=>{const b=window.AudioContext||window.webkitAudioContext;i||(i=new b),i.state==="suspended"&&await i.resume(),i&&!E&&(E=i.createMediaStreamDestination())},stop:()=>{f=!0,V(),G(),n.length=0,s=!1,o=!1,a=!1,u=!1,c=0,l=0,d=0,D=0,L=null,A=null,ie=null,I()},markStreamComplete:b=>{if(D=Math.max(D,lt(b)),u=!0,!a&&b.length>0){re(b);return}se()},playAudioChunk:async(b,P,H,le,j,q,p)=>{if(f)return;L=b,A=P;const S=Bi(p?.sampleRate),x=p?.newStream===!0,_=de();if(!H?.trim()){if(le.length===0&&j.length===0)return;he(_,b,P),x&&p?.onNewStream?.(),W(b,P,le,j,0,!0,T),D=lt(b),!o&&D>0&&re(b),e.onNotify();return}n.push({audio:H,audioBuffer:null,utterance:_,visemes:le,words:j,isNewSegment:q,sampleRate:S,newStream:x,onNewStream:p?.onNewStream,visemesQueued:!1}),await $(b,P)},queueTimingsOnly:(b,P,H,le,j,q)=>{if(f)return;const p=de();he(p,b,P),W(b,P,H,le,0,!0,T),p.segmentOffsetMs=0,D=lt(b)},getPlaybackElapsedMs:()=>a&&i&&l>0?Math.max(0,(i.currentTime-l)*1e3*w):o?Math.max(0,(performance.now()-d)*w):0,isSpeaking:()=>o?!0:!a||!i||l<=0?!1:(i.currentTime-l)*1e3<D,getVoiceStream:()=>E?E.stream:null,getPlaybackStartPerf:()=>d,bargeIn:()=>{f=!0,u=!1,V(),G(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,D=0,L=null,A=null,ie=null,I()},interrupt:()=>{f=!0,u=!1,V(),G(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,D=0,L=null,A=null,ie=null,I()}}}function zt(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 Oi(e,t,n=120){const r=zt(e,t);if(r!=="sil")return r;let i=null;for(const s of e){if(s.vtime>t)break;const o=s.vtime+s.vduration;o<=t&&t-o<=n&&(i=s)}return i?.viseme??"sil"}function aa(e,t,n=400){const r=t-n;let i=0;for(const s of e)if(s.vtime+s.vduration<r)i+=1;else break;i>0&&e.splice(0,i)}function oa(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Pr(e,t){const n=e.trim();if(!n)return null;try{const r=n.replace(/\s+/g,""),i=atob(r).length,s=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return i/2/s*1e3}catch{return null}}const pn=.5,yn=1.5,er="Olivia",tr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Ht=.85;function Nn(e,t=ht,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let u=0;const d=[],l=[];let c="",m="neutral",w="",T=dt;const f=new Set;let E=0,D=null,B=0,v=null;const k=()=>f.forEach(O=>O());let L=()=>!1;const A=Li({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:k,shouldHoldForWarmup:()=>L()},dt),ie=()=>A.getPlaybackElapsedMs(),de=(O,J=c)=>{if(!n.onLipsyncDebug)return;const W=ie(),he=i,K=wn(o).map(ee=>({viseme:ee.viseme,vtimeMs:ee.vtime}));n.onLipsyncDebug({event:O,spokenText:J,mood:m,playbackAnchorPerf:A.getPlaybackStartPerf(),playbackElapsedMs:W,queueLength:he.length,activeViseme:zt(he,W),segments:l.map(ee=>({...ee,visemes:[...ee.visemes]})),fullQueueLength:o.length,compactionSkipped:K})},I=(O,J)=>{n.onLipsyncDebug&&(D={event:O,spokenText:J},E===0&&(E=requestAnimationFrame(()=>{E=0;const W=D;D=null,W&&de(W.event,W.spokenText)})))},V=(O,J,W,he,K)=>{if(!n.onLipsyncDebug)return;const ee=i.slice(J),$=W.filter(X=>String(X.symbol??X.viseme??"").trim());l.push({spokenText:O,audioOffsetMs:ee[0]?.vtime??0,isNewSegment:he,chunkDurationMs:K,receivedAtMs:performance.now(),visemes:ee.map((X,_e)=>{const oe=$[_e];return{rawSymbol:String(oe?.symbol??oe?.viseme??X.viseme).trim(),viseme:X.viseme,startSec:Number(oe?.start??0),durationSec:Number(oe?.duration??0),vtimeMs:X.vtime,vdurationMs:X.vduration}})})},G=()=>{o.length=0,a.length=0,u=0},ae=(O,J,W,he,K)=>{if(O.length===0&&J.length===0)return;Ri(o,a,O,J,u,K);const ee=Di(O,u),$=W?Pr(W,he):null;u=Math.max(ee,$!=null?u+$:u)},se=()=>{B+=1,v?.abort(),v=null,A.stop(),i.length=0,s.length=0,G(),d.length=0,m="neutral",l.length=0,c="",e("idle"),I("reset"),k()};return{setDeveloperToken:O=>{w=O},setTtsEngineId:O=>{T=O},getTtsEngineId:()=>T,speak:async(O,J)=>{se();const W=B;v=new AbortController,e("loading"),c=O,l.length=0,G();const he=w.trim();if(!he)throw new Error("Developer token required for avatar_ttsWithPoses");const K=et(J?.ttsEngineId,J?.voiceId),ee=K.ttsEngineId??T??dt;A.resetForNewStream(ee),A.setStreamTtsEngineId(ee);const $=K.voiceId??(ee===nt?dn:er),X=J?.speakingRate??Ht,_e=Math.max(pn,Math.min(yn,X)),oe={user_query:O,ttsEngineId:ee,speakingRate:_e,tenant:"aiTwin"};ii.has(ee)&&(oe.voice_id=$);const b=fn(J?.language);b&&(oe.language=b);try{const P=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${he}`},body:JSON.stringify(oe),signal:v.signal});if(!P.ok)throw new Error(`avatar_ttsWithPoses failed (${P.status})`);const H=P.body;if(!H)throw new Error("No response body");const le=H.getReader(),j=new TextDecoder;let q="",p=!0;const S=async x=>{if(W!==B)return;const _=yi(x);if(_){if(_.event==="audio"){const U=_.data.chunk,Z=_.data.visemes??[],te=_.data.words??[],z=_.data.is_new_segment??!1,be=_.data.sample_rate,Xe=Number(_.data.audio_offset_ms??0),Pt=i.length;if(ae(Z,te,U,be,ee),U){const pt=p;p=!1,await A.playAudioChunk(i,s,U,Z,te,z,{sampleRate:be,newStream:pt,audioOffsetMs:Xe}),V(O,Pt,Z,z,Pr(U,be)),I("audio_chunk",O)}else(Z.length>0||te.length>0)&&(A.queueTimingsOnly(i,s,Z,te,z,{audioOffsetMs:Xe,newStream:p}),V(O,Pt,Z,z,null),I("audio_chunk",O))}else if(_.event==="metadata"){const U=_.data.mood;typeof U=="string"&&U.trim()&&(m=U.trim());const Z=_.data.sentence_emotions;if(Array.isArray(Z)){d.length=0;for(const te of Z){if(!te||typeof te!="object")continue;const z=te;d.push({sentence_index:Number(z.sentence_index??0),text:String(z.text??""),sentiment:typeof z.sentiment=="string"?z.sentiment:void 0,emotion:String(z.emotion??m),start_word:Number(z.start_word??0),end_word:Number(z.end_word??0)})}}k(),I("metadata",O)}else if(_.event==="error")throw new Error(String(_.data.message??"avatar_ttsWithPoses stream error"))}};for(;W===B;){const{done:x,value:_}=await le.read();_&&(q+=j.decode(_,{stream:!0}));const U=q.split(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("react/jsx-runtime"),h=require("react"),us=require("@pipecat-ai/client-js"),Hn=require("@pipecat-ai/websocket-transport"),we=require("pixi.js");var xn=typeof document<"u"?document.currentScript:null;const ds="https://aitwin.bubu.social",ri={publicBase:ds},fs="0.6.5",ms={version:fs},hs={},ht="https://ai.aitwin.me",$n=`${ri.publicBase}/custom-faces`,gs=`${ri.publicBase}/aitwin-workers/v${ms.version}/visemeDiffPreview.worker.js`;function ws(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:xn&&xn.tagName.toUpperCase()==="SCRIPT"&&xn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?hs?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():gs}const ps="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",In=3e3,Ot=16,Er=3e3,ys=4e3,vs=.85,_s=8,jn=400,Kn="eng_a7f2b9c1",un="eng_d4e8f3a2",tt="eng_c9b1e6d4",nt="visemetts",dt=tt,dn="eve",ii=new Set([un,tt,nt]),Gn={[Kn]:"oculus_direct",[tt]:"oculus_direct",[nt]:"oculus_direct",[un]:"inworld_word"},Dn={google:Kn,inworld:un,cartesia:tt,visemetts:nt};function bs(e){const t=e.trim();if(t)return t in Gn?t:Dn[t.toLowerCase()]}function si(e){const t=e?.trim();if(!t)return{};const n=t.indexOf(":");if(n<=0)return{voiceId:t};const r=bs(t.slice(0,n));if(!r)return{voiceId:t};const i=t.slice(n+1).trim();return{ttsEngineId:r,voiceId:i||void 0}}function et(e,t){const n=si(t);return{ttsEngineId:e??n.ttsEngineId,voiceId:n.voiceId}}function ai(e){return Gn[e]}function Ss(e){return e===tt}function oi(e){return e===nt}function Ts(e){if(e.ttsEngineId&&e.ttsEngineId in Gn)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Dn?Dn[t]:dt}class nn extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}function qn(e,...t){const n=typeof e=="string"?e:e?.brainId?.trim()||e?.knowledgeContextId?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}async function ci(e,t=ps){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new nn;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new nn(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,u=String(a.authToken??o??"").trim()||void 0,d=qn(a);return{...a,ttsEngineId:Ts(i.data),authToken:u,brainId:d,knowledgeContextId:d}}const Yn="thumbnail.webp";function li(e,t=$n){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Yn}`}function xr(e){const t=e?.trim();if(!t)return null;try{return li(t)}catch{return null}}function ks(e){if(!e)return null;const t=(e.binBase||e.twinBase).trim().replace(/\/$/,"");return t?`${t}/${Yn}`:null}const Es="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",xs="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Is="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",As="6TNvp3SCs4Og0a1ijm9TommXLql1",Ms="Swaraj Mali";async function Nt(){const e=await fetch(Es,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":xs,"Client-Secret":Is},body:JSON.stringify({userId:As,userName:Ms})});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 Ps(e,t=ht){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 Cs(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 Xt(e){return Uint8Array.from(e)}function Rs(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Ds(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=Xt(n.subarray(0,12)),i=Xt(n.subarray(12,28)),s=Xt(n.subarray(28)),o=Xt(Rs(s,i)),a=await crypto.subtle.importKey("raw",Cs(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let Bn=null;const Fn=new Set;function Jt(e){return e.includes("/custom-faces/")}function rn(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||Jt(t)||Jt(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=Jt(t)?t:Jt(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function gt(e){return rn(e).encrypted}function Ln(e,t=$n){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function ui(e,t){return(e??t)?.trim()||void 0}function di(e){Bn=rn(e);for(const t of Fn)t()}function Bs(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return rn(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return rn({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function wt(){if(!Bn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Bn}function fi(e){return Fn.add(e),()=>Fn.delete(e)}function sn(){const e=wt();return gt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Fs(){const e=wt();return gt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function mi(){const e=wt();return gt(e)?e.binBase:e.twinBase}function Wt(){return gt(wt())}function hi(){const e=wt();return gt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function gi(){const e=wt();return gt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}const ft=[{code:"en",label:"English",visemetts:!0,cartesia:!0},{code:"es",label:"Spanish",visemetts:!0,cartesia:!0},{code:"es-MX",label:"Spanish (Mexico)",visemetts:!0,cartesia:!0},{code:"es-ES",label:"Spanish (Spain)",visemetts:!0,cartesia:!0},{code:"pt",label:"Portuguese",visemetts:!0,cartesia:!0},{code:"pt-BR",label:"Portuguese (Brazil)",visemetts:!0,cartesia:!0},{code:"pt-PT",label:"Portuguese (Portugal)",visemetts:!0,cartesia:!0},{code:"fr",label:"French",visemetts:!0,cartesia:!0},{code:"de",label:"German",visemetts:!0,cartesia:!0},{code:"it",label:"Italian",visemetts:!0,cartesia:!0},{code:"zh",label:"Chinese",visemetts:!0,cartesia:!0},{code:"ja",label:"Japanese",visemetts:!0,cartesia:!0},{code:"hi",label:"Hindi",visemetts:!0,cartesia:!0},{code:"ko",label:"Korean",visemetts:!0,cartesia:!0},{code:"ru",label:"Russian",visemetts:!0,cartesia:!0},{code:"tr",label:"Turkish",visemetts:!0,cartesia:!0},{code:"id",label:"Indonesian",visemetts:!0,cartesia:!0},{code:"ar",label:"Arabic",visemetts:!0,cartesia:!0},{code:"ar-EG",label:"Arabic (Egypt)",visemetts:!0,cartesia:!0},{code:"ar-AE",label:"Arabic (UAE)",visemetts:!0,cartesia:!0},{code:"vi",label:"Vietnamese",visemetts:!0,cartesia:!0},{code:"bn",label:"Bengali",visemetts:!0,cartesia:!0},{code:"auto",label:"Auto-detect",visemetts:!0,cartesia:!1},{code:"nl",label:"Dutch",visemetts:!1,cartesia:!0},{code:"pl",label:"Polish",visemetts:!1,cartesia:!0},{code:"sv",label:"Swedish",visemetts:!1,cartesia:!0},{code:"tl",label:"Tagalog",visemetts:!1,cartesia:!0},{code:"bg",label:"Bulgarian",visemetts:!1,cartesia:!0},{code:"ro",label:"Romanian",visemetts:!1,cartesia:!0},{code:"cs",label:"Czech",visemetts:!1,cartesia:!0},{code:"el",label:"Greek",visemetts:!1,cartesia:!0},{code:"fi",label:"Finnish",visemetts:!1,cartesia:!0},{code:"hr",label:"Croatian",visemetts:!1,cartesia:!0},{code:"ms",label:"Malay",visemetts:!1,cartesia:!0},{code:"sk",label:"Slovak",visemetts:!1,cartesia:!0},{code:"da",label:"Danish",visemetts:!1,cartesia:!0},{code:"ta",label:"Tamil",visemetts:!1,cartesia:!0},{code:"uk",label:"Ukrainian",visemetts:!1,cartesia:!0},{code:"hu",label:"Hungarian",visemetts:!1,cartesia:!0},{code:"no",label:"Norwegian",visemetts:!1,cartesia:!0},{code:"th",label:"Thai",visemetts:!1,cartesia:!0},{code:"he",label:"Hebrew",visemetts:!1,cartesia:!0},{code:"ka",label:"Georgian",visemetts:!1,cartesia:!0},{code:"te",label:"Telugu",visemetts:!1,cartesia:!0},{code:"gu",label:"Gujarati",visemetts:!1,cartesia:!0},{code:"kn",label:"Kannada",visemetts:!1,cartesia:!0},{code:"ml",label:"Malayalam",visemetts:!1,cartesia:!0},{code:"mr",label:"Marathi",visemetts:!1,cartesia:!0},{code:"pa",label:"Punjabi",visemetts:!1,cartesia:!0}],wi=ft.map(e=>e.code),Ls=new Set(wi),Os=new Set(ft.filter(e=>e.visemetts).map(e=>e.code)),Ns=new Set(ft.filter(e=>e.cartesia).map(e=>e.code)),Vs="en";function pi(e){return Ls.has(e)}function fn(e){const t=e?.trim();if(t)return t}function Us(e){return e===nt?ft.filter(t=>t.visemetts).map(t=>t.code):e===tt?ft.filter(t=>t.cartesia).map(t=>t.code):ft.filter(t=>t.visemetts&&t.cartesia).map(t=>t.code)}function Ws(e,t){const n=t.trim();return n?e===nt?Os.has(n):e===tt?Ns.has(n):pi(n):!1}function yi(e){const t=e.split(/\r?\n/);let n="",r="";for(const s of t)s.startsWith("event:")?n=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());if(!n)return null;let i={};if(r)try{i=JSON.parse(r)}catch{i={raw:r}}return{event:n,data:i}}const vi=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],zs=new Map(vi.map(e=>[e.toLowerCase(),e]));function mn(e){const t=(e??"").trim();return t?zs.get(t.toLowerCase())??"sil":"sil"}const Hs={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 $s(e){if(!e)return["sil"];const t=e.toLowerCase();return Hs[t]??["sil"]}function _i(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const i=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(i*n))}function Et(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function hn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||Et(n,t)!=="w"||t>0&&Et(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function js(e,t){const n=e.toLowerCase(),r=Et(n,t),i=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":i.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function Ks(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";if(hn(n,t))return"FF";const i=Et(n,t);return i==="u"||i==="w"?"U":"O"}function Gs(e,t){const n=e.toLowerCase();if(hn(n,t))return"FF";const r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const i=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(i)||Et(n,t)==="o"?"O":"U"}const Zt={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function qs(e,t){const n=e.toLowerCase(),r=Et(n,t);if(Zt[r])return Zt[r];for(let i=0;i<n.length;i++){const s=n[i];if(Zt[s])return Zt[s]}return"DD"}function bi(e,t,n){const r=$s(e);if(r.length===1)return r[0];const i=t.trim();if(!i)return r[0];const s=(e??"").toLowerCase(),o=Math.max(0,n);switch(s){case"aei":return js(i,o);case"o":return Ks(i,o);case"qw":return Gs(i,o);case"cdgknstxyz":return qs(i,o);default:return r[0]}}const Qn=16,On=47,Si=new Set(["aa","E","I"]),Ti=new Set(["DD","SS","kk","CH"]),Ys=[Si,Ti];function Qs(e){for(const t of Ys)if(t.has(e))return t;return null}function Xs(e){return Qs(e)!=null}function ki(e,t=Qn){return t<=0?e:Math.round(e/t)*t}function Xn(e,t=Qn){return e.map(n=>({...n,vtime:ki(n.vtime,t)}))}function Ei(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 Jn(e){if(e.length<=2)return[...e];const t=[e[0]];for(let n=1;n<e.length-1;n++){const r=e[n],i=e[n+1],s=t[t.length-1];if(!Xs(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<On||a<On||t.push(r)}return t.push(e[e.length-1]),t}function gn(e){return Jn(Ei(Xn(e)))}function xi(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function wn(e){const t=Ei(Xn(e)),n=Jn(t),r=new Set(n.map(s=>s.vtime)),i=[];for(const s of t)r.has(s.vtime)||i.push({viseme:s.viseme,vtime:s.vtime});return i}function Js(e){return wn(e).map(t=>t.viseme)}const Zs=32,Ir=48;function Ii(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function Ai(e){let t=null,n=-1;for(const r of e){if(r.viseme==="sil")continue;const i=r.vtime+r.vduration;i>n&&(t=r,n=i)}return t}function ea(e){return gn(e).find(n=>n.viseme!=="sil")??null}function lt(e){const t=Ii(e);return Ai(e)?t+jn:t}function ta(e){const t=[],n=ea(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=Ai(e),i=Ii(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+jn}),t}function Mi(e){const t=gn(e),n=[];for(let r=0;r<t.length-1;r++){const i=t[r].viseme,s=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;i===s||a<=o||n.push({from:i,to:s,fromVtime:o,toVtime:a})}return n}function Pi(e){return e.length===0?[]:[...ta(e),...Mi(e)]}function na(e,t){let n=null;for(const r of e){const{transStart:i,transEnd:s}=Ci(r.fromVtime,r.toVtime,r.from,r.to);t>=i&&t<s&&(n=r)}return n}function Ci(e,t,n,r){const i=Math.max(0,t-e);if((n==="PP"||r==="PP")&&i>Ir){const d=Ir,l=t,c=l-d;return{gapMs:i,effectiveGapMs:d,holdEnd:c,transStart:c,transEnd:l}}const o=i>0?Math.max(i,Zs):0,a=e,u=e+o;return{gapMs:i,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:u}}function Ri(e,t,n,r,i,s){r.forEach(o=>{const u=String(o.word??"").trim();if(!u)return;const d=Math.round((o.start??0)*1e3),l=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:u,wtime:i+d,wduration:l,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),n.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const u=Math.round((o.start??0)*1e3),d=Math.max(1,Math.round((o.duration??0)*1e3)),l=i+u,c=Fi(t,l),m=c?_i(c,l):0;let w;ai(s)==="oculus_direct"?(w=mn(a),w==="U"&&c&&hn(c.word,m)&&(w="FF")):w=bi(a,c?.word??"",m),e.push({viseme:w,weight:1,vtime:l,vduration:d})})}function Di(e,t){let n=t;for(const r of e){const i=Math.round((r.start??0)*1e3),s=Math.max(1,Math.round((r.duration??0)*1e3));n=Math.max(n,t+i+s)}return n}const Zn=16e3;function Bi(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Zn}function ra(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 ia(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Ar(e,t,n=Zn){const r=t.byteOffset%2===0?t:t.slice(),i=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),s=new Float32Array(i.length);for(let a=0;a<i.length;a++)s[a]=i[a]>=32768?-(65536-i[a])/32768:i[a]/32767;const o=e.createBuffer(1,s.length,n);return o.copyToChannel(s,0),o}function sa(e){const t=ra(e),n=window.atob(t),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return r}async function Mr(e,t,n=Zn){const r=sa(t),i=Bi(n);if(ia(r)){const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(s)}if(r.length>=2&&r.length%2===0)return Ar(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return Ar(e,r,i)}}function Fi(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Li(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,u=!1,d=0,l=0,c=0,m=null,w=1,T=t,f=!1,E=null,D=0,B=!1,v=!1,k=0,L=null,A=null,ie=null;const de=()=>({visemes:[],words:[],segmentOffsetMs:0}),I=()=>{v=!1,k=0},V=()=>{m!=null&&(clearTimeout(m),m=null)},G=()=>{for(const b of r){try{b.onended=null,b.stop(0)}catch{}try{b.disconnect()}catch{}}r.length=0},ae=()=>{for(const b of r)b.playbackRate.value=w},se=()=>{if(!(f||!u||s||v||r.length>0||n.length>0)){if(a&&i&&l>0){const b=(i.currentTime-l)*1e3;if(b<D){V();const P=w>0?(D-b)/w:D-b;m=setTimeout(()=>{f||(o=!1,m=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,P));return}}o=!1,V(),e.onSpeakingDone(),e.onNotify()}},re=b=>{const P=lt(b);if(P<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,d=performance.now(),e.onSpeakingStart(),e.onNotify(),V();const H=w>0?P/w:P;m=setTimeout(()=>{f||(o=!1,m=null,e.onSpeakingDone(),e.onNotify())},H)},O=(b,P,H,le)=>{P.length!==0&&(c=H,P.forEach(j=>{const p=String(j.word??"").trim();if(!p)return;const S=Math.round((j.start??0)*1e3),x=j.duration!=null?Math.round(j.duration*1e3):j.end!=null?Math.max(1,Math.round((j.end-(j.start??0))*1e3)):0;b.push({word:p,wtime:c+S,wduration:x,queueIndex:b.length,gesture:j.gesture??null,emphasis:j.emphasis===!0})}))},J=(b,P,H,le,j,q)=>{H.length!==0&&(c=le,H.forEach(p=>{const S=String(p.symbol??p.viseme??"").trim();if(!S)return;const x=Math.round((p.start??0)*1e3),_=Math.max(1,Math.round((p.duration??0)*1e3)),U=c+x,Z=Fi(P,U),te=Z?_i(Z,U):0;let z;ai(q)==="oculus_direct"?(z=mn(S),z==="U"&&Z&&hn(Z.word,te)&&(z="FF")):z=bi(S,Z?.word??"",te),b.push({viseme:z,weight:1,vtime:U,vduration:_})}),e.onNotify())},W=(b,P,H,le,j,q,p)=>{O(P,le,j),J(b,P,H,j,q,p)},he=(b,P,H)=>{ie===b&&b.visemes===P||(P.length=0,H.length=0,b.visemes=P,b.words=H,b.segmentOffsetMs=0,ie=b,c=0,D=0)},K=async()=>{const b=window.AudioContext||window.webkitAudioContext;return i||(i=new b),i.state==="suspended"&&await i.resume(),E||(E=i.createMediaStreamDestination()),i},ee=(b,P)=>{if(!i)return 0;const H=i,le=H.currentTime,j=le+.02;if(P.isFirstAudio){l<=0&&(l=j);const p=(j-le)*1e3;d=performance.now()+p}P.onBeforeStart?.(j);const q=H.createBufferSource();return q.buffer=b,q.playbackRate.value=w,q.connect(H.destination),E&&q.connect(E),r.push(q),f?(r.pop(),j):(P.isFirstAudio&&(o=!0,e.onSpeakingStart()),q.onended=()=>{const p=r.indexOf(q);p>=0&&r.splice(p,1),e.onNotify(),!f&&(L&&A?$(L,A):se())},q.start(j),j)},$=async(b,P)=>{if(f||s||r.length>0)return;if(n.length===0){se();return}s=!0;let H=!1;try{const le=await K();if(f)return;const j=n[0];if(!j)return;const q=!o;if(B&&(e.shouldHoldForWarmup?.()??!1)&&(v||q&&j.newStream)||v){he(j.utterance,b,P);for(const x of n){if(f)return;x.audioBuffer||(x.audioBuffer=await Mr(le,x.audio,x.sampleRate)),a=!0,v||(v=!0,k=0,x.newStream&&x.onNewStream?.()),x.visemesQueued||(W(b,P,x.visemes,x.words,k,!0,T),x.visemesQueued=!0,k+=Math.round(x.audioBuffer.duration*1e3),D=Math.max(D,lt(b)))}e.onNotify();return}const S=n.shift();if(!S||(S.audioBuffer||(S.audioBuffer=await Mr(le,S.audio,S.sampleRate)),f))return;a=!0,V(),he(S.utterance,b,P),S.visemesQueued=!1,S.newStream&&S.onNewStream?.(),ee(S.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:x=>{l=x,c=0,d=performance.now()+(x-le.currentTime)*1e3,b.length=0,P.length=0,W(b,P,S.visemes,S.words,0,!0,T),S.visemesQueued=!0,S.utterance.segmentOffsetMs=0}}),H=r.length>0,D=lt(b),e.onNotify()}catch(le){console.error("[avatarChunkPlayback] audio chunk failed:",le)}finally{if(s=!1,f)return;if(v){n.some(j=>!j.audioBuffer||!j.visemesQueued)&&$(b,P);return}!H&&r.length===0&&n.length>0?$(b,P):r.length===0&&n.length===0&&se()}};return{setStreamTtsEngineId:b=>{T=b},setPlaybackSpeed:b=>{w=Math.max(.1,Math.min(1,b)),ae()},getPlaybackSpeed:()=>w,setLipsyncWarmupHoldEnabled:b=>{B=b,b||I()},isWarmingUp:()=>v,releaseWarmupHold:()=>{if(v){v=!1,k=0;for(const b of n)b.newStream=!1;L&&A&&$(L,A),e.onNotify()}},resetForNewStream:b=>{f=!1,u=!1,T=b,D=0},resumeBotStream:()=>{f=!1,u=!1},clearAborted:()=>{f=!1},primeAudioContext:async()=>{const b=window.AudioContext||window.webkitAudioContext;i||(i=new b),i.state==="suspended"&&await i.resume(),i&&!E&&(E=i.createMediaStreamDestination())},stop:()=>{f=!0,V(),G(),n.length=0,s=!1,o=!1,a=!1,u=!1,c=0,l=0,d=0,D=0,L=null,A=null,ie=null,I()},markStreamComplete:b=>{if(D=Math.max(D,lt(b)),u=!0,!a&&b.length>0){re(b);return}se()},playAudioChunk:async(b,P,H,le,j,q,p)=>{if(f)return;L=b,A=P;const S=Bi(p?.sampleRate),x=p?.newStream===!0,_=de();if(!H?.trim()){if(le.length===0&&j.length===0)return;he(_,b,P),x&&p?.onNewStream?.(),W(b,P,le,j,0,!0,T),D=lt(b),!o&&D>0&&re(b),e.onNotify();return}n.push({audio:H,audioBuffer:null,utterance:_,visemes:le,words:j,isNewSegment:q,sampleRate:S,newStream:x,onNewStream:p?.onNewStream,visemesQueued:!1}),await $(b,P)},queueTimingsOnly:(b,P,H,le,j,q)=>{if(f)return;const p=de();he(p,b,P),W(b,P,H,le,0,!0,T),p.segmentOffsetMs=0,D=lt(b)},getPlaybackElapsedMs:()=>a&&i&&l>0?Math.max(0,(i.currentTime-l)*1e3*w):o?Math.max(0,(performance.now()-d)*w):0,isSpeaking:()=>o?!0:!a||!i||l<=0?!1:(i.currentTime-l)*1e3<D,getVoiceStream:()=>E?E.stream:null,getPlaybackStartPerf:()=>d,bargeIn:()=>{f=!0,u=!1,V(),G(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,D=0,L=null,A=null,ie=null,I()},interrupt:()=>{f=!0,u=!1,V(),G(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,D=0,L=null,A=null,ie=null,I()}}}function zt(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 Oi(e,t,n=120){const r=zt(e,t);if(r!=="sil")return r;let i=null;for(const s of e){if(s.vtime>t)break;const o=s.vtime+s.vduration;o<=t&&t-o<=n&&(i=s)}return i?.viseme??"sil"}function aa(e,t,n=400){const r=t-n;let i=0;for(const s of e)if(s.vtime+s.vduration<r)i+=1;else break;i>0&&e.splice(0,i)}function oa(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Pr(e,t){const n=e.trim();if(!n)return null;try{const r=n.replace(/\s+/g,""),i=atob(r).length,s=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return i/2/s*1e3}catch{return null}}const pn=.5,yn=1.5,er="Olivia",tr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Ht=.85;function Nn(e,t=ht,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let u=0;const d=[],l=[];let c="",m="neutral",w="",T=dt;const f=new Set;let E=0,D=null,B=0,v=null;const k=()=>f.forEach(O=>O());let L=()=>!1;const A=Li({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:k,shouldHoldForWarmup:()=>L()},dt),ie=()=>A.getPlaybackElapsedMs(),de=(O,J=c)=>{if(!n.onLipsyncDebug)return;const W=ie(),he=i,K=wn(o).map(ee=>({viseme:ee.viseme,vtimeMs:ee.vtime}));n.onLipsyncDebug({event:O,spokenText:J,mood:m,playbackAnchorPerf:A.getPlaybackStartPerf(),playbackElapsedMs:W,queueLength:he.length,activeViseme:zt(he,W),segments:l.map(ee=>({...ee,visemes:[...ee.visemes]})),fullQueueLength:o.length,compactionSkipped:K})},I=(O,J)=>{n.onLipsyncDebug&&(D={event:O,spokenText:J},E===0&&(E=requestAnimationFrame(()=>{E=0;const W=D;D=null,W&&de(W.event,W.spokenText)})))},V=(O,J,W,he,K)=>{if(!n.onLipsyncDebug)return;const ee=i.slice(J),$=W.filter(X=>String(X.symbol??X.viseme??"").trim());l.push({spokenText:O,audioOffsetMs:ee[0]?.vtime??0,isNewSegment:he,chunkDurationMs:K,receivedAtMs:performance.now(),visemes:ee.map((X,_e)=>{const oe=$[_e];return{rawSymbol:String(oe?.symbol??oe?.viseme??X.viseme).trim(),viseme:X.viseme,startSec:Number(oe?.start??0),durationSec:Number(oe?.duration??0),vtimeMs:X.vtime,vdurationMs:X.vduration}})})},G=()=>{o.length=0,a.length=0,u=0},ae=(O,J,W,he,K)=>{if(O.length===0&&J.length===0)return;Ri(o,a,O,J,u,K);const ee=Di(O,u),$=W?Pr(W,he):null;u=Math.max(ee,$!=null?u+$:u)},se=()=>{B+=1,v?.abort(),v=null,A.stop(),i.length=0,s.length=0,G(),d.length=0,m="neutral",l.length=0,c="",e("idle"),I("reset"),k()};return{setDeveloperToken:O=>{w=O},setTtsEngineId:O=>{T=O},getTtsEngineId:()=>T,speak:async(O,J)=>{se();const W=B;v=new AbortController,e("loading"),c=O,l.length=0,G();const he=w.trim();if(!he)throw new Error("Developer token required for avatar_ttsWithPoses");const K=et(J?.ttsEngineId,J?.voiceId),ee=K.ttsEngineId??T??dt;A.resetForNewStream(ee),A.setStreamTtsEngineId(ee);const $=K.voiceId??(ee===nt?dn:er),X=J?.speakingRate??Ht,_e=Math.max(pn,Math.min(yn,X)),oe={user_query:O,ttsEngineId:ee,speakingRate:_e,tenant:"aiTwin"};ii.has(ee)&&(oe.voice_id=$);const b=fn(J?.language);b&&(oe.language=b);try{const P=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${he}`},body:JSON.stringify(oe),signal:v.signal});if(!P.ok)throw new Error(`avatar_ttsWithPoses failed (${P.status})`);const H=P.body;if(!H)throw new Error("No response body");const le=H.getReader(),j=new TextDecoder;let q="",p=!0;const S=async x=>{if(W!==B)return;const _=yi(x);if(_){if(_.event==="audio"){const U=_.data.chunk,Z=_.data.visemes??[],te=_.data.words??[],z=_.data.is_new_segment??!1,be=_.data.sample_rate,Xe=Number(_.data.audio_offset_ms??0),Pt=i.length;if(ae(Z,te,U,be,ee),U){const pt=p;p=!1,await A.playAudioChunk(i,s,U,Z,te,z,{sampleRate:be,newStream:pt,audioOffsetMs:Xe}),V(O,Pt,Z,z,Pr(U,be)),I("audio_chunk",O)}else(Z.length>0||te.length>0)&&(A.queueTimingsOnly(i,s,Z,te,z,{audioOffsetMs:Xe,newStream:p}),V(O,Pt,Z,z,null),I("audio_chunk",O))}else if(_.event==="metadata"){const U=_.data.mood;typeof U=="string"&&U.trim()&&(m=U.trim());const Z=_.data.sentence_emotions;if(Array.isArray(Z)){d.length=0;for(const te of Z){if(!te||typeof te!="object")continue;const z=te;d.push({sentence_index:Number(z.sentence_index??0),text:String(z.text??""),sentiment:typeof z.sentiment=="string"?z.sentiment:void 0,emotion:String(z.emotion??m),start_word:Number(z.start_word??0),end_word:Number(z.end_word??0)})}}k(),I("metadata",O)}else if(_.event==="error")throw new Error(String(_.data.message??"avatar_ttsWithPoses stream error"))}};for(;W===B;){const{done:x,value:_}=await le.read();_&&(q+=j.decode(_,{stream:!0}));const U=q.split(`
2
2
 
3
3
  `);q=U.pop()??"";for(const Z of U)await S(Z);if(x){q.trim()&&await S(q.trim()),A.markStreamComplete(i),I("bot_stopped",O);break}}}catch(P){if(W!==B||P instanceof DOMException&&P.name==="AbortError")return;throw console.error("[avatarTtsLipsync]",P),se(),e("error"),P}},stop:se,getVisemeQueue:()=>i,getWordQueue:()=>s,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>d,getStreamMood:()=>m,getPlaybackElapsedMs:()=>A.getPlaybackElapsedMs(),isSpeaking:()=>A.isSpeaking(),isWarmingUp:()=>A.isWarmingUp(),releaseWarmupHold:()=>A.releaseWarmupHold(),setLipsyncWarmupHold:(O,J)=>{J&&(L=J),A.setLipsyncWarmupHoldEnabled(O)},getVoiceStream:()=>A.getVoiceStream(),setPlaybackSpeed:O=>{A.setPlaybackSpeed(O)},getPlaybackSpeed:()=>A.getPlaybackSpeed(),subscribe:O=>(f.add(O),()=>f.delete(O))}}const nr=16e3,rr=16e3;class ca extends Hn.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 la extends Hn.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,nr,rr)}bufferBotAudio(t,n){}}const ua=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Cr(e){return ua.test(e.trim())}function da(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function Ni(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??ht,r=new URL(`${da(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const i=et(e.ttsEngineId,e.voiceId),s=i.ttsEngineId;s&&r.searchParams.set("ttsEngineId",s);const o=i.voiceId?.trim();o&&(s&&oi(s)?Cr(o)||r.searchParams.set("voiceId",o):Cr(o)&&r.searchParams.set("voiceId",o));const a=fn(e.language);a&&r.searchParams.set("language",a);const u=e.brainId?.trim()||e.personaId?.trim();u&&r.searchParams.set("brainId",u);const d=e.speakingRate??Ht;r.searchParams.set("speaking_rate",String(Math.max(pn,Math.min(yn,d)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),e.speakOnlyWhenSpokenTo&&r.searchParams.set("speakOnlyWhenSpokenTo","true");const l=e.avatarName?.trim();return l&&r.searchParams.set("avatarName",l),r.toString()}function An(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 fa(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 Rr(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function ma(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function Vi(e,t={}){const n=[],r=[],i=[],s=[];let o=0;const a=[],u=[];let d="",l="neutral",c=tt,m=!1,w=null,T=null,f={...t},E=0,D=null;const B=new Set,v=[];let k=!1,L=null,A=!0,ie="default";const de=new Set;let I=null,V=0,G=!1,ae=!1,se=null,re=!1;const O=()=>{se!=null&&(clearTimeout(se),se=null)},J=()=>{O(),se=setTimeout(()=>{se=null,A&&(K.markStreamComplete(n),oe("bot_stopped"))},450)},W=()=>B.forEach(g=>g());let he=()=>!1;const K=Li({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{re=!1,ae=!1,e("done")},onNotify:W,shouldHoldForWarmup:()=>he()},c),ee=()=>{if(L)return L;const g=new MessageChannel;return g.port1.onmessage=()=>{const C=v.shift();C!==void 0&&be(C),v.length>0?g.port2.postMessage(null):k=!1},L=g,g},$=g=>{v.push(g),!k&&(k=!0,ee().port2.postMessage(null))},X=()=>K.getPlaybackElapsedMs(),_e=(g,C=d)=>{if(!f.onLipsyncDebug)return;const ne=X(),ue=n,Te=wn(i).map(ve=>({viseme:ve.viseme,vtimeMs:ve.vtime}));f.onLipsyncDebug({event:g,spokenText:C,mood:l,playbackAnchorPerf:K.getPlaybackStartPerf(),playbackElapsedMs:ne,queueLength:ue.length,activeViseme:zt(ue,ne),segments:u.map(ve=>({...ve,visemes:[...ve.visemes]})),fullQueueLength:i.length,compactionSkipped:Te})},oe=(g,C)=>{f.onLipsyncDebug&&(D={event:g,spokenText:C},E===0&&(E=requestAnimationFrame(()=>{E=0;const ne=D;D=null,ne&&_e(ne.event,ne.spokenText)})))},b=()=>{A=!0,de.clear(),K.clearAborted()},P=()=>{const g=ma(w);if(g){ie=`bot-${Date.now()}`,g.interruptedTrackIds={[ie]:!0};try{g.interrupt?.()}catch{}}const C=T;try{C?.interrupt?.()}catch{}},H=g=>{if(re&&K.isSpeaking())return!0;const C=g.context_id?.trim();return C&&de.has(C)?!0:A?!1:!(g.type==="avatar_metadata"||Rr(g))},le=g=>{A=!1,re=!1;const C=g.context_id?.trim();C&&de.add(C),O(),G=!1,ae=!1,v.length=0,k=!1,I?.abort(),I=null,V+=1,P(),K.bargeIn(),j(),e("idle"),oe("interrupt"),W()},j=()=>{n.length=0,r.length=0,i.length=0,s.length=0,o=0,u.length=0,d="",l="neutral",a.length=0},q=()=>{O(),ae=!1,G=!1,K.stop(),j(),oe("reset"),W()},p=()=>{q(),e("idle"),W()},S=(g,C)=>{typeof g.mood=="string"&&g.mood.trim()&&(l=g.mood.trim()),Array.isArray(g.sentence_emotions)&&g.sentence_emotions.length>0&&(C&&(a.length=0),a.push(...An(g.sentence_emotions,l)))},x=g=>{if(H({...g,type:"avatar_metadata"}))return;b(),G=!0;const C=String(g.spoken_text??g.text??"").trim();C&&(d=C),K.resetForNewStream(c),typeof g.mood=="string"&&g.mood.trim()&&(l=g.mood.trim()),a.length=0,a.push(...An(g.sentence_emotions,l)),Array.isArray(g.gestures)&&g.gestures,oe("metadata",C),W()},_=(g,C,ne,ue)=>{if(!f.onLipsyncDebug)return;const Te=n.slice(ne),ve=ue.filter(ke=>String(ke.symbol??ke.viseme??"").trim());u.push({spokenText:C,audioOffsetMs:Te[0]?.vtime??0,isNewSegment:!!g.is_new_segment,chunkDurationMs:g.chunk_duration_ms!=null?Number(g.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:Te.map((ke,We)=>{const Fe=ve[We];return{rawSymbol:String(Fe?.symbol??Fe?.viseme??ke.viseme).trim(),viseme:ke.viseme,startSec:Number(Fe?.start??0),durationSec:Number(Fe?.duration??0),vtimeMs:ke.vtime,vdurationMs:ke.vduration}})})},U=(g,C,ne,ue)=>{if(g.length===0&&C.length===0)return;Ri(i,s,g,C,o,c);const Te=Di(g,o);let ve=null;const ke=ne.trim();if(ke)try{const We=atob(ke.replace(/\s+/g,"")).length,Fe=Number.isFinite(ue)&&(ue??0)>0?Number(ue):16e3;ve=We/2/Fe*1e3}catch{ve=null}o=Math.max(Te,ve!=null?o+ve:o)},Z=g=>{if(H(g))return;const C=Rr(g);C&&(O(),b());const ne=String(g.spoken_text??g.text??"").trim(),ue=g.visemes??[],Te=g.words??[],ve=String(g.chunk??"").trim(),ke=G||C||!ae;G&&(G=!1),ke&&(ae=!0),ne&&(d=ne),S(g,C),ke?(K.resetForNewStream(c),i.length=0,s.length=0,o=0):C&&K.resumeBotStream(),U(ue,Te,ve,g.sample_rate);const We=n.length;K.playAudioChunk(n,r,ve,ue,Te,C,{sampleRate:g.sample_rate,newStream:ke,audioOffsetMs:Number(g.audio_offset_ms??0),onNewStream:()=>{u.length=0}}).then(()=>{_(g,ne,We,ue),oe("audio_chunk",ne),J()})},te=g=>{if(H(g))return;(g.is_new_segment||Number(g.audio_offset_ms??-1)===0)&&b(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const C=String(g.spoken_text??g.text??"").trim();C&&(d=C),S(g,!!g.is_new_segment),U(g.visemes??[],g.words??[],"",void 0);const ne=n.length;K.queueTimingsOnly(n,r,g.visemes??[],g.words??[],!!g.is_new_segment,{audioOffsetMs:Number(g.audio_offset_ms??0)}),_(g,C,ne,g.visemes??[]),oe("lipsync",C),W()},z=async g=>{const C=String(g.text??"").trim();if(!C)return;const ne=f.authToken?.trim();if(!ne){console.error("[realtimeVoice] avatar_speak requires authToken");return}I?.abort();const ue=new AbortController;I=ue;const Te=++V;b(),K.resetForNewStream(c),d=C;const ke=`${(f.apiBase??ht).replace(/\/$/,"")}/avatar_ttsWithPoses`,We=et(c,f.voiceId);We.ttsEngineId&&(c=We.ttsEngineId,K.setStreamTtsEngineId(c));const Fe=We.voiceId?.trim()||(c===nt?dn:tr),$t=f.speakingRate??Ht,bn=Math.max(pn,Math.min(yn,$t)),Rt={user_query:C,ttsEngineId:c,speakingRate:bn,tenant:"aiTwin"};ii.has(c)&&(Rt.voice_id=Fe);const yt=fn(f.language);yt&&(Rt.language=yt);try{const Ce=await fetch(ke,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${ne}`},body:JSON.stringify(Rt),signal:ue.signal});if(!Ce.ok)throw new Error(`avatar_ttsWithPoses failed (${Ce.status})`);const He=Ce.body;if(!He)throw new Error("No response body");const vt=He.getReader(),Ie=new TextDecoder;let xe="",$e=!0;const je=async rt=>{if(Te!==V||ue.signal.aborted||!A)return;const pe=yi(rt);if(pe){if(pe.event==="audio"){const Le=pe.data.chunk,Pe=pe.data.visemes??[],Oe=pe.data.words??[],Ne=pe.data.is_new_segment??!1,Dt=pe.data.sample_rate,ct=Number(pe.data.audio_offset_ms??0);if(Le){const Bt=$e;$e=!1,await K.playAudioChunk(n,r,Le,Pe,Oe,Ne,{sampleRate:Dt,newStream:Bt,audioOffsetMs:ct})}else(Pe.length>0||Oe.length>0)&&K.queueTimingsOnly(n,r,Pe,Oe,Ne,{audioOffsetMs:ct,newStream:$e})}else if(pe.event==="metadata"){const Le=pe.data.mood;typeof Le=="string"&&Le.trim()&&(l=Le.trim());const Pe=pe.data.sentence_emotions;Array.isArray(Pe)&&(a.length=0,a.push(...An(Pe,l))),W()}else if(pe.event==="error")throw new Error(String(pe.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(Te!==V||ue.signal.aborted||!A);){const{done:rt,value:pe}=await vt.read();pe&&(xe+=Ie.decode(pe,{stream:!0}));const Le=xe.split(`
4
4
 
@@ -44,5 +44,5 @@ void main(void)
44
44
  float keep = step(uThreshold + 1e-6, peak);
45
45
  finalColor = vec4(color.rgb, keep);
46
46
  }
47
- `;function Gr(e=5){const t=new we.Filter({glProgram:we.GlProgram.from({vertex:Io,fragment:Ao,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=n=>{t.resources.thresholdUniforms.uniforms.uThreshold=n/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function Mo(e,t,n){return e>n||t>n}function Po(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function Co(e,t){return t!=null&&t>0?Math.floor(t):Po(e)}function Ro(e,t){const n=document.createElement("canvas");n.width=t.w,n.height=t.h;const r=n.getContext("2d");if(!r)throw new Error("Failed to acquire 2d context for atlas cell crop");return r.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}function ts(e){return fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load image: ${e}`);return t.blob()}).then(t=>createImageBitmap(t))}async function qr(e,t,n,r,i){const s=n?await Hi(e,i):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),o=s.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,u=async(c,m)=>{const w=Ki(t,m,n),T=n?await ha(await Mt(w,i??"")):await ts(w);if(Mo(T.width,T.height,r))return console.info(`[PixiVisemeCompositor] Sheet ${m} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${r}; using per-cell crops.`),{mode:"cells",bitmap:T};const f=we.Texture.from(T);return f.source.scaleMode="nearest",{mode:"full",texture:f}};a.set(o.index,await u(o.index,o.path));for(const c of s.sheets??[])c.index!==o.index&&c.path&&a.set(c.index,await u(c.index,c.path));const d=new Map;for(const c of s.cells??[])c.path&&d.set(c.path,c);const l=new Map;for(const c of s.sheets??[])l.set(c.index,c);return{atlasMeta:s,cellByPath:d,sheetByIndex:l,diffBase:t,sheets:a}}async function Do(e,t={}){const n=new we.Application;try{await n.init({canvas:e,width:842,height:1264,preference:"webgl",autoStart:!1,antialias:!1,resolution:1,autoDensity:!1,backgroundAlpha:1,backgroundColor:0,powerPreference:"high-performance"})}catch(p){throw n.destroy({removeView:!1}),p}if(n.renderer.type!==we.RendererType.WEBGL)throw n.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const r=Co(n.renderer.gl,t.maxTextureSize);let i=!1,s=!1,o=!1;const a=n.canvas,u=()=>{i=!0,!s&&!o&&(s=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",u);const d=new we.Sprite(we.Texture.EMPTY),l=new we.Sprite(we.Texture.EMPTY);l.visible=!1,l.alpha=0;const c=new we.Sprite(we.Texture.EMPTY),m=new we.Sprite(we.Texture.EMPTY),w=new we.Sprite(we.Texture.EMPTY);w.visible=!1;const T=Gr(5),f=Gr(5);c.filters=[T],m.filters=[f],n.stage.addChild(d),n.stage.addChild(l),n.stage.addChild(c),n.stage.addChild(m),n.stage.addChild(w);let E=null,D=null,B=null,v=null,k=null,L=null,A=null,ie=842,de=1264,I=null,V=5;const G=new Map;let ae=null,se=null,re=null;const O=fi(()=>{G.clear(),L=null,A=null,E=null,I=null}),J=(p,S)=>{ie=p,de=S,n.renderer.resize(p,S),(e.width!==p||e.height!==S)&&(e.width=p,e.height=S)},W=()=>{c.visible=!1,m.visible=!1,c.texture=we.Texture.EMPTY,m.texture=we.Texture.EMPTY,ae=null,se=null},he=()=>{k=null,l.visible=!1,l.alpha=0},K=()=>{d.visible=!0,d.width=ie,d.height=de,d.x=0,d.y=0},ee=()=>{l.width=ie,l.height=de,l.x=0,l.y=0},$=()=>{w.visible=!1,he(),E&&(d.texture=E,K())},X=()=>{!k&&!l.visible||$()},_e=p=>{if(o||i||!E){$();return}const S=Math.max(0,p);if(!D||S<=0){$();return}W(),w.visible=!1,d.texture=D,K(),l.texture=E,ee(),l.alpha=0,l.visible=!0,k={startMs:performance.now(),durationMs:S},q()},oe=(p=performance.now())=>{if(!k)return!1;if(o||i)return X(),!1;const S=(p-k.startMs)/Math.max(1,k.durationMs);if(S>=1)return $(),q(),!1;const x=Math.min(1,Math.max(0,S)),_=x*x*(3-2*x);return l.alpha=_,l.visible=!0,q(),!0},b=()=>{if(B){try{B.resource=null}catch{}B.destroy(),B=null}D&&(D.destroy(!1),D=null),v=null},P=(p,S)=>{const x=p.cellByPath.get(S);if(!x||!zi(x))return null;const _=`${p.diffBase}::${S}`;let U=G.get(_);if(!U){const Z=x.sheet??0,te=p.sheets.get(Z);if(!te)return null;let z,be=!1;if(te.mode==="full")z=new we.Texture({source:te.texture.source,frame:new we.Rectangle(x.x,x.y,x.w,x.h)});else{const Xe=Ro(te.bitmap,x);z=we.Texture.from(Xe),z.source.scaleMode="nearest",be=!0}U={texture:z,ownsSource:be},G.set(_,U)}return{texture:U.texture,cell:x}},H=(p,S,x,_)=>{if(!_||!x)return p.visible=!1,p.texture=we.Texture.EMPTY,!1;const U=P(x,_);if(!U)return p.visible=!1,p.texture=we.Texture.EMPTY,!1;const Z=Wi(x.atlasMeta,U.cell);return S.setThreshold(V),p.texture=U.texture,p.x=Z.x,p.y=Z.y,p.width=U.cell.w,p.height=U.cell.h,p.visible=!0,!0},le=p=>{if(!p||!L)return null;const S=I??new Set(L.cellByPath.keys());return ir(p,S)??(S.has(p)?p:null)},j=p=>{w.visible=!1,$();const S=le(p.mouthPath),x=p.expressionPath&&A?ar(p.expressionPath,_=>A.cellByPath.has(_)):null;S!==ae?(H(c,T,L,S),ae=S):S?c.visible=!0:c.visible=!1,x!==se?(H(m,f,A,x),se=x):x?m.visible=!0:m.visible=!1},q=()=>{if(!(o||i||document.hidden))try{n.render()}catch{}};return{async loadAssets(p){if(o)return{width:ie,height:de,visemePaths:[]};const S=Wt();if(S&&!p)throw new Error("Encrypted assets enabled but no key provided");const x=S?await wa(await Mt(sn(),p??"")):await ts(sn());E&&E.destroy(!0),E=we.Texture.from(x),E.source.scaleMode="linear";const _=mi();L=await qr(hi(),_,S,r,p);try{A=await qr(gi(),_,S,r,p)}catch(Z){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",Z),A=null}const U=Ui(L.atlasMeta,x.width,x.height);return J(U.width,U.height),V=vn(L.atlasMeta),T.setThreshold(V),f.setThreshold(V),I=new Set(L.cellByPath.keys()),G.clear(),$(),W(),q(),{width:U.width,height:U.height,visemePaths:[...L.cellByPath.keys()]}},getVisemeAtlasPaths(){return I},drawLiveFrame(p){o||i||!E||(X(),j(p),q())},drawIdleVideo(p,S){o||i||document.hidden||S&&!S()||p.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(he(),W(),w.visible=!1,!D||v!==p?(b(),B=new we.VideoSource({resource:p,autoPlay:!1,updateFPS:0}),B.autoUpdate=!1,D=new we.Texture({source:B}),v=p):D.source.update(),d.texture=D,K(),q())},beginIdleToSilCrossfade:_e,tickIdleToSilCrossfade:oe,finishIdleToSilCrossfade:X,isIdleToSilCrossfading(){return k!=null},renderSilOnly(){o||i||!E||(W(),$(),q())},blitBitmap(p){o||i||(X(),W(),re&&(re.destroy(!0),re=null),re=we.Texture.from(p),w.texture=re,w.visible=!0,w.x=0,w.y=0,w.width=ie,w.height=de,d.visible=!1,q())},async compositePrefetchFrame(p){return null},renderFrame:q,isContextLost(){return i},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",u),O(),b(),re&&(re.destroy(!0),re=null);for(const{texture:S,ownsSource:x}of G.values())S.destroy(x);G.clear(),E&&(E.destroy(!0),E=null);const p=S=>{S.mode==="full"?S.texture.destroy(!0):S.bitmap.close()};if(L)for(const S of L.sheets.values())p(S);if(A)for(const S of A.sheets.values())p(S);T.destroy(!0),f.destroy(!0),n.destroy({removeView:!1},{children:!0,texture:!0})}}}const Yr=-1,tn=1e5,Qr=new Map;async function Bo(e){let t=Qr.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),Qr.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function Fo(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function zn(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 Xr(e,t){let n=0,r=null;const i=fr(async(s,o)=>(await Un(),await Wn(e,s),i.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(s){const o=await Un(s);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,i.reset(),await eo(e)},drawLiveFrame(s,o,a,u){i.enqueue(o,a,u)},async compositePrefetchFrame(s,o){try{return await Za(s)}catch{return null}},blitBitmap(s,o){zn(s,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(s,o){n+=1;const a=n;t.onStatus?.(o),await Wn(s,{mouthPath:xt(o),expressionPath:null})},dispose(){n+=1,i.reset()}}}function Lo(e,t,n){let r=null,i=1,s=0,o=!1,a=!1,u=null;const d=new Map,l=new Map;let c=tn;const m=fr(async(B,v,k)=>(d.set(v,{drawKey:k.drawKey,onDisplayed:k.onDisplayed}),await E({type:"drawFrame",diffPath:B.mouthPath,expressionDiffPath:B.expressionPath,liveSeq:v},void 0,!0),!1)),w=B=>{if(B===Yr){let L=-1,A;for(const[ie,de]of d)ie>=L&&(L=ie,A=de);L>=0&&d.delete(L),A?.onDisplayed?.(A.drawKey);return}const v=-B,k=d.get(v);d.delete(v),k?.onDisplayed?.(k.drawKey)},T=new Map,f=(B,v)=>{a||!r||r.postMessage(B,[])},E=(B,v,k=!1)=>{if(a)return Promise.resolve();const L=i++;return new Promise((A,ie)=>{T.set(L,{resolve:de=>A(de),reject:ie,generation:typeof B.generation=="number"?B.generation:void 0,expectRenderDone:k}),f({...B,requestId:L})})},D=(async()=>{r=await Bo(n),r.onmessage=B=>{if(a)return;const v=B.data;if(v.type==="status"){t.onStatus?.(v.label);return}if(v.type==="frame"){if(v.generation<=-tn){const A=-v.generation,ie=l.get(A);l.delete(A),ie?.resolve(v.bitmap);return}const L=v.generation<0;if(!L&&v.generation!==s){v.bitmap.close();return}if(L&&!(v.generation===Yr)){const ie=-v.generation;if(!m.isLatestSeq(ie)){at()?.onWorkerStale(),v.bitmap.close();return}}if(L&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){at()?.onWorkerStale(),v.bitmap.close();return}zn(e,v.bitmap),v.bitmap.close(),L&&w(v.generation);return}const k=T.get(v.requestId);if(k)switch(v.type){case"ready":T.delete(v.requestId),k.resolve();break;case"loadAssetsDone":T.delete(v.requestId),u=v.visemePaths?.length?new Set(v.visemePaths):null,k.resolve({width:v.width,height:v.height,visemePaths:v.visemePaths});break;case"renderDone":if(k.expectRenderDone&&k.generation!=null&&v.generation!==k.generation)return;T.delete(v.requestId),k.resolve();break;case"renderAborted":T.delete(v.requestId),k.resolve();break;case"error":T.delete(v.requestId),t.onError?.(v.message),k.reject(new Error(v.message));break}},r.onerror=B=>{if(a)return;const v=B.message||"Worker error";t.onError?.(v);for(const[,k]of T)k.reject(new Error(v));T.clear()},await E({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(B){if(a)return{width:842,height:1264};if(await D,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await E({type:"loadAssets",keyHex:B,urls:Bs(wt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return u},async renderSilOnly(){if(a||(await D,a))return;s+=1,m.reset(),d.clear(),l.forEach(({resolve:v})=>v(null)),l.clear(),c=tn;const B=s;await E({type:"cancelLiveDraws"}),await E({type:"renderSil",generation:B},void 0,!0)},drawLiveFrame(B,v,k,L){a||D.then(()=>{a||m.enqueue(v,k,L)})},compositePrefetchFrame(B,v){return a?Promise.resolve(null):D.then(()=>{if(a)return null;const k=++c;return new Promise(L=>{l.set(k,{resolve:L}),E({type:"drawFrame",diffPath:B.mouthPath,expressionDiffPath:B.expressionPath,liveSeq:k},void 0,!0).catch(()=>{l.delete(k),L(null)})})})},blitBitmap(B,v){zn(B,v)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(B,v,k={}){if(a||(await D,a))return;s+=1,m.reset(),d.clear();const L=s;try{await E({type:"cancelLiveDraws"}),await E({type:"renderViseme",generation:L,to:v,from:k.from,transitionDurationMs:k.transitionDurationMs,gapMs:k.gapMs,threshold:k.threshold},void 0,!0)}catch(A){if(A?.name==="AbortError")return;throw A}},dispose(){if(!a){a=!0,s+=1,m.reset(),d.clear(),l.forEach(({resolve:B})=>B(null)),l.clear(),c=tn;for(const[,B]of T)B.resolve();T.clear(),r?.terminate(),r=null}}}}async function Oo(e,t){const n=await Do(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let r=0,i=null,s=!1;const o=fr(async(a,u)=>s?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(at()?.onWorkerStale(),!1):(n.drawLiveFrame(a),o.isLatestSeq(u)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(s)return{width:842,height:1264};const u=await n.loadAssets(a);return i=u.visemePaths?.length?new Set(u.visemePaths):null,u},getVisemeAtlasPaths(){return i},async renderSilOnly(){s||(r+=1,o.reset(),n.renderSilOnly())},drawLiveFrame(a,u,d,l){s||o.enqueue(u,d,l)},async compositePrefetchFrame(a,u){if(s)return null;try{return await n.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,u){s||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||n.blitBitmap(u)},drawIdleVideo(a,u){s||n.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){s||n.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return s?!1:n.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){s||n.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return s?!1:n.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,u){if(s)return;r+=1;const d=r;o.reset(),t.onStatus?.(u),n.drawLiveFrame({mouthPath:xt(u),expressionPath:null})},dispose(){s||(s=!0,r+=1,o.reset(),n.dispose())}}}function Jr(e,t){if(!Fo())return Xr(e,t);const n=ws(t.workerScriptUrl);try{return Lo(e,t,n)}catch{return Xr(e,t)}}function No(e,t={}){if(t.preferLegacyRenderer)return Jr(e,t);let n=null,r=!1,i=null,s=!1;const o=()=>n?Promise.resolve(n):(i||(i=(async()=>{try{const a=await Oo(e,t);if(s)throw a.dispose(),new Error("Renderer disposed during Pixi init");return r=!0,n=a,a}catch(a){if(s)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),n=Jr(e,t),r=!1,n}})()),i);return{get usesWorker(){return n?.usesWorker??!1},get usesPixi(){return r},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return n?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,u,d,l){o().then(c=>{s||c.drawLiveFrame(a,u,d,l)})},async compositePrefetchFrame(a,u){return(await o()).compositePrefetchFrame(a,u)},blitBitmap(a,u){n&&n.blitBitmap(a,u)},drawIdleVideo(a,u){n?.usesPixi&&n.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){n?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return n?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){n?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return n?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return n?.supportsBufferedPlayback??!1},async renderViseme(a,u,d){return(await o()).renderViseme(a,u,d)},dispose(){s=!0,i=null,n?.dispose(),n=null}}}class Vo extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Cn(e,t,n){return new Promise((r,i)=>{const s=globalThis.setTimeout(()=>{i(new Vo(n,t))},t);e.then(o=>{globalThis.clearTimeout(s),r(o)},o=>{globalThis.clearTimeout(s),i(o)})})}const Uo={overflow:"hidden",position:"relative",display:"inline-block",lineHeight:0},Wo={display:"block",maxWidth:"100%",height:"auto"},zo={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 Rn(e){return Ss(e)?tr:oi(e)?dn:er}function Je(e,t){return t?.isSpeaking()||t?.isWarmingUp()?t:e.isSpeaking()||e.isWarmingUp()?e:t?.isConnected()?t:e}const ns=h.forwardRef(function({id:t,avatarId:n,faceId:r,assets:i,authToken:s,apiBase:o,ttsEngineId:a,voiceId:u,language:d,speakingRate:l=Ht,className:c,style:m,canvasStyle:w,onStatusChange:T,onDisplayStatus:f,onError:E,onReady:D,showErrorOverlay:B=!0,loadingThumbnailUrl:v,onUserTranscript:k,onBotOutput:L,onRealtimeLipsyncDebug:A,onFrameRenderStats:ie,lipsyncBufferedPlayback:de=!0,lipsyncPlaybackWarmupMs:I=1500,idleHandoffHoldMs:V=ho,pixiMaxTextureSize:G,captions:ae},se){const re=h.useRef(null),O=h.useRef(null),J=h.useRef(null),W=h.useRef(de);W.current=de;const he=h.useRef(I);he.current=I;const K=h.useRef(V);K.current=V;const ee=h.useRef(0),$=h.useRef(ur()),X=h.useRef(Ha()),_e=h.useRef(!1),oe=h.useRef(null),b=h.useRef(null),P=h.useRef(0),H=h.useRef(0),le=h.useRef(0),j=h.useRef(null),q=h.useRef(null),p=h.useRef(!1),S=h.useRef(!1),x=h.useRef(!1),_=h.useRef(!1),U=h.useRef("sil"),Z=h.useRef(0),te=h.useRef(!1),z=h.useRef(null),be=h.useRef(!1),[Xe,Pt]=h.useState("idle"),[pt,Ct]=h.useState(null),[ot,_n]=h.useState(!1),[g,C]=h.useState(!1),[ne,ue]=h.useState(!1),[Te,ve]=h.useState(),[ke,We]=h.useState({width:842,height:1264}),[Fe,$t]=h.useState(null),[bn,Rt]=h.useState(0),yt=h.useRef(!1),Ce=h.useRef(s??null),He=o?.trim()||ht,vt=h.useRef(null),Ie=h.useRef(null),{ttsEngineId:xe,voiceId:$e}=h.useMemo(()=>{const y=et(a,u),M=y.ttsEngineId??dt;return{ttsEngineId:M,voiceId:y.voiceId??Rn(M)}},[a,u]),je=h.useRef(!1),rt=h.useRef({width:842,height:1264}),pe=h.useRef(null),Le=h.useRef("sil"),Pe=h.useRef(""),Oe=h.useMemo(()=>no(ae),[ae]),Ne=h.useCallback(()=>{Pe.current="",$t(null)},[]);h.useEffect(()=>{Oe.enabled||Ne()},[Oe.enabled,Ne]);const Dt=h.useCallback(y=>{if(!Oe.enabled)return;const M=y.isSpeaking(),N=y.isWarmingUp();if(!M||N){Pe.current&&Ne();return}const F=to(y.getWordQueue());if(!F){Pe.current&&Ne();return}F!==Pe.current&&(Pe.current=F,$t(F))},[Oe.enabled,Ne]),ct=h.useRef(void 0),Bt=h.useRef(new Map),mr=h.useRef(D),hr=h.useRef(T),ye=h.useRef(f),gr=h.useRef(E),wr=h.useRef(k),pr=h.useRef(L),jt=h.useRef(A),yr=h.useRef(ie),_t=h.useRef(mo());mr.current=D,hr.current=T,ye.current=f,gr.current=E,wr.current=k,pr.current=L,jt.current=A,yr.current=ie,h.useEffect(()=>{const y=_t.current;return zr(y),()=>zr(null)},[]);const vr=h.useCallback(y=>{const M=et(y?.ttsEngineId??a,y?.voiceId??u),N=M.ttsEngineId??Ie.current?.ttsEngineId??dt,F=M.voiceId??Ie.current?.voiceId??Rn(N);return{ttsEngineId:N,voiceId:F}},[a,u]),it=h.useCallback(y=>{Ct(y),ue(!0),gr.current?.(y)},[]),Ft=h.useCallback(y=>{Pt(y),hr.current?.(y)},[]),fe=h.useRef(Nn(Ft,He,{onLipsyncDebug:y=>jt.current?.(y)})),me=h.useRef(null),_r=h.useRef(()=>{});h.useEffect(()=>(fe.current=Nn(Ft,He,{onLipsyncDebug:y=>jt.current?.(y)}),s&&fe.current.setDeveloperToken(s),fe.current.setTtsEngineId(xe),()=>{fe.current.stop();const y=me.current;y&&(y.disconnect(),me.current=null)}),[Ft,He]);const br=h.useCallback(()=>(me.current||(me.current=Vi(Ft,{speakingRate:l,language:d,onUserTranscript:(y,M)=>wr.current?.(y,M),onBotOutput:y=>pr.current?.(y),onLipsyncDebug:y=>jt.current?.(y)}),me.current.setTtsEngineId(xe),_r.current(!0)),me.current),[Ft,l,d,xe]),Re=h.useCallback(()=>{j.current!=null&&(clearTimeout(j.current),j.current=null)},[]),De=h.useCallback(()=>{q.current!=null&&(clearTimeout(q.current),q.current=null),x.current=!1},[]),Kt=h.useCallback(()=>{if(_.current)return;const y=O.current;if(_.current=!0,De(),p.current=!1,S.current=!1,!be.current||!z.current){y?.renderSilOnly();return}z.current.setActive(!1);const M=z.current.getVideo();if(y?.usesPixi){y.drawIdleVideo(M),y.beginIdleToSilCrossfade($r);return}(async()=>{const N=re.current;N&&await Mn(N,M,null,void 0,rt.current).catch(()=>{}),await new Promise(F=>setTimeout(F,$r)),_.current&&await y?.renderSilOnly()})()},[De]),Sr=h.useCallback(()=>{!be.current||!z.current||(_.current=!1,O.current?.finishIdleToSilCrossfade(),De(),x.current=!0,q.current=setTimeout(()=>{if(q.current=null,Je(fe.current,me.current).isSpeaking()){x.current=!1;return}if(p.current){x.current=!1;return}const y=z.current;if(!y){x.current=!1;return}y.restart(),y.setActive(!0);const M=y.getVideo();let N=!1;const F=()=>{N||(N=!0,M.removeEventListener("playing",Q),x.current=!1)},Q=()=>{F()};if(M.addEventListener("playing",Q,{once:!0}),M.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!M.paused){F();return}setTimeout(F,300)},K.current))},[De]),bt=h.useCallback(()=>{if(Re(),ye.current?.("sil"),p.current=!1,_.current=!1,!be.current||!z.current){x.current=!1;return}Sr()},[Re,Sr]),Sn=h.useCallback(async y=>{const M=H.current,N=O.current,F=re.current,Q=()=>{y?.fallbackOnly||(p.current=!1)};if(!N||!F||!ot){Q();return}if(Je(fe.current,me.current).isSpeaking()){Q();return}if(y?.fallbackOnly){if(!p.current||(Be($.current),await N.renderSilOnly(),M!==H.current)||Je(fe.current,me.current).isSpeaking())return;bt();return}if(jr($.current)){Be($.current),bt();return}if(W.current&&N.supportsBufferedPlayback&&!y?.fallbackOnly){if(Be($.current),J.current?.reset(),await N.renderSilOnly(),M!==H.current||Je(fe.current,me.current).isSpeaking())return;bt();return}const Ee=vo(Je(fe.current,me.current).getVisemeQueue(),Z.current,U.current),Ve=_o(Ee,pe.current);if(Be($.current),!Ve){if(await N.renderSilOnly(),M!==H.current||Je(fe.current,me.current).isSpeaking())return;bt();return}try{await N.renderViseme(F,"sil",{from:Ee,transitionDurationMs:Ji})}catch(Me){if(Me?.name!=="AbortError")throw Me}if(M!==H.current){Q();return}if(Je(fe.current,me.current).isSpeaking()){Q();return}bt()},[ot,bt]),St=h.useCallback(()=>{if(S.current||p.current)return;S.current=!0,p.current=!0,Re();const y=H.current;Sn().finally(()=>{S.current=!1}),j.current=setTimeout(()=>{j.current=null,y===H.current&&Sn({fallbackOnly:!0})},bo())},[Re,Sn]),Tr=h.useCallback(async()=>{const y=Math.floor(Date.now()/1e3);if(vt.current&&y<vt.current.expiresAt-60)return vt.current.key;const M=Ce.current??await Nt();Ce.current=M,fe.current.setDeveloperToken(M);const N=await Ps(M,He);return vt.current={key:N.value,expiresAt:N.expiresAt},N.value},[He]);h.useEffect(()=>{s&&(Ce.current=s,fe.current.setDeveloperToken(s))},[s]),h.useEffect(()=>{fe.current.setTtsEngineId(xe),me.current?.setTtsEngineId(xe),Ie.current&&(Ie.current.ttsEngineId=xe)},[xe]),h.useEffect(()=>{Ie.current&&(Ie.current.voiceId=$e)},[$e]);const Ke=h.useMemo(()=>ui(n,r),[n,r]),os=h.useMemo(()=>i?JSON.stringify(i):Ke?`face:${Ke}`:`id:${t??""}`,[i,Ke,t]),cs=h.useMemo(()=>{const y=v?.trim();return y||(xr(Ke)??xr(Te)??ks(i))},[v,Ke,Te,i]);return h.useEffect(()=>{if(!t&&!i&&!Ke){it("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let y=!1;je.current=!1,_n(!1),C(!1),ue(!1),ve(Ke),Ct(null),Ie.current=null,z.current=null,be.current=!1;const M=re.current;if(!M)return;let N=null;return(async()=>{try{let F,Q,Se,Ee;if(i)F=i,Q=xe,Se=$e;else if(Ke)ye.current?.("loadFace"),F=Ln(Ke),Q=xe,Se=$e;else{ye.current?.("getAiTwin");const Y=await Cn(ci(t),3e4,"getAiTwin");if(y)return;if(!Y.faceId?.trim())throw new Error("getAiTwin returned no faceId");ve(Y.faceId.trim());const ce=et(a,u);Q=ce.ttsEngineId??Y.ttsEngineId,Se=ce.voiceId??Y.voiceId??Rn(Q),Ee=qn(Y),F=Ln(Y.faceId)}Ie.current={ttsEngineId:Q,voiceId:Se,brainId:Ee},di(F),z.current=$a();const Ve=!!(i&&!gt(i));N=No(M,{preferLegacyRenderer:Ve,pixiMaxTextureSize:G,onStatus:Y=>{y||ye.current?.(Y)},onError:Y=>{y||it(Y)},shouldAcceptLiveFrame:()=>{if(_e.current)return!0;if(p.current)return!1;const Y=Je(fe.current,me.current);return Y.isSpeaking()||Y.isWarmingUp()},onWebGlContextLost:()=>{y||yt.current||(yt.current=!0,queueMicrotask(()=>{y||Rt(Y=>Y+1)}))}}),O.current=N,J.current=xo(N),yt.current=!1;const Me=Y=>{const ce=()=>{if(!Y||he.current<=0)return!1;const Ae=O.current;return Ae?W.current&&Ae.supportsBufferedPlayback?!0:Ae.usesPixi:!1};fe.current.setLipsyncWarmupHold(Y,ce),me.current?.setLipsyncWarmupHold(Y,ce)};_r.current=Me,Me(!0),ye.current?.("auth");const Ge=Ce.current??s??await Cn(Nt(),3e4,"getAuthToken");if(y)return;Ce.current=Ge,fe.current.setDeveloperToken(Ge),fe.current.setTtsEngineId(Q);const Gt=Wt()?await Tr():void 0;if(y)return;ye.current?.("loadAssets");const ge=await Cn(N.loadAssets(Gt),18e4,"load face assets");if(!y&&ge.width>0&&ge.height>0&&(rt.current=ge,We(ge)),y)return;pe.current=N.getVisemeAtlasPaths(),je.current=!0,_n(!0),mr.current?.(),N.renderSilOnly().then(()=>{y||ye.current?.("sil")}),(async()=>{try{const Y=await va(Gt);if(await z.current.load(Y),y)return;be.current=!0,C(!0),Be($.current),z.current.setActive(!0);const ce=z.current.getVideo();N.usesPixi?N.drawIdleVideo(ce):await Mn(M,ce,null,void 0,rt.current)}catch(Y){if(y)return;be.current=!1,C(!1),console.warn("[AiTwin] Idle video unavailable:",Y)}finally{y||(ue(!0),ye.current?.("idle"))}})()}catch(F){if(y)return;if(F instanceof nn){it(F.message);return}it(F instanceof Error?F.message:"Failed to load AI twin")}})(),()=>{y=!0,z.current?.dispose(),N?.dispose(),O.current=null}},[os,i,Ke,t,xe,$e,a,u,s,G,Tr,it,bn]),h.useEffect(()=>{const y={current:!1},M=()=>{const N=re.current,F=O.current,Q=Je(fe.current,me.current);if(!N||!F||!ot){P.current=requestAnimationFrame(M);return}if(document.hidden){z.current?.setActive(!1),P.current=requestAnimationFrame(M);return}const Se=Q.isSpeaking(),Ee=Q.isWarmingUp(),Ve=Se&&!te.current,Me=te.current&&!Se;Ve&&(Re(),De(),p.current=!1,S.current=!1,Be($.current),J.current?.reset(),_t.current.reset(),ct.current=void 0,le.current=0,U.current="sil",Z.current=0,Kt()),Me&&(X.current.reset(),z.current?.setActive(!1),J.current?.reset(),F.finishIdleToSilCrossfade(),Ne(),St());const Ge=Me||p.current||x.current||_.current,Gt=de&&F.supportsBufferedPlayback;if(Ee){if(Kt(),be.current&&z.current?.setActive(!1),F.usesPixi&&F.isIdleToSilCrossfading()){F.tickIdleToSilCrossfade(performance.now()),Q.getVisemeQueue().length>0&&ee.current===0&&(ee.current=performance.now()),te.current=Q.isSpeaking(),P.current=requestAnimationFrame(M);return}const ge=Q.getVisemeQueue();ge.length>0&&ee.current===0&&(ee.current=performance.now()),X.current.advance(performance.now());const Y=X.current.getExpressionPath(),ce=X.current.getDrawKey(),Ae={queue:ge,elapsedMs:0,expressionPath:Y,expressionDrawKey:ce,availablePaths:pe.current};let Ue=!1;Gt&&J.current?(J.current.warmupTick(Ae),Ue=J.current.isWarmupReady(Ae,he.current)):F.usesPixi&&Kr(N,ge,0,Y,ce,$.current,(Tt,qt,Tn,Yt)=>{F.drawLiveFrame(Tt,qt,Tn,qe=>{Yt?.(qe),Q.isWarmingUp()&&qe!==""&&!jr({lastDrawnKey:qe})&&(ee.current=0,Q.releaseWarmupHold())})},Tt=>{ye.current?.(Tt.label)},pe.current);const st=ee.current>0&&performance.now()-ee.current>ys;ye.current?.(Ue?"buffer ready":"buffering lipsync…"),(Ue||st)&&(ee.current=0,Q.releaseWarmupHold()),Dt(Q),te.current=Q.isSpeaking(),P.current=requestAnimationFrame(M);return}if(Se){Kt(),be.current&&z.current?.setActive(!1),F.usesPixi&&F.isIdleToSilCrossfading()&&F.finishIdleToSilCrossfade();const ge=Q.getVisemeQueue(),Y=Q.getPlaybackElapsedMs();aa(ge,Y),Z.current=Y;const ce=ge.length>0?zt(ge,Y):"sil";ce!=="sil"&&(U.current=ce);const Ae=qa(Y,Q.getSentenceEmotions(),Q.getWordQueue(),Q.getStreamMood());X.current.setTargetEmotion(Ae),X.current.setTargetEyebrow(Wa(Y,Q.getWordQueue(),mt(Ae))),X.current.advance(performance.now());const Ue=X.current.getExpressionPath(),st=X.current.getDrawKey(),Tt=(qe,kn,Lt,En)=>{const kr={label:Le.current,elapsedMs:Y,mouthPath:kn.mouthPath,transitionMeta:ct.current};Bt.current.set(Lt,kr),J.current?.markExternallyDisplayed(Lt,Ue),F.drawLiveFrame(qe,kn,Lt,Qt=>{const ls=Bt.current.get(Qt)??kr;Bt.current.delete(Qt),_t.current.onDrawDisplayed(ls,ge),J.current?.markExternallyDisplayed(Qt,Ue),En?.(Qt)})},qt=qe=>{Le.current=qe.label,ct.current=qe.transitionMeta,ye.current?.(qe.label)},Tn=de&&F.supportsBufferedPlayback;let Yt=!1;Tn&&J.current&&(Yt=J.current.tick({canvas:N,queue:ge,elapsedMs:Y,expressionPath:Ue,expressionDrawKey:st,playbackState:$.current,availablePaths:pe.current,onStatus:qt,onDisplayed:(kn,Lt,En)=>{_t.current.onDrawDisplayed({label:En,elapsedMs:Y,mouthPath:Lt,transitionMeta:ct.current},ge)}}).usedBuffer),Yt||Kr(N,ge,Y,Ue,st,$.current,Tt,qt,pe.current),_t.current.onRafTickSpeaking(),yr.current?.(_t.current.snapshot(ge,Y))}else if(!Ge&&_e.current){z.current?.setActive(!1),X.current.advance(performance.now());const ge=X.current.getExpressionPath(),Y=X.current.getDrawKey();Pn(N,ge,Y,$.current,(ce,Ae,Ue,st)=>F.drawLiveFrame(ce,Ae,Ue,st),ce=>{if(b.current){ye.current?.(b.current);return}const Ae=X.current.getTargetEmotion();ye.current?.(ce==="sil"||ce==="blink"?`${Ae}${ce==="blink"?" · blink":""}`:ce)},null,oe.current)}else if(!Ge&&be.current&&z.current){const ge=z.current,Y=ge.getVideo();if(Y.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){ge.setActive(!0);const ce=()=>!Q.isSpeaking()&&!p.current&&!x.current&&!_e.current;F.usesPixi?(F.drawIdleVideo(Y,ce),ce()&&ye.current?.("idle")):y.current||(y.current=!0,Mn(N,Y,null,void 0,rt.current,ce).then(()=>ye.current?.("idle")).finally(()=>{y.current=!1}))}else Pn(N,null,"__sil__",$.current,(ce,Ae,Ue,st)=>F.drawLiveFrame(ce,Ae,Ue,st),ce=>ye.current?.(ce))}else Ge||Pn(N,null,"__sil__",$.current,(ge,Y,ce,Ae)=>F.drawLiveFrame(ge,Y,ce,Ae),ge=>ye.current?.(ge));Oe.enabled&&Dt(Q),te.current=Se,P.current=requestAnimationFrame(M)};return P.current=requestAnimationFrame(M),()=>{cancelAnimationFrame(P.current),Re(),De(),fe.current.stop(),me.current?.stop()}},[ot,g,St,Re,De,Kt,Dt,Ne,Oe.enabled]),h.useImperativeHandle(se,()=>({speakText:async(y,M)=>{const N=y.trim();if(!N)return;const F=O.current;if(!F||!je.current&&!ot)throw new Error("AI twin is not ready");const{ttsEngineId:Q,voiceId:Se}=vr(M);Ct(null),Ne(),H.current+=1,Re(),De(),p.current=!1,S.current=!1,U.current="sil",Z.current=0,Be($.current),_e.current=!1,oe.current=null,b.current=null,X.current.reset(),te.current=!1,_.current=!1,F.finishIdleToSilCrossfade();try{await fe.current.speak(N,{voiceId:Se,speakingRate:M?.speakingRate??l,ttsEngineId:Q,language:M?.language??d})}catch(Ee){throw _.current=!1,F.finishIdleToSilCrossfade(),St(),it(Ee instanceof Error?Ee.message:"TTS failed"),Ee}},stop:()=>{H.current+=1,Re(),De(),p.current=!1,S.current=!1,_.current=!1,O.current?.finishIdleToSilCrossfade(),fe.current.stop(),me.current?.stop(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,Ne(),St()},setTtsEngineId:y=>{fe.current.setTtsEngineId(y),me.current?.setTtsEngineId(y),Ie.current&&(Ie.current.ttsEngineId=y)},renderViseme:async(y,M)=>{const N=O.current,F=re.current;if(!N||!F||!je.current)throw new Error("AI twin is not ready");await N.renderViseme(F,y,{from:M?.from,transitionDurationMs:M?.transitionDurationMs,gapMs:M?.gapMs,onStatus:Q=>ye.current?.(Q)})},setEmotion:y=>{if(!je.current)throw new Error("AI twin is not ready");const M=O.current,N=re.current;if(!M||!N)throw new Error("AI twin is not ready");H.current+=1,Re(),De(),p.current=!1,S.current=!1,x.current=!1,_.current=!1,fe.current.stop(),me.current?.stop(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,M.finishIdleToSilCrossfade(),z.current?.setActive(!1);const F=Ze(y);_e.current=!0,oe.current=null,b.current=null,X.current.snapToEmotion(F);const Q=X.current.getExpressionPath(),Se=X.current.getDrawKey(),Ee={mouthPath:null,expressionPath:Q},Ve=Ut(Ee,Se);$.current.lastDrawnKey="",M.drawLiveFrame(N,Ee,Ve,Ge=>{Ge===Ve&&($.current.lastDrawnKey=Ve)});const Me=mt(F);ye.current?.(Q?`${F} · brow ${Me>0?"+":""}${Me}`:`${F} · brow 0 (sil base)`)},getEmotion:()=>_e.current?X.current.getTargetEmotion():null,clearEmotionPreview:()=>{_e.current=!1,oe.current=null,b.current=null,X.current.reset(),Be($.current),ye.current?.("idle")},setViseme:y=>{if(!je.current)throw new Error("AI twin is not ready");const M=O.current,N=re.current;if(!M||!N)throw new Error("AI twin is not ready");H.current+=1,Re(),De(),p.current=!1,S.current=!1,x.current=!1,_.current=!1,fe.current.stop(),me.current?.stop(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,M.finishIdleToSilCrossfade(),z.current?.setActive(!1);const F=mn(y);_e.current=!0,b.current=F,oe.current=F==="sil"?null:xt(F),X.current.snapToEmotion("neutral");const Q=X.current.getExpressionPath(),Se=X.current.getDrawKey(),Ve={mouthPath:oe.current,expressionPath:Q},Me=Ut(Ve,Se);$.current.lastDrawnKey="",M.drawLiveFrame(N,Ve,Me,Ge=>{Ge===Me&&($.current.lastDrawnKey=Me)}),ye.current?.(F)},getViseme:()=>_e.current?b.current:null,isReady:()=>je.current,getStatus:()=>Xe,connect:async(y={})=>{Ct(null);try{let M=y.authToken?.trim();M||(M=Ce.current??s??await Nt(),Ce.current=M);const N=et(y.ttsEngineId??a,y.voiceId??u),F=N.voiceId??Ie.current?.voiceId,Q=y.brainId?.trim()||y.personaId?.trim()||Ie.current?.brainId,Se=N.ttsEngineId??Ie.current?.ttsEngineId??xe,Ee=br();Se&&Ee.setTtsEngineId(Se),await Ee.unlockAudio(),await Ee.connect({...y,apiBase:y.apiBase?.trim()||He,authToken:M,voiceId:F,brainId:Q,ttsEngineId:Se,speakingRate:y.speakingRate??l,language:y.language??d})}catch(M){throw it(M instanceof Error?M.message:"Voice connect failed"),M}},disconnect:async()=>{const y=me.current;y&&(H.current+=1,Re(),De(),p.current=!1,S.current=!1,_.current=!1,O.current?.finishIdleToSilCrossfade(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,await y.disconnect(),St())},isConnected:()=>me.current?.isConnected()??!1,getVoiceStream:()=>me.current?.getVoiceStream()??fe.current?.getVoiceStream()??null,setMuted:y=>{const M=fe.current,N=me.current;M?.setMuted?.(y),N?.setMuted?.(y)},isMuted:()=>{const y=me.current,M=fe.current;return y?.isMuted?.()??M?.isMuted?.()??!1},getBrainId:()=>Ie.current?.brainId?.trim()||null,getPersonaId:()=>Ie.current?.brainId?.trim()||null}),[ot,l,d,s,xe,$e,Re,De,St,it,vr,br,Xe,He]),R.jsxs("div",{className:c,style:{...Uo,...m},children:[R.jsx("canvas",{ref:re,width:ke.width,height:ke.height,style:{...Wo,...w},"aria-label":t?`AI twin ${t}`:"AI twin face"}),!ne&&!pt?R.jsx(uo,{thumbnailUrl:cs}):null,B&&pt?R.jsx("div",{style:zo,children:pt}):null,Oe.enabled&&Fe?R.jsx(ao,{text:Fe,style:Oe.style},Fe):null]})});async function Ho(e){try{const t=await e.json();if(typeof t.detail=="string"&&t.detail.trim())return t.detail;if(typeof t.error=="string"&&t.error.trim())return t.error}catch{}return`avatarReply failed (${e.status})`}async function rs(e){const t=e.message.trim();if(!t)throw new Error("Message is required");const n=e.authToken.trim();if(!n)throw new Error("Auth token is required");const r=(e.apiBase?.trim()||ht).replace(/\/$/,""),i=await fetch(`${r}/avatarReply`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`,Accept:"text/event-stream"},body:JSON.stringify({message:t,history:e.history??[],brainId:e.brainId?.trim()||e.personaId?.trim()||""})});if(!i.ok)throw new Error(await Ho(i));if(!i.body)throw new Error("avatarReply response body is empty");const s=i.body.getReader(),o=new TextDecoder;let a="",u="",d="",l="";for(;;){const{done:c,value:m}=await s.read();if(c)break;a+=o.decode(m,{stream:!0});const w=a.split(`
47
+ `;function Gr(e=5){const t=new we.Filter({glProgram:we.GlProgram.from({vertex:Io,fragment:Ao,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=n=>{t.resources.thresholdUniforms.uniforms.uThreshold=n/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function Mo(e,t,n){return e>n||t>n}function Po(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function Co(e,t){return t!=null&&t>0?Math.floor(t):Po(e)}function Ro(e,t){const n=document.createElement("canvas");n.width=t.w,n.height=t.h;const r=n.getContext("2d");if(!r)throw new Error("Failed to acquire 2d context for atlas cell crop");return r.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}function ts(e){return fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load image: ${e}`);return t.blob()}).then(t=>createImageBitmap(t))}async function qr(e,t,n,r,i){const s=n?await Hi(e,i):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),o=s.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,u=async(c,m)=>{const w=Ki(t,m,n),T=n?await ha(await Mt(w,i??"")):await ts(w);if(Mo(T.width,T.height,r))return console.info(`[PixiVisemeCompositor] Sheet ${m} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${r}; using per-cell crops.`),{mode:"cells",bitmap:T};const f=we.Texture.from(T);return f.source.scaleMode="nearest",{mode:"full",texture:f}};a.set(o.index,await u(o.index,o.path));for(const c of s.sheets??[])c.index!==o.index&&c.path&&a.set(c.index,await u(c.index,c.path));const d=new Map;for(const c of s.cells??[])c.path&&d.set(c.path,c);const l=new Map;for(const c of s.sheets??[])l.set(c.index,c);return{atlasMeta:s,cellByPath:d,sheetByIndex:l,diffBase:t,sheets:a}}async function Do(e,t={}){const n=new we.Application;try{await n.init({canvas:e,width:842,height:1264,preference:"webgl",autoStart:!1,antialias:!1,resolution:1,autoDensity:!1,backgroundAlpha:1,backgroundColor:0,powerPreference:"high-performance"})}catch(p){throw n.destroy({removeView:!1}),p}if(n.renderer.type!==we.RendererType.WEBGL)throw n.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const r=Co(n.renderer.gl,t.maxTextureSize);let i=!1,s=!1,o=!1;const a=n.canvas,u=()=>{i=!0,!s&&!o&&(s=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",u);const d=new we.Sprite(we.Texture.EMPTY),l=new we.Sprite(we.Texture.EMPTY);l.visible=!1,l.alpha=0;const c=new we.Sprite(we.Texture.EMPTY),m=new we.Sprite(we.Texture.EMPTY),w=new we.Sprite(we.Texture.EMPTY);w.visible=!1;const T=Gr(5),f=Gr(5);c.filters=[T],m.filters=[f],n.stage.addChild(d),n.stage.addChild(l),n.stage.addChild(c),n.stage.addChild(m),n.stage.addChild(w);let E=null,D=null,B=null,v=null,k=null,L=null,A=null,ie=842,de=1264,I=null,V=5;const G=new Map;let ae=null,se=null,re=null;const O=fi(()=>{G.clear(),L=null,A=null,E=null,I=null}),J=(p,S)=>{ie=p,de=S,n.renderer.resize(p,S),(e.width!==p||e.height!==S)&&(e.width=p,e.height=S)},W=()=>{c.visible=!1,m.visible=!1,c.texture=we.Texture.EMPTY,m.texture=we.Texture.EMPTY,ae=null,se=null},he=()=>{k=null,l.visible=!1,l.alpha=0},K=()=>{d.visible=!0,d.width=ie,d.height=de,d.x=0,d.y=0},ee=()=>{l.width=ie,l.height=de,l.x=0,l.y=0},$=()=>{w.visible=!1,he(),E&&(d.texture=E,K())},X=()=>{!k&&!l.visible||$()},_e=p=>{if(o||i||!E){$();return}const S=Math.max(0,p);if(!D||S<=0){$();return}W(),w.visible=!1,d.texture=D,K(),l.texture=E,ee(),l.alpha=0,l.visible=!0,k={startMs:performance.now(),durationMs:S},q()},oe=(p=performance.now())=>{if(!k)return!1;if(o||i)return X(),!1;const S=(p-k.startMs)/Math.max(1,k.durationMs);if(S>=1)return $(),q(),!1;const x=Math.min(1,Math.max(0,S)),_=x*x*(3-2*x);return l.alpha=_,l.visible=!0,q(),!0},b=()=>{if(B){try{B.resource=null}catch{}B.destroy(),B=null}D&&(D.destroy(!1),D=null),v=null},P=(p,S)=>{const x=p.cellByPath.get(S);if(!x||!zi(x))return null;const _=`${p.diffBase}::${S}`;let U=G.get(_);if(!U){const Z=x.sheet??0,te=p.sheets.get(Z);if(!te)return null;let z,be=!1;if(te.mode==="full")z=new we.Texture({source:te.texture.source,frame:new we.Rectangle(x.x,x.y,x.w,x.h)});else{const Xe=Ro(te.bitmap,x);z=we.Texture.from(Xe),z.source.scaleMode="nearest",be=!0}U={texture:z,ownsSource:be},G.set(_,U)}return{texture:U.texture,cell:x}},H=(p,S,x,_)=>{if(!_||!x)return p.visible=!1,p.texture=we.Texture.EMPTY,!1;const U=P(x,_);if(!U)return p.visible=!1,p.texture=we.Texture.EMPTY,!1;const Z=Wi(x.atlasMeta,U.cell);return S.setThreshold(V),p.texture=U.texture,p.x=Z.x,p.y=Z.y,p.width=U.cell.w,p.height=U.cell.h,p.visible=!0,!0},le=p=>{if(!p||!L)return null;const S=I??new Set(L.cellByPath.keys());return ir(p,S)??(S.has(p)?p:null)},j=p=>{w.visible=!1,$();const S=le(p.mouthPath),x=p.expressionPath&&A?ar(p.expressionPath,_=>A.cellByPath.has(_)):null;S!==ae?(H(c,T,L,S),ae=S):S?c.visible=!0:c.visible=!1,x!==se?(H(m,f,A,x),se=x):x?m.visible=!0:m.visible=!1},q=()=>{if(!(o||i||document.hidden))try{n.render()}catch{}};return{async loadAssets(p){if(o)return{width:ie,height:de,visemePaths:[]};const S=Wt();if(S&&!p)throw new Error("Encrypted assets enabled but no key provided");const x=S?await wa(await Mt(sn(),p??"")):await ts(sn());E&&E.destroy(!0),E=we.Texture.from(x),E.source.scaleMode="linear";const _=mi();L=await qr(hi(),_,S,r,p);try{A=await qr(gi(),_,S,r,p)}catch(Z){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",Z),A=null}const U=Ui(L.atlasMeta,x.width,x.height);return J(U.width,U.height),V=vn(L.atlasMeta),T.setThreshold(V),f.setThreshold(V),I=new Set(L.cellByPath.keys()),G.clear(),$(),W(),q(),{width:U.width,height:U.height,visemePaths:[...L.cellByPath.keys()]}},getVisemeAtlasPaths(){return I},drawLiveFrame(p){o||i||!E||(X(),j(p),q())},drawIdleVideo(p,S){o||i||document.hidden||S&&!S()||p.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(he(),W(),w.visible=!1,!D||v!==p?(b(),B=new we.VideoSource({resource:p,autoPlay:!1,updateFPS:0}),B.autoUpdate=!1,D=new we.Texture({source:B}),v=p):D.source.update(),d.texture=D,K(),q())},beginIdleToSilCrossfade:_e,tickIdleToSilCrossfade:oe,finishIdleToSilCrossfade:X,isIdleToSilCrossfading(){return k!=null},renderSilOnly(){o||i||!E||(W(),$(),q())},blitBitmap(p){o||i||(X(),W(),re&&(re.destroy(!0),re=null),re=we.Texture.from(p),w.texture=re,w.visible=!0,w.x=0,w.y=0,w.width=ie,w.height=de,d.visible=!1,q())},async compositePrefetchFrame(p){return null},renderFrame:q,isContextLost(){return i},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",u),O(),b(),re&&(re.destroy(!0),re=null);for(const{texture:S,ownsSource:x}of G.values())S.destroy(x);G.clear(),E&&(E.destroy(!0),E=null);const p=S=>{S.mode==="full"?S.texture.destroy(!0):S.bitmap.close()};if(L)for(const S of L.sheets.values())p(S);if(A)for(const S of A.sheets.values())p(S);T.destroy(!0),f.destroy(!0),n.destroy({removeView:!1},{children:!0,texture:!0})}}}const Yr=-1,tn=1e5,Qr=new Map;async function Bo(e){let t=Qr.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),Qr.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function Fo(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function zn(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 Xr(e,t){let n=0,r=null;const i=fr(async(s,o)=>(await Un(),await Wn(e,s),i.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(s){const o=await Un(s);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,i.reset(),await eo(e)},drawLiveFrame(s,o,a,u){i.enqueue(o,a,u)},async compositePrefetchFrame(s,o){try{return await Za(s)}catch{return null}},blitBitmap(s,o){zn(s,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(s,o){n+=1;const a=n;t.onStatus?.(o),await Wn(s,{mouthPath:xt(o),expressionPath:null})},dispose(){n+=1,i.reset()}}}function Lo(e,t,n){let r=null,i=1,s=0,o=!1,a=!1,u=null;const d=new Map,l=new Map;let c=tn;const m=fr(async(B,v,k)=>(d.set(v,{drawKey:k.drawKey,onDisplayed:k.onDisplayed}),await E({type:"drawFrame",diffPath:B.mouthPath,expressionDiffPath:B.expressionPath,liveSeq:v},void 0,!0),!1)),w=B=>{if(B===Yr){let L=-1,A;for(const[ie,de]of d)ie>=L&&(L=ie,A=de);L>=0&&d.delete(L),A?.onDisplayed?.(A.drawKey);return}const v=-B,k=d.get(v);d.delete(v),k?.onDisplayed?.(k.drawKey)},T=new Map,f=(B,v)=>{a||!r||r.postMessage(B,[])},E=(B,v,k=!1)=>{if(a)return Promise.resolve();const L=i++;return new Promise((A,ie)=>{T.set(L,{resolve:de=>A(de),reject:ie,generation:typeof B.generation=="number"?B.generation:void 0,expectRenderDone:k}),f({...B,requestId:L})})},D=(async()=>{r=await Bo(n),r.onmessage=B=>{if(a)return;const v=B.data;if(v.type==="status"){t.onStatus?.(v.label);return}if(v.type==="frame"){if(v.generation<=-tn){const A=-v.generation,ie=l.get(A);l.delete(A),ie?.resolve(v.bitmap);return}const L=v.generation<0;if(!L&&v.generation!==s){v.bitmap.close();return}if(L&&!(v.generation===Yr)){const ie=-v.generation;if(!m.isLatestSeq(ie)){at()?.onWorkerStale(),v.bitmap.close();return}}if(L&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){at()?.onWorkerStale(),v.bitmap.close();return}zn(e,v.bitmap),v.bitmap.close(),L&&w(v.generation);return}const k=T.get(v.requestId);if(k)switch(v.type){case"ready":T.delete(v.requestId),k.resolve();break;case"loadAssetsDone":T.delete(v.requestId),u=v.visemePaths?.length?new Set(v.visemePaths):null,k.resolve({width:v.width,height:v.height,visemePaths:v.visemePaths});break;case"renderDone":if(k.expectRenderDone&&k.generation!=null&&v.generation!==k.generation)return;T.delete(v.requestId),k.resolve();break;case"renderAborted":T.delete(v.requestId),k.resolve();break;case"error":T.delete(v.requestId),t.onError?.(v.message),k.reject(new Error(v.message));break}},r.onerror=B=>{if(a)return;const v=B.message||"Worker error";t.onError?.(v);for(const[,k]of T)k.reject(new Error(v));T.clear()},await E({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(B){if(a)return{width:842,height:1264};if(await D,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await E({type:"loadAssets",keyHex:B,urls:Bs(wt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return u},async renderSilOnly(){if(a||(await D,a))return;s+=1,m.reset(),d.clear(),l.forEach(({resolve:v})=>v(null)),l.clear(),c=tn;const B=s;await E({type:"cancelLiveDraws"}),await E({type:"renderSil",generation:B},void 0,!0)},drawLiveFrame(B,v,k,L){a||D.then(()=>{a||m.enqueue(v,k,L)})},compositePrefetchFrame(B,v){return a?Promise.resolve(null):D.then(()=>{if(a)return null;const k=++c;return new Promise(L=>{l.set(k,{resolve:L}),E({type:"drawFrame",diffPath:B.mouthPath,expressionDiffPath:B.expressionPath,liveSeq:k},void 0,!0).catch(()=>{l.delete(k),L(null)})})})},blitBitmap(B,v){zn(B,v)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(B,v,k={}){if(a||(await D,a))return;s+=1,m.reset(),d.clear();const L=s;try{await E({type:"cancelLiveDraws"}),await E({type:"renderViseme",generation:L,to:v,from:k.from,transitionDurationMs:k.transitionDurationMs,gapMs:k.gapMs,threshold:k.threshold},void 0,!0)}catch(A){if(A?.name==="AbortError")return;throw A}},dispose(){if(!a){a=!0,s+=1,m.reset(),d.clear(),l.forEach(({resolve:B})=>B(null)),l.clear(),c=tn;for(const[,B]of T)B.resolve();T.clear(),r?.terminate(),r=null}}}}async function Oo(e,t){const n=await Do(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let r=0,i=null,s=!1;const o=fr(async(a,u)=>s?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(at()?.onWorkerStale(),!1):(n.drawLiveFrame(a),o.isLatestSeq(u)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(s)return{width:842,height:1264};const u=await n.loadAssets(a);return i=u.visemePaths?.length?new Set(u.visemePaths):null,u},getVisemeAtlasPaths(){return i},async renderSilOnly(){s||(r+=1,o.reset(),n.renderSilOnly())},drawLiveFrame(a,u,d,l){s||o.enqueue(u,d,l)},async compositePrefetchFrame(a,u){if(s)return null;try{return await n.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,u){s||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||n.blitBitmap(u)},drawIdleVideo(a,u){s||n.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){s||n.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return s?!1:n.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){s||n.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return s?!1:n.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,u){if(s)return;r+=1;const d=r;o.reset(),t.onStatus?.(u),n.drawLiveFrame({mouthPath:xt(u),expressionPath:null})},dispose(){s||(s=!0,r+=1,o.reset(),n.dispose())}}}function Jr(e,t){if(!Fo())return Xr(e,t);const n=ws(t.workerScriptUrl);try{return Lo(e,t,n)}catch{return Xr(e,t)}}function No(e,t={}){if(t.preferLegacyRenderer)return Jr(e,t);let n=null,r=!1,i=null,s=!1;const o=()=>n?Promise.resolve(n):(i||(i=(async()=>{try{const a=await Oo(e,t);if(s)throw a.dispose(),new Error("Renderer disposed during Pixi init");return r=!0,n=a,a}catch(a){if(s)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),n=Jr(e,t),r=!1,n}})()),i);return{get usesWorker(){return n?.usesWorker??!1},get usesPixi(){return r},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return n?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,u,d,l){o().then(c=>{s||c.drawLiveFrame(a,u,d,l)})},async compositePrefetchFrame(a,u){return(await o()).compositePrefetchFrame(a,u)},blitBitmap(a,u){n&&n.blitBitmap(a,u)},drawIdleVideo(a,u){n?.usesPixi&&n.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){n?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return n?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){n?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return n?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return n?.supportsBufferedPlayback??!1},async renderViseme(a,u,d){return(await o()).renderViseme(a,u,d)},dispose(){s=!0,i=null,n?.dispose(),n=null}}}class Vo extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Cn(e,t,n){return new Promise((r,i)=>{const s=globalThis.setTimeout(()=>{i(new Vo(n,t))},t);e.then(o=>{globalThis.clearTimeout(s),r(o)},o=>{globalThis.clearTimeout(s),i(o)})})}const Uo={overflow:"hidden",position:"relative",display:"inline-block",lineHeight:0},Wo={display:"block",maxWidth:"100%",height:"auto"},zo={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 Rn(e){return Ss(e)?tr:oi(e)?dn:er}function Je(e,t){return t?.isSpeaking()||t?.isWarmingUp()?t:e.isSpeaking()||e.isWarmingUp()?e:t?.isConnected()?t:e}const ns=h.forwardRef(function({id:t,avatarId:n,faceId:r,assets:i,authToken:s,apiBase:o,ttsEngineId:a,voiceId:u,language:d,speakingRate:l=Ht,className:c,style:m,canvasStyle:w,onStatusChange:T,onDisplayStatus:f,onError:E,onReady:D,showErrorOverlay:B=!0,loadingThumbnailUrl:v,onUserTranscript:k,onBotOutput:L,onRealtimeLipsyncDebug:A,onFrameRenderStats:ie,lipsyncBufferedPlayback:de=!0,lipsyncPlaybackWarmupMs:I=1500,idleHandoffHoldMs:V=ho,pixiMaxTextureSize:G,captions:ae},se){const re=h.useRef(null),O=h.useRef(null),J=h.useRef(null),W=h.useRef(de);W.current=de;const he=h.useRef(I);he.current=I;const K=h.useRef(V);K.current=V;const ee=h.useRef(0),$=h.useRef(ur()),X=h.useRef(Ha()),_e=h.useRef(!1),oe=h.useRef(null),b=h.useRef(null),P=h.useRef(0),H=h.useRef(0),le=h.useRef(0),j=h.useRef(null),q=h.useRef(null),p=h.useRef(!1),S=h.useRef(!1),x=h.useRef(!1),_=h.useRef(!1),U=h.useRef("sil"),Z=h.useRef(0),te=h.useRef(!1),z=h.useRef(null),be=h.useRef(!1),[Xe,Pt]=h.useState("idle"),[pt,Ct]=h.useState(null),[ot,_n]=h.useState(!1),[g,C]=h.useState(!1),[ne,ue]=h.useState(!1),[Te,ve]=h.useState(),[ke,We]=h.useState({width:842,height:1264}),[Fe,$t]=h.useState(null),[bn,Rt]=h.useState(0),yt=h.useRef(!1),Ce=h.useRef(s??null),He=o?.trim()||ht,vt=h.useRef(null),Ie=h.useRef(null),{ttsEngineId:xe,voiceId:$e}=h.useMemo(()=>{const y=et(a,u),M=y.ttsEngineId??dt;return{ttsEngineId:M,voiceId:y.voiceId??Rn(M)}},[a,u]),je=h.useRef(!1),rt=h.useRef({width:842,height:1264}),pe=h.useRef(null),Le=h.useRef("sil"),Pe=h.useRef(""),Oe=h.useMemo(()=>no(ae),[ae]),Ne=h.useCallback(()=>{Pe.current="",$t(null)},[]);h.useEffect(()=>{Oe.enabled||Ne()},[Oe.enabled,Ne]);const Dt=h.useCallback(y=>{if(!Oe.enabled)return;const M=y.isSpeaking(),N=y.isWarmingUp();if(!M||N){Pe.current&&Ne();return}const F=to(y.getWordQueue());if(!F){Pe.current&&Ne();return}F!==Pe.current&&(Pe.current=F,$t(F))},[Oe.enabled,Ne]),ct=h.useRef(void 0),Bt=h.useRef(new Map),mr=h.useRef(D),hr=h.useRef(T),ye=h.useRef(f),gr=h.useRef(E),wr=h.useRef(k),pr=h.useRef(L),jt=h.useRef(A),yr=h.useRef(ie),_t=h.useRef(mo());mr.current=D,hr.current=T,ye.current=f,gr.current=E,wr.current=k,pr.current=L,jt.current=A,yr.current=ie,h.useEffect(()=>{const y=_t.current;return zr(y),()=>zr(null)},[]);const vr=h.useCallback(y=>{const M=et(y?.ttsEngineId??a,y?.voiceId??u),N=M.ttsEngineId??Ie.current?.ttsEngineId??dt,F=M.voiceId??Ie.current?.voiceId??Rn(N);return{ttsEngineId:N,voiceId:F}},[a,u]),it=h.useCallback(y=>{Ct(y),ue(!0),gr.current?.(y)},[]),Ft=h.useCallback(y=>{Pt(y),hr.current?.(y)},[]),fe=h.useRef(Nn(Ft,He,{onLipsyncDebug:y=>jt.current?.(y)})),me=h.useRef(null),_r=h.useRef(()=>{});h.useEffect(()=>(fe.current=Nn(Ft,He,{onLipsyncDebug:y=>jt.current?.(y)}),s&&fe.current.setDeveloperToken(s),fe.current.setTtsEngineId(xe),()=>{fe.current.stop();const y=me.current;y&&(y.disconnect(),me.current=null)}),[Ft,He]);const br=h.useCallback(()=>(me.current||(me.current=Vi(Ft,{speakingRate:l,language:d,onUserTranscript:(y,M)=>wr.current?.(y,M),onBotOutput:y=>pr.current?.(y),onLipsyncDebug:y=>jt.current?.(y)}),me.current.setTtsEngineId(xe),_r.current(!0)),me.current),[Ft,l,d,xe]),Re=h.useCallback(()=>{j.current!=null&&(clearTimeout(j.current),j.current=null)},[]),De=h.useCallback(()=>{q.current!=null&&(clearTimeout(q.current),q.current=null),x.current=!1},[]),Kt=h.useCallback(()=>{if(_.current)return;const y=O.current;if(_.current=!0,De(),p.current=!1,S.current=!1,!be.current||!z.current){y?.renderSilOnly();return}z.current.setActive(!1);const M=z.current.getVideo();if(y?.usesPixi){y.drawIdleVideo(M),y.beginIdleToSilCrossfade($r);return}(async()=>{const N=re.current;N&&await Mn(N,M,null,void 0,rt.current).catch(()=>{}),await new Promise(F=>setTimeout(F,$r)),_.current&&await y?.renderSilOnly()})()},[De]),Sr=h.useCallback(()=>{!be.current||!z.current||(_.current=!1,O.current?.finishIdleToSilCrossfade(),De(),x.current=!0,q.current=setTimeout(()=>{if(q.current=null,Je(fe.current,me.current).isSpeaking()){x.current=!1;return}if(p.current){x.current=!1;return}const y=z.current;if(!y){x.current=!1;return}y.restart(),y.setActive(!0);const M=y.getVideo();let N=!1;const F=()=>{N||(N=!0,M.removeEventListener("playing",Q),x.current=!1)},Q=()=>{F()};if(M.addEventListener("playing",Q,{once:!0}),M.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!M.paused){F();return}setTimeout(F,300)},K.current))},[De]),bt=h.useCallback(()=>{if(Re(),ye.current?.("sil"),p.current=!1,_.current=!1,!be.current||!z.current){x.current=!1;return}Sr()},[Re,Sr]),Sn=h.useCallback(async y=>{const M=H.current,N=O.current,F=re.current,Q=()=>{y?.fallbackOnly||(p.current=!1)};if(!N||!F||!ot){Q();return}if(Je(fe.current,me.current).isSpeaking()){Q();return}if(y?.fallbackOnly){if(!p.current||(Be($.current),await N.renderSilOnly(),M!==H.current)||Je(fe.current,me.current).isSpeaking())return;bt();return}if(jr($.current)){Be($.current),bt();return}if(W.current&&N.supportsBufferedPlayback&&!y?.fallbackOnly){if(Be($.current),J.current?.reset(),await N.renderSilOnly(),M!==H.current||Je(fe.current,me.current).isSpeaking())return;bt();return}const Ee=vo(Je(fe.current,me.current).getVisemeQueue(),Z.current,U.current),Ve=_o(Ee,pe.current);if(Be($.current),!Ve){if(await N.renderSilOnly(),M!==H.current||Je(fe.current,me.current).isSpeaking())return;bt();return}try{await N.renderViseme(F,"sil",{from:Ee,transitionDurationMs:Ji})}catch(Me){if(Me?.name!=="AbortError")throw Me}if(M!==H.current){Q();return}if(Je(fe.current,me.current).isSpeaking()){Q();return}bt()},[ot,bt]),St=h.useCallback(()=>{if(S.current||p.current)return;S.current=!0,p.current=!0,Re();const y=H.current;Sn().finally(()=>{S.current=!1}),j.current=setTimeout(()=>{j.current=null,y===H.current&&Sn({fallbackOnly:!0})},bo())},[Re,Sn]),Tr=h.useCallback(async()=>{const y=Math.floor(Date.now()/1e3);if(vt.current&&y<vt.current.expiresAt-60)return vt.current.key;const M=Ce.current??await Nt();Ce.current=M,fe.current.setDeveloperToken(M);const N=await Ps(M,He);return vt.current={key:N.value,expiresAt:N.expiresAt},N.value},[He]);h.useEffect(()=>{s&&(Ce.current=s,fe.current.setDeveloperToken(s))},[s]),h.useEffect(()=>{fe.current.setTtsEngineId(xe),me.current?.setTtsEngineId(xe),Ie.current&&(Ie.current.ttsEngineId=xe)},[xe]),h.useEffect(()=>{Ie.current&&(Ie.current.voiceId=$e)},[$e]);const Ke=h.useMemo(()=>ui(n,r),[n,r]),os=h.useMemo(()=>i?JSON.stringify(i):Ke?`face:${Ke}`:`id:${t??""}`,[i,Ke,t]),cs=h.useMemo(()=>{const y=v?.trim();return y||(xr(Ke)??xr(Te)??ks(i))},[v,Ke,Te,i]);return h.useEffect(()=>{if(!t&&!i&&!Ke){it("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let y=!1;je.current=!1,_n(!1),C(!1),ue(!1),ve(Ke),Ct(null),Ie.current=null,z.current=null,be.current=!1;const M=re.current;if(!M)return;let N=null;return(async()=>{try{let F,Q,Se,Ee;if(i)F=i,Q=xe,Se=$e;else if(Ke)ye.current?.("loadFace"),F=Ln(Ke),Q=xe,Se=$e;else{ye.current?.("getAiTwin");const Y=await Cn(ci(t),3e4,"getAiTwin");if(y)return;if(!Y.faceId?.trim())throw new Error("getAiTwin returned no faceId");ve(Y.faceId.trim());const ce=et(a,u);Q=ce.ttsEngineId??Y.ttsEngineId,Se=ce.voiceId??Y.voiceId??Rn(Q),Ee=qn(Y),F=Ln(Y.faceId)}Ie.current={ttsEngineId:Q,voiceId:Se,brainId:Ee},di(F),z.current=$a();const Ve=!!(i&&!gt(i));N=No(M,{preferLegacyRenderer:Ve,pixiMaxTextureSize:G,onStatus:Y=>{y||ye.current?.(Y)},onError:Y=>{y||it(Y)},shouldAcceptLiveFrame:()=>{if(_e.current)return!0;if(p.current)return!1;const Y=Je(fe.current,me.current);return Y.isSpeaking()||Y.isWarmingUp()},onWebGlContextLost:()=>{y||yt.current||(yt.current=!0,queueMicrotask(()=>{y||Rt(Y=>Y+1)}))}}),O.current=N,J.current=xo(N),yt.current=!1;const Me=Y=>{const ce=()=>{if(!Y||he.current<=0)return!1;const Ae=O.current;return Ae?W.current&&Ae.supportsBufferedPlayback?!0:Ae.usesPixi:!1};fe.current.setLipsyncWarmupHold(Y,ce),me.current?.setLipsyncWarmupHold(Y,ce)};_r.current=Me,Me(!0),ye.current?.("auth");const Ge=Ce.current??s??await Cn(Nt(),3e4,"getAuthToken");if(y)return;Ce.current=Ge,fe.current.setDeveloperToken(Ge),fe.current.setTtsEngineId(Q);const Gt=Wt()?await Tr():void 0;if(y)return;ye.current?.("loadAssets");const ge=await Cn(N.loadAssets(Gt),18e4,"load face assets");if(!y&&ge.width>0&&ge.height>0&&(rt.current=ge,We(ge)),y)return;pe.current=N.getVisemeAtlasPaths(),je.current=!0,_n(!0),mr.current?.(),N.renderSilOnly().then(()=>{y||ye.current?.("sil")}),(async()=>{try{const Y=await va(Gt);if(await z.current.load(Y),y)return;be.current=!0,C(!0),Be($.current),z.current.setActive(!0);const ce=z.current.getVideo();N.usesPixi?N.drawIdleVideo(ce):await Mn(M,ce,null,void 0,rt.current)}catch(Y){if(y)return;be.current=!1,C(!1),console.warn("[AiTwin] Idle video unavailable:",Y)}finally{y||(ue(!0),ye.current?.("idle"))}})()}catch(F){if(y)return;if(F instanceof nn){it(F.message);return}it(F instanceof Error?F.message:"Failed to load AI twin")}})(),()=>{y=!0,z.current?.dispose(),N?.dispose(),O.current=null}},[os,i,Ke,t,xe,$e,a,u,s,G,Tr,it,bn]),h.useEffect(()=>{const y={current:!1},M=()=>{const N=re.current,F=O.current,Q=Je(fe.current,me.current);if(!N||!F||!ot){P.current=requestAnimationFrame(M);return}if(document.hidden){z.current?.setActive(!1),P.current=requestAnimationFrame(M);return}const Se=Q.isSpeaking(),Ee=Q.isWarmingUp(),Ve=Se&&!te.current,Me=te.current&&!Se;Ve&&(Re(),De(),p.current=!1,S.current=!1,Be($.current),J.current?.reset(),_t.current.reset(),ct.current=void 0,le.current=0,U.current="sil",Z.current=0,Kt()),Me&&(X.current.reset(),z.current?.setActive(!1),J.current?.reset(),F.finishIdleToSilCrossfade(),Ne(),St());const Ge=Me||p.current||x.current||_.current,Gt=de&&F.supportsBufferedPlayback;if(Ee){if(Kt(),be.current&&z.current?.setActive(!1),F.usesPixi&&F.isIdleToSilCrossfading()){F.tickIdleToSilCrossfade(performance.now()),Q.getVisemeQueue().length>0&&ee.current===0&&(ee.current=performance.now()),te.current=Q.isSpeaking(),P.current=requestAnimationFrame(M);return}const ge=Q.getVisemeQueue();ge.length>0&&ee.current===0&&(ee.current=performance.now()),X.current.advance(performance.now());const Y=X.current.getExpressionPath(),ce=X.current.getDrawKey(),Ae={queue:ge,elapsedMs:0,expressionPath:Y,expressionDrawKey:ce,availablePaths:pe.current};let Ue=!1;Gt&&J.current?(J.current.warmupTick(Ae),Ue=J.current.isWarmupReady(Ae,he.current)):F.usesPixi&&Kr(N,ge,0,Y,ce,$.current,(Tt,qt,Tn,Yt)=>{F.drawLiveFrame(Tt,qt,Tn,qe=>{Yt?.(qe),Q.isWarmingUp()&&qe!==""&&!jr({lastDrawnKey:qe})&&(ee.current=0,Q.releaseWarmupHold())})},Tt=>{ye.current?.(Tt.label)},pe.current);const st=ee.current>0&&performance.now()-ee.current>ys;ye.current?.(Ue?"buffer ready":"buffering lipsync…"),(Ue||st)&&(ee.current=0,Q.releaseWarmupHold()),Dt(Q),te.current=Q.isSpeaking(),P.current=requestAnimationFrame(M);return}if(Se){Kt(),be.current&&z.current?.setActive(!1),F.usesPixi&&F.isIdleToSilCrossfading()&&F.finishIdleToSilCrossfade();const ge=Q.getVisemeQueue(),Y=Q.getPlaybackElapsedMs();aa(ge,Y),Z.current=Y;const ce=ge.length>0?zt(ge,Y):"sil";ce!=="sil"&&(U.current=ce);const Ae=qa(Y,Q.getSentenceEmotions(),Q.getWordQueue(),Q.getStreamMood());X.current.setTargetEmotion(Ae),X.current.setTargetEyebrow(Wa(Y,Q.getWordQueue(),mt(Ae))),X.current.advance(performance.now());const Ue=X.current.getExpressionPath(),st=X.current.getDrawKey(),Tt=(qe,kn,Lt,En)=>{const kr={label:Le.current,elapsedMs:Y,mouthPath:kn.mouthPath,transitionMeta:ct.current};Bt.current.set(Lt,kr),J.current?.markExternallyDisplayed(Lt,Ue),F.drawLiveFrame(qe,kn,Lt,Qt=>{const ls=Bt.current.get(Qt)??kr;Bt.current.delete(Qt),_t.current.onDrawDisplayed(ls,ge),J.current?.markExternallyDisplayed(Qt,Ue),En?.(Qt)})},qt=qe=>{Le.current=qe.label,ct.current=qe.transitionMeta,ye.current?.(qe.label)},Tn=de&&F.supportsBufferedPlayback;let Yt=!1;Tn&&J.current&&(Yt=J.current.tick({canvas:N,queue:ge,elapsedMs:Y,expressionPath:Ue,expressionDrawKey:st,playbackState:$.current,availablePaths:pe.current,onStatus:qt,onDisplayed:(kn,Lt,En)=>{_t.current.onDrawDisplayed({label:En,elapsedMs:Y,mouthPath:Lt,transitionMeta:ct.current},ge)}}).usedBuffer),Yt||Kr(N,ge,Y,Ue,st,$.current,Tt,qt,pe.current),_t.current.onRafTickSpeaking(),yr.current?.(_t.current.snapshot(ge,Y))}else if(!Ge&&_e.current){z.current?.setActive(!1),X.current.advance(performance.now());const ge=X.current.getExpressionPath(),Y=X.current.getDrawKey();Pn(N,ge,Y,$.current,(ce,Ae,Ue,st)=>F.drawLiveFrame(ce,Ae,Ue,st),ce=>{if(b.current){ye.current?.(b.current);return}const Ae=X.current.getTargetEmotion();ye.current?.(ce==="sil"||ce==="blink"?`${Ae}${ce==="blink"?" · blink":""}`:ce)},null,oe.current)}else if(!Ge&&be.current&&z.current){const ge=z.current,Y=ge.getVideo();if(Y.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){ge.setActive(!0);const ce=()=>!Q.isSpeaking()&&!p.current&&!x.current&&!_e.current;F.usesPixi?(F.drawIdleVideo(Y,ce),ce()&&ye.current?.("idle")):y.current||(y.current=!0,Mn(N,Y,null,void 0,rt.current,ce).then(()=>ye.current?.("idle")).finally(()=>{y.current=!1}))}else Pn(N,null,"__sil__",$.current,(ce,Ae,Ue,st)=>F.drawLiveFrame(ce,Ae,Ue,st),ce=>ye.current?.(ce))}else Ge||Pn(N,null,"__sil__",$.current,(ge,Y,ce,Ae)=>F.drawLiveFrame(ge,Y,ce,Ae),ge=>ye.current?.(ge));Oe.enabled&&Dt(Q),te.current=Se,P.current=requestAnimationFrame(M)};return P.current=requestAnimationFrame(M),()=>{cancelAnimationFrame(P.current),Re(),De(),fe.current.stop(),me.current?.stop()}},[ot,g,St,Re,De,Kt,Dt,Ne,Oe.enabled]),h.useImperativeHandle(se,()=>({speakText:async(y,M)=>{const N=y.trim();if(!N)return;const F=O.current;if(!F||!je.current&&!ot)throw new Error("AI twin is not ready");const{ttsEngineId:Q,voiceId:Se}=vr(M);Ct(null),Ne(),H.current+=1,Re(),De(),p.current=!1,S.current=!1,U.current="sil",Z.current=0,Be($.current),_e.current=!1,oe.current=null,b.current=null,X.current.reset(),te.current=!1,_.current=!1,F.finishIdleToSilCrossfade();try{await fe.current.speak(N,{voiceId:Se,speakingRate:M?.speakingRate??l,ttsEngineId:Q,language:M?.language??d})}catch(Ee){throw _.current=!1,F.finishIdleToSilCrossfade(),St(),it(Ee instanceof Error?Ee.message:"TTS failed"),Ee}},stop:()=>{H.current+=1,Re(),De(),p.current=!1,S.current=!1,_.current=!1,O.current?.finishIdleToSilCrossfade(),fe.current.stop(),me.current?.stop(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,Ne(),St()},setTtsEngineId:y=>{fe.current.setTtsEngineId(y),me.current?.setTtsEngineId(y),Ie.current&&(Ie.current.ttsEngineId=y)},renderViseme:async(y,M)=>{const N=O.current,F=re.current;if(!N||!F||!je.current)throw new Error("AI twin is not ready");await N.renderViseme(F,y,{from:M?.from,transitionDurationMs:M?.transitionDurationMs,gapMs:M?.gapMs,onStatus:Q=>ye.current?.(Q)})},setEmotion:y=>{if(!je.current)throw new Error("AI twin is not ready");const M=O.current,N=re.current;if(!M||!N)throw new Error("AI twin is not ready");H.current+=1,Re(),De(),p.current=!1,S.current=!1,x.current=!1,_.current=!1,fe.current.stop(),me.current?.stop(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,M.finishIdleToSilCrossfade(),z.current?.setActive(!1);const F=Ze(y);_e.current=!0,oe.current=null,b.current=null,X.current.snapToEmotion(F);const Q=X.current.getExpressionPath(),Se=X.current.getDrawKey(),Ee={mouthPath:null,expressionPath:Q},Ve=Ut(Ee,Se);$.current.lastDrawnKey="",M.drawLiveFrame(N,Ee,Ve,Ge=>{Ge===Ve&&($.current.lastDrawnKey=Ve)});const Me=mt(F);ye.current?.(Q?`${F} · brow ${Me>0?"+":""}${Me}`:`${F} · brow 0 (sil base)`)},getEmotion:()=>_e.current?X.current.getTargetEmotion():null,clearEmotionPreview:()=>{_e.current=!1,oe.current=null,b.current=null,X.current.reset(),Be($.current),ye.current?.("idle")},setViseme:y=>{if(!je.current)throw new Error("AI twin is not ready");const M=O.current,N=re.current;if(!M||!N)throw new Error("AI twin is not ready");H.current+=1,Re(),De(),p.current=!1,S.current=!1,x.current=!1,_.current=!1,fe.current.stop(),me.current?.stop(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,M.finishIdleToSilCrossfade(),z.current?.setActive(!1);const F=mn(y);_e.current=!0,b.current=F,oe.current=F==="sil"?null:xt(F),X.current.snapToEmotion("neutral");const Q=X.current.getExpressionPath(),Se=X.current.getDrawKey(),Ve={mouthPath:oe.current,expressionPath:Q},Me=Ut(Ve,Se);$.current.lastDrawnKey="",M.drawLiveFrame(N,Ve,Me,Ge=>{Ge===Me&&($.current.lastDrawnKey=Me)}),ye.current?.(F)},getViseme:()=>_e.current?b.current:null,isReady:()=>je.current,getStatus:()=>Xe,connect:async(y={})=>{Ct(null);try{let M=y.authToken?.trim();M||(M=Ce.current??s??await Nt(),Ce.current=M);const N=et(y.ttsEngineId??a,y.voiceId??u),F=N.voiceId??Ie.current?.voiceId,Q=y.brainId?.trim()||y.personaId?.trim()||Ie.current?.brainId,Se=N.ttsEngineId??Ie.current?.ttsEngineId??xe,Ee=br();Se&&Ee.setTtsEngineId(Se),await Ee.unlockAudio(),await Ee.connect({...y,apiBase:y.apiBase?.trim()||He,authToken:M,voiceId:F,brainId:Q,ttsEngineId:Se,speakingRate:y.speakingRate??l,language:y.language??d})}catch(M){throw it(M instanceof Error?M.message:"Voice connect failed"),M}},disconnect:async()=>{const y=me.current;y&&(H.current+=1,Re(),De(),p.current=!1,S.current=!1,_.current=!1,O.current?.finishIdleToSilCrossfade(),Be($.current),J.current?.reset(),ee.current=0,te.current=!1,await y.disconnect(),St())},isConnected:()=>me.current?.isConnected()??!1,getVoiceStream:()=>me.current?.getVoiceStream()??fe.current?.getVoiceStream()??null,setMuted:y=>{const M=fe.current,N=me.current;M?.setMuted?.(y),N?.setMuted?.(y)},isMuted:()=>{const y=me.current,M=fe.current;return y?.isMuted?.()??M?.isMuted?.()??!1},getBrainId:()=>Ie.current?.brainId?.trim()||null,getPersonaId:()=>Ie.current?.brainId?.trim()||null}),[ot,l,d,s,xe,$e,Re,De,St,it,vr,br,Xe,He]),R.jsxs("div",{className:c,style:{...Uo,...m},children:[R.jsx("canvas",{ref:re,width:ke.width,height:ke.height,style:{...Wo,...w},"aria-label":t?`AI twin ${t}`:"AI twin face"}),!ne&&!pt?R.jsx(uo,{thumbnailUrl:cs}):null,B&&pt?R.jsx("div",{style:zo,children:pt}):null,Oe.enabled&&Fe?R.jsx(ao,{text:Fe,style:Oe.style},Fe):null]})});async function Ho(e){try{const t=await e.json();if(typeof t.detail=="string"&&t.detail.trim())return t.detail;if(typeof t.error=="string"&&t.error.trim())return t.error}catch{}return`avatarReply failed (${e.status})`}async function rs(e){const t=e.message.trim();if(!t)throw new Error("Message is required");const n=e.authToken.trim();if(!n)throw new Error("Auth token is required");const r=(e.apiBase?.trim()||ht).replace(/\/$/,""),i=await fetch(`${r}/avatarReply`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`,Accept:"text/event-stream"},body:JSON.stringify({message:t,history:e.history??[],brainId:e.brainId?.trim()||e.personaId?.trim()||"",tenant:"aiTwin"})});if(!i.ok)throw new Error(await Ho(i));if(!i.body)throw new Error("avatarReply response body is empty");const s=i.body.getReader(),o=new TextDecoder;let a="",u="",d="",l="";for(;;){const{done:c,value:m}=await s.read();if(c)break;a+=o.decode(m,{stream:!0});const w=a.split(`
48
48
  `);a=w.pop()||"";for(const T of w){if(T.startsWith("event: ")){l=T.slice(7).trim();continue}if(!T.startsWith("data: "))continue;const f=T.slice(6).trim();if(!f)continue;let E;try{E=JSON.parse(f)}catch{continue}if(l==="spokenText")u=E.text||"",e.onSpokenText?.(u);else if(l==="displayText")d=E.text||"";else if(l==="error")throw new Error(E.error||"avatarReply stream error")}}if(!u.trim()||!d.trim())throw new Error("avatarReply stream missing displayText or spokenText");return{displayText:d.trim(),spokenText:u.trim()}}function $o({muted:e}){return e?R.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[R.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),R.jsx("path",{d:"m16 9.5 5 5m0-5-5 5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]}):R.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[R.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),R.jsx("path",{d:"M15.5 8.5a4.5 4.5 0 0 1 0 7M18.5 6a8 8 0 0 1 0 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]})}function jo(){return R.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:R.jsx("path",{d:"M8 5.5v13l11-6.5L8 5.5Z"})})}function Ko(){return R.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:R.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"1.5"})})}function Go(){return R.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:R.jsx("path",{d:"M5 6.5A2.5 2.5 0 0 1 7.5 4h9A2.5 2.5 0 0 1 19 6.5v7A2.5 2.5 0 0 1 16.5 16H10l-4 3.5V16H7.5A2.5 2.5 0 0 1 5 13.5v-7Z",stroke:"currentColor",strokeWidth:"2",strokeLinejoin:"round"})})}function is({className:e}){return R.jsx("span",{className:e??"aitwin-widget__spinner","aria-hidden":!0,children:R.jsx("svg",{viewBox:"0 0 24 24",fill:"none",children:R.jsx("circle",{cx:"12",cy:"12",r:"9",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeDasharray:"40 20"})})})}function qo({muted:e,onToggle:t}){return R.jsx("button",{type:"button",className:"aitwin-widget__mute",onClick:t,"aria-label":e?"Unmute":"Mute","aria-pressed":e,children:R.jsx($o,{muted:e})})}function Yo(){return R.jsxs("div",{className:"aitwin-widget__connecting",role:"status","aria-live":"polite",children:[R.jsx(is,{className:"aitwin-widget__spinner aitwin-widget__spinner--accent"}),R.jsx("span",{children:"Connecting..."})]})}function Qo(e){const t=e.connecting||e.textSending||e.status==="loading"||e.status==="speaking",n=e.connecting?"Connecting...":e.connected?"End Talk":"Talk",r=["aitwin-widget__action",e.textMode&&!e.connecting?"":"aitwin-widget__action--primary",e.connecting?"aitwin-widget__action--connecting":""].filter(Boolean).join(" ");return R.jsxs("div",{className:"aitwin-widget__controls",children:[R.jsxs("div",{className:"aitwin-widget__actions",children:[R.jsxs("button",{type:"button",className:r,onClick:e.onTalk,disabled:!e.ready||e.connecting||e.textSending,"aria-busy":e.connecting,children:[e.connecting?R.jsx(is,{className:"aitwin-widget__spinner aitwin-widget__spinner--on-accent"}):e.connected?R.jsx(Ko,{}):R.jsx(jo,{}),R.jsx("span",{children:n})]}),R.jsxs("button",{type:"button",className:e.textMode?"aitwin-widget__action aitwin-widget__action--primary":"aitwin-widget__action",onClick:e.onTextMode,disabled:!e.ready||e.connecting||e.textSending,"aria-pressed":e.textMode,children:[R.jsx(Go,{}),R.jsx("span",{children:"Text"})]})]}),e.textMode?R.jsxs("form",{className:"aitwin-widget__composer",onSubmit:i=>{i.preventDefault(),e.onSendText()},children:[R.jsx("input",{type:"text",className:"aitwin-widget__composer-input",value:e.textDraft,onChange:i=>e.onTextDraftChange(i.target.value),placeholder:e.textSending?"Getting reply...":"Type a message…",autoComplete:"off",disabled:!e.ready||t}),R.jsx("button",{type:"submit",className:"aitwin-widget__composer-send",disabled:!e.ready||t||!e.textDraft.trim()&&!e.textSending,"aria-busy":e.textSending,children:e.textSending?"…":"Send"})]}):null,e.error?R.jsx("p",{className:"aitwin-widget__controls-error",role:"alert",children:e.error}):null]})}const Zr=97,Xo=3500;function Jo(e,t){const n=Math.max(0,e),r=1-Math.exp(-n/Xo);return Math.min(Zr,Math.round(r*Zr))}function Zo(e){const[t,n]=h.useState(null),[r,i]=h.useState(()=>Date.now());return h.useEffect(()=>{if(!e){n(null);return}const s=Date.now();n(s),i(s);let o=0;const a=()=>{i(Date.now()),o=window.requestAnimationFrame(a)};return o=window.requestAnimationFrame(a),()=>{window.cancelAnimationFrame(o)}},[e]),e?t==null?0:Jo(r-t):100}const ec="M259.01,593.87v-101.49c.33-6.31,4.94-11.26,10.21-11.88,6.42-.75,13.18,4.99,13.13,12.92-.42,45.09-.83,90.17-1.25,135.26.03,1.56.56,15.43,11.95,23.2,6.18,4.21,12.57,4.6,15.42,4.58-.42-112.77-.83-225.54-1.25-338.31-.08-2.55-1.03-46.36,21.17-55.34,2.05-.83,4.42-1.41,7.17-1.56v453.42c.07,12.06,1.98,37.84,19.03,62.73,7.01,10.23,14.79,17.71,21.4,22.99V222.42c-.01-3.72.48-11.67,5.35-19.87,7-11.77,18.13-15.82,21.4-16.95,10.42-3.61,19.49-2.06,23.48-1.11v684.96c.59,4.03,1.78,9.72,4.45,16.12,1.93,4.63,8.84,20.57,26.47,31.26,13.48,8.18,26.56,9.23,32.86,9.31-1.3-256.11-2.59-512.22-3.89-768.33.76-16.43,14.57-28.94,29.73-28.34,13.53.53,25.39,11.39,27.23,25.84-1.1,264.68-2.2,529.35-3.3,794.03,4.33.92,22.38,4.25,38.94-6.53,10.26-6.68,15.24-15.72,17.09-19.17,5.55-10.36,6.42-19.98,6.53-25.01-.72-246.99-1.43-493.97-2.15-740.96,2.27-.06,34.75-.44,48.29,22.68,3.41,5.83,4.87,11.86,5.34,17.19v674.68c5.92-2.16,39.19-14.94,50.16-47.79,3.12-9.34,3.68-18.03,3.33-25.01.03-193.22.06-386.43.09-579.65,4.12,1.18,28.28,8.48,36.17,30.08,1.64,4.49,2.32,8.88,2.43,12.92.02,146.42.05,292.84.07,439.25,3.82-1.71,19.51-9.22,25.56-26.47,2.15-6.12,2.48-11.73,2.29-15.89.01-114.91.03-229.81.04-344.72,2.36-.1,7.51.02,12.74,3.13,9.1,5.4,10.87,15.35,11.12,16.88.35,11.49.69,22.97,1.04,34.46.46,37.05.93,74.1,1.39,111.15v152.69c3.39-.72,9.77-2.67,14.31-8.34,3.62-4.52,4.51-9.46,5.56-15.28.91-5.04.95-9.31.83-12.23.02-38.81.03-77.62.05-116.43";function tc({className:e="aitwin-widget__logo",strokeWidth:t=15,durationMs:n=2600,delayMs:r=0,loop:i=!1}){return R.jsx("svg",{viewBox:"0 0 1080 1080",className:e,role:"img","aria-label":"AITWIN logo",children:R.jsx("path",{className:i?"aitwin-widget__logo-draw aitwin-widget__logo-draw--loop":"aitwin-widget__logo-draw",d:ec,fill:"none",stroke:"currentColor",strokeWidth:t,strokeMiterlimit:10,pathLength:1,style:{animationDuration:`${n}ms`,animationDelay:`${r}ms`}})})}function nc({progress:e}){const t=Math.max(0,Math.min(100,Math.round(e)));return R.jsx("div",{className:"aitwin-widget__face-loading","aria-live":"polite","aria-label":`Loading ${t} percent`,children:R.jsxs("div",{className:"aitwin-widget__face-loading-content",children:[R.jsx(tc,{className:"aitwin-widget__logo",loop:!0,durationMs:2600}),R.jsxs("div",{className:"aitwin-widget__face-loading-bar-wrap",children:[R.jsx("div",{role:"progressbar","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":100,className:"aitwin-widget__face-loading-track",children:R.jsx("div",{className:"aitwin-widget__face-loading-fill",style:{width:`${t}%`}})}),R.jsxs("p",{className:"aitwin-widget__face-loading-pct",children:[t,"%"]})]})]})})}function ei(e){const t=e.id?.trim()||void 0,n=e.faceId?.trim()||e.avatarId?.trim()||void 0;return{id:n?void 0:t,faceId:n,authToken:e.authToken?.trim()||void 0,apiBase:e.apiBase?.trim()||void 0,voiceId:e.voiceId?.trim()||void 0,speakingRate:e.speakingRate,language:e.language}}function rc(e){return[e.id??"",e.faceId??"",e.authToken?.slice(0,16)??"",e.voiceId??"",e.apiBase??"",String(e.speakingRate??"")].join("|")}const ti={display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",lineHeight:0},ic={display:"block",height:"100%",width:"100%",objectFit:"cover",objectPosition:"top"},sc=h.forwardRef(function({options:t},n){const r=h.useRef(null),i=h.useRef(t);i.current={...i.current,onReady:t.onReady,onStatusChange:t.onStatusChange,onError:t.onError,onUserTranscript:t.onUserTranscript,onBotOutput:t.onBotOutput};const[s,o]=h.useState(!!t.showControls),[a,u]=h.useState(()=>ei(t)),[d,l]=h.useState(!1),[c,m]=h.useState(!1),[w,T]=h.useState(!1),[f,E]=h.useState(!1),[D,B]=h.useState("idle"),[v,k]=h.useState(null),[L,A]=h.useState(!1),[ie,de]=h.useState(!1),[I,V]=h.useState(""),[G,ae]=h.useState(!1),[se,re]=h.useState([]),[O,J]=h.useState(t.brainId?.trim()||t.personaId?.trim()||void 0),W=h.useCallback(_=>{i.current={...i.current,..._},_.showControls!==void 0&&o(!!_.showControls),(_.brainId!==void 0||_.personaId!==void 0)&&J((_.brainId??_.personaId)?.trim()||void 0),u(U=>ei({id:_.id??U.id,faceId:_.faceId??_.avatarId??U.faceId,authToken:_.authToken??U.authToken,apiBase:_.apiBase??U.apiBase,voiceId:_.voiceId??U.voiceId,speakingRate:_.speakingRate??U.speakingRate,language:_.language??U.language}))},[]);h.useImperativeHandle(n,()=>({getTwin:()=>r.current,applyOptions:W}),[W]),h.useEffect(()=>{W(t)},[W,t.id,t.faceId,t.avatarId,t.authToken,t.apiBase,t.voiceId,t.speakingRate,t.showControls,t.brainId,t.personaId]);const he=h.useCallback(()=>{l(!0),k(null)},[]),K=h.useCallback(_=>{_==="idle"&&m(!0)},[]),ee=h.useCallback(_=>{B(_),i.current.onStatusChange?.(_)},[]),$=h.useCallback(_=>{k(_),l(!1),m(!1),E(!1),i.current.onError?.(_)},[]),X=h.useCallback((_,U)=>{i.current.onUserTranscript?.(_,U)},[]),_e=h.useCallback(_=>{i.current.onBotOutput?.(_)},[]);h.useEffect(()=>{if(!s)return;const _=window.setInterval(()=>{T(!!r.current?.isConnected())},400);return()=>window.clearInterval(_)},[s,a]);const oe=rc(a),b=!!(a.id||a.faceId),P=d&&c,H=b&&!P&&!v,le=Zo(H),j=h.useRef(oe);h.useEffect(()=>{P&&i.current.onReady?.()},[P]),h.useEffect(()=>{P&&r.current?.setMuted(L)},[P,L,a]),h.useEffect(()=>{re([])},[a.id,a.faceId]),h.useEffect(()=>{j.current!==oe&&(j.current=oe,l(!1),m(!1),k(null),E(!1),T(!1),B("idle"))},[oe]);const q=()=>{const _=r.current;if(!_?.isReady())return;if(k(null),de(!1),_.isConnected()){E(!1),_.disconnect().finally(()=>{T(!1)});return}E(!0);const U={authToken:a.authToken,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language,apiBase:a.apiBase};_.connect(U).then(()=>{T(!!_.isConnected())}).catch(Z=>{const te=Z instanceof Error?Z.message:"Failed to connect voice.";k(te),i.current.onError?.(te)}).finally(()=>{E(!1)})},p=()=>{de(_=>!_),k(null)},S=()=>{const _=I.trim(),U=r.current;!_||!U?.isReady()||G||(k(null),V(""),ae(!0),i.current.onUserTranscript?.(_,!0),(async()=>{try{const Z=a.authToken?.trim()||await Nt(),te=O||U.getBrainId()?.trim()||void 0,z=await rs({message:_,authToken:Z,apiBase:a.apiBase||ht,brainId:te,history:se});re(be=>[...be,{role:"user",content:_},{role:"assistant",content:z.displayText}]),i.current.onBotOutput?.(z.displayText),await U.speakText(z.spokenText,{voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language})}catch(Z){const te=Z instanceof Error?Z.message:"Failed to get reply.";k(te),i.current.onError?.(te)}finally{ae(!1)}})())},x=()=>{const _=!L;A(_),r.current?.setMuted(_)};return R.jsxs("div",{className:"aitwin-widget__layout",children:[R.jsxs("div",{className:"aitwin-widget__stage",children:[b?R.jsx("div",{style:ti,children:R.jsx(ns,{ref:r,id:a.id,faceId:a.faceId,authToken:a.authToken,apiBase:a.apiBase,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language,style:ti,canvasStyle:ic,onReady:he,onDisplayStatus:K,onStatusChange:ee,onError:$,onUserTranscript:X,onBotOutput:_e,loadingThumbnailUrl:t.loadingThumbnailUrl},oe)}):R.jsx("p",{className:"aitwin-widget__hint",style:{padding:16},children:"Pass id or faceId to load a twin."}),H?R.jsx(nc,{progress:le}):null,s?R.jsx(qo,{muted:L,onToggle:x}):null,s&&f?R.jsx(Yo,{}):null]}),s?R.jsx(Qo,{ready:P,connected:w,connecting:f,status:D,textMode:ie,textDraft:I,textSending:G,error:v,onTalk:q,onTextMode:p,onTextDraftChange:V,onSendText:S}):null]})}),ac=".aitwin-widget{--aitwin-border: rgba(255, 255, 255, .12);--aitwin-text: #f4f4f5;--aitwin-muted: #a1a1aa;--aitwin-accent: #f97316;--aitwin-accent-hover: #fb923c;--aitwin-font: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;--aitwin-size: 1;--aitwin-stage-width: calc(200px * var(--aitwin-size));--aitwin-stage-height: calc(267px * var(--aitwin-size));--aitwin-action-height: calc(40px * var(--aitwin-size));--aitwin-action-font: calc(13px * var(--aitwin-size));--aitwin-action-radius: calc(10px * var(--aitwin-size));--aitwin-action-gap: calc(6px * var(--aitwin-size));--aitwin-mute-size: calc(28px * var(--aitwin-size));--aitwin-layout-gap: calc(8px * var(--aitwin-size));box-sizing:border-box;color:var(--aitwin-text);font-family:var(--aitwin-font);font-size:calc(12px * var(--aitwin-size));line-height:1.45;width:fit-content;max-width:100%}.aitwin-widget *,.aitwin-widget *:before,.aitwin-widget *:after{box-sizing:border-box}.aitwin-widget__layout{display:flex;flex-direction:column;gap:var(--aitwin-layout-gap);width:fit-content;max-width:100%}.aitwin-widget__stage{align-items:center;background:#0a0a0b;border:1px solid var(--aitwin-border);border-radius:calc(10px * var(--aitwin-size));display:flex;flex-shrink:0;height:var(--aitwin-stage-height);justify-content:center;line-height:0;overflow:hidden;position:relative;width:var(--aitwin-stage-width)}.aitwin-widget__stage .aitwin-root,.aitwin-widget__stage canvas{display:block;height:100%;object-fit:cover;object-position:top;width:100%}.aitwin-widget__hint{color:var(--aitwin-muted);font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget__mute{align-items:center;background:#28282cb8;border:none;border-radius:999px;color:#fff;cursor:pointer;display:inline-flex;height:var(--aitwin-mute-size);justify-content:center;padding:0;position:absolute;right:calc(8px * var(--aitwin-size));top:calc(8px * var(--aitwin-size));width:var(--aitwin-mute-size);z-index:2}.aitwin-widget__mute:hover{background:#37373cd9}.aitwin-widget__mute svg{height:calc(15px * var(--aitwin-size));width:calc(15px * var(--aitwin-size))}.aitwin-widget__controls{display:flex;flex-direction:column;gap:var(--aitwin-action-gap);width:var(--aitwin-stage-width)}.aitwin-widget__actions{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr 1fr;width:100%}.aitwin-widget__action{align-items:center;background:transparent;border:1.5px solid var(--aitwin-accent);border-radius:999px;color:var(--aitwin-accent);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--aitwin-action-font);font-weight:600;gap:calc(6px * var(--aitwin-size));height:var(--aitwin-action-height);justify-content:center;padding:0 calc(10px * var(--aitwin-size))}.aitwin-widget__action svg{flex-shrink:0;height:calc(12px * var(--aitwin-size));width:calc(12px * var(--aitwin-size))}.aitwin-widget__action:hover:not(:disabled){background:#f973161a}.aitwin-widget__action:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__action--primary{background:var(--aitwin-accent);border-color:transparent;color:#fff}.aitwin-widget__action--primary:hover:not(:disabled){background:var(--aitwin-accent-hover)}.aitwin-widget__action--connecting:disabled{cursor:progress;opacity:1}.aitwin-widget__spinner{display:inline-flex;flex-shrink:0;height:calc(14px * var(--aitwin-size));width:calc(14px * var(--aitwin-size))}.aitwin-widget__spinner svg{animation:aitwin-widget-spin .8s linear infinite;display:block;height:100%;width:100%}.aitwin-widget__spinner--accent{color:var(--aitwin-accent);height:calc(16px * var(--aitwin-size));width:calc(16px * var(--aitwin-size))}.aitwin-widget__spinner--on-accent{color:#fff}@keyframes aitwin-widget-spin{to{transform:rotate(360deg)}}.aitwin-widget__connecting{align-items:center;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);background:#ffffffe0;border-radius:999px;bottom:calc(14px * var(--aitwin-size));box-shadow:0 4px 16px #0000001f;color:#3f3f46;display:inline-flex;font-size:calc(12px * var(--aitwin-size));font-weight:600;gap:calc(8px * var(--aitwin-size));left:50%;line-height:1;padding:calc(8px * var(--aitwin-size)) calc(14px * var(--aitwin-size));pointer-events:none;position:absolute;transform:translate(-50%);z-index:3}.aitwin-widget__face-loading{background:transparent;inset:0;overflow:hidden;pointer-events:none;position:absolute;z-index:4}.aitwin-widget__face-loading-content{align-items:center;display:flex;flex-direction:column;gap:calc(12px * var(--aitwin-size));inset:0;justify-content:center;padding:calc(24px * var(--aitwin-size));position:absolute;z-index:1}.aitwin-widget__logo{color:#fff;display:block;flex-shrink:0;height:calc(64px * var(--aitwin-size));margin-bottom:calc(4px * var(--aitwin-size));width:calc(64px * var(--aitwin-size))}.aitwin-widget__logo-draw{stroke-dasharray:1;stroke-dashoffset:1;animation:aitwin-widget-logo-draw 2.6s ease-in-out forwards}.aitwin-widget__logo-draw--loop{animation:aitwin-widget-logo-draw-loop 2.6s ease-in-out infinite}@keyframes aitwin-widget-logo-draw{to{stroke-dashoffset:0}}@keyframes aitwin-widget-logo-draw-loop{0%{stroke-dashoffset:1}45%{stroke-dashoffset:0}55%{stroke-dashoffset:0}to{stroke-dashoffset:-1}}@media(prefers-reduced-motion:reduce){.aitwin-widget__logo-draw,.aitwin-widget__logo-draw--loop{animation:none;stroke-dashoffset:0}}.aitwin-widget__face-loading-bar-wrap{max-width:calc(220px * var(--aitwin-size));width:100%}.aitwin-widget__face-loading-track{background:#fff3;border-radius:999px;height:calc(4px * var(--aitwin-size));overflow:hidden;width:100%}.aitwin-widget__face-loading-fill{background:var(--aitwin-accent);border-radius:999px;height:100%;transition:width .3s ease-out}.aitwin-widget__face-loading-pct{color:#ffffffbf;font-size:calc(12px * var(--aitwin-size));margin:calc(8px * var(--aitwin-size)) 0 0;text-align:center}.aitwin-widget__composer{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr auto;width:100%}.aitwin-widget__composer-input{background:#ffffff0a;border:1px solid var(--aitwin-border);border-radius:var(--aitwin-action-radius);color:var(--aitwin-text);font-family:inherit;font-size:calc(12px * var(--aitwin-size));min-width:0;outline:none;padding:calc(8px * var(--aitwin-size)) calc(10px * var(--aitwin-size))}.aitwin-widget__composer-input:focus{border-color:#f973168c}.aitwin-widget__composer-send{background:var(--aitwin-accent);border:none;border-radius:var(--aitwin-action-radius);color:#fff;cursor:pointer;font-family:inherit;font-size:calc(12px * var(--aitwin-size));font-weight:600;padding:0 calc(12px * var(--aitwin-size))}.aitwin-widget__composer-send:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__controls-error{color:#fecaca;font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget--float{bottom:20px;filter:drop-shadow(0 12px 32px rgba(0,0,0,.45));height:fit-content;margin:0;max-width:calc(100vw - 40px);position:fixed;right:20px;width:fit-content;z-index:2147483000}",ni="data-aitwin-widget-style";function ss(){if(typeof document>"u")return;const e=ac.trim();if(!e){console.warn("[AiTwinWidget] styles.css?inline resolved empty — chrome will be unstyled");return}const t=document.querySelector(`style[${ni}]`);if(t){if((t.textContent??"").trim().length>0)return;t.textContent=e;return}const n=document.createElement("style");n.setAttribute(ni,"1"),n.textContent=e,(document.head??document.documentElement).appendChild(n)}typeof document<"u"&&ss();const oc=h.forwardRef(function(t,n){ss();const r=h.useRef(null);h.useImperativeHandle(n,()=>({speakText:async(s,o)=>{const a=r.current?.getTwin();if(!a)throw new Error("AiTwinWidget: twin is not mounted");return a.speakText(s,o)},connect:async s=>{const o=r.current?.getTwin();if(!o)throw new Error("AiTwinWidget: twin is not mounted");return o.connect(s)},disconnect:async()=>{const s=r.current?.getTwin();if(s)return s.disconnect()},stop:()=>{r.current?.getTwin()?.stop()},isReady:()=>!!r.current?.getTwin()?.isReady(),isConnected:()=>!!r.current?.getTwin()?.isConnected(),getTwin:()=>r.current?.getTwin()??null}),[]);const i=!!t.float;return R.jsx("div",{className:i?"aitwin-widget aitwin-widget--float":"aitwin-widget",children:R.jsx(sc,{ref:r,options:t})})}),cc=new Set([".png",".jpg",".jpeg",".webp"]);function as(e=".png"){const t=e.toLowerCase();return cc.has(t)?`source${t}`:"source.png"}function lc(e,t=$n,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${as(n)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Yn;exports.AiTwin=ns;exports.AiTwinNotFoundError=nn;exports.AiTwinWidget=oc;exports.CONSONANT_SKIP_GROUP=Ti;exports.DEFAULT_TTS_ENGINE_ID=dt;exports.DEFAULT_TTS_LANGUAGE=Vs;exports.EMOTION_TO_EYEBROW=Gi;exports.EXPRESSION_ATLAS_EMOTIONS=Ra;exports.MIC_SAMPLE_RATE=nr;exports.OCULUS_VISEME_IDS=vi;exports.PLAYBACK_SAMPLE_RATE=rr;exports.SPEAKING_RATE_MAX=yn;exports.SPEAKING_RATE_MIN=pn;exports.TTS_ENGINE_CARTESIA=tt;exports.TTS_ENGINE_GOOGLE=Kn;exports.TTS_ENGINE_INWORLD=un;exports.TTS_ENGINE_VISEMETTS=nt;exports.TTS_LANGUAGE_CATALOG=ft;exports.TTS_LANGUAGE_CODES=wi;exports.VISEME_IDS=_a;exports.VISEME_SKIP_GAP_MS=On;exports.VISEME_TEST_CARTESIA_VOICE_ID=tr;exports.VISEME_TEST_SPEAKING_RATE=Ht;exports.VISEME_TEST_VISEMETTS_VOICE_ID=dn;exports.VISEME_TEST_VOICE_ID=er;exports.VISEME_VTIME_GRID_MS=Qn;exports.VOWEL_SKIP_GROUP=Si;exports.aiTwinSourceFilename=as;exports.buildPlaybackTransitions=Pi;exports.buildPlaybackVisemeSeries=gn;exports.buildRawVisemeTransitions=Mi;exports.buildVoiceWebSocketUrl=Ni;exports.compactSkippableVisemes=Jn;exports.createAvatarTtsLipsyncController=Nn;exports.createRealtimeVoiceLipsyncController=Vi;exports.emotionToEyebrow=mt;exports.faceAssetUrls=Ln;exports.fetchAiTwin=ci;exports.fetchAvatarReply=rs;exports.fetchDevAuthToken=Nt;exports.getAiTwinSourceUrl=lc;exports.getAiTwinThumbnailUrl=li;exports.isTtsLanguageCode=pi;exports.isTtsLanguageSupported=Ws;exports.listSkippedVisemeEntries=wn;exports.listSkippedVisemes=Js;exports.normalizeOculusViseme=mn;exports.normalizeStreamEmotion=Ze;exports.normalizeTtsLanguage=fn;exports.parsePackedVoiceId=si;exports.resolveDirectFaceId=ui;exports.resolveTwinBrainId=qn;exports.resolveVisemeAtTime=zt;exports.resolveVisemeFromPlaybackSeries=xi;exports.resolveWordAtTime=oa;exports.setActiveTwinAssets=di;exports.snapVisemeQueueToGrid=Xn;exports.snapVisemeVtimeToGrid=ki;exports.splitVoiceIdSpec=et;exports.ttsLanguagesForEngine=Us;
package/dist/aitwin.js CHANGED
@@ -5,7 +5,7 @@ import { WebSocketTransport as Xi, DailyMediaManager as Ji, ProtobufFrameSeriali
5
5
  import { Filter as ea, GlProgram as ta, Application as na, RendererType as ra, Sprite as zt, Texture as Re, VideoSource as ia, Rectangle as aa } from "pixi.js";
6
6
  const sa = "https://aitwin.bubu.social", Zr = {
7
7
  publicBase: sa
8
- }, oa = "0.6.4", ca = {
8
+ }, oa = "0.6.5", ca = {
9
9
  version: oa
10
10
  }, la = {}, gt = "https://ai.aitwin.me", Un = `${Zr.publicBase}/custom-faces`, ua = `${Zr.publicBase}/aitwin-workers/v${ca.version}/visemeDiffPreview.worker.js`;
11
11
  function da(e) {
@@ -4971,7 +4971,8 @@ async function Qo(e) {
4971
4971
  body: JSON.stringify({
4972
4972
  message: t,
4973
4973
  history: e.history ?? [],
4974
- brainId: e.brainId?.trim() || e.personaId?.trim() || ""
4974
+ brainId: e.brainId?.trim() || e.personaId?.trim() || "",
4975
+ tenant: "aiTwin"
4975
4976
  })
4976
4977
  });
4977
4978
  if (!i.ok)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoji/aitwin",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "description": "Embeddable React AI twin face with TTS lipsync",
5
5
  "type": "module",
6
6
  "main": "./dist/aitwin.cjs",