@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 +2 -2
- package/dist/aitwin.js +3 -2
- package/package.json +1 -1
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.
|
|
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)
|