@streamoji/aitwin 0.6.9 → 0.7.1
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 +6 -6
- package/dist/aitwin.js +2761 -2715
- package/dist/index.d.ts +3 -0
- package/package.json +2 -2
package/dist/aitwin.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=require("react/jsx-runtime"),h=require("react"),gs=require("@pipecat-ai/client-js"),Qn=require("@pipecat-ai/websocket-transport"),ye=require("pixi.js");var Rn=typeof document<"u"?document.currentScript:null;const ws="https://aitwin.bubu.social",ui={publicBase:ws},ys="0.6.9",vs={version:ys},_s={},Ct="https://ai.aitwin.me",Xn=`${ui.publicBase}/custom-faces`,bs=`${ui.publicBase}/aitwin-workers/v${vs.version}/visemeDiffPreview.worker.js`;function Ss(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Rn&&Rn.tagName.toUpperCase()==="SCRIPT"&&Rn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?_s?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():bs}const Ts="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Cn=3e3,Ot=16,Cr=3e3,ks=4e3,Es=.85,xs=8,Jn=400,Zn="eng_a7f2b9c1",dn="eng_d4e8f3a2",st="eng_c9b1e6d4",at="visemetts",ht=st,fn="eve",Un=new Set([dn,st,at]),er={[Zn]:"oculus_direct",[st]:"oculus_direct",[at]:"oculus_direct",[dn]:"inworld_word"},Vn={google:Zn,inworld:dn,cartesia:st,visemetts:at};function Is(e){const t=e.trim();if(t)return t in er?t:Vn[t.toLowerCase()]}function di(e){const t=e?.trim();if(!t)return{};const n=t.indexOf(":");if(n<=0)return{voiceId:t};const r=Is(t.slice(0,n));if(!r)return{voiceId:t};const i=t.slice(n+1).trim();return{ttsEngineId:r,voiceId:i||void 0}}function it(e,t){const n=di(t);return{ttsEngineId:n.ttsEngineId??e,voiceId:n.voiceId}}function fi(e){return er[e]}function mi(e){return e===st}function hi(e){return e===at}function As(e){if(e.ttsEngineId&&e.ttsEngineId in er)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Vn?Vn[t]:ht}class rn extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}function tr(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}}function nr(e,...t){const n=typeof e=="string"?e:e?.brainUrl?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}function Ms(e){const t=(e??"").trim();if(!t)return;let n;try{n=new URL(t)}catch{throw new Error("brainUrl must be an http or https URL")}if(n.protocol!=="http:"&&n.protocol!=="https:")throw new Error("brainUrl must be an http or https URL");if(!n.host)throw new Error("brainUrl must be an http or https URL");if(n.hash)throw new Error("brainUrl must not include a fragment");return t}async function pi(e,t=Ts){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new rn;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new rn(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,u=String(a.authToken??o??"").trim()||void 0,d=tr(a),l=nr(a);return{...a,ttsEngineId:As(i.data),authToken:u,brainId:d,knowledgeContextId:d,brainUrl:l}}const rr="thumbnail.webp";function gi(e,t=Xn){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${rr}`}function Dr(e){const t=e?.trim();if(!t)return null;try{return gi(t)}catch{return null}}function Ps(e){if(!e)return null;const t=(e.binBase||e.twinBase).trim().replace(/\/$/,"");return t?`${t}/${rr}`:null}const Rs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Cs="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Ds="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Bs="6TNvp3SCs4Og0a1ijm9TommXLql1",Fs="Swaraj Mali";async function nn(){const e=await fetch(Rs,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Cs,"Client-Secret":Ds},body:JSON.stringify({userId:Bs,userName:Fs})});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 Ls(e,t=Ct){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 Ns(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 Os(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Us(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(Os(s,i)),a=await crypto.subtle.importKey("raw",Ns(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let Wn=null;const zn=new Set;function Jt(e){return e.includes("/custom-faces/")}function sn(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 wt(e){return sn(e).encrypted}function Hn(e,t=Xn){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function wi(e,t){return(e??t)?.trim()||void 0}function yi(e){Wn=sn(e);for(const t of zn)t()}function Vs(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return sn(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return sn({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function yt(){if(!Wn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Wn}function vi(e){return zn.add(e),()=>zn.delete(e)}function an(){const e=yt();return wt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Ws(){const e=yt();return wt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function _i(){const e=yt();return wt(e)?e.binBase:e.twinBase}function Wt(){return wt(yt())}function bi(){const e=yt();return wt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function Si(){const e=yt();return wt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}const pt=[{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}],Ti=pt.map(e=>e.code),zs=new Set(Ti),Hs=new Set(pt.filter(e=>e.visemetts).map(e=>e.code)),$s=new Set(pt.filter(e=>e.cartesia).map(e=>e.code)),js="en";function ki(e){return zs.has(e)}function mn(e){const t=e?.trim();if(t)return t}function Ks(e){return e===at?pt.filter(t=>t.visemetts).map(t=>t.code):e===st?pt.filter(t=>t.cartesia).map(t=>t.code):pt.filter(t=>t.visemetts&&t.cartesia).map(t=>t.code)}function Gs(e,t){const n=t.trim();return n?e===at?Hs.has(n):e===st?$s.has(n):ki(n):!1}function Ei(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 xi=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],qs=new Map(xi.map(e=>[e.toLowerCase(),e]));function hn(e){const t=(e??"").trim();return t?qs.get(t.toLowerCase())??"sil":"sil"}const Ys={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 Qs(e){if(!e)return["sil"];const t=e.toLowerCase();return Ys[t]??["sil"]}function Ii(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 At(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function pn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||At(n,t)!=="w"||t>0&&At(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function Xs(e,t){const n=e.toLowerCase(),r=At(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 Js(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(pn(n,t))return"FF";const i=At(n,t);return i==="u"||i==="w"?"U":"O"}function Zs(e,t){const n=e.toLowerCase();if(pn(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)||At(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 ea(e,t){const n=e.toLowerCase(),r=At(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 Ai(e,t,n){const r=Qs(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 Xs(i,o);case"o":return Js(i,o);case"qw":return Zs(i,o);case"cdgknstxyz":return ea(i,o);default:return r[0]}}const ir=16,$n=47,Mi=new Set(["aa","E","I"]),Pi=new Set(["DD","SS","kk","CH"]),ta=[Mi,Pi];function na(e){for(const t of ta)if(t.has(e))return t;return null}function ra(e){return na(e)!=null}function Ri(e,t=ir){return t<=0?e:Math.round(e/t)*t}function sr(e,t=ir){return e.map(n=>({...n,vtime:Ri(n.vtime,t)}))}function Ci(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 ar(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(!ra(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<$n||a<$n||t.push(r)}return t.push(e[e.length-1]),t}function gn(e){return ar(Ci(sr(e)))}function Di(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=Ci(sr(e)),n=ar(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 ia(e){return wn(e).map(t=>t.viseme)}const sa=32,Br=48;function Bi(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function Fi(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 aa(e){return gn(e).find(n=>n.viseme!=="sil")??null}function ft(e){const t=Bi(e);return Fi(e)?t+Jn:t}function oa(e){const t=[],n=aa(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=Fi(e),i=Bi(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+Jn}),t}function Li(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 Ni(e){return e.length===0?[]:[...oa(e),...Li(e)]}function ca(e,t,n=!1){let r=null;for(const i of e){const{transStart:s,transEnd:o}=Oi(i.fromVtime,i.toVtime,i.from,i.to,n);t>=s&&t<o&&(r=i)}return r}function Oi(e,t,n,r,i=!1){const s=Math.max(0,t-e);if(i&&(n==="PP"||r==="PP")&&s>Br){const l=Br,c=t,f=c-l;return{gapMs:s,effectiveGapMs:l,holdEnd:f,transStart:f,transEnd:c}}const a=s>0?Math.max(s,sa):0,u=e,d=e+a;return{gapMs:s,effectiveGapMs:a,holdEnd:e,transStart:u,transEnd:d}}function Ui(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=zi(t,l),f=c?Ii(c,l):0;let g;fi(s)==="oculus_direct"?(g=hn(a),g==="U"&&c&&pn(c.word,f)&&(g="FF")):g=Ai(a,c?.word??"",f),e.push({viseme:g,weight:1,vtime:l,vduration:d})})}function Vi(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 or=16e3;function Wi(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:or}function la(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 ua(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Fr(e,t,n=or){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 da(e){const t=la(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 Lr(e,t,n=or){const r=da(t),i=Wi(n);if(ua(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 Fr(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return Fr(e,r,i)}}function zi(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Hi(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,u=!1,d=0,l=0,c=0,f=null,g=1,T=t,m=!1,I=null,L=0,O=!1,b=!1,E=0,V=null,D=null,oe=null;const pe=()=>({visemes:[],words:[],segmentOffsetMs:0}),P=()=>{b=!1,E=0},z=()=>{f!=null&&(clearTimeout(f),f=null)},Q=()=>{for(const v of r){try{v.onended=null,v.stop(0)}catch{}try{v.disconnect()}catch{}}r.length=0},le=()=>{for(const v of r)v.playbackRate.value=g},ce=()=>{if(!(m||!u||s||b||r.length>0||n.length>0)){if(a&&i&&l>0){const v=(i.currentTime-l)*1e3;if(v<L){z();const N=g>0?(L-v)/g:L-v;f=setTimeout(()=>{m||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,N));return}}o=!1,z(),e.onSpeakingDone(),e.onNotify()}},re=v=>{const N=ft(v);if(N<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,d=performance.now(),e.onSpeakingStart(),e.onNotify(),z();const U=g>0?N/g:N;f=setTimeout(()=>{m||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},U)},ue=(v,N,U,Y)=>{N.length!==0&&(c=U,N.forEach(G=>{const _=String(G.word??"").trim();if(!_)return;const y=Math.round((G.start??0)*1e3),S=G.duration!=null?Math.round(G.duration*1e3):G.end!=null?Math.max(1,Math.round((G.end-(G.start??0))*1e3)):0;v.push({word:_,wtime:c+y,wduration:S,queueIndex:v.length,gesture:G.gesture??null,emphasis:G.emphasis===!0})}))},we=(v,N,U,Y,G,Z)=>{U.length!==0&&(c=Y,U.forEach(_=>{const y=String(_.symbol??_.viseme??"").trim();if(!y)return;const S=Math.round((_.start??0)*1e3),K=Math.max(1,Math.round((_.duration??0)*1e3)),ee=c+S,x=zi(N,ee),J=x?Ii(x,ee):0;let ne;fi(Z)==="oculus_direct"?(ne=hn(y),ne==="U"&&x&&pn(x.word,J)&&(ne="FF")):ne=Ai(y,x?.word??"",J),v.push({viseme:ne,weight:1,vtime:ee,vduration:K})}),e.onNotify())},se=(v,N,U,Y,G,Z,_)=>{ue(N,Y,G),we(v,N,U,G,Z,_)},W=(v,N,U)=>{oe===v&&v.visemes===N||(N.length=0,U.length=0,v.visemes=N,v.words=U,v.segmentOffsetMs=0,oe=v,c=0,L=0)},M=async()=>{const v=window.AudioContext||window.webkitAudioContext;return i||(i=new v),i.state==="suspended"&&await i.resume(),I||(I=i.createMediaStreamDestination()),i},q=(v,N)=>{if(!i)return 0;const U=i,Y=U.currentTime,G=Y+.02;if(N.isFirstAudio){l<=0&&(l=G);const _=(G-Y)*1e3;d=performance.now()+_}N.onBeforeStart?.(G);const Z=U.createBufferSource();return Z.buffer=v,Z.playbackRate.value=g,Z.connect(U.destination),I&&Z.connect(I),r.push(Z),m?(r.pop(),G):(N.isFirstAudio&&(o=!0,e.onSpeakingStart()),Z.onended=()=>{const _=r.indexOf(Z);_>=0&&r.splice(_,1),e.onNotify(),!m&&(V&&D?R(V,D):ce())},Z.start(G),G)},R=async(v,N)=>{if(m||s||r.length>0)return;if(n.length===0){ce();return}s=!0;let U=!1;try{const Y=await M();if(m)return;const G=n[0];if(!G)return;const Z=!o;if(O&&(e.shouldHoldForWarmup?.()??!1)&&(b||Z&&G.newStream)||b){W(G.utterance,v,N);for(const S of n){if(m)return;S.audioBuffer||(S.audioBuffer=await Lr(Y,S.audio,S.sampleRate)),a=!0,b||(b=!0,E=0,S.newStream&&S.onNewStream?.()),S.visemesQueued||(se(v,N,S.visemes,S.words,E,!0,T),S.visemesQueued=!0,E+=Math.round(S.audioBuffer.duration*1e3),L=Math.max(L,ft(v)))}e.onNotify();return}const y=n.shift();if(!y||(y.audioBuffer||(y.audioBuffer=await Lr(Y,y.audio,y.sampleRate)),m))return;a=!0,z(),W(y.utterance,v,N),y.visemesQueued=!1,y.newStream&&y.onNewStream?.(),q(y.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:S=>{l=S,c=0,d=performance.now()+(S-Y.currentTime)*1e3,v.length=0,N.length=0,se(v,N,y.visemes,y.words,0,!0,T),y.visemesQueued=!0,y.utterance.segmentOffsetMs=0}}),U=r.length>0,L=ft(v),e.onNotify()}catch(Y){console.error("[avatarChunkPlayback] audio chunk failed:",Y)}finally{if(s=!1,m)return;if(b){n.some(G=>!G.audioBuffer||!G.visemesQueued)&&R(v,N);return}!U&&r.length===0&&n.length>0?R(v,N):r.length===0&&n.length===0&&ce()}};return{setStreamTtsEngineId:v=>{T=v},setPlaybackSpeed:v=>{g=Math.max(.1,Math.min(1,v)),le()},getPlaybackSpeed:()=>g,setLipsyncWarmupHoldEnabled:v=>{O=v,v||P()},isWarmingUp:()=>b,releaseWarmupHold:()=>{if(b){b=!1,E=0;for(const v of n)v.newStream=!1;V&&D&&R(V,D),e.onNotify()}},resetForNewStream:v=>{m=!1,u=!1,T=v,L=0},resumeBotStream:()=>{m=!1,u=!1},clearAborted:()=>{m=!1},primeAudioContext:async()=>{const v=window.AudioContext||window.webkitAudioContext;i||(i=new v),i.state==="suspended"&&await i.resume(),i&&!I&&(I=i.createMediaStreamDestination())},stop:()=>{m=!0,z(),Q(),n.length=0,s=!1,o=!1,a=!1,u=!1,c=0,l=0,d=0,L=0,V=null,D=null,oe=null,P()},markStreamComplete:v=>{if(L=Math.max(L,ft(v)),u=!0,!a&&v.length>0){re(v);return}ce()},playAudioChunk:async(v,N,U,Y,G,Z,_)=>{if(m)return;V=v,D=N;const y=Wi(_?.sampleRate),S=_?.newStream===!0,K=pe();if(!U?.trim()){if(Y.length===0&&G.length===0)return;W(K,v,N),S&&_?.onNewStream?.(),se(v,N,Y,G,0,!0,T),L=ft(v),!o&&L>0&&re(v),e.onNotify();return}n.push({audio:U,audioBuffer:null,utterance:K,visemes:Y,words:G,isNewSegment:Z,sampleRate:y,newStream:S,onNewStream:_?.onNewStream,visemesQueued:!1}),await R(v,N)},queueTimingsOnly:(v,N,U,Y,G,Z)=>{if(m)return;const _=pe();W(_,v,N),se(v,N,U,Y,0,!0,T),_.segmentOffsetMs=0,L=ft(v)},getPlaybackElapsedMs:()=>a&&i&&l>0?Math.max(0,(i.currentTime-l)*1e3*g):o?Math.max(0,(performance.now()-d)*g):0,isSpeaking:()=>o?!0:!a||!i||l<=0?!1:(i.currentTime-l)*1e3<L,getVoiceStream:()=>I?I.stream:null,getPlaybackStartPerf:()=>d,bargeIn:()=>{m=!0,u=!1,z(),Q(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,L=0,V=null,D=null,oe=null,P()},interrupt:()=>{m=!0,u=!1,z(),Q(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,L=0,V=null,D=null,oe=null,P()}}}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 $i(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 fa(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 ma(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Nr(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 yn=.5,vn=1.5,cr="Olivia",lr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Ht=.85;function jn(e,t=Ct,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let u=0;const d=[],l=[];let c="",f="neutral",g="",T=ht;const m=new Set;let I=0,L=null,O=0,b=null;const E=()=>m.forEach(W=>W());let V=()=>!1;const D=Hi({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:E,shouldHoldForWarmup:()=>V()},ht),oe=()=>D.getPlaybackElapsedMs(),pe=(W,M=c)=>{if(!n.onLipsyncDebug)return;const q=oe(),R=i,H=wn(o).map(X=>({viseme:X.viseme,vtimeMs:X.vtime}));n.onLipsyncDebug({event:W,spokenText:M,mood:f,playbackAnchorPerf:D.getPlaybackStartPerf(),playbackElapsedMs:q,queueLength:R.length,activeViseme:zt(R,q),segments:l.map(X=>({...X,visemes:[...X.visemes]})),fullQueueLength:o.length,compactionSkipped:H})},P=(W,M)=>{n.onLipsyncDebug&&(L={event:W,spokenText:M},I===0&&(I=requestAnimationFrame(()=>{I=0;const q=L;L=null,q&&pe(q.event,q.spokenText)})))},z=(W,M,q,R,H)=>{if(!n.onLipsyncDebug)return;const X=i.slice(M),ae=q.filter(v=>String(v.symbol??v.viseme??"").trim());l.push({spokenText:W,audioOffsetMs:X[0]?.vtime??0,isNewSegment:R,chunkDurationMs:H,receivedAtMs:performance.now(),visemes:X.map((v,N)=>{const U=ae[N];return{rawSymbol:String(U?.symbol??U?.viseme??v.viseme).trim(),viseme:v.viseme,startSec:Number(U?.start??0),durationSec:Number(U?.duration??0),vtimeMs:v.vtime,vdurationMs:v.vduration}})})},Q=()=>{o.length=0,a.length=0,u=0},le=(W,M,q,R,H)=>{if(W.length===0&&M.length===0)return;Ui(o,a,W,M,u,H);const X=Vi(W,u),ae=q?Nr(q,R):null;u=Math.max(X,ae!=null?u+ae:u)},ce=()=>{O+=1,b?.abort(),b=null,D.stop(),i.length=0,s.length=0,Q(),d.length=0,f="neutral",l.length=0,c="",e("idle"),P("reset"),E()},re=W=>{const M=it(W?.ttsEngineId,W?.voiceId),q=M.ttsEngineId??T??ht,R=M.voiceId??(q===at?fn:cr),H=W?.speakingRate??Ht,X=Math.max(yn,Math.min(vn,H));return{engineId:q,voiceId:R,speakingRate:X,language:mn(W?.language)}},ue=async W=>{ce();const M=O;b=new AbortController,e("loading"),c=W.debugSpokenFallback,l.length=0,Q();const q=g.trim();if(!q)throw new Error("Developer token required for avatar_ttsWithPoses");D.resetForNewStream(W.engineId),D.setStreamTtsEngineId(W.engineId);let R="",H="";try{const X=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${q}`,Accept:"text/event-stream"},body:JSON.stringify(W.requestBody),signal:b.signal});if(!X.ok)throw new Error(`avatar_ttsWithPoses failed (${X.status})`);const ae=X.body;if(!ae)throw new Error("No response body");const v=ae.getReader(),N=new TextDecoder;let U="",Y=!0;const G=()=>R||W.debugSpokenFallback,Z=async _=>{if(M!==O)return;const y=Ei(_);if(y){if(y.event==="spokenText"){const S=typeof y.data.text=="string"?y.data.text.trim():"";S&&(R=S,c=S,W.onSpokenText?.(S),E());return}if(y.event==="displayText"){const S=typeof y.data.text=="string"?y.data.text.trim():"";S&&(H=S,W.onDisplayText?.(S),E());return}if(y.event!=="done"){if(y.event==="audio"){const S=y.data.chunk,K=y.data.visemes??[],ee=y.data.words??[],x=y.data.is_new_segment??!1,J=y.data.sample_rate,ne=Number(y.data.audio_offset_ms??0),te=i.length,Se=G();if(le(K,ee,S,J,W.engineId),S){const ut=Y;Y=!1,await D.playAudioChunk(i,s,S,K,ee,x,{sampleRate:J,newStream:ut,audioOffsetMs:ne}),z(Se,te,K,x,Nr(S,J)),P("audio_chunk",Se)}else(K.length>0||ee.length>0)&&(D.queueTimingsOnly(i,s,K,ee,x,{audioOffsetMs:ne,newStream:Y}),z(Se,te,K,x,null),P("audio_chunk",Se))}else if(y.event==="metadata"){const S=y.data.mood;typeof S=="string"&&S.trim()&&(f=S.trim());const K=y.data.spoken_text??y.data.text;typeof K=="string"&&K.trim()&&!R&&(R=K.trim(),c=R);const ee=y.data.sentence_emotions;if(Array.isArray(ee)){d.length=0;for(const x of ee){if(!x||typeof x!="object")continue;const J=x;d.push({sentence_index:Number(J.sentence_index??0),text:String(J.text??""),sentiment:typeof J.sentiment=="string"?J.sentiment:void 0,emotion:String(J.emotion??f),start_word:Number(J.start_word??0),end_word:Number(J.end_word??0)})}}E(),P("metadata",G())}else if(y.event==="error")throw new Error(String(y.data.message??"avatar_ttsWithPoses stream error"))}}};for(;;){if(M!==O)return{displayText:H,spokenText:R,aborted:!0};const{done:_,value:y}=await v.read();y&&(U+=N.decode(y,{stream:!0}));const S=U.split(`
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const O=require("react/jsx-runtime"),m=require("react"),ws=require("@pipecat-ai/client-js"),Zn=require("@pipecat-ai/websocket-transport"),ye=require("pixi.js");var Bn=typeof document<"u"?document.currentScript:null;const ys="https://aitwin.bubu.social",fi={publicBase:ys},vs="0.7.1",_s={version:vs},bs={},Dt="https://ai.aitwin.me",er=`${fi.publicBase}/custom-faces`,Ss=`${fi.publicBase}/aitwin-workers/v${_s.version}/visemeDiffPreview.worker.js`;function Ts(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Bn&&Bn.tagName.toUpperCase()==="SCRIPT"&&Bn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?bs?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Ss}const ks="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Fn=3e3,Vt=16,Br=3e3,Es=4e3,xs=.85,Is=8,tr=400,nr="eng_a7f2b9c1",hn="eng_d4e8f3a2",at="eng_c9b1e6d4",ot="visemetts",ht=at,pn="eve",Hn=new Set([hn,at,ot]),rr={[nr]:"oculus_direct",[at]:"oculus_direct",[ot]:"oculus_direct",[hn]:"inworld_word"},$n={google:nr,inworld:hn,cartesia:at,visemetts:ot};function As(e){const t=e.trim();if(t)return t in rr?t:$n[t.toLowerCase()]}function mi(e){const t=e?.trim();if(!t)return{};const n=t.indexOf(":");if(n<=0)return{voiceId:t};const r=As(t.slice(0,n));if(!r)return{voiceId:t};const i=t.slice(n+1).trim();return{ttsEngineId:r,voiceId:i||void 0}}function st(e,t){const n=mi(t);return{ttsEngineId:n.ttsEngineId??e,voiceId:n.voiceId}}function hi(e){return rr[e]}function pi(e){return e===at}function gi(e){return e===ot}function Ms(e){if(e.ttsEngineId&&e.ttsEngineId in rr)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in $n?$n[t]:ht}class on extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}function ir(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}}function sr(e,...t){const n=typeof e=="string"?e:e?.brainUrl?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}function Rs(e){const t=(e??"").trim();if(!t)return;let n;try{n=new URL(t)}catch{throw new Error("brainUrl must be an http or https URL")}if(n.protocol!=="http:"&&n.protocol!=="https:")throw new Error("brainUrl must be an http or https URL");if(!n.host)throw new Error("brainUrl must be an http or https URL");if(n.hash)throw new Error("brainUrl must not include a fragment");return t}async function wi(e,t=ks){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new on;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new on(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,u=String(a.authToken??o??"").trim()||void 0,d=ir(a),l=sr(a);return{...a,ttsEngineId:Ms(i.data),authToken:u,brainId:d,knowledgeContextId:d,brainUrl:l}}const ar="thumbnail.webp";function yi(e,t=er){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${ar}`}function Fr(e){const t=e?.trim();if(!t)return null;try{return yi(t)}catch{return null}}function Ps(e){if(!e)return null;const t=(e.binBase||e.twinBase).trim().replace(/\/$/,"");return t?`${t}/${ar}`:null}const Cs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Ds="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Bs="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Fs="6TNvp3SCs4Og0a1ijm9TommXLql1",Ls="Swaraj Mali";async function an(){const e=await fetch(Cs,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Ds,"Client-Secret":Bs},body:JSON.stringify({userId:Fs,userName:Ls})});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 Os(e,t=Dt){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 Ns(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 en(e){return Uint8Array.from(e)}function Us(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Vs(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=en(n.subarray(0,12)),i=en(n.subarray(12,28)),s=en(n.subarray(28)),o=en(Us(s,i)),a=await crypto.subtle.importKey("raw",Ns(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let zn=null;const jn=new Set;function tn(e){return e.includes("/custom-faces/")}function cn(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||tn(t)||tn(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=tn(t)?t:tn(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function wt(e){return cn(e).encrypted}function Kn(e,t=er){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function vi(e,t){return(e??t)?.trim()||void 0}function _i(e){zn=cn(e);for(const t of jn)t()}function Ws(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return cn(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return cn({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function yt(){if(!zn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return zn}function bi(e){return jn.add(e),()=>jn.delete(e)}function ln(){const e=yt();return wt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Hs(){const e=yt();return wt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Si(){const e=yt();return wt(e)?e.binBase:e.twinBase}function zt(){return wt(yt())}function Ti(){const e=yt();return wt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function ki(){const e=yt();return wt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}const pt=[{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}],Ei=pt.map(e=>e.code),$s=new Set(Ei),zs=new Set(pt.filter(e=>e.visemetts).map(e=>e.code)),js=new Set(pt.filter(e=>e.cartesia).map(e=>e.code)),Ks="en";function xi(e){return $s.has(e)}function gn(e){const t=e?.trim();if(t)return t}function Gs(e){return e===ot?pt.filter(t=>t.visemetts).map(t=>t.code):e===at?pt.filter(t=>t.cartesia).map(t=>t.code):pt.filter(t=>t.visemetts&&t.cartesia).map(t=>t.code)}function qs(e,t){const n=t.trim();return n?e===ot?zs.has(n):e===at?js.has(n):xi(n):!1}function Ii(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 Ai=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],Ys=new Map(Ai.map(e=>[e.toLowerCase(),e]));function wn(e){const t=(e??"").trim();return t?Ys.get(t.toLowerCase())??"sil":"sil"}const Qs={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 Xs(e){if(!e)return["sil"];const t=e.toLowerCase();return Qs[t]??["sil"]}function Mi(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 Mt(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function yn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||Mt(n,t)!=="w"||t>0&&Mt(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function Js(e,t){const n=e.toLowerCase(),r=Mt(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 Zs(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(yn(n,t))return"FF";const i=Mt(n,t);return i==="u"||i==="w"?"U":"O"}function ea(e,t){const n=e.toLowerCase();if(yn(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)||Mt(n,t)==="o"?"O":"U"}const nn={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function ta(e,t){const n=e.toLowerCase(),r=Mt(n,t);if(nn[r])return nn[r];for(let i=0;i<n.length;i++){const s=n[i];if(nn[s])return nn[s]}return"DD"}function Ri(e,t,n){const r=Xs(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 Zs(i,o);case"qw":return ea(i,o);case"cdgknstxyz":return ta(i,o);default:return r[0]}}const or=16,Gn=47,Pi=new Set(["aa","E","I"]),Ci=new Set(["DD","SS","kk","CH"]),na=[Pi,Ci];function ra(e){for(const t of na)if(t.has(e))return t;return null}function ia(e){return ra(e)!=null}function Di(e,t=or){return t<=0?e:Math.round(e/t)*t}function cr(e,t=or){return e.map(n=>({...n,vtime:Di(n.vtime,t)}))}function Bi(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 lr(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(!ia(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<Gn||a<Gn||t.push(r)}return t.push(e[e.length-1]),t}function vn(e){return lr(Bi(cr(e)))}function Fi(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function _n(e){const t=Bi(cr(e)),n=lr(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 sa(e){return _n(e).map(t=>t.viseme)}const aa=32,Lr=48;function Li(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function Oi(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 oa(e){return vn(e).find(n=>n.viseme!=="sil")??null}function ft(e){const t=Li(e);return Oi(e)?t+tr:t}function ca(e){const t=[],n=oa(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=Oi(e),i=Li(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+tr}),t}function Ni(e){const t=vn(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 Ui(e){return e.length===0?[]:[...ca(e),...Ni(e)]}function la(e,t,n=!1){let r=null;for(const i of e){const{transStart:s,transEnd:o}=Vi(i.fromVtime,i.toVtime,i.from,i.to,n);t>=s&&t<o&&(r=i)}return r}function Vi(e,t,n,r,i=!1){const s=Math.max(0,t-e);if(i&&(n==="PP"||r==="PP")&&s>Lr){const l=Lr,c=t,f=c-l;return{gapMs:s,effectiveGapMs:l,holdEnd:f,transStart:f,transEnd:c}}const a=s>0?Math.max(s,aa):0,u=e,d=e+a;return{gapMs:s,effectiveGapMs:a,holdEnd:e,transStart:u,transEnd:d}}function Wi(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=zi(t,l),f=c?Mi(c,l):0;let w;hi(s)==="oculus_direct"?(w=wn(a),w==="U"&&c&&yn(c.word,f)&&(w="FF")):w=Ri(a,c?.word??"",f),e.push({viseme:w,weight:1,vtime:l,vduration:d})})}function Hi(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 ur=16e3;function $i(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:ur}function ua(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 da(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Or(e,t,n=ur){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 fa(e){const t=ua(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 Nr(e,t,n=ur){const r=fa(t),i=$i(n);if(da(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 Or(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return Or(e,r,i)}}function zi(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function ji(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,u=!1,d=0,l=0,c=0,f=null,w=1,T=t,h=!1,E=null,W=null,L=!1,v=0,k=!1,N=!1,B=0,ie=null,re=null,P=null;const G=()=>({visemes:[],words:[],segmentOffsetMs:0}),Q=()=>{N=!1,B=0},te=()=>{f!=null&&(clearTimeout(f),f=null)},le=()=>{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},oe=()=>{if(!(h||!u||s||N||r.length>0||n.length>0)){if(a&&i&&l>0){const b=(i.currentTime-l)*1e3;if(b<v){te();const U=w>0?(v-b)/w:v-b;f=setTimeout(()=>{h||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,U));return}}o=!1,te(),e.onSpeakingDone(),e.onNotify()}},ge=b=>{const U=ft(b);if(U<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,d=performance.now(),e.onSpeakingStart(),e.onNotify(),te();const Y=w>0?U/w:U;f=setTimeout(()=>{h||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},Y)},ce=(b,U,Y,_)=>{U.length!==0&&(c=Y,U.forEach(g=>{const R=String(g.word??"").trim();if(!R)return;const V=Math.round((g.start??0)*1e3),X=g.duration!=null?Math.round(g.duration*1e3):g.end!=null?Math.max(1,Math.round((g.end-(g.start??0))*1e3)):0;b.push({word:R,wtime:c+V,wduration:X,queueIndex:b.length,gesture:g.gesture??null,emphasis:g.emphasis===!0})}))},H=(b,U,Y,_,g,S)=>{Y.length!==0&&(c=_,Y.forEach(R=>{const V=String(R.symbol??R.viseme??"").trim();if(!V)return;const X=Math.round((R.start??0)*1e3),ue=Math.max(1,Math.round((R.duration??0)*1e3)),I=c+X,$=zi(U,I),de=$?Mi($,I):0;let Re;hi(S)==="oculus_direct"?(Re=wn(V),Re==="U"&&$&&yn($.word,de)&&(Re="FF")):Re=Ri(V,$?.word??"",de),b.push({viseme:Re,weight:1,vtime:I,vduration:ue})}),e.onNotify())},A=(b,U,Y,_,g,S,R)=>{ce(U,_,g),H(b,U,Y,g,S,R)},q=(b,U,Y)=>{P===b&&b.visemes===U||(U.length=0,Y.length=0,b.visemes=U,b.words=Y,b.segmentOffsetMs=0,P=b,c=0,v=0)},C=b=>(W||(W=b.createGain(),W.gain.value=L?0:1,W.connect(b.destination)),W),z=async()=>{const b=window.AudioContext||window.webkitAudioContext;return i||(i=new b,W=null,E=null),i.state==="suspended"&&await i.resume(),C(i),E||(E=i.createMediaStreamDestination()),i},J=(b,U)=>{if(!i)return 0;const Y=i,_=Y.currentTime,g=_+.02;if(U.isFirstAudio){l<=0&&(l=g);const R=(g-_)*1e3;d=performance.now()+R}U.onBeforeStart?.(g);const S=Y.createBufferSource();return S.buffer=b,S.playbackRate.value=w,S.connect(C(Y)),E&&S.connect(E),r.push(S),h?(r.pop(),g):(U.isFirstAudio&&(o=!0,e.onSpeakingStart()),S.onended=()=>{const R=r.indexOf(S);R>=0&&r.splice(R,1),e.onNotify(),!h&&(ie&&re?ee(ie,re):oe())},S.start(g),g)},ee=async(b,U)=>{if(h||s||r.length>0)return;if(n.length===0){oe();return}s=!0;let Y=!1;try{const _=await z();if(h)return;const g=n[0];if(!g)return;const S=!o;if(k&&(e.shouldHoldForWarmup?.()??!1)&&(N||S&&g.newStream)||N){q(g.utterance,b,U);for(const X of n){if(h)return;X.audioBuffer||(X.audioBuffer=await Nr(_,X.audio,X.sampleRate)),a=!0,N||(N=!0,B=0,X.newStream&&X.onNewStream?.()),X.visemesQueued||(A(b,U,X.visemes,X.words,B,!0,T),X.visemesQueued=!0,B+=Math.round(X.audioBuffer.duration*1e3),v=Math.max(v,ft(b)))}e.onNotify();return}const V=n.shift();if(!V||(V.audioBuffer||(V.audioBuffer=await Nr(_,V.audio,V.sampleRate)),h))return;a=!0,te(),q(V.utterance,b,U),V.visemesQueued=!1,V.newStream&&V.onNewStream?.(),J(V.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:X=>{l=X,c=0,d=performance.now()+(X-_.currentTime)*1e3,b.length=0,U.length=0,A(b,U,V.visemes,V.words,0,!0,T),V.visemesQueued=!0,V.utterance.segmentOffsetMs=0}}),Y=r.length>0,v=ft(b),e.onNotify()}catch(_){console.error("[avatarChunkPlayback] audio chunk failed:",_)}finally{if(s=!1,h)return;if(N){n.some(g=>!g.audioBuffer||!g.visemesQueued)&&ee(b,U);return}!Y&&r.length===0&&n.length>0?ee(b,U):r.length===0&&n.length===0&&oe()}};return{setStreamTtsEngineId:b=>{T=b},setPlaybackSpeed:b=>{w=Math.max(.1,Math.min(1,b)),ae()},getPlaybackSpeed:()=>w,setMuted:b=>{L=b,W&&(W.gain.value=b?0:1)},isMuted:()=>L,setLipsyncWarmupHoldEnabled:b=>{k=b,b||Q()},isWarmingUp:()=>N,releaseWarmupHold:()=>{if(N){N=!1,B=0;for(const b of n)b.newStream=!1;ie&&re&&ee(ie,re),e.onNotify()}},resetForNewStream:b=>{h=!1,u=!1,T=b,v=0},resumeBotStream:()=>{h=!1,u=!1},clearAborted:()=>{h=!1},primeAudioContext:async()=>{const b=window.AudioContext||window.webkitAudioContext;i||(i=new b,W=null,E=null),i.state==="suspended"&&await i.resume(),C(i),E||(E=i.createMediaStreamDestination())},stop:()=>{h=!0,te(),le(),n.length=0,s=!1,o=!1,a=!1,u=!1,c=0,l=0,d=0,v=0,ie=null,re=null,P=null,Q()},markStreamComplete:b=>{if(v=Math.max(v,ft(b)),u=!0,!a&&b.length>0){ge(b);return}oe()},playAudioChunk:async(b,U,Y,_,g,S,R)=>{if(h)return;ie=b,re=U;const V=$i(R?.sampleRate),X=R?.newStream===!0,ue=G();if(!Y?.trim()){if(_.length===0&&g.length===0)return;q(ue,b,U),X&&R?.onNewStream?.(),A(b,U,_,g,0,!0,T),v=ft(b),!o&&v>0&&ge(b),e.onNotify();return}n.push({audio:Y,audioBuffer:null,utterance:ue,visemes:_,words:g,isNewSegment:S,sampleRate:V,newStream:X,onNewStream:R?.onNewStream,visemesQueued:!1}),await ee(b,U)},queueTimingsOnly:(b,U,Y,_,g,S)=>{if(h)return;const R=G();q(R,b,U),A(b,U,Y,_,0,!0,T),R.segmentOffsetMs=0,v=ft(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<v,getVoiceStream:()=>E?E.stream:null,getPlaybackStartPerf:()=>d,bargeIn:()=>{h=!0,u=!1,te(),le(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,v=0,ie=null,re=null,P=null,Q()},interrupt:()=>{h=!0,u=!1,te(),le(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,v=0,ie=null,re=null,P=null,Q()}}}function jt(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 Ki(e,t,n=120){const r=jt(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 ma(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 ha(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Ur(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 bn=.5,Sn=1.5,dr="Olivia",fr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Kt=.85;function qn(e,t=Dt,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let u=0;const d=[],l=[];let c="",f="neutral",w="",T=ht;const h=new Set;let E=0,W=null,L=0,v=null;const k=()=>h.forEach(H=>H());let N=()=>!1;const B=ji({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:k,shouldHoldForWarmup:()=>N()},ht),ie=()=>B.getPlaybackElapsedMs(),re=(H,A=c)=>{if(!n.onLipsyncDebug)return;const q=ie(),C=i,z=_n(o).map(J=>({viseme:J.viseme,vtimeMs:J.vtime}));n.onLipsyncDebug({event:H,spokenText:A,mood:f,playbackAnchorPerf:B.getPlaybackStartPerf(),playbackElapsedMs:q,queueLength:C.length,activeViseme:jt(C,q),segments:l.map(J=>({...J,visemes:[...J.visemes]})),fullQueueLength:o.length,compactionSkipped:z})},P=(H,A)=>{n.onLipsyncDebug&&(W={event:H,spokenText:A},E===0&&(E=requestAnimationFrame(()=>{E=0;const q=W;W=null,q&&re(q.event,q.spokenText)})))},G=(H,A,q,C,z)=>{if(!n.onLipsyncDebug)return;const J=i.slice(A),ee=q.filter(ne=>String(ne.symbol??ne.viseme??"").trim());l.push({spokenText:H,audioOffsetMs:J[0]?.vtime??0,isNewSegment:C,chunkDurationMs:z,receivedAtMs:performance.now(),visemes:J.map((ne,Te)=>{const Z=ee[Te];return{rawSymbol:String(Z?.symbol??Z?.viseme??ne.viseme).trim(),viseme:ne.viseme,startSec:Number(Z?.start??0),durationSec:Number(Z?.duration??0),vtimeMs:ne.vtime,vdurationMs:ne.vduration}})})},Q=()=>{o.length=0,a.length=0,u=0},te=(H,A,q,C,z)=>{if(H.length===0&&A.length===0)return;Wi(o,a,H,A,u,z);const J=Hi(H,u),ee=q?Ur(q,C):null;u=Math.max(J,ee!=null?u+ee:u)},le=()=>{L+=1,v?.abort(),v=null,B.stop(),i.length=0,s.length=0,Q(),d.length=0,f="neutral",l.length=0,c="",e("idle"),P("reset"),k()},ae=H=>{const A=st(H?.ttsEngineId,H?.voiceId),q=A.ttsEngineId??T??ht,C=A.voiceId??(q===ot?pn:dr),z=H?.speakingRate??Kt,J=Math.max(bn,Math.min(Sn,z));return{engineId:q,voiceId:C,speakingRate:J,language:gn(H?.language)}},oe=async H=>{le();const A=L;v=new AbortController,e("loading"),c=H.debugSpokenFallback,l.length=0,Q();const q=w.trim();if(!q)throw new Error("Developer token required for avatar_ttsWithPoses");B.resetForNewStream(H.engineId),B.setStreamTtsEngineId(H.engineId);let C="",z="";try{const J=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${q}`,Accept:"text/event-stream"},body:JSON.stringify(H.requestBody),signal:v.signal});if(!J.ok)throw new Error(`avatar_ttsWithPoses failed (${J.status})`);const ee=J.body;if(!ee)throw new Error("No response body");const ne=ee.getReader(),Te=new TextDecoder;let Z="",b=!0;const U=()=>C||H.debugSpokenFallback,Y=async _=>{if(A!==L)return;const g=Ii(_);if(g){if(g.event==="spokenText"){const S=typeof g.data.text=="string"?g.data.text.trim():"";S&&(C=S,c=S,H.onSpokenText?.(S),k());return}if(g.event==="displayText"){const S=typeof g.data.text=="string"?g.data.text.trim():"";S&&(z=S,H.onDisplayText?.(S),k());return}if(g.event!=="done"){if(g.event==="audio"){const S=g.data.chunk,R=g.data.visemes??[],V=g.data.words??[],X=g.data.is_new_segment??!1,ue=g.data.sample_rate,I=Number(g.data.audio_offset_ms??0),$=i.length,de=U();if(te(R,V,S,ue,H.engineId),S){const Re=b;b=!1,await B.playAudioChunk(i,s,S,R,V,X,{sampleRate:ue,newStream:Re,audioOffsetMs:I}),G(de,$,R,X,Ur(S,ue)),P("audio_chunk",de)}else(R.length>0||V.length>0)&&(B.queueTimingsOnly(i,s,R,V,X,{audioOffsetMs:I,newStream:b}),G(de,$,R,X,null),P("audio_chunk",de))}else if(g.event==="metadata"){const S=g.data.mood;typeof S=="string"&&S.trim()&&(f=S.trim());const R=g.data.spoken_text??g.data.text;typeof R=="string"&&R.trim()&&!C&&(C=R.trim(),c=C);const V=g.data.sentence_emotions;if(Array.isArray(V)){d.length=0;for(const X of V){if(!X||typeof X!="object")continue;const ue=X;d.push({sentence_index:Number(ue.sentence_index??0),text:String(ue.text??""),sentiment:typeof ue.sentiment=="string"?ue.sentiment:void 0,emotion:String(ue.emotion??f),start_word:Number(ue.start_word??0),end_word:Number(ue.end_word??0)})}}k(),P("metadata",U())}else if(g.event==="error")throw new Error(String(g.data.message??"avatar_ttsWithPoses stream error"))}}};for(;;){if(A!==L)return{displayText:z,spokenText:C,aborted:!0};const{done:_,value:g}=await ne.read();g&&(Z+=Te.decode(g,{stream:!0}));const S=Z.split(`
|
|
2
2
|
|
|
3
|
-
`);U=S.pop()??"";for(const K of S)await Z(K);if(_){U.trim()&&await Z(U.trim()),D.markStreamComplete(i),P("bot_stopped",G());break}}}catch(X){if(M!==O)return{displayText:H,spokenText:R,aborted:!0};if(X instanceof DOMException&&X.name==="AbortError")return{displayText:H,spokenText:R,aborted:!0};throw console.error("[avatarTtsLipsync]",X),ce(),e("error"),X}return{displayText:H,spokenText:R}};return{setDeveloperToken:W=>{g=W},setTtsEngineId:W=>{T=W},getTtsEngineId:()=>T,speak:async(W,M)=>{const{engineId:q,voiceId:R,speakingRate:H,language:X}=re(M),ae={user_query:W,ttsEngineId:q,speakingRate:H,tenant:"aiTwin"};Un.has(q)&&(ae.voice_id=R),X&&(ae.language=X),await ue({requestBody:ae,engineId:q,debugSpokenFallback:W})},speakWithReply:async(W,M)=>{const q=W.trim();if(!q)throw new Error("Message is required");const{engineId:R,voiceId:H,speakingRate:X,language:ae}=re(M),v={generateReply:!0,message:q,ttsEngineId:R,speakingRate:X,tenant:"aiTwin",history:M?.history??[]};Un.has(R)&&(v.voice_id=H),ae&&(v.language=ae);const N=M?.brainId?.trim();N&&(v.brainId=N);const U=M?.brainUrl?.trim();U&&(v.brainUrl=U);const Y=await ue({requestBody:v,engineId:R,debugSpokenFallback:q,onSpokenText:M?.onSpokenText,onDisplayText:M?.onDisplayText});if(Y.aborted)return{spokenText:Y.spokenText,displayText:Y.displayText};if(!Y.spokenText&&!Y.displayText)throw new Error("avatar_ttsWithPoses generateReply stream missing spokenText or displayText");return{spokenText:Y.spokenText||Y.displayText,displayText:Y.displayText||Y.spokenText}},stop:ce,getVisemeQueue:()=>i,getWordQueue:()=>s,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>d,getStreamMood:()=>f,getPlaybackElapsedMs:()=>D.getPlaybackElapsedMs(),isSpeaking:()=>D.isSpeaking(),isWarmingUp:()=>D.isWarmingUp(),releaseWarmupHold:()=>D.releaseWarmupHold(),setLipsyncWarmupHold:(W,M)=>{M&&(V=M),D.setLipsyncWarmupHoldEnabled(W)},getVoiceStream:()=>D.getVoiceStream(),setPlaybackSpeed:W=>{D.setPlaybackSpeed(W)},getPlaybackSpeed:()=>D.getPlaybackSpeed(),subscribe:W=>(m.add(W),()=>m.delete(W))}}const ur=16e3,dr=16e3;class ha extends Qn.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 pa extends Qn.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,ur,dr)}bufferBotAudio(t,n){}}const ga=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Or(e){return ga.test(e.trim())}function wa(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function ji(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??Ct,r=new URL(`${wa(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const i=it(e.ttsEngineId,e.voiceId),s=i.ttsEngineId;s&&r.searchParams.set("ttsEngineId",s);const o=i.voiceId?.trim();o&&(s&&hi(s)?Or(o)||r.searchParams.set("voiceId",o):Or(o)&&r.searchParams.set("voiceId",o));const a=mn(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.brainUrl?.trim();d&&r.searchParams.set("brainUrl",d);const l=e.speakingRate??Ht;r.searchParams.set("speaking_rate",String(Math.max(yn,Math.min(vn,l)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),e.speakOnlyWhenSpokenTo&&r.searchParams.set("speakOnlyWhenSpokenTo","true");const c=e.avatarName?.trim();return c&&r.searchParams.set("avatarName",c),r.toString()}function Dn(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 ya(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 Ur(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function va(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function Ki(e,t={}){const n=[],r=[],i=[],s=[];let o=0;const a=[],u=[];let d="",l="neutral",c=st,f=!1,g=null,T=null,m={...t},I=0,L=null;const O=new Set,b=[];let E=!1,V=null,D=!0,oe="default";const pe=new Set;let P=null,z=0,Q=!1,le=!1,ce=null,re=!1;const ue=()=>{ce!=null&&(clearTimeout(ce),ce=null)},we=()=>{ue(),ce=setTimeout(()=>{ce=null,D&&(M.markStreamComplete(n),ae("bot_stopped"))},450)},se=()=>O.forEach(p=>p());let W=()=>!1;const M=Hi({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{re=!1,le=!1,e("done")},onNotify:se,shouldHoldForWarmup:()=>W()},c),q=()=>{if(V)return V;const p=new MessageChannel;return p.port1.onmessage=()=>{const B=b.shift();B!==void 0&&te(B),b.length>0?p.port2.postMessage(null):E=!1},V=p,p},R=p=>{b.push(p),!E&&(E=!0,q().port2.postMessage(null))},H=()=>M.getPlaybackElapsedMs(),X=(p,B=d)=>{if(!m.onLipsyncDebug)return;const ie=H(),de=n,Me=wn(i).map(Ee=>({viseme:Ee.viseme,vtimeMs:Ee.vtime}));m.onLipsyncDebug({event:p,spokenText:B,mood:l,playbackAnchorPerf:M.getPlaybackStartPerf(),playbackElapsedMs:ie,queueLength:de.length,activeViseme:zt(de,ie),segments:u.map(Ee=>({...Ee,visemes:[...Ee.visemes]})),fullQueueLength:i.length,compactionSkipped:Me})},ae=(p,B)=>{m.onLipsyncDebug&&(L={event:p,spokenText:B},I===0&&(I=requestAnimationFrame(()=>{I=0;const ie=L;L=null,ie&&X(ie.event,ie.spokenText)})))},v=()=>{D=!0,pe.clear(),M.clearAborted()},N=()=>{const p=va(g);if(p){oe=`bot-${Date.now()}`,p.interruptedTrackIds={[oe]:!0};try{p.interrupt?.()}catch{}}const B=T;try{B?.interrupt?.()}catch{}},U=p=>{if(re&&M.isSpeaking())return!0;const B=p.context_id?.trim();return B&&pe.has(B)?!0:D?!1:!(p.type==="avatar_metadata"||Ur(p))},Y=p=>{D=!1,re=!1;const B=p.context_id?.trim();B&&pe.add(B),ue(),Q=!1,le=!1,b.length=0,E=!1,P?.abort(),P=null,z+=1,N(),M.bargeIn(),G(),e("idle"),ae("interrupt"),se()},G=()=>{n.length=0,r.length=0,i.length=0,s.length=0,o=0,u.length=0,d="",l="neutral",a.length=0},Z=()=>{ue(),le=!1,Q=!1,M.stop(),G(),ae("reset"),se()},_=()=>{Z(),e("idle"),se()},y=(p,B)=>{typeof p.mood=="string"&&p.mood.trim()&&(l=p.mood.trim()),Array.isArray(p.sentence_emotions)&&p.sentence_emotions.length>0&&(B&&(a.length=0),a.push(...Dn(p.sentence_emotions,l)))},S=p=>{if(U({...p,type:"avatar_metadata"}))return;v(),Q=!0;const B=String(p.spoken_text??p.text??"").trim();B&&(d=B),M.resetForNewStream(c),typeof p.mood=="string"&&p.mood.trim()&&(l=p.mood.trim()),a.length=0,a.push(...Dn(p.sentence_emotions,l)),Array.isArray(p.gestures)&&p.gestures,ae("metadata",B),se()},K=(p,B,ie,de)=>{if(!m.onLipsyncDebug)return;const Me=n.slice(ie),Ee=de.filter(Pe=>String(Pe.symbol??Pe.viseme??"").trim());u.push({spokenText:B,audioOffsetMs:Me[0]?.vtime??0,isNewSegment:!!p.is_new_segment,chunkDurationMs:p.chunk_duration_ms!=null?Number(p.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:Me.map((Pe,ze)=>{const Oe=Ee[ze];return{rawSymbol:String(Oe?.symbol??Oe?.viseme??Pe.viseme).trim(),viseme:Pe.viseme,startSec:Number(Oe?.start??0),durationSec:Number(Oe?.duration??0),vtimeMs:Pe.vtime,vdurationMs:Pe.vduration}})})},ee=(p,B,ie,de)=>{if(p.length===0&&B.length===0)return;Ui(i,s,p,B,o,c);const Me=Vi(p,o);let Ee=null;const Pe=ie.trim();if(Pe)try{const ze=atob(Pe.replace(/\s+/g,"")).length,Oe=Number.isFinite(de)&&(de??0)>0?Number(de):16e3;Ee=ze/2/Oe*1e3}catch{Ee=null}o=Math.max(Me,Ee!=null?o+Ee:o)},x=p=>{if(U(p))return;const B=Ur(p);B&&(ue(),v());const ie=String(p.spoken_text??p.text??"").trim(),de=p.visemes??[],Me=p.words??[],Ee=String(p.chunk??"").trim(),Pe=Q||B||!le;Q&&(Q=!1),Pe&&(le=!0),ie&&(d=ie),y(p,B),Pe?(M.resetForNewStream(c),i.length=0,s.length=0,o=0):B&&M.resumeBotStream(),ee(de,Me,Ee,p.sample_rate);const ze=n.length;M.playAudioChunk(n,r,Ee,de,Me,B,{sampleRate:p.sample_rate,newStream:Pe,audioOffsetMs:Number(p.audio_offset_ms??0),onNewStream:()=>{u.length=0}}).then(()=>{K(p,ie,ze,de),ae("audio_chunk",ie),we()})},J=p=>{if(U(p))return;(p.is_new_segment||Number(p.audio_offset_ms??-1)===0)&&v(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const B=String(p.spoken_text??p.text??"").trim();B&&(d=B),y(p,!!p.is_new_segment),ee(p.visemes??[],p.words??[],"",void 0);const ie=n.length;M.queueTimingsOnly(n,r,p.visemes??[],p.words??[],!!p.is_new_segment,{audioOffsetMs:Number(p.audio_offset_ms??0)}),K(p,B,ie,p.visemes??[]),ae("lipsync",B),se()},ne=async p=>{const B=String(p.text??"").trim();if(!B)return;const ie=m.authToken?.trim();if(!ie){console.error("[realtimeVoice] avatar_speak requires authToken");return}P?.abort();const de=new AbortController;P=de;const Me=++z;v(),M.resetForNewStream(c),d=B;const Pe=`${(m.apiBase??Ct).replace(/\/$/,"")}/avatar_ttsWithPoses`,ze=it(c,m.voiceId);ze.ttsEngineId&&(c=ze.ttsEngineId,M.setStreamTtsEngineId(c));const Oe=ze.voiceId?.trim()||(c===at?fn:lr),jt=m.speakingRate??Ht,Sn=Math.max(yn,Math.min(vn,jt)),Bt={user_query:B,ttsEngineId:c,speakingRate:Sn,tenant:"aiTwin"};Un.has(c)&&(Bt.voice_id=Oe);const _t=mn(m.language);_t&&(Bt.language=_t);try{const Ne=await fetch(Pe,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${ie}`},body:JSON.stringify(Bt),signal:de.signal});if(!Ne.ok)throw new Error(`avatar_ttsWithPoses failed (${Ne.status})`);const Ge=Ne.body;if(!Ge)throw new Error("No response body");const bt=Ge.getReader(),xe=new TextDecoder;let Re="",qe=!0;const Ue=async Ve=>{if(Me!==z||de.signal.aborted||!D)return;const Ie=Ei(Ve);if(Ie){if(Ie.event==="audio"){const De=Ie.data.chunk,He=Ie.data.visemes??[],et=Ie.data.words??[],$e=Ie.data.is_new_segment??!1,We=Ie.data.sample_rate,St=Number(Ie.data.audio_offset_ms??0);if(De){const Tt=qe;qe=!1,await M.playAudioChunk(n,r,De,He,et,$e,{sampleRate:We,newStream:Tt,audioOffsetMs:St})}else(He.length>0||et.length>0)&&M.queueTimingsOnly(n,r,He,et,$e,{audioOffsetMs:St,newStream:qe})}else if(Ie.event==="metadata"){const De=Ie.data.mood;typeof De=="string"&&De.trim()&&(l=De.trim());const He=Ie.data.sentence_emotions;Array.isArray(He)&&(a.length=0,a.push(...Dn(He,l))),se()}else if(Ie.event==="error")throw new Error(String(Ie.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(Me!==z||de.signal.aborted||!D);){const{done:Ve,value:Ie}=await bt.read();Ie&&(Re+=xe.decode(Ie,{stream:!0}));const De=Re.split(`
|
|
3
|
+
`);Z=S.pop()??"";for(const R of S)await Y(R);if(_){Z.trim()&&await Y(Z.trim()),B.markStreamComplete(i),P("bot_stopped",U());break}}}catch(J){if(A!==L)return{displayText:z,spokenText:C,aborted:!0};if(J instanceof DOMException&&J.name==="AbortError")return{displayText:z,spokenText:C,aborted:!0};throw console.error("[avatarTtsLipsync]",J),le(),e("error"),J}return{displayText:z,spokenText:C}};return{setDeveloperToken:H=>{w=H},setTtsEngineId:H=>{T=H},getTtsEngineId:()=>T,speak:async(H,A)=>{const{engineId:q,voiceId:C,speakingRate:z,language:J}=ae(A),ee={user_query:H,ttsEngineId:q,speakingRate:z,tenant:"aiTwin"};Hn.has(q)&&(ee.voice_id=C),J&&(ee.language=J),await oe({requestBody:ee,engineId:q,debugSpokenFallback:H})},speakWithReply:async(H,A)=>{const q=H.trim();if(!q)throw new Error("Message is required");const{engineId:C,voiceId:z,speakingRate:J,language:ee}=ae(A),ne={generateReply:!0,message:q,ttsEngineId:C,speakingRate:J,tenant:"aiTwin",history:A?.history??[]};Hn.has(C)&&(ne.voice_id=z),ee&&(ne.language=ee);const Te=A?.brainId?.trim();Te&&(ne.brainId=Te);const Z=A?.brainUrl?.trim();Z&&(ne.brainUrl=Z);const b=await oe({requestBody:ne,engineId:C,debugSpokenFallback:q,onSpokenText:A?.onSpokenText,onDisplayText:A?.onDisplayText});if(b.aborted)return{spokenText:b.spokenText,displayText:b.displayText};if(!b.spokenText&&!b.displayText)throw new Error("avatar_ttsWithPoses generateReply stream missing spokenText or displayText");return{spokenText:b.spokenText||b.displayText,displayText:b.displayText||b.spokenText}},stop:le,getVisemeQueue:()=>i,getWordQueue:()=>s,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>d,getStreamMood:()=>f,getPlaybackElapsedMs:()=>B.getPlaybackElapsedMs(),isSpeaking:()=>B.isSpeaking(),isWarmingUp:()=>B.isWarmingUp(),releaseWarmupHold:()=>B.releaseWarmupHold(),setLipsyncWarmupHold:(H,A)=>{A&&(N=A),B.setLipsyncWarmupHoldEnabled(H)},getVoiceStream:()=>B.getVoiceStream(),setMuted:H=>{B.setMuted(H)},isMuted:()=>B.isMuted(),setPlaybackSpeed:H=>{B.setPlaybackSpeed(H)},getPlaybackSpeed:()=>B.getPlaybackSpeed(),subscribe:H=>(h.add(H),()=>h.delete(H))}}function Wt(e){if(e==null)return!1;if(typeof e=="object"){const r=e;if(r.type==="permissions"||r.name==="NotAllowedError"||r.name==="PermissionDeniedError")return!0}const n=(e instanceof Error?`${e.name} ${e.message}`:typeof e=="string"?e:String(e)).toLowerCase();return!!(n.includes("notallowederror")||n.includes("permissiondeniederror")||n.includes("permission denied")||n.includes("permissions denied")||n.includes("microphone access denied")||(n.includes("microphone")||n.includes(" mic"))&&(n.includes("denied")||n.includes("blocked")||n.includes("not allowed")||n.includes("permission")))}async function pa(){if(typeof navigator>"u"||!navigator.permissions?.query)return!1;try{return(await navigator.permissions.query({name:"microphone"})).state==="denied"}catch{return!1}}const mr=16e3,hr=16e3;class ga extends Zn.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 wa extends Zn.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,mr,hr)}bufferBotAudio(t,n){}}const ya=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Vr(e){return ya.test(e.trim())}function va(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function Gi(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??Dt,r=new URL(`${va(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const i=st(e.ttsEngineId,e.voiceId),s=i.ttsEngineId;s&&r.searchParams.set("ttsEngineId",s);const o=i.voiceId?.trim();o&&(s&&gi(s)?Vr(o)||r.searchParams.set("voiceId",o):Vr(o)&&r.searchParams.set("voiceId",o));const a=gn(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.brainUrl?.trim();d&&r.searchParams.set("brainUrl",d);const l=e.speakingRate??Kt;r.searchParams.set("speaking_rate",String(Math.max(bn,Math.min(Sn,l)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),e.speakOnlyWhenSpokenTo&&r.searchParams.set("speakOnlyWhenSpokenTo","true");const c=e.avatarName?.trim();return c&&r.searchParams.set("avatarName",c),r.toString()}function Ln(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 _a(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 Wr(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function ba(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function qi(e,t={}){const n=[],r=[],i=[],s=[];let o=0;const a=[],u=[];let d="",l="neutral",c=at,f=!1,w=null,T=null,h={...t},E=0,W=null;const L=new Set,v=[];let k=!1,N=null,B=!0,ie="default";const re=new Set;let P=null,G=0,Q=!1,te=!1,le=null,ae=!1;const oe=()=>{le!=null&&(clearTimeout(le),le=null)},ge=()=>{oe(),le=setTimeout(()=>{le=null,B&&(A.markStreamComplete(n),ee("bot_stopped"))},450)},ce=()=>L.forEach(p=>p());let H=()=>!1;const A=ji({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{ae=!1,te=!1,e("done")},onNotify:ce,shouldHoldForWarmup:()=>H()},c),q=()=>{if(N)return N;const p=new MessageChannel;return p.port1.onmessage=()=>{const D=v.shift();D!==void 0&&$(D),v.length>0?p.port2.postMessage(null):k=!1},N=p,p},C=p=>{v.push(p),!k&&(k=!0,q().port2.postMessage(null))},z=()=>A.getPlaybackElapsedMs(),J=(p,D=d)=>{if(!h.onLipsyncDebug)return;const se=z(),fe=n,_e=_n(i).map(xe=>({viseme:xe.viseme,vtimeMs:xe.vtime}));h.onLipsyncDebug({event:p,spokenText:D,mood:l,playbackAnchorPerf:A.getPlaybackStartPerf(),playbackElapsedMs:se,queueLength:fe.length,activeViseme:jt(fe,se),segments:u.map(xe=>({...xe,visemes:[...xe.visemes]})),fullQueueLength:i.length,compactionSkipped:_e})},ee=(p,D)=>{h.onLipsyncDebug&&(W={event:p,spokenText:D},E===0&&(E=requestAnimationFrame(()=>{E=0;const se=W;W=null,se&&J(se.event,se.spokenText)})))},ne=()=>{B=!0,re.clear(),A.clearAborted()},Te=()=>{const p=ba(w);if(p){ie=`bot-${Date.now()}`,p.interruptedTrackIds={[ie]:!0};try{p.interrupt?.()}catch{}}const D=T;try{D?.interrupt?.()}catch{}},Z=p=>{if(ae&&A.isSpeaking())return!0;const D=p.context_id?.trim();return D&&re.has(D)?!0:B?!1:!(p.type==="avatar_metadata"||Wr(p))},b=p=>{B=!1,ae=!1;const D=p.context_id?.trim();D&&re.add(D),oe(),Q=!1,te=!1,v.length=0,k=!1,P?.abort(),P=null,G+=1,Te(),A.bargeIn(),U(),e("idle"),ee("interrupt"),ce()},U=()=>{n.length=0,r.length=0,i.length=0,s.length=0,o=0,u.length=0,d="",l="neutral",a.length=0},Y=()=>{oe(),te=!1,Q=!1,A.stop(),U(),ee("reset"),ce()},_=()=>{Y(),e("idle"),ce()},g=(p,D)=>{typeof p.mood=="string"&&p.mood.trim()&&(l=p.mood.trim()),Array.isArray(p.sentence_emotions)&&p.sentence_emotions.length>0&&(D&&(a.length=0),a.push(...Ln(p.sentence_emotions,l)))},S=p=>{if(Z({...p,type:"avatar_metadata"}))return;ne(),Q=!0;const D=String(p.spoken_text??p.text??"").trim();D&&(d=D),A.resetForNewStream(c),typeof p.mood=="string"&&p.mood.trim()&&(l=p.mood.trim()),a.length=0,a.push(...Ln(p.sentence_emotions,l)),Array.isArray(p.gestures)&&p.gestures,ee("metadata",D),ce()},R=(p,D,se,fe)=>{if(!h.onLipsyncDebug)return;const _e=n.slice(se),xe=fe.filter(Pe=>String(Pe.symbol??Pe.viseme??"").trim());u.push({spokenText:D,audioOffsetMs:_e[0]?.vtime??0,isNewSegment:!!p.is_new_segment,chunkDurationMs:p.chunk_duration_ms!=null?Number(p.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:_e.map((Pe,$e)=>{const Ue=xe[$e];return{rawSymbol:String(Ue?.symbol??Ue?.viseme??Pe.viseme).trim(),viseme:Pe.viseme,startSec:Number(Ue?.start??0),durationSec:Number(Ue?.duration??0),vtimeMs:Pe.vtime,vdurationMs:Pe.vduration}})})},V=(p,D,se,fe)=>{if(p.length===0&&D.length===0)return;Wi(i,s,p,D,o,c);const _e=Hi(p,o);let xe=null;const Pe=se.trim();if(Pe)try{const $e=atob(Pe.replace(/\s+/g,"")).length,Ue=Number.isFinite(fe)&&(fe??0)>0?Number(fe):16e3;xe=$e/2/Ue*1e3}catch{xe=null}o=Math.max(_e,xe!=null?o+xe:o)},X=p=>{if(Z(p))return;const D=Wr(p);D&&(oe(),ne());const se=String(p.spoken_text??p.text??"").trim(),fe=p.visemes??[],_e=p.words??[],xe=String(p.chunk??"").trim(),Pe=Q||D||!te;Q&&(Q=!1),Pe&&(te=!0),se&&(d=se),g(p,D),Pe?(A.resetForNewStream(c),i.length=0,s.length=0,o=0):D&&A.resumeBotStream(),V(fe,_e,xe,p.sample_rate);const $e=n.length;A.playAudioChunk(n,r,xe,fe,_e,D,{sampleRate:p.sample_rate,newStream:Pe,audioOffsetMs:Number(p.audio_offset_ms??0),onNewStream:()=>{u.length=0}}).then(()=>{R(p,se,$e,fe),ee("audio_chunk",se),ge()})},ue=p=>{if(Z(p))return;(p.is_new_segment||Number(p.audio_offset_ms??-1)===0)&&ne(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const D=String(p.spoken_text??p.text??"").trim();D&&(d=D),g(p,!!p.is_new_segment),V(p.visemes??[],p.words??[],"",void 0);const se=n.length;A.queueTimingsOnly(n,r,p.visemes??[],p.words??[],!!p.is_new_segment,{audioOffsetMs:Number(p.audio_offset_ms??0)}),R(p,D,se,p.visemes??[]),ee("lipsync",D),ce()},I=async p=>{const D=String(p.text??"").trim();if(!D)return;const se=h.authToken?.trim();if(!se){console.error("[realtimeVoice] avatar_speak requires authToken");return}P?.abort();const fe=new AbortController;P=fe;const _e=++G;ne(),A.resetForNewStream(c),d=D;const Pe=`${(h.apiBase??Dt).replace(/\/$/,"")}/avatar_ttsWithPoses`,$e=st(c,h.voiceId);$e.ttsEngineId&&(c=$e.ttsEngineId,A.setStreamTtsEngineId(c));const Ue=$e.voiceId?.trim()||(c===ot?pn:fr),Gt=h.speakingRate??Kt,En=Math.max(bn,Math.min(Sn,Gt)),Lt={user_query:D,ttsEngineId:c,speakingRate:En,tenant:"aiTwin"};Hn.has(c)&&(Lt.voice_id=Ue);const bt=gn(h.language);bt&&(Lt.language=bt);try{const Ne=await fetch(Pe,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${se}`},body:JSON.stringify(Lt),signal:fe.signal});if(!Ne.ok)throw new Error(`avatar_ttsWithPoses failed (${Ne.status})`);const qe=Ne.body;if(!qe)throw new Error("No response body");const St=qe.getReader(),Ie=new TextDecoder;let Ce="",Ye=!0;const Ve=async We=>{if(_e!==G||fe.signal.aborted||!B)return;const Ae=Ii(We);if(Ae){if(Ae.event==="audio"){const Be=Ae.data.chunk,ze=Ae.data.visemes??[],tt=Ae.data.words??[],je=Ae.data.is_new_segment??!1,He=Ae.data.sample_rate,Tt=Number(Ae.data.audio_offset_ms??0);if(Be){const kt=Ye;Ye=!1,await A.playAudioChunk(n,r,Be,ze,tt,je,{sampleRate:He,newStream:kt,audioOffsetMs:Tt})}else(ze.length>0||tt.length>0)&&A.queueTimingsOnly(n,r,ze,tt,je,{audioOffsetMs:Tt,newStream:Ye})}else if(Ae.event==="metadata"){const Be=Ae.data.mood;typeof Be=="string"&&Be.trim()&&(l=Be.trim());const ze=Ae.data.sentence_emotions;Array.isArray(ze)&&(a.length=0,a.push(...Ln(ze,l))),ce()}else if(Ae.event==="error")throw new Error(String(Ae.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(_e!==G||fe.signal.aborted||!B);){const{done:We,value:Ae}=await St.read();Ae&&(Ce+=Ie.decode(Ae,{stream:!0}));const Be=Ce.split(`
|
|
4
4
|
|
|
5
|
-
`);Re=De.pop()??"";for(const He of De)await Ue(He);if(Ve){Re.trim()&&await Ue(Re.trim()),Me===z&&!de.signal.aborted&&D&&M.markStreamComplete(n);break}}}catch(Ne){if(de.signal.aborted||!D)return;console.error("[realtimeVoice] avatar_speak failed:",Ne),e("error"),se()}finally{P===de&&(P=null)}},te=p=>{const B=ya(p);if(!B){console.warn("[realtimeVoice] server message with no payload",p);return}const ie=String(B.type??"unknown");switch(ie!=="avatar_metadata"&&ie!=="avatar_audio_chunk"&&ie!=="avatar_lipsync"&&ie!=="avatar_interrupt"&&ie!=="error"&&console.debug("[realtimeVoice] server message",ie,B),ie){case"avatar_metadata":S(B);break;case"avatar_audio_chunk":x(B);break;case"avatar_lipsync":J(B);break;case"avatar_interrupt":Y(B);break;case"error":{const de=String(B.message??"Voice session error");console.error("[realtimeVoice] server error:",de),e("error"),se();break}case"avatar_speak":ne(B);break}},Se=()=>g||(T=new pa,g=new gs.PipecatClient({transport:new Qn.WebSocketTransport({mediaManager:T,serializer:new ha,recorderSampleRate:ur,playerSampleRate:dr}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{f=!0,e("idle"),se()},onDisconnected:()=>{f=!1,_()},onError:p=>{const B=typeof p=="object"&&p!==null&&"data"in p?String(p.data??p):String(p);console.error("[realtimeVoice]",B,p),e("error"),se()},onTransportStateChanged:p=>{p==="error"&&(e("error"),se())},onServerMessage:p=>{R(p)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{v(),ae("bot_started")},onBotStoppedSpeaking:()=>{D&&we()},onUserTranscript:p=>{String(p.text??""),m.onUserTranscript?.(p.text,!!p.final)},onBotOutput:p=>{m.onBotOutput?.(p.text)}}}),g);return{setDeveloperToken:p=>{},setTtsEngineId:p=>{c=p,M.setStreamTtsEngineId(p)},getTtsEngineId:()=>c,speak:async(p,B)=>{const ie=p.trim();if(ie){if(!g||!f)throw new Error("Realtime voice is not connected. Call connect() first.");Z(),await g.sendText(ie)}},speakWithReply:async(p,B)=>{throw new Error("speakWithReply is not available on the voice session; use AiTwin.speakWithReply()")},stop:()=>{P?.abort(),P=null,z+=1,v(),Z(),e("idle"),se()},connect:async p=>{p&&(m={...m,...p});const B=it(m.ttsEngineId,m.voiceId);if(B.ttsEngineId&&(c=B.ttsEngineId,M.setStreamTtsEngineId(c)),m={...m,ttsEngineId:c,...B.voiceId?{voiceId:B.voiceId}:{}},!m.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const ie=Se();await ie.initDevices();const de=ji({...m,ttsEngineId:c});console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",de);try{await ie.connect({wsUrl:de})}catch(Me){f=!1,e("error"),se();const Ee=Me instanceof Error?Me.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${Ee} — ${de}`)}f=!0,e("idle"),se()},disconnect:async()=>{if(ue(),Q=!1,le=!1,b.length=0,E=!1,P?.abort(),P=null,z+=1,v(),g)try{await g.disconnect()}catch(p){console.error("[realtimeVoice] disconnect failed:",p)}f=!1,_()},isConnected:()=>f,unlockAudio:async()=>{await M.primeAudioContext()},getVisemeQueue:()=>n,getWordQueue:()=>r,getFullVisemeQueue:()=>i,getFullWordQueue:()=>s,getSentenceEmotions:()=>a,getStreamMood:()=>l,getPlaybackElapsedMs:H,isSpeaking:()=>M.isSpeaking(),isWarmingUp:()=>M.isWarmingUp(),releaseWarmupHold:()=>M.releaseWarmupHold(),setLipsyncWarmupHold:(p,B)=>{B&&(W=B),M.setLipsyncWarmupHoldEnabled(p)},getVoiceStream:()=>M.getVoiceStream(),setPlaybackSpeed:p=>{M.setPlaybackSpeed(p)},getPlaybackSpeed:()=>M.getPlaybackSpeed(),subscribe:p=>(O.add(p),()=>O.delete(p))}}function Gi(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function qi(e,t){const n=e.crop;return{x:t?.source_x??n?.x??0,y:t?.source_y??n?.y??0,width:t?.source_w??n?.width??e.frame_width??0,height:t?.source_h??n?.height??e.frame_height??0}}function Yi(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function Dt(e,t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const r=await n.arrayBuffer();return Us(r,t)}async function Qi(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await Dt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function _a(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function ba(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted image"))},s.src=n})}async function Sa(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function Ta(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted PNG"))},s.src=n})}function ka(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Ea(e){const t=Ws();if(!Wt())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await Dt(t,e);return ka(n)}function It(e,t){return`${e}/${t}_minus_sil.png`}const Xi=5;function _n(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const n=e?.crop?.content_threshold;return typeof n=="number"&&n>0?n:Xi}const xa=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Kn=["t01_0.25","t02_0.50","t03_0.75"],Ia=Kn.length,Vr=new Set(["aa__kk","aa__nn","aa__sil","CH__aa","CH__DD","CH__E","CH__FF","CH__I","CH__kk","CH__nn","CH__O","CH__PP","CH__RR","CH__sil","CH__SS","CH__TH","CH__U","DD__aa","DD__E","DD__FF","DD__I","DD__kk","DD__nn","DD__O","DD__PP","DD__RR","DD__sil","DD__SS","DD__TH","DD__U","E__aa","E__FF","E__I","E__kk","E__nn","E__O","E__PP","E__RR","E__sil","E__SS","E__TH","E__U","FF__aa","FF__I","FF__kk","FF__nn","FF__O","FF__PP","FF__RR","FF__sil","FF__SS","FF__TH","FF__U","I__aa","I__kk","I__nn","I__O","I__PP","I__RR","I__sil","I__SS","I__TH","I__U","kk__nn","kk__sil","nn__sil","O__aa","O__kk","O__nn","O__PP","O__RR","O__sil","O__SS","O__TH","O__U","PP__aa","PP__kk","PP__nn","PP__RR","PP__sil","PP__SS","PP__TH","PP__U","RR__aa","RR__kk","RR__nn","RR__sil","RR__SS","RR__TH","RR__U","SS__aa","SS__kk","SS__nn","SS__sil","SS__TH","SS__U","TH__aa","TH__kk","TH__nn","TH__sil","TH__U","U__aa","U__kk","U__nn","U__sil"]);function Wr(e,t){return`${e}__${t}`}function zr(e,t){return`pairs/${e}/${t}_minus_sil.png`}function Mt(e){return`${e}_minus_sil.png`}function fr(e,t){if(t.has(e))return e;const n=/^pairs\/([^/]+)\//.exec(e);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const i=Mt(r);return t.has(i)?i:null}function Ji(e,t){return e.filter(n=>t.has(n))}function Aa(e,t,n){const r=mr(e,t);return Ji(r,n).length>0}function mr(e,t){if(e===t)return[];const n=[],r=Wr(e,t);if(Vr.has(r)){for(const s of Kn)n.push(zr(r,s));return n}const i=Wr(t,e);if(Vr.has(i)){for(let s=Ia-1;s>=0;s--)n.push(zr(i,Kn[s]));return n}return[]}function Ma(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function Pa(e,t){return Ma(t).map(r=>e[r]).filter(r=>r!=null)}function Ra(e,t,n,r){if(r<=0)return 0;const s=Math.max(1,n-t)/r,o=e-t,a=Math.floor(o/s);return Math.min(r-1,Math.max(0,a))}function Zi(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,i=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${i}.bin`}const Ca=[.32,.24,.16,.08,0],Da=Ca.map(e=>`eyes_${e.toFixed(2)}`),Ba=["eyes_0.32","eyes_0.16","eyes_0.00"],Fa=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Ke=2,La=-20,on=16,es={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Ut(e){return`brow_${e}`}function gt(e){return es[e]}function Ze(e){return Math.max(La,Math.min(on,e))}function Na(e,t){if(e===t)return[];const n=e<t,r=n?Ke:-Ke,i=[];let s=e;if(s%Ke!==0){const o=n?Math.ceil(s/Ke)*Ke:Math.floor(s/Ke)*Ke,a=Ze(o);if(n?a>=t:a<=t)return[t];s=a,i.push(s)}for(;;){const o=s+r;if(n?o>=t:o<=t){t!==s&&i.push(t);break}s=o,i.push(s)}return i}function Hr(e){const t=Ze(e);if(t%Ke===0)return[t];const n=Math.floor(t/Ke)*Ke,r=Math.min(on,n+Ke),i=Ze(n);return t-i<=r-t?i===r?[i]:[i,r]:i===r?[r]:[r,i]}const Oa=["fear","anger","sad","neutral","love","happy","disgust"],Ua={fear:"fear",afraid:"fear",anxiety:"fear",anger:"anger",angry:"anger",mad:"anger",sad:"sad",sadness:"sad",sorrow:"sad",neutral:"neutral",calm:"neutral",love:"love",loving:"love",affection:"love",happy:"happy",happiness:"happy",joy:"happy",joyful:"happy",excited:"happy",disgust:"disgust",disgusted:"disgust"};function rt(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?Ua[n]??t:t}function ts(e){return e===0?null:It(Ut(e),"eyes_standard")}function ns(e){return ts(gt(e))}const Va={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function hr(e,t){if(!e)return null;if(t(e))return e;const n=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const i=Number(n[1]),s=n[2];for(const a of Hr(i)){if(a===i)continue;const u=It(Ut(a),s);if(t(u))return u}const o=Va[i];if(o){const a=It(o,s);if(t(a))return a}return null}const r=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const i=r[1],s=r[2],o=gt(i);for(const a of[o,...Hr(o)]){const u=It(Ut(a),s);if(t(u))return u}}return null}function $r(e,t){const n=Ut(gt(e));return!t||t==="eyes_standard"?ns(e):e==="neutral"&&t==="eyes_standard"?null:It(n,t)}function Wa(e,t){const n=[];for(const r of t)n.push($r(e,r));for(let r=t.length-2;r>=0;r--)n.push($r(e,t[r]));return n.push(ns(e)),n}function za(e){return It(Ut(e),"eyes_standard")}function Ha(e,t){return Na(e,t).map(za)}const $a=6;function ja(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Ka(e){const t=Ze(e);return t>=on?on:Ze(t+$a)}function Ga(e,t,n){const r=Ze(n);return ja(t,e)?.emphasis?Ka(r):r}function jr(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const n=Number.parseInt(t[1],10);return Number.isFinite(n)?Ze(n):null}function Je(e,t){return e+Math.random()*(t-e)}function Kr(){return Je(14,32)}function qa(e){if(e)return{holdMinMs:10,holdMaxMs:18,closedExtraMs:0};const t=Math.random();return t<.18?{holdMinMs:38,holdMaxMs:62,closedExtraMs:Je(40,90)}:t<.42?{holdMinMs:26,holdMaxMs:44,closedExtraMs:Je(12,36)}:t<.82?{holdMinMs:14,holdMaxMs:28,closedExtraMs:Math.random()<.35?Je(8,22):0}:{holdMinMs:10,holdMaxMs:18,closedExtraMs:0}}function Gr(e,t){const n=Je(e.holdMinMs,e.holdMaxMs);return t?n+e.closedExtraMs:n}function Ya(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:i=.18,doubleBlinkGapMinMs:s=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:u=380,minDwellMs:d=550}=e;let l="neutral",c="neutral",f=0,g=0,T=0,m={kind:"idle",nextBlinkAt:performance.now()+t},I=null,L="__eyes_open__|neutral|brow:0";function O(P=l){L=`${I??"__eyes_open__"}|${P}|brow:${g}`}function b(P,z=l){I=P;const Q=jr(P);Q!=null?g=Q:P==null&&(g=0),O(z)}function E(P){return ts(P)}function V(P,z,Q){const le=Ze(z),ce=Ze(Q);if(f=ce,le===ce){b(E(ce));return}const re=[...Ha(le,ce),E(ce)];m={kind:"browBlend",paths:re,index:0,holdUntil:P+Kr(),targetBrow:ce},b(re[0]??null)}function D(P,z){m={kind:"idle",nextBlinkAt:P+Je(n,r)},c=z,b(E(f),z)}function oe(P,z,Q){const le=Q?Ba:Math.random()<a?Da:Fa,ce=qa(Q),re=le.length-1;m={kind:"playing",paths:Wa(z,le),index:0,holdUntil:P+Gr(ce,re===0),after:"idle",blinkEmotion:z,pace:ce,closedFrameIndex:re},c=z,b(m.paths[0]??null,z)}function pe(P){if(m.kind==="browBlend"){for(;P>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=P+Kr();const z=m.paths[m.index]??null;b(z),P>=m.holdUntil&&m.index>=m.paths.length-1&&(g=m.targetBrow,f=m.targetBrow,b(E(m.targetBrow)),m={kind:"idle",nextBlinkAt:P+u});return}if(m.kind==="idle"){b(E(f),c),P>=m.nextBlinkAt&&oe(P,c,!1);return}if(m.kind==="doublePause"){b(E(f),m.blinkEmotion),P>=m.resumeAt&&oe(P,m.blinkEmotion,!0);return}if(m.kind==="playing"){for(;P>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=P+Gr(m.pace,m.index===m.closedFrameIndex);if(b(m.paths[m.index]??null,m.blinkEmotion),P>=m.holdUntil&&m.index>=m.paths.length-1){if(m.after==="resumeIdle"){D(P+u,l);return}if(m.after==="doublePause"){m={kind:"doublePause",resumeAt:P+Je(s,o),blinkEmotion:m.blinkEmotion},b(E(f),m.blinkEmotion);return}if(m.after==="idle"&&Math.random()<i){m={kind:"doublePause",resumeAt:P+Je(s,o),blinkEmotion:m.blinkEmotion},b(E(f),m.blinkEmotion);return}D(P,m.blinkEmotion)}}}return{advance:pe,setTargetEmotion(P,z){const Q=rt(P,l);if(Q===l)return;const le=performance.now();!z?.force&&d>0&&!(l==="neutral"&&Q!=="neutral")&&le-T<d||(l=Q,c=Q,T=le)},setTargetEyebrow(P){const z=Ze(P);if(z===f)return;const Q=performance.now(),le=m.kind==="browBlend"?jr(I)??g:g;f=z,!(z===le&&m.kind!=="browBlend")&&(m.kind==="playing"||m.kind==="doublePause"||V(Q,le,z))},snapToEmotion(P){const z=rt(P),Q=gt(z);l=z,c=z,f=Q,g=Q,T=performance.now(),m={kind:"idle",nextBlinkAt:performance.now()+Je(4e3,7e3)},b(E(Q),z)},getTargetEmotion:()=>l,getTargetEyebrow:()=>f,getExpressionPath:()=>I,getDrawKey:()=>L,reset(){l="neutral",c="neutral",f=0,g=0,T=0,D(performance.now()+Je(n,r),"neutral")}}}function Qa(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const i=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(s){t&&r===s||(i(),t=!1,r=s,s.startsWith("blob:")&&(n=s),await new Promise((o,a)=>{const u=()=>{const d=e.duration;if(!Number.isFinite(d)||d<=0){a(new Error(`Idle video has invalid duration: ${s}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",u,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${s}`)),{once:!0}),e.src=s,e.load()}))},isReady(){return t},getVideo(){return e},setActive(s){t&&(s?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},setLooping(s){e.loop=s},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),i(),t=!1,r=""}}}const Xa=50,rs=400;function Ja(e,t,n){return e.filter(r=>{const i=r.queueIndex??-1;return i>=t&&i<=n})}function Za(e,t){const n=[];for(const r of e){const i=Ja(t,r.start_word,r.end_word);if(i.length===0)continue;const s=i[0],o=i[i.length-1];n.push({sentence:r,startMs:Math.max(0,s.wtime-Xa),endMs:o.wtime+o.wduration+rs})}return n.sort((r,i)=>r.startMs-i.startMs)}function eo(e,t,n,r="neutral"){const i=rt(r);if(t.length===0)return i;if(n.length===0||e<n[0].wtime)return rt(t[0]?.emotion,i);const s=Za(t,n);let o=null;for(const d of s)e>=d.startMs&&e<=d.endMs&&(o=d);if(o)return rt(o.sentence.emotion,i);const a=n[n.length-1],u=a.wtime+a.wduration;return e>u+rs?rt(t[t.length-1]?.emotion,i):i}function pr(e,t,n,r,i=Xi){const s=new OffscreenCanvas(n,r),o=s.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const a=o.getImageData(0,0,n,r),u=o.createImageData(n,r);u.data.set(a.data);const l=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const c of t){l.clearRect(0,0,n,r),l.drawImage(c,0,0,n,r);const f=l.getImageData(0,0,n,r);for(let g=0;g<u.data.length;g+=4){const T=f.data[g],m=f.data[g+1],I=f.data[g+2];f.data[g+3]>0&&Math.max(T,m,I)>i&&(u.data[g]=T,u.data[g+1]=m,u.data[g+2]=I,u.data[g+3]=255)}}return o.putImageData(u,0,0),s}let mt=null,Pt=null;const cn=new Map;function to(){mt=null,Pt=null,cn.clear()}vi(to);function no(e){return e??Pt??void 0}function gr(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function ro(e){return Wt()?Ta(await Dt(an(),e??"")):gr(an())}async function qr(e,t,n,r){const i=n?await Qi(e,r):await fetch(e).then(d=>{if(!d.ok)throw new Error(`Failed to load ${e}`);return d.json()}),s=i.sheets?.[0];if(!s?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await ba(await Dt(Zi(t,s.path,n),r??"")):await gr(`${t}/${s.path}`),a=new Map;for(const d of i.cells??[])d.path&&a.set(d.path,d);const u=new Map;for(const d of i.sheets??[])u.set(d.index,d);return{atlas:o,atlasMeta:i,cellByPath:a,sheetByIndex:u,diffBase:t}}async function Gn(e){const t=no(e),n=Wt();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(mt&&(!n||Pt===(t??null))){const s=await mt;return{...Rt(s),visemePaths:[...s.viseme.cellByPath.keys()]}}Pt=t??null,cn.clear();const r=_i();mt=(async()=>{const s=await ro(t),o=await qr(bi(),r,n,t);let a=null;try{a=await qr(Si(),r,n,t)}catch{a=null}return{sil:s,viseme:o,expression:a}})();const i=await mt;return{...Rt(i),visemePaths:[...i.viseme.cellByPath.keys()]}}async function wr(e){if(await Gn(e),!mt)throw new Error("Assets not loaded");return mt}function Rt(e){return Gi(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function io(e,t){const n=document.createElement("canvas");return n.width=t.w,n.height=t.h,n.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}async function ln(e,t,n){const r=`${t.diffBase}::${n}`,i=cn.get(r);if(i)return i;const s=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const a=qi(t.atlasMeta,o),u=Rt(e);if(Yi(o)){const c=io(t,o),f=document.createElement("canvas");f.width=u.width,f.height=u.height;const g=f.getContext("2d");return g.fillStyle="#000",g.fillRect(0,0,u.width,u.height),g.drawImage(c,a.x,a.y),f}const d=`${t.diffBase}/${n}`,l=await gr(d);if(l.naturalWidth===u.width&&l.naturalHeight===u.height)return l;throw new Error(`Diff PNG wrong size for ${n}`)})();return cn.set(r,s),s}async function Bn(e,t,n,r,i,s){if(i){const{width:g,height:T}=i;if(s&&!s()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const m=document.createElement("canvas");m.width=g,m.height=T;const I=m.getContext("2d");if(I.clearRect(0,0,g,T),I.drawImage(t,0,0,g,T),s&&!s())return;(e.width!==g||e.height!==T)&&(e.width=g,e.height=T);const L=e.getContext("2d");L.clearRect(0,0,g,T),L.drawImage(m,0,0);return}const o=await wr(),a=_n(o.viseme.atlasMeta),{width:u,height:d}=Rt(o);(e.width!==u||e.height!==d)&&(e.width=u,e.height=d);const l=[],c=e.getContext("2d");if(c.clearRect(0,0,u,d),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const g=o.sil;c.drawImage(g,0,0,u,d);return}if(l.length===0){c.drawImage(t,0,0,u,d);return}const f=pr(t,l,u,d,a);c.drawImage(f,0,0)}async function qn(e,t,n){const r=await wr(Pt??void 0),i=_n(r.viseme.atlasMeta),{width:s,height:o}=Rt(r);(e.width!==s||e.height!==o)&&(e.width=s,e.height=o);const a=[];if(t.mouthPath){const l=new Set(r.viseme.cellByPath.keys()),c=fr(t.mouthPath,l)??(l.has(t.mouthPath)?t.mouthPath:null);c&&a.push(await ln(r,r.viseme,c))}if(t.expressionPath&&r.expression){const l=hr(t.expressionPath,c=>r.expression.cellByPath.has(c));l&&a.push(await ln(r,r.expression,l))}const u=e.getContext("2d");if(u.clearRect(0,0,s,o),a.length===0){u.drawImage(r.sil,0,0,s,o);return}const d=pr(r.sil,a,s,o,i);u.drawImage(d,0,0)}async function so(e,t){const n=await wr(Pt??void 0),r=_n(n.viseme.atlasMeta),{width:i,height:s}=Rt(n),o=[];if(e.mouthPath){const l=new Set(n.viseme.cellByPath.keys()),c=fr(e.mouthPath,l)??(l.has(e.mouthPath)?e.mouthPath:null);c&&o.push(await ln(n,n.viseme,c))}if(e.expressionPath&&n.expression){const l=hr(e.expressionPath,c=>n.expression.cellByPath.has(c));l&&o.push(await ln(n,n.expression,l))}const a=new OffscreenCanvas(i,s),u=a.getContext("2d");if(o.length===0)return u.drawImage(n.sil,0,0,i,s),a.transferToImageBitmap();const d=pr(n.sil,o,i,s,r);return u.drawImage(d,0,0),a.transferToImageBitmap()}async function ao(e){await qn(e,{mouthPath:null,expressionPath:null})}const en={fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"clamp(0.875rem, 2.5vw, 1.125rem)",color:"rgba(255,255,255,0.85)"};function oo(e){return e.length===0?"":e.map(t=>t.word).join(" ")}function co(e){if(!e)return{enabled:!1,style:en};const t=e===!0?{}:e;return{enabled:!0,style:{fontFamily:t.fontFamily??en.fontFamily,fontSize:t.fontSize??en.fontSize,color:t.color??en.color}}}const lo={position:"absolute",bottom:0,left:0,right:0,display:"flex",justifyContent:"center",padding:"0.75rem 1rem",pointerEvents:"none"},uo={display:"inline-block",maxWidth:"100%",padding:"0.45rem 0.85rem",borderRadius:"0.75rem",background:"rgba(0,0,0,0.55)",lineHeight:1.4,textAlign:"center"},fo={display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden",maxWidth:"100%",margin:0};function mo({text:e,style:t}){return F.jsx("div",{style:lo,"aria-live":"polite","aria-atomic":"true",children:F.jsx("div",{style:{...uo,fontFamily:t.fontFamily,fontSize:t.fontSize,color:t.color},children:F.jsx("p",{style:fo,children:e})})})}const ho={inset:0,overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:3},po={filter:"blur(22px)",height:"100%",inset:0,objectFit:"cover",objectPosition:"top",position:"absolute",transform:"scale(1.08)",width:"100%"},go={backdropFilter:"blur(10px)",WebkitBackdropFilter:"blur(10px)",inset:0,position:"absolute"};function wo({thumbnailUrl:e}){const[t,n]=h.useState(!1);h.useEffect(()=>{n(!1)},[e]);const r=!!e&&t;return F.jsxs("div",{style:ho,"aria-hidden":!0,children:[e?F.jsx("img",{src:e,alt:"",style:{...po,opacity:r?1:0,transition:"opacity 0.45s ease"},onLoad:()=>n(!0),onError:()=>n(!1)}):null,F.jsx("div",{style:{...go,background:r?"rgba(0, 0, 0, 0.28)":"rgba(10, 10, 11, 0.92)"}})]})}let is=null;function Yr(e){is=e}function lt(){return is}function yo(e){return`${e.from}→${e.to}@${e.fromVtime}`}function Qr(){return{rafTicksSpeaking:0,rafTicksDeduped:0,drawsRequested:0,drawsDisplayed:0,queueSuperseded:0,workerStale:0,rifeFramesOmittedByGap:0,transitionFramesSampled:0,transitionFramesDisplayed:0,transitionFramesMissed:0,bufferTicks:0,bufferHits:0,bufferUnderruns:0,bufferPrefetched:0}}function vo(){let e=Qr();const t=new Set,n=new Set,r=new Set;let i="",s=-1,o="";const a=()=>{e=Qr(),t.clear(),n.clear(),r.clear(),i="",s=-1,o=""},u=l=>{t.add(l)},d=l=>{l&&r.add(l)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(l,c){const f=yo(l);e.transitionFramesSampled+=1,f!==i&&(i=f,s=-1,o!==f&&(o=f,e.rifeFramesOmittedByGap+=l.omittedByGap)),c&&n.add(c),s>=0&&l.frameIdx>s+1&&(e.transitionFramesMissed+=l.frameIdx-s-1),s=l.frameIdx},onBufferTick(){e.bufferTicks+=1},onBufferHit(){e.bufferHits+=1},onBufferUnderrun(){e.bufferUnderruns+=1},onBufferPrefetched(){e.bufferPrefetched+=1},onBufferReset(){},onDrawDisplayed(l,c){if(e.drawsDisplayed+=1,l.transitionMeta){e.transitionFramesDisplayed+=1;const g=l.transitionMeta;u(g.fromVtime),u(g.toVtime),d(l.mouthPath);return}if(l.label.includes("→")){e.transitionFramesDisplayed+=1;return}const f=l.label.trim();if(!(!f||f==="sil")){for(const g of c)if(g.viseme===f&&l.elapsedMs>=g.vtime&&l.elapsedMs<g.vtime+g.vduration){u(g.vtime);break}}},snapshot(l,c){let f=0,g=0;for(const O of l)if(O.viseme!=="sil"){if(O.vtime>=c)break;f+=1,t.has(O.vtime)&&(g+=1)}const T=f>0?Math.round(g/f*100):100,m=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),I=f-g,L=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:L,renderLoss:m,visemeSlotsTotal:f,visemeSlotsCovered:g,visemeCoveragePct:T,transitionFramesUniqueSampled:n.size,transitionFramesUniquePainted:r.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+m,visemesShown:g,visemesSkipped:I,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const ss=Jn,_o=500,Xr=500,bo=450,Fn=.05,So=100,To=600,as="__sil__";function Jr(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===as:!1}function yr(){return{lastDrawnKey:""}}function Le(e){e.lastDrawnKey="",e.transitionCache=void 0}function ko(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=Ni(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Eo(e,t){let n="sil";for(const r of e)r.viseme!=="sil"&&(t!=null&&r.vtime>t||(n=r.viseme));return n}function xo(e,t,n,r=120){if(n!=="sil")return n;const i=$i(e,t,r);return i!=="sil"?i:Eo(e,t)}function Io(e,t){return e==="sil"?!1:t?Aa(e,"sil",t):mr(e,"sil").length>0}function Ao(){return ss+To}function un(e){return e??as}function vr(e,t,n,r,i=So){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=ft(e))return{diffPath:null,label:"sil"};const s=r?.holdPp===!0,o=ko(e,r),a=ca(o,t,s);if(a){const l=Oi(a.fromVtime,a.toVtime,a.from,a.to,s);if(t>=l.transStart&&t<l.transEnd){let c=mr(a.from,a.to);n&&(c=Ji(c,n));const f=Pa(c,l.effectiveGapMs);if(f.length>0){const g=Ra(t,l.transStart,l.transEnd,f.length);return{diffPath:f[g]??f[f.length-1],label:`${a.from}→${a.to}`,transitionMeta:{from:a.from,to:a.to,fromVtime:a.fromVtime,toVtime:a.toVtime,frameIdx:g,frameCount:f.length,fullFrameCount:c.length,omittedByGap:Math.max(0,c.length-f.length)}}}return{diffPath:Mt(a.to),label:a.to}}}const u=gn(e);let d=Di(u,t);return d==="sil"&&(d=$i(e,t,i)),d==="sil"?{diffPath:null,label:"sil"}:{diffPath:Mt(d),label:d}}function Vt(e,t){const n=t??un(e.expressionPath);return`${un(e.mouthPath)}|${n}`}function Zr(e,t,n,r,i,s,o,a,u,d){const l=vr(t,n,u,s),c={mouthPath:l.diffPath,expressionPath:r},f=Vt(c,i),g=lt();if(l.transitionMeta&&g?.onTransitionSample(l.transitionMeta,l.diffPath),f===s.lastDrawnKey){g?.onDrawDeduped();return}g?.onDrawRequested(),a(l),s.lastDrawnKey=f,o(e,c,f,T=>{T===f&&(s.lastDrawnKey=f)})}function Ln(e,t,n,r,i,s,o=null,a=null){const u={mouthPath:a,expressionPath:t},d=o!=null?`|idle@${Math.round(o*1e3)}`:"",l=Vt(u,n)+d;!(o!=null)&&l===r.lastDrawnKey||(s(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),i(e,u,l,f=>{f===l&&(r.lastDrawnKey=l)}))}function os(e,t,n,r,i=Ot,s){if(n<=t||e.length===0)return[];const o=s??yr(),a=[];let u="";for(let d=t;d<n;d+=i){const l=vr(e,d,r,o),c=un(l.diffPath);c!==u&&(u=c,a.push({displayAtMs:d,mouthPath:l.diffPath,mouthKey:c,label:l.label}))}return a}const Mo=3;function _r(e){let t=0;const n=[];let r=!1,i=!1;const s=async()=>{if(!r){r=!0;try{for(;n.length>0;){const a=n.shift(),u=++t;await e(a.diffs,u,a)&&u===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n.length>0&&s()}}},o=()=>{i||(i=!0,queueMicrotask(()=>{i=!1,s()}))};return{enqueue(a,u,d){const l=n.findIndex(c=>c.drawKey===u);l>=0?n[l]={diffs:a,drawKey:u,onDisplayed:d}:(n.length>=Mo&&(n.shift(),lt()?.onQueueSuperseded()),n.push({diffs:a,drawKey:u,onDisplayed:d})),o()},reset(){t+=1,n.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function Po(e,t=2){const n=[],r=new Set;let i=0,s=!1,o=0;const a=(d,l)=>`${d}|${l}`,u=async()=>{if(!s){s=!0;try{for(;i<t&&n.length>0;){const d=n.shift(),l=a(d.displayAtMs,d.drawKey);if(r.has(l))continue;r.add(l),i+=1;const c=o;try{await e(d)}finally{if(r.delete(l),i-=1,c!==o)return}}}finally{s=!1,n.length>0&&i<t&&u()}}};return{enqueue(d){const l=a(d.displayAtMs,d.drawKey);r.has(l)||n.some(c=>a(c.displayAtMs,c.drawKey)===l)||(n.push(d),u())},isQueuedOrInflight(d,l){const c=a(d,l);return r.has(c)?!0:n.some(f=>a(f.displayAtMs,f.drawKey)===c)},reset(){o+=1,n.length=0,r.clear(),i=0},pendingCount(){return n.length+i}}}function Ro(){const e=new Map,t=n=>{n.bitmap.close()};return{has(n,r){return e.has(r)},markRendered(n,r,i,s,o){const a=e.get(r);a&&t(a),e.set(r,{displayAtMs:n,mouthKey:r,label:i,mouthPath:s,bitmap:o})},findForMouthKey(n){return e.get(n)??null},removeThrough(n){},pruneBefore(n){},reset(){for(const n of e.values())t(n);e.clear()},size(){return e.size}}}function Co(e,t,n,r,i,s){const o=os(t,n,r,i,Ot,s);if(o.length===0)return{ready:0,total:0};let a=0;for(const u of o)e.has(u.displayAtMs,u.mouthKey)&&(a+=1);return{ready:a,total:o.length}}function Do(e){const t=Ro(),n=yr(),r=new Set;let i="",s=null;const o=Po(async c=>{try{if(!e.supportsBufferedPlayback)return;const f=await e.compositePrefetchFrame(c.diffs,c.mouthKey);if(!f)return;t.markRendered(c.displayAtMs,c.mouthKey,c.label,c.mouthPath,f),lt()?.onBufferPrefetched()}finally{r.delete(c.mouthKey)}},xs),a=c=>{for(const f of c)t.has(f.displayAtMs,f.mouthKey)||r.has(f.mouthKey)||o.isQueuedOrInflight(0,f.mouthKey)||(r.add(f.mouthKey),o.enqueue({...f,displayAtMs:0,drawKey:f.mouthKey,diffs:{mouthPath:f.mouthPath,expressionPath:null}}))},u=(c,f,g,T=Cn)=>{if(!e.supportsBufferedPlayback)return;const m=Math.max(0,f-Ot*4),I=os(c,m,f+T,g,Ot,n);a(I)},d=(c,f)=>{i=c,s=f},l=(c,f)=>!(i!==c||s!==f);return{reset(){t.reset(),o.reset(),r.clear(),Le(n),i="",s=null,lt()?.onBufferReset()},setHoldPp(c){n.holdPp=c},markExternallyDisplayed(c,f){d(c.split("|")[0]??c,f)},warmupTick(c){e.supportsBufferedPlayback&&u(c.queue,0,c.availablePaths,Math.max(Cr,Cn))},isWarmupReady(c,f=Cr){if(!e.supportsBufferedPlayback)return!0;const{ready:g,total:T}=Co(t,c.queue,0,f,c.availablePaths,n);return T===0?!1:g/T>=Es},getBufferedFrameCount:()=>t.size(),tick(c){n.holdPp=c.playbackState.holdPp===!0;const f=lt();f?.onBufferTick(),u(c.queue,c.elapsedMs,c.availablePaths),t.pruneBefore(c.elapsedMs-Cn);const g=vr(c.queue,c.elapsedMs,c.availablePaths,n),T=un(g.diffPath),m=Vt({mouthPath:g.diffPath,expressionPath:c.expressionPath},c.expressionDrawKey),I=()=>(d(T,c.expressionPath),f?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(l(T,c.expressionPath)||c.playbackState.lastDrawnKey===m)return I();const L=t.findForMouthKey(T,c.elapsedMs,Ot);return L&&c.expressionPath!=null?(f?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):L?(e.blitBitmap(c.canvas,L.bitmap),d(L.mouthKey,c.expressionPath),c.playbackState.lastDrawnKey=m,c.onStatus({diffPath:L.mouthPath,label:L.label}),c.onDisplayed(m,L.mouthPath,L.label),f?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(f?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const Bo=`
|
|
5
|
+
`);Ce=Be.pop()??"";for(const ze of Be)await Ve(ze);if(We){Ce.trim()&&await Ve(Ce.trim()),_e===G&&!fe.signal.aborted&&B&&A.markStreamComplete(n);break}}}catch(Ne){if(fe.signal.aborted||!B)return;console.error("[realtimeVoice] avatar_speak failed:",Ne),e("error"),ce()}finally{P===fe&&(P=null)}},$=p=>{const D=_a(p);if(!D){console.warn("[realtimeVoice] server message with no payload",p);return}const se=String(D.type??"unknown");switch(se!=="avatar_metadata"&&se!=="avatar_audio_chunk"&&se!=="avatar_lipsync"&&se!=="avatar_interrupt"&&se!=="error"&&console.debug("[realtimeVoice] server message",se,D),se){case"avatar_metadata":S(D);break;case"avatar_audio_chunk":X(D);break;case"avatar_lipsync":ue(D);break;case"avatar_interrupt":b(D);break;case"error":{const fe=String(D.message??"Voice session error");console.error("[realtimeVoice] server error:",fe),e("error"),ce();break}case"avatar_speak":I(D);break}},de=()=>w||(T=new wa,w=new ws.PipecatClient({transport:new Zn.WebSocketTransport({mediaManager:T,serializer:new ga,recorderSampleRate:mr,playerSampleRate:hr}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{f=!0,e("idle"),ce()},onDisconnected:()=>{f=!1,_()},onError:p=>{const D=typeof p=="object"&&p!==null&&"data"in p?String(p.data??p):String(p);console.error("[realtimeVoice]",D,p),e("error"),ce()},onTransportStateChanged:p=>{p==="error"&&(e("error"),ce())},onServerMessage:p=>{C(p)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{ne(),ee("bot_started")},onBotStoppedSpeaking:()=>{B&&ge()},onUserTranscript:p=>{String(p.text??""),h.onUserTranscript?.(p.text,!!p.final)},onBotOutput:p=>{h.onBotOutput?.(p.text)}}}),w);return{setDeveloperToken:p=>{},setTtsEngineId:p=>{c=p,A.setStreamTtsEngineId(p)},getTtsEngineId:()=>c,speak:async(p,D)=>{const se=p.trim();if(se){if(!w||!f)throw new Error("Realtime voice is not connected. Call connect() first.");Y(),await w.sendText(se)}},speakWithReply:async(p,D)=>{throw new Error("speakWithReply is not available on the voice session; use AiTwin.speakWithReply()")},stop:()=>{P?.abort(),P=null,G+=1,ne(),Y(),e("idle"),ce()},connect:async p=>{p&&(h={...h,...p});const D=st(h.ttsEngineId,h.voiceId);if(D.ttsEngineId&&(c=D.ttsEngineId,A.setStreamTtsEngineId(c)),h={...h,ttsEngineId:c,...D.voiceId?{voiceId:D.voiceId}:{}},!h.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const se=de();try{await se.initDevices()}catch(_e){throw f=!1,e("idle"),ce(),Wt(_e)?new Error("Microphone access denied"):_e instanceof Error?_e:new Error("Failed to initialize microphone")}const fe=Gi({...h,ttsEngineId:c});console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",fe);try{await se.connect({wsUrl:fe})}catch(_e){if(f=!1,e("error"),ce(),Wt(_e))throw e("idle"),new Error("Microphone access denied");const xe=_e instanceof Error?_e.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${xe} — ${fe}`)}f=!0,e("idle"),ce()},disconnect:async()=>{if(oe(),Q=!1,te=!1,v.length=0,k=!1,P?.abort(),P=null,G+=1,ne(),w)try{await w.disconnect()}catch(p){console.error("[realtimeVoice] disconnect failed:",p)}f=!1,_()},isConnected:()=>f,unlockAudio:async()=>{await A.primeAudioContext()},getVisemeQueue:()=>n,getWordQueue:()=>r,getFullVisemeQueue:()=>i,getFullWordQueue:()=>s,getSentenceEmotions:()=>a,getStreamMood:()=>l,getPlaybackElapsedMs:z,isSpeaking:()=>A.isSpeaking(),isWarmingUp:()=>A.isWarmingUp(),releaseWarmupHold:()=>A.releaseWarmupHold(),setLipsyncWarmupHold:(p,D)=>{D&&(H=D),A.setLipsyncWarmupHoldEnabled(p)},getVoiceStream:()=>A.getVoiceStream(),setMuted:p=>{A.setMuted(p)},isMuted:()=>A.isMuted(),setPlaybackSpeed:p=>{A.setPlaybackSpeed(p)},getPlaybackSpeed:()=>A.getPlaybackSpeed(),subscribe:p=>(L.add(p),()=>L.delete(p))}}function Yi(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function Qi(e,t){const n=e.crop;return{x:t?.source_x??n?.x??0,y:t?.source_y??n?.y??0,width:t?.source_w??n?.width??e.frame_width??0,height:t?.source_h??n?.height??e.frame_height??0}}function Xi(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function Bt(e,t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const r=await n.arrayBuffer();return Vs(r,t)}async function Ji(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await Bt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function Sa(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function Ta(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted image"))},s.src=n})}async function ka(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function Ea(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted PNG"))},s.src=n})}function xa(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Ia(e){const t=Hs();if(!zt())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await Bt(t,e);return xa(n)}function At(e,t){return`${e}/${t}_minus_sil.png`}const Zi=5;function Tn(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const n=e?.crop?.content_threshold;return typeof n=="number"&&n>0?n:Zi}const Aa=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Yn=["t01_0.25","t02_0.50","t03_0.75"],Ma=Yn.length,Hr=new Set(["aa__kk","aa__nn","aa__sil","CH__aa","CH__DD","CH__E","CH__FF","CH__I","CH__kk","CH__nn","CH__O","CH__PP","CH__RR","CH__sil","CH__SS","CH__TH","CH__U","DD__aa","DD__E","DD__FF","DD__I","DD__kk","DD__nn","DD__O","DD__PP","DD__RR","DD__sil","DD__SS","DD__TH","DD__U","E__aa","E__FF","E__I","E__kk","E__nn","E__O","E__PP","E__RR","E__sil","E__SS","E__TH","E__U","FF__aa","FF__I","FF__kk","FF__nn","FF__O","FF__PP","FF__RR","FF__sil","FF__SS","FF__TH","FF__U","I__aa","I__kk","I__nn","I__O","I__PP","I__RR","I__sil","I__SS","I__TH","I__U","kk__nn","kk__sil","nn__sil","O__aa","O__kk","O__nn","O__PP","O__RR","O__sil","O__SS","O__TH","O__U","PP__aa","PP__kk","PP__nn","PP__RR","PP__sil","PP__SS","PP__TH","PP__U","RR__aa","RR__kk","RR__nn","RR__sil","RR__SS","RR__TH","RR__U","SS__aa","SS__kk","SS__nn","SS__sil","SS__TH","SS__U","TH__aa","TH__kk","TH__nn","TH__sil","TH__U","U__aa","U__kk","U__nn","U__sil"]);function $r(e,t){return`${e}__${t}`}function zr(e,t){return`pairs/${e}/${t}_minus_sil.png`}function Rt(e){return`${e}_minus_sil.png`}function pr(e,t){if(t.has(e))return e;const n=/^pairs\/([^/]+)\//.exec(e);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const i=Rt(r);return t.has(i)?i:null}function es(e,t){return e.filter(n=>t.has(n))}function Ra(e,t,n){const r=gr(e,t);return es(r,n).length>0}function gr(e,t){if(e===t)return[];const n=[],r=$r(e,t);if(Hr.has(r)){for(const s of Yn)n.push(zr(r,s));return n}const i=$r(t,e);if(Hr.has(i)){for(let s=Ma-1;s>=0;s--)n.push(zr(i,Yn[s]));return n}return[]}function Pa(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function Ca(e,t){return Pa(t).map(r=>e[r]).filter(r=>r!=null)}function Da(e,t,n,r){if(r<=0)return 0;const s=Math.max(1,n-t)/r,o=e-t,a=Math.floor(o/s);return Math.min(r-1,Math.max(0,a))}function ts(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,i=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${i}.bin`}const Ba=[.32,.24,.16,.08,0],Fa=Ba.map(e=>`eyes_${e.toFixed(2)}`),La=["eyes_0.32","eyes_0.16","eyes_0.00"],Oa=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Ge=2,Na=-20,un=16,ns={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Ht(e){return`brow_${e}`}function gt(e){return ns[e]}function et(e){return Math.max(Na,Math.min(un,e))}function Ua(e,t){if(e===t)return[];const n=e<t,r=n?Ge:-Ge,i=[];let s=e;if(s%Ge!==0){const o=n?Math.ceil(s/Ge)*Ge:Math.floor(s/Ge)*Ge,a=et(o);if(n?a>=t:a<=t)return[t];s=a,i.push(s)}for(;;){const o=s+r;if(n?o>=t:o<=t){t!==s&&i.push(t);break}s=o,i.push(s)}return i}function jr(e){const t=et(e);if(t%Ge===0)return[t];const n=Math.floor(t/Ge)*Ge,r=Math.min(un,n+Ge),i=et(n);return t-i<=r-t?i===r?[i]:[i,r]:i===r?[r]:[r,i]}const Va=["fear","anger","sad","neutral","love","happy","disgust"],Wa={fear:"fear",afraid:"fear",anxiety:"fear",anger:"anger",angry:"anger",mad:"anger",sad:"sad",sadness:"sad",sorrow:"sad",neutral:"neutral",calm:"neutral",love:"love",loving:"love",affection:"love",happy:"happy",happiness:"happy",joy:"happy",joyful:"happy",excited:"happy",disgust:"disgust",disgusted:"disgust"};function it(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?Wa[n]??t:t}function rs(e){return e===0?null:At(Ht(e),"eyes_standard")}function is(e){return rs(gt(e))}const Ha={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function wr(e,t){if(!e)return null;if(t(e))return e;const n=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const i=Number(n[1]),s=n[2];for(const a of jr(i)){if(a===i)continue;const u=At(Ht(a),s);if(t(u))return u}const o=Ha[i];if(o){const a=At(o,s);if(t(a))return a}return null}const r=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const i=r[1],s=r[2],o=gt(i);for(const a of[o,...jr(o)]){const u=At(Ht(a),s);if(t(u))return u}}return null}function Kr(e,t){const n=Ht(gt(e));return!t||t==="eyes_standard"?is(e):e==="neutral"&&t==="eyes_standard"?null:At(n,t)}function $a(e,t){const n=[];for(const r of t)n.push(Kr(e,r));for(let r=t.length-2;r>=0;r--)n.push(Kr(e,t[r]));return n.push(is(e)),n}function za(e){return At(Ht(e),"eyes_standard")}function ja(e,t){return Ua(e,t).map(za)}const Ka=6;function Ga(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function qa(e){const t=et(e);return t>=un?un:et(t+Ka)}function Ya(e,t,n){const r=et(n);return Ga(t,e)?.emphasis?qa(r):r}function Gr(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const n=Number.parseInt(t[1],10);return Number.isFinite(n)?et(n):null}function Ze(e,t){return e+Math.random()*(t-e)}function qr(){return Ze(14,32)}function Qa(e){if(e)return{holdMinMs:10,holdMaxMs:18,closedExtraMs:0};const t=Math.random();return t<.18?{holdMinMs:38,holdMaxMs:62,closedExtraMs:Ze(40,90)}:t<.42?{holdMinMs:26,holdMaxMs:44,closedExtraMs:Ze(12,36)}:t<.82?{holdMinMs:14,holdMaxMs:28,closedExtraMs:Math.random()<.35?Ze(8,22):0}:{holdMinMs:10,holdMaxMs:18,closedExtraMs:0}}function Yr(e,t){const n=Ze(e.holdMinMs,e.holdMaxMs);return t?n+e.closedExtraMs:n}function Xa(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:i=.18,doubleBlinkGapMinMs:s=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:u=380,minDwellMs:d=550}=e;let l="neutral",c="neutral",f=0,w=0,T=0,h={kind:"idle",nextBlinkAt:performance.now()+t},E=null,W="__eyes_open__|neutral|brow:0";function L(P=l){W=`${E??"__eyes_open__"}|${P}|brow:${w}`}function v(P,G=l){E=P;const Q=Gr(P);Q!=null?w=Q:P==null&&(w=0),L(G)}function k(P){return rs(P)}function N(P,G,Q){const te=et(G),le=et(Q);if(f=le,te===le){v(k(le));return}const ae=[...ja(te,le),k(le)];h={kind:"browBlend",paths:ae,index:0,holdUntil:P+qr(),targetBrow:le},v(ae[0]??null)}function B(P,G){h={kind:"idle",nextBlinkAt:P+Ze(n,r)},c=G,v(k(f),G)}function ie(P,G,Q){const te=Q?La:Math.random()<a?Fa:Oa,le=Qa(Q),ae=te.length-1;h={kind:"playing",paths:$a(G,te),index:0,holdUntil:P+Yr(le,ae===0),after:"idle",blinkEmotion:G,pace:le,closedFrameIndex:ae},c=G,v(h.paths[0]??null,G)}function re(P){if(h.kind==="browBlend"){for(;P>=h.holdUntil&&h.index<h.paths.length-1;)h.index+=1,h.holdUntil=P+qr();const G=h.paths[h.index]??null;v(G),P>=h.holdUntil&&h.index>=h.paths.length-1&&(w=h.targetBrow,f=h.targetBrow,v(k(h.targetBrow)),h={kind:"idle",nextBlinkAt:P+u});return}if(h.kind==="idle"){v(k(f),c),P>=h.nextBlinkAt&&ie(P,c,!1);return}if(h.kind==="doublePause"){v(k(f),h.blinkEmotion),P>=h.resumeAt&&ie(P,h.blinkEmotion,!0);return}if(h.kind==="playing"){for(;P>=h.holdUntil&&h.index<h.paths.length-1;)h.index+=1,h.holdUntil=P+Yr(h.pace,h.index===h.closedFrameIndex);if(v(h.paths[h.index]??null,h.blinkEmotion),P>=h.holdUntil&&h.index>=h.paths.length-1){if(h.after==="resumeIdle"){B(P+u,l);return}if(h.after==="doublePause"){h={kind:"doublePause",resumeAt:P+Ze(s,o),blinkEmotion:h.blinkEmotion},v(k(f),h.blinkEmotion);return}if(h.after==="idle"&&Math.random()<i){h={kind:"doublePause",resumeAt:P+Ze(s,o),blinkEmotion:h.blinkEmotion},v(k(f),h.blinkEmotion);return}B(P,h.blinkEmotion)}}}return{advance:re,setTargetEmotion(P,G){const Q=it(P,l);if(Q===l)return;const te=performance.now();!G?.force&&d>0&&!(l==="neutral"&&Q!=="neutral")&&te-T<d||(l=Q,c=Q,T=te)},setTargetEyebrow(P){const G=et(P);if(G===f)return;const Q=performance.now(),te=h.kind==="browBlend"?Gr(E)??w:w;f=G,!(G===te&&h.kind!=="browBlend")&&(h.kind==="playing"||h.kind==="doublePause"||N(Q,te,G))},snapToEmotion(P){const G=it(P),Q=gt(G);l=G,c=G,f=Q,w=Q,T=performance.now(),h={kind:"idle",nextBlinkAt:performance.now()+Ze(4e3,7e3)},v(k(Q),G)},getTargetEmotion:()=>l,getTargetEyebrow:()=>f,getExpressionPath:()=>E,getDrawKey:()=>W,reset(){l="neutral",c="neutral",f=0,w=0,T=0,B(performance.now()+Ze(n,r),"neutral")}}}function Ja(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const i=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(s){t&&r===s||(i(),t=!1,r=s,s.startsWith("blob:")&&(n=s),await new Promise((o,a)=>{const u=()=>{const d=e.duration;if(!Number.isFinite(d)||d<=0){a(new Error(`Idle video has invalid duration: ${s}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",u,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${s}`)),{once:!0}),e.src=s,e.load()}))},isReady(){return t},getVideo(){return e},setActive(s){t&&(s?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},setLooping(s){e.loop=s},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),i(),t=!1,r=""}}}const Za=50,ss=400;function eo(e,t,n){return e.filter(r=>{const i=r.queueIndex??-1;return i>=t&&i<=n})}function to(e,t){const n=[];for(const r of e){const i=eo(t,r.start_word,r.end_word);if(i.length===0)continue;const s=i[0],o=i[i.length-1];n.push({sentence:r,startMs:Math.max(0,s.wtime-Za),endMs:o.wtime+o.wduration+ss})}return n.sort((r,i)=>r.startMs-i.startMs)}function no(e,t,n,r="neutral"){const i=it(r);if(t.length===0)return i;if(n.length===0||e<n[0].wtime)return it(t[0]?.emotion,i);const s=to(t,n);let o=null;for(const d of s)e>=d.startMs&&e<=d.endMs&&(o=d);if(o)return it(o.sentence.emotion,i);const a=n[n.length-1],u=a.wtime+a.wduration;return e>u+ss?it(t[t.length-1]?.emotion,i):i}function yr(e,t,n,r,i=Zi){const s=new OffscreenCanvas(n,r),o=s.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const a=o.getImageData(0,0,n,r),u=o.createImageData(n,r);u.data.set(a.data);const l=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const c of t){l.clearRect(0,0,n,r),l.drawImage(c,0,0,n,r);const f=l.getImageData(0,0,n,r);for(let w=0;w<u.data.length;w+=4){const T=f.data[w],h=f.data[w+1],E=f.data[w+2];f.data[w+3]>0&&Math.max(T,h,E)>i&&(u.data[w]=T,u.data[w+1]=h,u.data[w+2]=E,u.data[w+3]=255)}}return o.putImageData(u,0,0),s}let mt=null,Pt=null;const dn=new Map;function ro(){mt=null,Pt=null,dn.clear()}bi(ro);function io(e){return e??Pt??void 0}function vr(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function so(e){return zt()?Ea(await Bt(ln(),e??"")):vr(ln())}async function Qr(e,t,n,r){const i=n?await Ji(e,r):await fetch(e).then(d=>{if(!d.ok)throw new Error(`Failed to load ${e}`);return d.json()}),s=i.sheets?.[0];if(!s?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await Ta(await Bt(ts(t,s.path,n),r??"")):await vr(`${t}/${s.path}`),a=new Map;for(const d of i.cells??[])d.path&&a.set(d.path,d);const u=new Map;for(const d of i.sheets??[])u.set(d.index,d);return{atlas:o,atlasMeta:i,cellByPath:a,sheetByIndex:u,diffBase:t}}async function Qn(e){const t=io(e),n=zt();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(mt&&(!n||Pt===(t??null))){const s=await mt;return{...Ct(s),visemePaths:[...s.viseme.cellByPath.keys()]}}Pt=t??null,dn.clear();const r=Si();mt=(async()=>{const s=await so(t),o=await Qr(Ti(),r,n,t);let a=null;try{a=await Qr(ki(),r,n,t)}catch{a=null}return{sil:s,viseme:o,expression:a}})();const i=await mt;return{...Ct(i),visemePaths:[...i.viseme.cellByPath.keys()]}}async function _r(e){if(await Qn(e),!mt)throw new Error("Assets not loaded");return mt}function Ct(e){return Yi(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function ao(e,t){const n=document.createElement("canvas");return n.width=t.w,n.height=t.h,n.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}async function fn(e,t,n){const r=`${t.diffBase}::${n}`,i=dn.get(r);if(i)return i;const s=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const a=Qi(t.atlasMeta,o),u=Ct(e);if(Xi(o)){const c=ao(t,o),f=document.createElement("canvas");f.width=u.width,f.height=u.height;const w=f.getContext("2d");return w.fillStyle="#000",w.fillRect(0,0,u.width,u.height),w.drawImage(c,a.x,a.y),f}const d=`${t.diffBase}/${n}`,l=await vr(d);if(l.naturalWidth===u.width&&l.naturalHeight===u.height)return l;throw new Error(`Diff PNG wrong size for ${n}`)})();return dn.set(r,s),s}async function On(e,t,n,r,i,s){if(i){const{width:w,height:T}=i;if(s&&!s()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const h=document.createElement("canvas");h.width=w,h.height=T;const E=h.getContext("2d");if(E.clearRect(0,0,w,T),E.drawImage(t,0,0,w,T),s&&!s())return;(e.width!==w||e.height!==T)&&(e.width=w,e.height=T);const W=e.getContext("2d");W.clearRect(0,0,w,T),W.drawImage(h,0,0);return}const o=await _r(),a=Tn(o.viseme.atlasMeta),{width:u,height:d}=Ct(o);(e.width!==u||e.height!==d)&&(e.width=u,e.height=d);const l=[],c=e.getContext("2d");if(c.clearRect(0,0,u,d),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const w=o.sil;c.drawImage(w,0,0,u,d);return}if(l.length===0){c.drawImage(t,0,0,u,d);return}const f=yr(t,l,u,d,a);c.drawImage(f,0,0)}async function Xn(e,t,n){const r=await _r(Pt??void 0),i=Tn(r.viseme.atlasMeta),{width:s,height:o}=Ct(r);(e.width!==s||e.height!==o)&&(e.width=s,e.height=o);const a=[];if(t.mouthPath){const l=new Set(r.viseme.cellByPath.keys()),c=pr(t.mouthPath,l)??(l.has(t.mouthPath)?t.mouthPath:null);c&&a.push(await fn(r,r.viseme,c))}if(t.expressionPath&&r.expression){const l=wr(t.expressionPath,c=>r.expression.cellByPath.has(c));l&&a.push(await fn(r,r.expression,l))}const u=e.getContext("2d");if(u.clearRect(0,0,s,o),a.length===0){u.drawImage(r.sil,0,0,s,o);return}const d=yr(r.sil,a,s,o,i);u.drawImage(d,0,0)}async function oo(e,t){const n=await _r(Pt??void 0),r=Tn(n.viseme.atlasMeta),{width:i,height:s}=Ct(n),o=[];if(e.mouthPath){const l=new Set(n.viseme.cellByPath.keys()),c=pr(e.mouthPath,l)??(l.has(e.mouthPath)?e.mouthPath:null);c&&o.push(await fn(n,n.viseme,c))}if(e.expressionPath&&n.expression){const l=wr(e.expressionPath,c=>n.expression.cellByPath.has(c));l&&o.push(await fn(n,n.expression,l))}const a=new OffscreenCanvas(i,s),u=a.getContext("2d");if(o.length===0)return u.drawImage(n.sil,0,0,i,s),a.transferToImageBitmap();const d=yr(n.sil,o,i,s,r);return u.drawImage(d,0,0),a.transferToImageBitmap()}async function co(e){await Xn(e,{mouthPath:null,expressionPath:null})}const rn={fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"clamp(0.875rem, 2.5vw, 1.125rem)",color:"rgba(255,255,255,0.85)"};function lo(e){return e.length===0?"":e.map(t=>t.word).join(" ")}function uo(e){if(!e)return{enabled:!1,style:rn};const t=e===!0?{}:e;return{enabled:!0,style:{fontFamily:t.fontFamily??rn.fontFamily,fontSize:t.fontSize??rn.fontSize,color:t.color??rn.color}}}const fo={position:"absolute",bottom:0,left:0,right:0,display:"flex",justifyContent:"center",padding:"0.75rem 1rem",pointerEvents:"none"},mo={display:"inline-block",maxWidth:"100%",padding:"0.45rem 0.85rem",borderRadius:"0.75rem",background:"rgba(0,0,0,0.55)",lineHeight:1.4,textAlign:"center"},ho={display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden",maxWidth:"100%",margin:0};function po({text:e,style:t}){return O.jsx("div",{style:fo,"aria-live":"polite","aria-atomic":"true",children:O.jsx("div",{style:{...mo,fontFamily:t.fontFamily,fontSize:t.fontSize,color:t.color},children:O.jsx("p",{style:ho,children:e})})})}const go={inset:0,overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:3},wo={filter:"blur(22px)",height:"100%",inset:0,objectFit:"cover",objectPosition:"top",position:"absolute",transform:"scale(1.08)",width:"100%"},yo={backdropFilter:"blur(10px)",WebkitBackdropFilter:"blur(10px)",inset:0,position:"absolute"};function vo({thumbnailUrl:e}){const[t,n]=m.useState(!1);m.useEffect(()=>{n(!1)},[e]);const r=!!e&&t;return O.jsxs("div",{style:go,"aria-hidden":!0,children:[e?O.jsx("img",{src:e,alt:"",style:{...wo,opacity:r?1:0,transition:"opacity 0.45s ease"},onLoad:()=>n(!0),onError:()=>n(!1)}):null,O.jsx("div",{style:{...yo,background:r?"rgba(0, 0, 0, 0.28)":"rgba(10, 10, 11, 0.92)"}})]})}let as=null;function Xr(e){as=e}function ut(){return as}function _o(e){return`${e.from}→${e.to}@${e.fromVtime}`}function Jr(){return{rafTicksSpeaking:0,rafTicksDeduped:0,drawsRequested:0,drawsDisplayed:0,queueSuperseded:0,workerStale:0,rifeFramesOmittedByGap:0,transitionFramesSampled:0,transitionFramesDisplayed:0,transitionFramesMissed:0,bufferTicks:0,bufferHits:0,bufferUnderruns:0,bufferPrefetched:0}}function bo(){let e=Jr();const t=new Set,n=new Set,r=new Set;let i="",s=-1,o="";const a=()=>{e=Jr(),t.clear(),n.clear(),r.clear(),i="",s=-1,o=""},u=l=>{t.add(l)},d=l=>{l&&r.add(l)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(l,c){const f=_o(l);e.transitionFramesSampled+=1,f!==i&&(i=f,s=-1,o!==f&&(o=f,e.rifeFramesOmittedByGap+=l.omittedByGap)),c&&n.add(c),s>=0&&l.frameIdx>s+1&&(e.transitionFramesMissed+=l.frameIdx-s-1),s=l.frameIdx},onBufferTick(){e.bufferTicks+=1},onBufferHit(){e.bufferHits+=1},onBufferUnderrun(){e.bufferUnderruns+=1},onBufferPrefetched(){e.bufferPrefetched+=1},onBufferReset(){},onDrawDisplayed(l,c){if(e.drawsDisplayed+=1,l.transitionMeta){e.transitionFramesDisplayed+=1;const w=l.transitionMeta;u(w.fromVtime),u(w.toVtime),d(l.mouthPath);return}if(l.label.includes("→")){e.transitionFramesDisplayed+=1;return}const f=l.label.trim();if(!(!f||f==="sil")){for(const w of c)if(w.viseme===f&&l.elapsedMs>=w.vtime&&l.elapsedMs<w.vtime+w.vduration){u(w.vtime);break}}},snapshot(l,c){let f=0,w=0;for(const L of l)if(L.viseme!=="sil"){if(L.vtime>=c)break;f+=1,t.has(L.vtime)&&(w+=1)}const T=f>0?Math.round(w/f*100):100,h=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),E=f-w,W=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:W,renderLoss:h,visemeSlotsTotal:f,visemeSlotsCovered:w,visemeCoveragePct:T,transitionFramesUniqueSampled:n.size,transitionFramesUniquePainted:r.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+h,visemesShown:w,visemesSkipped:E,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const os=tr,So=500,Zr=500,To=450,Nn=.05,ko=100,Eo=600,cs="__sil__";function ei(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===cs:!1}function br(){return{lastDrawnKey:""}}function Oe(e){e.lastDrawnKey="",e.transitionCache=void 0}function xo(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=Ui(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Io(e,t){let n="sil";for(const r of e)r.viseme!=="sil"&&(t!=null&&r.vtime>t||(n=r.viseme));return n}function Ao(e,t,n,r=120){if(n!=="sil")return n;const i=Ki(e,t,r);return i!=="sil"?i:Io(e,t)}function Mo(e,t){return e==="sil"?!1:t?Ra(e,"sil",t):gr(e,"sil").length>0}function Ro(){return os+Eo}function mn(e){return e??cs}function Sr(e,t,n,r,i=ko){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=ft(e))return{diffPath:null,label:"sil"};const s=r?.holdPp===!0,o=xo(e,r),a=la(o,t,s);if(a){const l=Vi(a.fromVtime,a.toVtime,a.from,a.to,s);if(t>=l.transStart&&t<l.transEnd){let c=gr(a.from,a.to);n&&(c=es(c,n));const f=Ca(c,l.effectiveGapMs);if(f.length>0){const w=Da(t,l.transStart,l.transEnd,f.length);return{diffPath:f[w]??f[f.length-1],label:`${a.from}→${a.to}`,transitionMeta:{from:a.from,to:a.to,fromVtime:a.fromVtime,toVtime:a.toVtime,frameIdx:w,frameCount:f.length,fullFrameCount:c.length,omittedByGap:Math.max(0,c.length-f.length)}}}return{diffPath:Rt(a.to),label:a.to}}}const u=vn(e);let d=Fi(u,t);return d==="sil"&&(d=Ki(e,t,i)),d==="sil"?{diffPath:null,label:"sil"}:{diffPath:Rt(d),label:d}}function $t(e,t){const n=t??mn(e.expressionPath);return`${mn(e.mouthPath)}|${n}`}function ti(e,t,n,r,i,s,o,a,u,d){const l=Sr(t,n,u,s),c={mouthPath:l.diffPath,expressionPath:r},f=$t(c,i),w=ut();if(l.transitionMeta&&w?.onTransitionSample(l.transitionMeta,l.diffPath),f===s.lastDrawnKey){w?.onDrawDeduped();return}w?.onDrawRequested(),a(l),s.lastDrawnKey=f,o(e,c,f,T=>{T===f&&(s.lastDrawnKey=f)})}function Un(e,t,n,r,i,s,o=null,a=null){const u={mouthPath:a,expressionPath:t},d=o!=null?`|idle@${Math.round(o*1e3)}`:"",l=$t(u,n)+d;!(o!=null)&&l===r.lastDrawnKey||(s(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),i(e,u,l,f=>{f===l&&(r.lastDrawnKey=l)}))}function ls(e,t,n,r,i=Vt,s){if(n<=t||e.length===0)return[];const o=s??br(),a=[];let u="";for(let d=t;d<n;d+=i){const l=Sr(e,d,r,o),c=mn(l.diffPath);c!==u&&(u=c,a.push({displayAtMs:d,mouthPath:l.diffPath,mouthKey:c,label:l.label}))}return a}const Po=3;function Tr(e){let t=0;const n=[];let r=!1,i=!1;const s=async()=>{if(!r){r=!0;try{for(;n.length>0;){const a=n.shift(),u=++t;await e(a.diffs,u,a)&&u===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n.length>0&&s()}}},o=()=>{i||(i=!0,queueMicrotask(()=>{i=!1,s()}))};return{enqueue(a,u,d){const l=n.findIndex(c=>c.drawKey===u);l>=0?n[l]={diffs:a,drawKey:u,onDisplayed:d}:(n.length>=Po&&(n.shift(),ut()?.onQueueSuperseded()),n.push({diffs:a,drawKey:u,onDisplayed:d})),o()},reset(){t+=1,n.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function Co(e,t=2){const n=[],r=new Set;let i=0,s=!1,o=0;const a=(d,l)=>`${d}|${l}`,u=async()=>{if(!s){s=!0;try{for(;i<t&&n.length>0;){const d=n.shift(),l=a(d.displayAtMs,d.drawKey);if(r.has(l))continue;r.add(l),i+=1;const c=o;try{await e(d)}finally{if(r.delete(l),i-=1,c!==o)return}}}finally{s=!1,n.length>0&&i<t&&u()}}};return{enqueue(d){const l=a(d.displayAtMs,d.drawKey);r.has(l)||n.some(c=>a(c.displayAtMs,c.drawKey)===l)||(n.push(d),u())},isQueuedOrInflight(d,l){const c=a(d,l);return r.has(c)?!0:n.some(f=>a(f.displayAtMs,f.drawKey)===c)},reset(){o+=1,n.length=0,r.clear(),i=0},pendingCount(){return n.length+i}}}function Do(){const e=new Map,t=n=>{n.bitmap.close()};return{has(n,r){return e.has(r)},markRendered(n,r,i,s,o){const a=e.get(r);a&&t(a),e.set(r,{displayAtMs:n,mouthKey:r,label:i,mouthPath:s,bitmap:o})},findForMouthKey(n){return e.get(n)??null},removeThrough(n){},pruneBefore(n){},reset(){for(const n of e.values())t(n);e.clear()},size(){return e.size}}}function Bo(e,t,n,r,i,s){const o=ls(t,n,r,i,Vt,s);if(o.length===0)return{ready:0,total:0};let a=0;for(const u of o)e.has(u.displayAtMs,u.mouthKey)&&(a+=1);return{ready:a,total:o.length}}function Fo(e){const t=Do(),n=br(),r=new Set;let i="",s=null;const o=Co(async c=>{try{if(!e.supportsBufferedPlayback)return;const f=await e.compositePrefetchFrame(c.diffs,c.mouthKey);if(!f)return;t.markRendered(c.displayAtMs,c.mouthKey,c.label,c.mouthPath,f),ut()?.onBufferPrefetched()}finally{r.delete(c.mouthKey)}},Is),a=c=>{for(const f of c)t.has(f.displayAtMs,f.mouthKey)||r.has(f.mouthKey)||o.isQueuedOrInflight(0,f.mouthKey)||(r.add(f.mouthKey),o.enqueue({...f,displayAtMs:0,drawKey:f.mouthKey,diffs:{mouthPath:f.mouthPath,expressionPath:null}}))},u=(c,f,w,T=Fn)=>{if(!e.supportsBufferedPlayback)return;const h=Math.max(0,f-Vt*4),E=ls(c,h,f+T,w,Vt,n);a(E)},d=(c,f)=>{i=c,s=f},l=(c,f)=>!(i!==c||s!==f);return{reset(){t.reset(),o.reset(),r.clear(),Oe(n),i="",s=null,ut()?.onBufferReset()},setHoldPp(c){n.holdPp=c},markExternallyDisplayed(c,f){d(c.split("|")[0]??c,f)},warmupTick(c){e.supportsBufferedPlayback&&u(c.queue,0,c.availablePaths,Math.max(Br,Fn))},isWarmupReady(c,f=Br){if(!e.supportsBufferedPlayback)return!0;const{ready:w,total:T}=Bo(t,c.queue,0,f,c.availablePaths,n);return T===0?!1:w/T>=xs},getBufferedFrameCount:()=>t.size(),tick(c){n.holdPp=c.playbackState.holdPp===!0;const f=ut();f?.onBufferTick(),u(c.queue,c.elapsedMs,c.availablePaths),t.pruneBefore(c.elapsedMs-Fn);const w=Sr(c.queue,c.elapsedMs,c.availablePaths,n),T=mn(w.diffPath),h=$t({mouthPath:w.diffPath,expressionPath:c.expressionPath},c.expressionDrawKey),E=()=>(d(T,c.expressionPath),f?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(l(T,c.expressionPath)||c.playbackState.lastDrawnKey===h)return E();const W=t.findForMouthKey(T,c.elapsedMs,Vt);return W&&c.expressionPath!=null?(f?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):W?(e.blitBitmap(c.canvas,W.bitmap),d(W.mouthKey,c.expressionPath),c.playbackState.lastDrawnKey=h,c.onStatus({diffPath:W.mouthPath,label:W.label}),c.onDisplayed(h,W.mouthPath,W.label),f?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(f?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const Lo=`
|
|
6
6
|
in vec2 aPosition;
|
|
7
7
|
out vec2 vTextureCoord;
|
|
8
8
|
|
|
@@ -30,7 +30,7 @@ void main(void)
|
|
|
30
30
|
gl_Position = filterVertexPosition();
|
|
31
31
|
vTextureCoord = filterTextureCoord();
|
|
32
32
|
}
|
|
33
|
-
`,
|
|
33
|
+
`,Oo=`
|
|
34
34
|
in vec2 vTextureCoord;
|
|
35
35
|
out vec4 finalColor;
|
|
36
36
|
|
|
@@ -44,5 +44,5 @@ void main(void)
|
|
|
44
44
|
float keep = step(uThreshold + 1e-6, peak) * color.a;
|
|
45
45
|
finalColor = vec4(color.rgb, keep);
|
|
46
46
|
}
|
|
47
|
-
`;function ei(e=5){const t=new ye.Filter({glProgram:ye.GlProgram.from({vertex:Bo,fragment:Fo,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 Lo(e,t,n){return e>n||t>n}function No(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function Oo(e,t){return t!=null&&t>0?Math.floor(t):No(e)}function Uo(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 cs(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 ti(e,t,n,r,i){const s=n?await Qi(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,f)=>{const g=Zi(t,f,n),T=n?await _a(await Dt(g,i??"")):await cs(g);if(Lo(T.width,T.height,r))return console.info(`[PixiVisemeCompositor] Sheet ${f} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${r}; using per-cell crops.`),{mode:"cells",bitmap:T};const m=ye.Texture.from(T);return m.source.scaleMode="nearest",{mode:"full",texture:m}};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 Vo(e,t={}){const n=new ye.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(_){throw n.destroy({removeView:!1}),_}if(n.renderer.type!==ye.RendererType.WEBGL)throw n.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const r=Oo(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 ye.Sprite(ye.Texture.EMPTY),l=new ye.Sprite(ye.Texture.EMPTY);l.visible=!1,l.alpha=0;const c=new ye.Sprite(ye.Texture.EMPTY),f=new ye.Sprite(ye.Texture.EMPTY),g=new ye.Sprite(ye.Texture.EMPTY);g.visible=!1;const T=ei(5),m=ei(5);c.filters=[T],f.filters=[m],n.stage.addChild(d),n.stage.addChild(l),n.stage.addChild(c),n.stage.addChild(f),n.stage.addChild(g);let I=null,L=null,O=null,b=null,E=null,V=null,D=null,oe=842,pe=1264,P=null,z=5;const Q=new Map;let le=null,ce=null,re=null;const ue=vi(()=>{Q.clear(),V=null,D=null,I=null,P=null}),we=(_,y)=>{oe=_,pe=y,n.renderer.resize(_,y),(e.width!==_||e.height!==y)&&(e.width=_,e.height=y)},se=()=>{c.visible=!1,f.visible=!1,c.texture=ye.Texture.EMPTY,f.texture=ye.Texture.EMPTY,le=null,ce=null},W=()=>{E=null,l.visible=!1,l.alpha=0},M=()=>{d.visible=!0,d.width=oe,d.height=pe,d.x=0,d.y=0},q=()=>{l.width=oe,l.height=pe,l.x=0,l.y=0},R=()=>{g.visible=!1,W(),I&&(d.texture=I,M())},H=()=>{E&&R()},X=_=>{if(o||i||!I){R();return}const y=Math.max(0,_);if(!L||y<=0){R();return}se(),g.visible=!1,d.texture=I,M(),l.texture=L,q(),l.alpha=1,l.visible=!0,E={startMs:performance.now(),durationMs:y},Z()},ae=(_=performance.now())=>{if(!E)return!1;if(o||i)return H(),!1;const y=(_-E.startMs)/Math.max(1,E.durationMs);if(y>=1)return R(),Z(),!1;const S=Math.min(1,Math.max(0,y)),K=S*S*(3-2*S);return l.alpha=1-K,l.visible=!0,Z(),!0},v=()=>{if(O){try{O.resource=null}catch{}O.destroy(),O=null}L&&(L.destroy(!1),L=null),b=null},N=(_,y)=>{const S=_.cellByPath.get(y);if(!S||!Yi(S))return null;const K=`${_.diffBase}::${y}`;let ee=Q.get(K);if(!ee){const x=S.sheet??0,J=_.sheets.get(x);if(!J)return null;let ne,te=!1;if(J.mode==="full")ne=new ye.Texture({source:J.texture.source,frame:new ye.Rectangle(S.x,S.y,S.w,S.h)});else{const Se=Uo(J.bitmap,S);ne=ye.Texture.from(Se),ne.source.scaleMode="nearest",te=!0}ee={texture:ne,ownsSource:te},Q.set(K,ee)}return{texture:ee.texture,cell:S}},U=(_,y,S,K)=>{if(!K||!S)return _.visible=!1,_.texture=ye.Texture.EMPTY,!1;const ee=N(S,K);if(!ee)return _.visible=!1,_.texture=ye.Texture.EMPTY,!1;const x=qi(S.atlasMeta,ee.cell);return y.setThreshold(z),_.texture=ee.texture,_.x=x.x,_.y=x.y,_.width=ee.cell.w,_.height=ee.cell.h,_.visible=!0,!0},Y=_=>{if(!_||!V)return null;const y=P??new Set(V.cellByPath.keys());return fr(_,y)??(y.has(_)?_:null)},G=_=>{g.visible=!1,R();const y=Y(_.mouthPath),S=_.expressionPath&&D?hr(_.expressionPath,K=>D.cellByPath.has(K)):null;y!==le?(U(c,T,V,y),le=y):y?c.visible=!0:c.visible=!1,S!==ce?(U(f,m,D,S),ce=S):S?f.visible=!0:f.visible=!1},Z=()=>{if(!(o||i||document.hidden))try{n.render()}catch{}};return{async loadAssets(_){if(o)return{width:oe,height:pe,visemePaths:[]};const y=Wt();if(y&&!_)throw new Error("Encrypted assets enabled but no key provided");const S=y?await Sa(await Dt(an(),_??"")):await cs(an());I&&I.destroy(!0),I=ye.Texture.from(S),I.source.scaleMode="linear";const K=_i();V=await ti(bi(),K,y,r,_);try{D=await ti(Si(),K,y,r,_)}catch(x){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",x),D=null}const ee=Gi(V.atlasMeta,S.width,S.height);return we(ee.width,ee.height),z=_n(V.atlasMeta),T.setThreshold(z),m.setThreshold(z),P=new Set(V.cellByPath.keys()),Q.clear(),R(),se(),Z(),{width:ee.width,height:ee.height,visemePaths:[...V.cellByPath.keys()]}},getVisemeAtlasPaths(){return P},drawLiveFrame(_){o||i||!I||(H(),G(_),Z())},drawIdleVideo(_,y){o||i||document.hidden||y&&!y()||_.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(E=null,se(),g.visible=!1,I&&(d.texture=I,M()),!L||b!==_?(v(),O=new ye.VideoSource({resource:_,autoPlay:!1,updateFPS:0}),O.autoUpdate=!1,L=new ye.Texture({source:O}),b=_):L.source.update(),l.texture=L,q(),l.alpha=1,l.visible=!0,Z())},beginIdleToSilCrossfade:X,tickIdleToSilCrossfade:ae,finishIdleToSilCrossfade:H,isIdleToSilCrossfading(){return E!=null},renderSilOnly(){o||i||!I||(se(),R(),Z())},blitBitmap(_){o||i||(H(),se(),re&&(re.destroy(!0),re=null),re=ye.Texture.from(_),g.texture=re,g.visible=!0,g.x=0,g.y=0,g.width=oe,g.height=pe,d.visible=!1,Z())},async compositePrefetchFrame(_){return null},renderFrame:Z,isContextLost(){return i},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",u),ue(),v(),re&&(re.destroy(!0),re=null);for(const{texture:y,ownsSource:S}of Q.values())y.destroy(S);Q.clear(),I&&(I.destroy(!0),I=null);const _=y=>{y.mode==="full"?y.texture.destroy(!0):y.bitmap.close()};if(V)for(const y of V.sheets.values())_(y);if(D)for(const y of D.sheets.values())_(y);T.destroy(!0),m.destroy(!0),n.destroy({removeView:!1},{children:!0,texture:!0})}}}const ni=-1,tn=1e5,ri=new Map;async function Wo(e){let t=ri.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),ri.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function zo(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Yn(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 ii(e,t){let n=0,r=null;const i=_r(async(s,o)=>(await Gn(),await qn(e,s),i.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(s){const o=await Gn(s);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,i.reset(),await ao(e)},drawLiveFrame(s,o,a,u){i.enqueue(o,a,u)},async compositePrefetchFrame(s,o){try{return await so(s)}catch{return null}},blitBitmap(s,o){Yn(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 qn(s,{mouthPath:Mt(o),expressionPath:null})},dispose(){n+=1,i.reset()}}}function Ho(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 f=_r(async(O,b,E)=>(d.set(b,{drawKey:E.drawKey,onDisplayed:E.onDisplayed}),await I({type:"drawFrame",diffPath:O.mouthPath,expressionDiffPath:O.expressionPath,liveSeq:b},void 0,!0),!1)),g=O=>{if(O===ni){let V=-1,D;for(const[oe,pe]of d)oe>=V&&(V=oe,D=pe);V>=0&&d.delete(V),D?.onDisplayed?.(D.drawKey);return}const b=-O,E=d.get(b);d.delete(b),E?.onDisplayed?.(E.drawKey)},T=new Map,m=(O,b)=>{a||!r||r.postMessage(O,[])},I=(O,b,E=!1)=>{if(a)return Promise.resolve();const V=i++;return new Promise((D,oe)=>{T.set(V,{resolve:pe=>D(pe),reject:oe,generation:typeof O.generation=="number"?O.generation:void 0,expectRenderDone:E}),m({...O,requestId:V})})},L=(async()=>{r=await Wo(n),r.onmessage=O=>{if(a)return;const b=O.data;if(b.type==="status"){t.onStatus?.(b.label);return}if(b.type==="frame"){if(b.generation<=-tn){const D=-b.generation,oe=l.get(D);l.delete(D),oe?.resolve(b.bitmap);return}const V=b.generation<0;if(!V&&b.generation!==s){b.bitmap.close();return}if(V&&!(b.generation===ni)){const oe=-b.generation;if(!f.isLatestSeq(oe)){lt()?.onWorkerStale(),b.bitmap.close();return}}if(V&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){lt()?.onWorkerStale(),b.bitmap.close();return}Yn(e,b.bitmap),b.bitmap.close(),V&&g(b.generation);return}const E=T.get(b.requestId);if(E)switch(b.type){case"ready":T.delete(b.requestId),E.resolve();break;case"loadAssetsDone":T.delete(b.requestId),u=b.visemePaths?.length?new Set(b.visemePaths):null,E.resolve({width:b.width,height:b.height,visemePaths:b.visemePaths});break;case"renderDone":if(E.expectRenderDone&&E.generation!=null&&b.generation!==E.generation)return;T.delete(b.requestId),E.resolve();break;case"renderAborted":T.delete(b.requestId),E.resolve();break;case"error":T.delete(b.requestId),t.onError?.(b.message),E.reject(new Error(b.message));break}},r.onerror=O=>{if(a)return;const b=O.message||"Worker error";t.onError?.(b);for(const[,E]of T)E.reject(new Error(b));T.clear()},await I({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(O){if(a)return{width:842,height:1264};if(await L,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await I({type:"loadAssets",keyHex:O,urls:Vs(yt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return u},async renderSilOnly(){if(a||(await L,a))return;s+=1,f.reset(),d.clear(),l.forEach(({resolve:b})=>b(null)),l.clear(),c=tn;const O=s;await I({type:"cancelLiveDraws"}),await I({type:"renderSil",generation:O},void 0,!0)},drawLiveFrame(O,b,E,V){a||L.then(()=>{a||f.enqueue(b,E,V)})},compositePrefetchFrame(O,b){return a?Promise.resolve(null):L.then(()=>{if(a)return null;const E=++c;return new Promise(V=>{l.set(E,{resolve:V}),I({type:"drawFrame",diffPath:O.mouthPath,expressionDiffPath:O.expressionPath,liveSeq:E},void 0,!0).catch(()=>{l.delete(E),V(null)})})})},blitBitmap(O,b){Yn(O,b)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(O,b,E={}){if(a||(await L,a))return;s+=1,f.reset(),d.clear();const V=s;try{await I({type:"cancelLiveDraws"}),await I({type:"renderViseme",generation:V,to:b,from:E.from,transitionDurationMs:E.transitionDurationMs,gapMs:E.gapMs,threshold:E.threshold},void 0,!0)}catch(D){if(D?.name==="AbortError")return;throw D}},dispose(){if(!a){a=!0,s+=1,f.reset(),d.clear(),l.forEach(({resolve:O})=>O(null)),l.clear(),c=tn;for(const[,O]of T)O.resolve();T.clear(),r?.terminate(),r=null}}}}async function $o(e,t){const n=await Vo(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let r=0,i=null,s=!1;const o=_r(async(a,u)=>s?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(lt()?.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:Mt(u),expressionPath:null})},dispose(){s||(s=!0,r+=1,o.reset(),n.dispose())}}}function si(e,t){if(!zo())return ii(e,t);const n=Ss(t.workerScriptUrl);try{return Ho(e,t,n)}catch{return ii(e,t)}}function jo(e,t={}){if(t.preferLegacyRenderer)return si(e,t);let n=null,r=!1,i=null,s=!1;const o=()=>n?Promise.resolve(n):(i||(i=(async()=>{try{const a=await $o(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=si(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 Ko extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Nn(e,t,n){return new Promise((r,i)=>{const s=globalThis.setTimeout(()=>{i(new Ko(n,t))},t);e.then(o=>{globalThis.clearTimeout(s),r(o)},o=>{globalThis.clearTimeout(s),i(o)})})}const Go={overflow:"hidden",position:"relative",display:"inline-block",lineHeight:0},qo={display:"block",maxWidth:"100%",height:"auto"},Yo={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 On(e){return mi(e)?lr:hi(e)?fn:cr}function nt(e,t){return t?.isSpeaking()||t?.isWarmingUp()?t:e.isSpeaking()||e.isWarmingUp()?e:t?.isConnected()?t:e}const ls=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:f,canvasStyle:g,onStatusChange:T,onDisplayStatus:m,onError:I,onReady:L,showErrorOverlay:O=!0,loadingThumbnailUrl:b,onUserTranscript:E,onBotOutput:V,onRealtimeLipsyncDebug:D,onFrameRenderStats:oe,lipsyncBufferedPlayback:pe=!0,lipsyncPlaybackWarmupMs:P=1500,idleHandoffHoldMs:z=_o,pixiMaxTextureSize:Q,captions:le},ce){const re=h.useRef(null),ue=h.useRef(null),we=h.useRef(null),se=h.useRef(pe);se.current=pe;const W=h.useRef(P);W.current=P;const M=h.useRef(z);M.current=z;const q=h.useRef(0),R=h.useRef(yr()),H=h.useRef(Ya()),X=h.useRef(!1),ae=h.useRef(null),v=h.useRef(null),N=h.useRef(0),U=h.useRef(0),Y=h.useRef(0),G=h.useRef(null),Z=h.useRef(null),_=h.useRef(!1),y=h.useRef(!1),S=h.useRef(!1),K=h.useRef(!1),ee=h.useRef(!1),x=h.useRef("sil"),J=h.useRef(0),ne=h.useRef(!1),te=h.useRef(null),Se=h.useRef(!1),[ut,br]=h.useState("idle"),[$t,vt]=h.useState(null),[ot,bn]=h.useState(!1),[p,B]=h.useState(!1),[ie,de]=h.useState(!1),[Me,Ee]=h.useState(),[Pe,ze]=h.useState({width:842,height:1264}),[Oe,jt]=h.useState(null),[Sn,Bt]=h.useState(0),_t=h.useRef(!1),Ne=h.useRef(s??null),Ge=o?.trim()||Ct,bt=h.useRef(null),xe=h.useRef(null),{ttsEngineId:Re,voiceId:qe}=h.useMemo(()=>{const w=it(a,u),k=w.ttsEngineId??ht;return{ttsEngineId:k,voiceId:w.voiceId??On(k)}},[a,u]),Ue=h.useCallback(w=>{const k=mi(w);R.current.holdPp=k,we.current?.setHoldPp(k)},[]),Ve=h.useRef(!1),Ie=h.useRef({width:842,height:1264}),De=h.useRef(null),He=h.useRef("sil"),et=h.useRef(""),$e=h.useMemo(()=>co(le),[le]),We=h.useCallback(()=>{et.current="",jt(null)},[]);h.useEffect(()=>{$e.enabled||We()},[$e.enabled,We]);const St=h.useCallback(w=>{if(!$e.enabled)return;const k=w.isSpeaking(),C=w.isWarmingUp();if(!k||C){et.current&&We();return}const A=oo(w.getWordQueue());if(!A){et.current&&We();return}A!==et.current&&(et.current=A,jt(A))},[$e.enabled,We]),Tt=h.useRef(void 0),Tn=h.useRef(new Map),Sr=h.useRef(L),Tr=h.useRef(T),Te=h.useRef(m),kr=h.useRef(I),Er=h.useRef(E),kn=h.useRef(V),Kt=h.useRef(D),xr=h.useRef(oe),kt=h.useRef(vo());Sr.current=L,Tr.current=T,Te.current=m,kr.current=I,Er.current=E,kn.current=V,Kt.current=D,xr.current=oe,h.useEffect(()=>{const w=kt.current;return Yr(w),()=>Yr(null)},[]);const En=h.useCallback(w=>{const k=it(w?.ttsEngineId??a,w?.voiceId??u),C=k.ttsEngineId??xe.current?.ttsEngineId??ht,A=k.voiceId??xe.current?.voiceId??On(C);return{ttsEngineId:C,voiceId:A}},[a,u]),tt=h.useCallback(w=>{vt(w),de(!0),kr.current?.(w)},[]),Ft=h.useCallback(w=>{br(w),Tr.current?.(w)},[]),me=h.useRef(jn(Ft,Ge,{onLipsyncDebug:w=>Kt.current?.(w)})),ge=h.useRef(null),Ir=h.useRef(()=>{});h.useEffect(()=>(me.current=jn(Ft,Ge,{onLipsyncDebug:w=>Kt.current?.(w)}),s&&me.current.setDeveloperToken(s),me.current.setTtsEngineId(Re),()=>{me.current.stop();const w=ge.current;w&&(w.disconnect(),ge.current=null)}),[Ft,Ge]);const Ar=h.useCallback(()=>(ge.current||(ge.current=Ki(Ft,{speakingRate:l,language:d,onUserTranscript:(w,k)=>Er.current?.(w,k),onBotOutput:w=>kn.current?.(w),onLipsyncDebug:w=>Kt.current?.(w)}),ge.current.setTtsEngineId(Re),Ir.current(!0)),ge.current),[Ft,l,d,Re]),Fe=h.useCallback(()=>{G.current!=null&&(clearTimeout(G.current),G.current=null)},[]),Be=h.useCallback(()=>{Z.current!=null&&(clearTimeout(Z.current),Z.current=null),S.current=!1},[]),xn=h.useCallback(()=>{ee.current=!0,Be(),te.current?.setLooping(!1)},[Be]),je=h.useCallback(()=>{ee.current=!1,te.current?.setLooping(!0)},[]),Lt=h.useCallback(()=>{if(K.current)return;const w=ue.current;if(K.current=!0,ee.current=!0,Be(),_.current=!1,y.current=!1,!Se.current||!te.current){w?.renderSilOnly();return}const k=te.current;k.setLooping(!1),k.setActive(!1);const C=k.getVideo();if(C.ended||Number.isFinite(C.currentTime)&&C.currentTime<=Fn){try{(C.ended||C.currentTime>Fn)&&(C.currentTime=0)}catch{}w?.renderSilOnly(),w?.finishIdleToSilCrossfade();return}if(w?.usesPixi){w.drawIdleVideo(C),w.beginIdleToSilCrossfade(Xr);return}(async()=>{const $=re.current;$&&await Bn($,C,null,void 0,Ie.current).catch(()=>{}),await new Promise(ve=>setTimeout(ve,Xr)),K.current&&await w?.renderSilOnly()})()},[Be]),Mr=h.useCallback(()=>{if(!(!Se.current||!te.current)){if(K.current=!1,ue.current?.finishIdleToSilCrossfade(),ue.current?.renderSilOnly(),Be(),ee.current){S.current=!1;return}S.current=!0,Z.current=setTimeout(()=>{if(Z.current=null,nt(me.current,ge.current).isSpeaking()){S.current=!1;return}if(_.current){S.current=!1;return}if(ee.current){S.current=!1;return}const w=te.current;if(!w){S.current=!1;return}je(),w.setLooping(!0),w.restart(),w.setActive(!0);const k=w.getVideo();let C=!1;const A=()=>{C||(C=!0,k.removeEventListener("playing",$),S.current=!1)},$=()=>{A()};if(k.addEventListener("playing",$,{once:!0}),k.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!k.paused){A();return}setTimeout(A,300)},M.current)}},[Be,je]),Et=h.useCallback(()=>{if(Fe(),Te.current?.("sil"),_.current=!1,K.current=!1,!Se.current||!te.current){S.current=!1,je();return}Mr()},[Fe,Mr,je]),In=h.useCallback(async w=>{const k=U.current,C=ue.current,A=re.current,$=()=>{w?.fallbackOnly||(_.current=!1)};if(!C||!A||!ot){$();return}if(nt(me.current,ge.current).isSpeaking()){$();return}if(w?.fallbackOnly){if(!_.current||(Le(R.current),await C.renderSilOnly(),k!==U.current)||nt(me.current,ge.current).isSpeaking())return;Et();return}if(Jr(R.current)){Le(R.current),Et();return}if(se.current&&C.supportsBufferedPlayback&&!w?.fallbackOnly){if(Le(R.current),we.current?.reset(),await C.renderSilOnly(),k!==U.current||nt(me.current,ge.current).isSpeaking())return;Et();return}const _e=xo(nt(me.current,ge.current).getVisemeQueue(),J.current,x.current),Ce=Io(_e,De.current);if(Le(R.current),!Ce){if(await C.renderSilOnly(),k!==U.current||nt(me.current,ge.current).isSpeaking())return;Et();return}try{await C.renderViseme(A,"sil",{from:_e,transitionDurationMs:ss})}catch(ke){if(ke?.name!=="AbortError")throw ke}if(k!==U.current){$();return}if(nt(me.current,ge.current).isSpeaking()){$();return}Et()},[ot,Et]),dt=h.useCallback(()=>{if(y.current||_.current)return;y.current=!0,_.current=!0,Fe();const w=U.current;In().finally(()=>{y.current=!1}),G.current=setTimeout(()=>{G.current=null,w===U.current&&In({fallbackOnly:!0})},Ao())},[Fe,In]),Pr=h.useCallback(async()=>{const w=Math.floor(Date.now()/1e3);if(bt.current&&w<bt.current.expiresAt-60)return bt.current.key;const k=Ne.current??await nn();Ne.current=k,me.current.setDeveloperToken(k);const C=await Ls(k,Ge);return bt.current={key:C.value,expiresAt:C.expiresAt},C.value},[Ge]);h.useEffect(()=>{s&&(Ne.current=s,me.current.setDeveloperToken(s))},[s]),h.useEffect(()=>{me.current.setTtsEngineId(Re),ge.current?.setTtsEngineId(Re),xe.current&&(xe.current.ttsEngineId=Re),Ue(Re)},[Re,Ue]),h.useEffect(()=>{xe.current&&(xe.current.voiceId=qe)},[qe]);const Ye=h.useMemo(()=>wi(n,r),[n,r]),ms=h.useMemo(()=>i?JSON.stringify(i):Ye?`face:${Ye}`:`id:${t??""}`,[i,Ye,t]),hs=h.useMemo(()=>{const w=b?.trim();return w||(Dr(Ye)??Dr(Me)??Ps(i))},[b,Ye,Me,i]);return h.useEffect(()=>{if(!t&&!i&&!Ye){tt("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let w=!1;Ve.current=!1,bn(!1),B(!1),de(!1),Ee(Ye),vt(null),xe.current=null,te.current=null,Se.current=!1;const k=re.current;if(!k)return;let C=null;return(async()=>{try{let A,$,ve,_e,Ce;if(i)A=i,$=Re,ve=qe;else if(Ye)Te.current?.("loadFace"),A=Hn(Ye),$=Re,ve=qe;else{Te.current?.("getAiTwin");const j=await Nn(pi(t),3e4,"getAiTwin");if(w)return;if(!j.faceId?.trim())throw new Error("getAiTwin returned no faceId");Ee(j.faceId.trim());const be=it(a,u);$=be.ttsEngineId??j.ttsEngineId,ve=be.voiceId??j.voiceId??On($),_e=tr(j),Ce=nr(j),A=Hn(j.faceId)}xe.current={ttsEngineId:$,voiceId:ve,brainId:_e,brainUrl:Ce},yi(A),te.current=Qa();const ke=!!(i&&!wt(i));C=jo(k,{preferLegacyRenderer:ke,pixiMaxTextureSize:Q,onStatus:j=>{w||Te.current?.(j)},onError:j=>{w||tt(j)},shouldAcceptLiveFrame:()=>{if(X.current)return!0;if(_.current)return!1;const j=nt(me.current,ge.current);return j.isSpeaking()||j.isWarmingUp()},onWebGlContextLost:()=>{w||_t.current||(_t.current=!0,queueMicrotask(()=>{w||Bt(j=>j+1)}))}}),ue.current=C,we.current=Do(C),Ue($),_t.current=!1;const Qe=j=>{const be=()=>{if(!j||W.current<=0)return!1;const Ae=ue.current;return Ae?se.current&&Ae.supportsBufferedPlayback?!0:Ae.usesPixi:!1};me.current.setLipsyncWarmupHold(j,be),ge.current?.setLipsyncWarmupHold(j,be)};Ir.current=Qe,Qe(!0),Te.current?.("auth");const Gt=Ne.current??s??await Nn(nn(),3e4,"getAuthToken");if(w)return;Ne.current=Gt,me.current.setDeveloperToken(Gt),me.current.setTtsEngineId($);const he=Wt()?await Pr():void 0;if(w)return;Te.current?.("loadAssets");const fe=await Nn(C.loadAssets(he),18e4,"load face assets");if(!w&&fe.width>0&&fe.height>0&&(Ie.current=fe,ze(fe)),w)return;De.current=C.getVisemeAtlasPaths(),Ve.current=!0,bn(!0),Sr.current?.(),C.renderSilOnly().then(()=>{w||Te.current?.("sil")}),(async()=>{try{const j=await Ea(he);if(await te.current.load(j),w||(Se.current=!0,B(!0),Le(R.current),await C.renderSilOnly(),w)||(await new Promise(Ae=>setTimeout(Ae,M.current)),w))return;te.current.setActive(!0);const be=te.current.getVideo();C.usesPixi?C.drawIdleVideo(be):await Bn(k,be,null,void 0,Ie.current)}catch(j){if(w)return;Se.current=!1,B(!1),console.warn("[AiTwin] Idle video unavailable:",j)}finally{w||(de(!0),Te.current?.("idle"))}})()}catch(A){if(w)return;if(A instanceof rn){tt(A.message);return}tt(A instanceof Error?A.message:"Failed to load AI twin")}})(),()=>{w=!0,te.current?.dispose(),C?.dispose(),ue.current=null}},[ms,i,Ye,t,Re,qe,a,u,s,Q,Pr,tt,Sn,Ue]),h.useEffect(()=>{const w={current:!1},k=()=>{const C=re.current,A=ue.current,$=nt(me.current,ge.current);if(!C||!A||!ot){N.current=requestAnimationFrame(k);return}if(document.hidden){te.current?.setActive(!1),N.current=requestAnimationFrame(k);return}const ve=$.isSpeaking(),_e=$.isWarmingUp(),Ce=ve&&!ne.current,ke=ne.current&&!ve;Ce&&(Fe(),Be(),_.current=!1,y.current=!1,Le(R.current),we.current?.reset(),kt.current.reset(),Tt.current=void 0,Y.current=0,x.current="sil",J.current=0,Lt()),ke&&(H.current.reset(),te.current?.setActive(!1),we.current?.reset(),A.finishIdleToSilCrossfade(),We(),ee.current=!1,dt());const Qe=ke||_.current||S.current||K.current,Gt=pe&&A.supportsBufferedPlayback;if(ee.current&&!ve&&!_e&&!ke&&!_.current&&!S.current){if(K.current){A.usesPixi&&A.isIdleToSilCrossfading()&&A.tickIdleToSilCrossfade(performance.now()),ne.current=ve,N.current=requestAnimationFrame(k);return}if(Se.current&&te.current){const he=te.current.getVideo();if(he.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){const fe=he.duration,j=he.currentTime,be=he.ended||Number.isFinite(j)&&j<=Fn,Ae=Number.isFinite(fe)&&fe>0&&Number.isFinite(j)?Math.max(0,(fe-j)*1e3):Number.POSITIVE_INFINITY;if(be||Ae<=bo){Lt(),A.usesPixi&&A.isIdleToSilCrossfading()&&A.tickIdleToSilCrossfade(performance.now()),ne.current=ve,N.current=requestAnimationFrame(k);return}}}}if(_e){if(Lt(),Se.current&&te.current?.setActive(!1),A.usesPixi&&A.isIdleToSilCrossfading()){A.tickIdleToSilCrossfade(performance.now()),$.getVisemeQueue().length>0&&q.current===0&&(q.current=performance.now()),ne.current=$.isSpeaking(),N.current=requestAnimationFrame(k);return}const he=$.getVisemeQueue();he.length>0&&q.current===0&&(q.current=performance.now()),H.current.advance(performance.now());const fe=H.current.getExpressionPath(),j=H.current.getDrawKey(),be={queue:he,elapsedMs:0,expressionPath:fe,expressionDrawKey:j,availablePaths:De.current};let Ae=!1;Gt&&we.current?(we.current.warmupTick(be),Ae=we.current.isWarmupReady(be,W.current)):A.usesPixi&&Zr(C,he,0,fe,j,R.current,(xt,qt,An,Yt)=>{A.drawLiveFrame(xt,qt,An,Xe=>{Yt?.(Xe),$.isWarmingUp()&&Xe!==""&&!Jr({lastDrawnKey:Xe})&&(q.current=0,$.releaseWarmupHold())})},xt=>{Te.current?.(xt.label)},De.current);const ct=q.current>0&&performance.now()-q.current>ks;Te.current?.(Ae?"buffer ready":"buffering lipsync…"),(Ae||ct)&&(q.current=0,$.releaseWarmupHold()),St($),ne.current=$.isSpeaking(),N.current=requestAnimationFrame(k);return}if(ve){Lt(),Se.current&&te.current?.setActive(!1),A.usesPixi&&A.isIdleToSilCrossfading()&&A.finishIdleToSilCrossfade();const he=$.getVisemeQueue(),fe=$.getPlaybackElapsedMs();fa(he,fe),J.current=fe;const j=he.length>0?zt(he,fe):"sil";j!=="sil"&&(x.current=j);const be=eo(fe,$.getSentenceEmotions(),$.getWordQueue(),$.getStreamMood());H.current.setTargetEmotion(be),H.current.setTargetEyebrow(Ga(fe,$.getWordQueue(),gt(be))),H.current.advance(performance.now());const Ae=H.current.getExpressionPath(),ct=H.current.getDrawKey(),xt=(Xe,Mn,Nt,Pn)=>{const Rr={label:He.current,elapsedMs:fe,mouthPath:Mn.mouthPath,transitionMeta:Tt.current};Tn.current.set(Nt,Rr),we.current?.markExternallyDisplayed(Nt,Ae),A.drawLiveFrame(Xe,Mn,Nt,Qt=>{const ps=Tn.current.get(Qt)??Rr;Tn.current.delete(Qt),kt.current.onDrawDisplayed(ps,he),we.current?.markExternallyDisplayed(Qt,Ae),Pn?.(Qt)})},qt=Xe=>{He.current=Xe.label,Tt.current=Xe.transitionMeta,Te.current?.(Xe.label)},An=pe&&A.supportsBufferedPlayback;let Yt=!1;An&&we.current&&(Yt=we.current.tick({canvas:C,queue:he,elapsedMs:fe,expressionPath:Ae,expressionDrawKey:ct,playbackState:R.current,availablePaths:De.current,onStatus:qt,onDisplayed:(Mn,Nt,Pn)=>{kt.current.onDrawDisplayed({label:Pn,elapsedMs:fe,mouthPath:Nt,transitionMeta:Tt.current},he)}}).usedBuffer),Yt||Zr(C,he,fe,Ae,ct,R.current,xt,qt,De.current),kt.current.onRafTickSpeaking(),xr.current?.(kt.current.snapshot(he,fe))}else if(!Qe&&X.current){te.current?.setActive(!1),H.current.advance(performance.now());const he=H.current.getExpressionPath(),fe=H.current.getDrawKey();Ln(C,he,fe,R.current,(j,be,Ae,ct)=>A.drawLiveFrame(j,be,Ae,ct),j=>{if(v.current){Te.current?.(v.current);return}const be=H.current.getTargetEmotion();Te.current?.(j==="sil"||j==="blink"?`${be}${j==="blink"?" · blink":""}`:j)},null,ae.current)}else if(!Qe&&Se.current&&te.current){const he=te.current,fe=he.getVideo();if(fe.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){he.setActive(!0);const j=()=>!$.isSpeaking()&&!_.current&&!S.current&&!X.current;A.usesPixi?(A.drawIdleVideo(fe,j),j()&&Te.current?.("idle")):w.current||(w.current=!0,Bn(C,fe,null,void 0,Ie.current,j).then(()=>Te.current?.("idle")).finally(()=>{w.current=!1}))}else Ln(C,null,"__sil__",R.current,(j,be,Ae,ct)=>A.drawLiveFrame(j,be,Ae,ct),j=>Te.current?.(j))}else Qe||Ln(C,null,"__sil__",R.current,(he,fe,j,be)=>A.drawLiveFrame(he,fe,j,be),he=>Te.current?.(he));$e.enabled&&St($),ne.current=ve,N.current=requestAnimationFrame(k)};return N.current=requestAnimationFrame(k),()=>{cancelAnimationFrame(N.current),Fe(),Be(),me.current.stop(),ge.current?.stop()}},[ot,p,dt,Fe,Be,Lt,St,We,$e.enabled]),h.useImperativeHandle(ce,()=>({speakText:async(w,k)=>{const C=w.trim();if(!C)return;const A=ue.current;if(!A||!Ve.current&&!ot)throw new Error("AI twin is not ready");const{ttsEngineId:$,voiceId:ve}=En(k);vt(null),We(),U.current+=1,Fe(),Be(),_.current=!1,y.current=!1,x.current="sil",J.current=0,Le(R.current),Ue($),X.current=!1,ae.current=null,v.current=null,H.current.reset(),ne.current=!1,xn(),K.current=!1,A.finishIdleToSilCrossfade();try{await me.current.speak(C,{voiceId:ve,speakingRate:k?.speakingRate??l,ttsEngineId:$,language:k?.language??d})}catch(_e){throw je(),K.current=!1,A.finishIdleToSilCrossfade(),dt(),tt(_e instanceof Error?_e.message:"TTS failed"),_e}},speakWithReply:async(w,k)=>{const C=w.trim();if(!C)return{displayText:"",spokenText:""};const A=ue.current;if(!A||!Ve.current&&!ot)throw new Error("AI twin is not ready");const{ttsEngineId:$,voiceId:ve}=En(k);vt(null),We(),U.current+=1,Fe(),Be(),_.current=!1,y.current=!1,x.current="sil",J.current=0,Le(R.current),Ue($),X.current=!1,ae.current=null,v.current=null,H.current.reset(),ne.current=!1,xn(),K.current=!1,A.finishIdleToSilCrossfade();const _e=k?.brainId?.trim()||xe.current?.brainId?.trim()||void 0,Ce=k?.brainUrl?.trim()||xe.current?.brainUrl?.trim()||void 0;try{return await me.current.speakWithReply(C,{...k,voiceId:ve,speakingRate:k?.speakingRate??l,ttsEngineId:$,language:k?.language??d,brainId:_e,brainUrl:Ce,onDisplayText:ke=>{k?.onDisplayText?.(ke),kn.current?.(ke)}})}catch(ke){throw je(),K.current=!1,A.finishIdleToSilCrossfade(),dt(),tt(ke instanceof Error?ke.message:"speakWithReply failed"),ke}},stop:()=>{U.current+=1,Fe(),Be(),_.current=!1,y.current=!1,K.current=!1,je(),ue.current?.finishIdleToSilCrossfade(),me.current.stop(),ge.current?.stop(),Le(R.current),we.current?.reset(),q.current=0,ne.current=!1,We(),dt()},setTtsEngineId:w=>{me.current.setTtsEngineId(w),ge.current?.setTtsEngineId(w),xe.current&&(xe.current.ttsEngineId=w),Ue(w)},renderViseme:async(w,k)=>{const C=ue.current,A=re.current;if(!C||!A||!Ve.current)throw new Error("AI twin is not ready");await C.renderViseme(A,w,{from:k?.from,transitionDurationMs:k?.transitionDurationMs,gapMs:k?.gapMs,onStatus:$=>Te.current?.($)})},setEmotion:w=>{if(!Ve.current)throw new Error("AI twin is not ready");const k=ue.current,C=re.current;if(!k||!C)throw new Error("AI twin is not ready");U.current+=1,Fe(),Be(),_.current=!1,y.current=!1,S.current=!1,K.current=!1,je(),me.current.stop(),ge.current?.stop(),Le(R.current),we.current?.reset(),q.current=0,ne.current=!1,k.finishIdleToSilCrossfade(),te.current?.setActive(!1);const A=rt(w);X.current=!0,ae.current=null,v.current=null,H.current.snapToEmotion(A);const $=H.current.getExpressionPath(),ve=H.current.getDrawKey(),_e={mouthPath:null,expressionPath:$},Ce=Vt(_e,ve);R.current.lastDrawnKey="",k.drawLiveFrame(C,_e,Ce,Qe=>{Qe===Ce&&(R.current.lastDrawnKey=Ce)});const ke=gt(A);Te.current?.($?`${A} · brow ${ke>0?"+":""}${ke}`:`${A} · brow 0 (sil base)`)},getEmotion:()=>X.current?H.current.getTargetEmotion():null,clearEmotionPreview:()=>{X.current=!1,ae.current=null,v.current=null,H.current.reset(),Le(R.current),Te.current?.("idle")},setViseme:w=>{if(!Ve.current)throw new Error("AI twin is not ready");const k=ue.current,C=re.current;if(!k||!C)throw new Error("AI twin is not ready");U.current+=1,Fe(),Be(),_.current=!1,y.current=!1,S.current=!1,K.current=!1,je(),me.current.stop(),ge.current?.stop(),Le(R.current),we.current?.reset(),q.current=0,ne.current=!1,k.finishIdleToSilCrossfade(),te.current?.setActive(!1);const A=hn(w);X.current=!0,v.current=A,ae.current=A==="sil"?null:Mt(A),H.current.snapToEmotion("neutral");const $=H.current.getExpressionPath(),ve=H.current.getDrawKey(),Ce={mouthPath:ae.current,expressionPath:$},ke=Vt(Ce,ve);R.current.lastDrawnKey="",k.drawLiveFrame(C,Ce,ke,Qe=>{Qe===ke&&(R.current.lastDrawnKey=ke)}),Te.current?.(A)},getViseme:()=>X.current?v.current:null,isReady:()=>Ve.current,getStatus:()=>ut,connect:async(w={})=>{vt(null);try{let k=w.authToken?.trim();k||(k=Ne.current??s??await nn(),Ne.current=k);const C=it(w.ttsEngineId??a,w.voiceId??u),A=C.voiceId??xe.current?.voiceId,$=w.brainId?.trim()||w.personaId?.trim()||xe.current?.brainId,ve=w.brainUrl?.trim()||xe.current?.brainUrl,_e=C.ttsEngineId??xe.current?.ttsEngineId??Re,Ce=Ar();_e&&Ce.setTtsEngineId(_e),_e&&Ue(_e),await Ce.unlockAudio(),await Ce.connect({...w,apiBase:w.apiBase?.trim()||Ge,authToken:k,voiceId:A,brainId:$,brainUrl:ve,ttsEngineId:_e,speakingRate:w.speakingRate??l,language:w.language??d})}catch(k){throw tt(k instanceof Error?k.message:"Voice connect failed"),k}},disconnect:async()=>{const w=ge.current;w&&(U.current+=1,Fe(),Be(),_.current=!1,y.current=!1,K.current=!1,je(),ue.current?.finishIdleToSilCrossfade(),Le(R.current),we.current?.reset(),q.current=0,ne.current=!1,await w.disconnect(),dt())},isConnected:()=>ge.current?.isConnected()??!1,getVoiceStream:()=>ge.current?.getVoiceStream()??me.current?.getVoiceStream()??null,setMuted:w=>{const k=me.current,C=ge.current;k?.setMuted?.(w),C?.setMuted?.(w)},isMuted:()=>{const w=ge.current,k=me.current;return w?.isMuted?.()??k?.isMuted?.()??!1},getBrainId:()=>xe.current?.brainId?.trim()||null,getPersonaId:()=>xe.current?.brainId?.trim()||null,getBrainUrl:()=>xe.current?.brainUrl?.trim()||null}),[ot,l,d,s,Re,qe,Fe,Be,dt,xn,je,tt,En,Ar,Ue,ut,Ge]),F.jsxs("div",{className:c,style:{...Go,...f},children:[F.jsx("canvas",{ref:re,width:Pe.width,height:Pe.height,style:{...qo,...g},"aria-label":t?`AI twin ${t}`:"AI twin face"}),!ie&&!$t?F.jsx(wo,{thumbnailUrl:hs}):null,O&&$t?F.jsx("div",{style:Yo,children:$t}):null,$e.enabled&&Oe?F.jsx(mo,{text:Oe,style:$e.style},Oe):null]})});function Qo({muted:e}){return e?F.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[F.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),F.jsx("path",{d:"m16 9.5 5 5m0-5-5 5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]}):F.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[F.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),F.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 Xo(){return F.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:F.jsx("path",{d:"M8 5.5v13l11-6.5L8 5.5Z"})})}function Jo(){return F.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:F.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"1.5"})})}function Zo(){return F.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:F.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 us({className:e}){return F.jsx("span",{className:e??"aitwin-widget__spinner","aria-hidden":!0,children:F.jsx("svg",{viewBox:"0 0 24 24",fill:"none",children:F.jsx("circle",{cx:"12",cy:"12",r:"9",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeDasharray:"40 20"})})})}function ec({muted:e,onToggle:t}){return F.jsx("button",{type:"button",className:"aitwin-widget__mute",onClick:t,"aria-label":e?"Unmute":"Mute","aria-pressed":e,children:F.jsx(Qo,{muted:e})})}function tc(){return F.jsxs("div",{className:"aitwin-widget__connecting",role:"status","aria-live":"polite",children:[F.jsx(us,{className:"aitwin-widget__spinner aitwin-widget__spinner--accent"}),F.jsx("span",{children:"Connecting..."})]})}function nc(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 F.jsxs("div",{className:"aitwin-widget__controls",children:[F.jsxs("div",{className:"aitwin-widget__actions",children:[F.jsxs("button",{type:"button",className:r,onClick:e.onTalk,disabled:!e.ready||e.connecting||e.textSending,"aria-busy":e.connecting,children:[e.connecting?F.jsx(us,{className:"aitwin-widget__spinner aitwin-widget__spinner--on-accent"}):e.connected?F.jsx(Jo,{}):F.jsx(Xo,{}),F.jsx("span",{children:n})]}),F.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:[F.jsx(Zo,{}),F.jsx("span",{children:"Text"})]})]}),e.textMode?F.jsxs("form",{className:"aitwin-widget__composer",onSubmit:i=>{i.preventDefault(),e.onSendText()},children:[F.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}),F.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?F.jsx("p",{className:"aitwin-widget__controls-error",role:"alert",children:e.error}):null]})}const ai=97,rc=3500;function ic(e,t){const n=Math.max(0,e),r=1-Math.exp(-n/rc);return Math.min(ai,Math.round(r*ai))}function sc(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:ic(r-t):100}const ac="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 oc({className:e="aitwin-widget__logo",strokeWidth:t=15,durationMs:n=2600,delayMs:r=0,loop:i=!1}){return F.jsx("svg",{viewBox:"0 0 1080 1080",className:e,role:"img","aria-label":"AITWIN logo",children:F.jsx("path",{className:i?"aitwin-widget__logo-draw aitwin-widget__logo-draw--loop":"aitwin-widget__logo-draw",d:ac,fill:"none",stroke:"currentColor",strokeWidth:t,strokeMiterlimit:10,pathLength:1,style:{animationDuration:`${n}ms`,animationDelay:`${r}ms`}})})}function cc({progress:e}){const t=Math.max(0,Math.min(100,Math.round(e)));return F.jsx("div",{className:"aitwin-widget__face-loading","aria-live":"polite","aria-label":`Loading ${t} percent`,children:F.jsxs("div",{className:"aitwin-widget__face-loading-content",children:[F.jsx(oc,{className:"aitwin-widget__logo",loop:!0,durationMs:2600}),F.jsxs("div",{className:"aitwin-widget__face-loading-bar-wrap",children:[F.jsx("div",{role:"progressbar","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":100,className:"aitwin-widget__face-loading-track",children:F.jsx("div",{className:"aitwin-widget__face-loading-fill",style:{width:`${t}%`}})}),F.jsxs("p",{className:"aitwin-widget__face-loading-pct",children:[t,"%"]})]})]})})}function oi(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 lc(e){return[e.id??"",e.faceId??"",e.authToken?.slice(0,16)??"",e.voiceId??"",e.apiBase??"",String(e.speakingRate??"")].join("|")}const ci={display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",lineHeight:0},uc={display:"block",height:"100%",width:"100%",objectFit:"cover",objectPosition:"top"},dc=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(()=>oi(t)),[d,l]=h.useState(!1),[c,f]=h.useState(!1),[g,T]=h.useState(!1),[m,I]=h.useState(!1),[L,O]=h.useState("idle"),[b,E]=h.useState(null),[V,D]=h.useState(!1),[oe,pe]=h.useState(!1),[P,z]=h.useState(""),[Q,le]=h.useState(!1),[ce,re]=h.useState([]),[ue,we]=h.useState(t.brainId?.trim()||t.personaId?.trim()||void 0),[se,W]=h.useState(t.brainUrl?.trim()||void 0),M=h.useCallback(x=>{i.current={...i.current,...x},x.showControls!==void 0&&o(!!x.showControls),(x.brainId!==void 0||x.personaId!==void 0)&&we((x.brainId??x.personaId)?.trim()||void 0),x.brainUrl!==void 0&&W(x.brainUrl.trim()||void 0),u(J=>oi({id:x.id??J.id,faceId:x.faceId??x.avatarId??J.faceId,authToken:x.authToken??J.authToken,apiBase:x.apiBase??J.apiBase,voiceId:x.voiceId??J.voiceId,speakingRate:x.speakingRate??J.speakingRate,language:x.language??J.language}))},[]);h.useImperativeHandle(n,()=>({getTwin:()=>r.current,applyOptions:M}),[M]),h.useEffect(()=>{M(t)},[M,t.id,t.faceId,t.avatarId,t.authToken,t.apiBase,t.voiceId,t.speakingRate,t.showControls,t.brainId,t.personaId,t.brainUrl]);const q=h.useCallback(()=>{l(!0),E(null)},[]),R=h.useCallback(x=>{x==="idle"&&f(!0)},[]),H=h.useCallback(x=>{O(x),i.current.onStatusChange?.(x)},[]),X=h.useCallback(x=>{E(x),l(!1),f(!1),I(!1),i.current.onError?.(x)},[]),ae=h.useCallback((x,J)=>{i.current.onUserTranscript?.(x,J)},[]),v=h.useCallback(x=>{i.current.onBotOutput?.(x)},[]);h.useEffect(()=>{if(!s)return;const x=window.setInterval(()=>{T(!!r.current?.isConnected())},400);return()=>window.clearInterval(x)},[s,a]);const N=lc(a),U=!!(a.id||a.faceId),Y=d&&c,G=U&&!Y&&!b,Z=sc(G),_=h.useRef(N);h.useEffect(()=>{Y&&i.current.onReady?.()},[Y]),h.useEffect(()=>{Y&&r.current?.setMuted(V)},[Y,V,a]),h.useEffect(()=>{re([])},[a.id,a.faceId]),h.useEffect(()=>{_.current!==N&&(_.current=N,l(!1),f(!1),E(null),I(!1),T(!1),O("idle"))},[N]);const y=()=>{const x=r.current;if(!x?.isReady())return;if(E(null),pe(!1),x.isConnected()){I(!1),x.disconnect().finally(()=>{T(!1)});return}I(!0);const J={authToken:a.authToken,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language,apiBase:a.apiBase,...ue?{brainId:ue}:{},...se?{brainUrl:se}:{}};x.connect(J).then(()=>{T(!!x.isConnected())}).catch(ne=>{const te=ne instanceof Error?ne.message:"Failed to connect voice.";E(te),i.current.onError?.(te)}).finally(()=>{I(!1)})},S=()=>{pe(x=>!x),E(null)},K=()=>{const x=P.trim(),J=r.current;!x||!J?.isReady()||Q||(E(null),z(""),le(!0),i.current.onUserTranscript?.(x,!0),(async()=>{try{const ne=ue||J.getBrainId()?.trim()||void 0,te=se||J.getBrainUrl()?.trim()||void 0,Se=await J.speakWithReply(x,{brainId:ne,brainUrl:te,history:ce,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language});Se.displayText&&re(ut=>[...ut,{role:"user",content:x},{role:"assistant",content:Se.displayText}])}catch(ne){const te=ne instanceof Error?ne.message:"Failed to get reply.";E(te),i.current.onError?.(te)}finally{le(!1)}})())},ee=()=>{const x=!V;D(x),r.current?.setMuted(x)};return F.jsxs("div",{className:"aitwin-widget__layout",children:[F.jsxs("div",{className:"aitwin-widget__stage",children:[U?F.jsx("div",{style:ci,children:F.jsx(ls,{ref:r,id:a.id,faceId:a.faceId,authToken:a.authToken,apiBase:a.apiBase,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language,style:ci,canvasStyle:uc,onReady:q,onDisplayStatus:R,onStatusChange:H,onError:X,onUserTranscript:ae,onBotOutput:v,loadingThumbnailUrl:t.loadingThumbnailUrl},N)}):F.jsx("p",{className:"aitwin-widget__hint",style:{padding:16},children:"Pass id or faceId to load a twin."}),G?F.jsx(cc,{progress:Z}):null,s?F.jsx(ec,{muted:V,onToggle:ee}):null,s&&m?F.jsx(tc,{}):null]}),s?F.jsx(nc,{ready:Y,connected:g,connecting:m,status:L,textMode:oe,textDraft:P,textSending:Q,error:b,onTalk:y,onTextMode:S,onTextDraftChange:z,onSendText:K}):null]})}),fc=".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}",li="data-aitwin-widget-style";function ds(){if(typeof document>"u")return;const e=fc.trim();if(!e){console.warn("[AiTwinWidget] styles.css?inline resolved empty — chrome will be unstyled");return}const t=document.querySelector(`style[${li}]`);if(t){if((t.textContent??"").trim().length>0)return;t.textContent=e;return}const n=document.createElement("style");n.setAttribute(li,"1"),n.textContent=e,(document.head??document.documentElement).appendChild(n)}typeof document<"u"&&ds();const mc=h.forwardRef(function(t,n){ds();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)},speakWithReply:async(s,o)=>{const a=r.current?.getTwin();if(!a)throw new Error("AiTwinWidget: twin is not mounted");return a.speakWithReply(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 F.jsx("div",{className:i?"aitwin-widget aitwin-widget--float":"aitwin-widget",children:F.jsx(dc,{ref:r,options:t})})}),hc=new Set([".png",".jpg",".jpeg",".webp"]);function fs(e=".png"){const t=e.toLowerCase();return hc.has(t)?`source${t}`:"source.png"}function pc(e,t=Xn,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${fs(n)}`}async function gc(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 wc(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()||Ct).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 gc(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:f}=await s.read();if(c)break;a+=o.decode(f,{stream:!0});const g=a.split(`
|
|
48
|
-
`);a=
|
|
47
|
+
`;function ni(e=5){const t=new ye.Filter({glProgram:ye.GlProgram.from({vertex:Lo,fragment:Oo,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 No(e,t,n){return e>n||t>n}function Uo(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function Vo(e,t){return t!=null&&t>0?Math.floor(t):Uo(e)}function Wo(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 us(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 ri(e,t,n,r,i){const s=n?await Ji(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,f)=>{const w=ts(t,f,n),T=n?await Sa(await Bt(w,i??"")):await us(w);if(No(T.width,T.height,r))return console.info(`[PixiVisemeCompositor] Sheet ${f} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${r}; using per-cell crops.`),{mode:"cells",bitmap:T};const h=ye.Texture.from(T);return h.source.scaleMode="nearest",{mode:"full",texture:h}};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 Ho(e,t={}){const n=new ye.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(_){throw n.destroy({removeView:!1}),_}if(n.renderer.type!==ye.RendererType.WEBGL)throw n.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const r=Vo(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 ye.Sprite(ye.Texture.EMPTY),l=new ye.Sprite(ye.Texture.EMPTY);l.visible=!1,l.alpha=0;const c=new ye.Sprite(ye.Texture.EMPTY),f=new ye.Sprite(ye.Texture.EMPTY),w=new ye.Sprite(ye.Texture.EMPTY);w.visible=!1;const T=ni(5),h=ni(5);c.filters=[T],f.filters=[h],n.stage.addChild(d),n.stage.addChild(l),n.stage.addChild(c),n.stage.addChild(f),n.stage.addChild(w);let E=null,W=null,L=null,v=null,k=null,N=null,B=null,ie=842,re=1264,P=null,G=5;const Q=new Map;let te=null,le=null,ae=null;const oe=bi(()=>{Q.clear(),N=null,B=null,E=null,P=null}),ge=(_,g)=>{ie=_,re=g,n.renderer.resize(_,g),(e.width!==_||e.height!==g)&&(e.width=_,e.height=g)},ce=()=>{c.visible=!1,f.visible=!1,c.texture=ye.Texture.EMPTY,f.texture=ye.Texture.EMPTY,te=null,le=null},H=()=>{k=null,l.visible=!1,l.alpha=0},A=()=>{d.visible=!0,d.width=ie,d.height=re,d.x=0,d.y=0},q=()=>{l.width=ie,l.height=re,l.x=0,l.y=0},C=()=>{w.visible=!1,H(),E&&(d.texture=E,A())},z=()=>{k&&C()},J=_=>{if(o||i||!E){C();return}const g=Math.max(0,_);if(!W||g<=0){C();return}ce(),w.visible=!1,d.texture=E,A(),l.texture=W,q(),l.alpha=1,l.visible=!0,k={startMs:performance.now(),durationMs:g},Y()},ee=(_=performance.now())=>{if(!k)return!1;if(o||i)return z(),!1;const g=(_-k.startMs)/Math.max(1,k.durationMs);if(g>=1)return C(),Y(),!1;const S=Math.min(1,Math.max(0,g)),R=S*S*(3-2*S);return l.alpha=1-R,l.visible=!0,Y(),!0},ne=()=>{if(L){try{L.resource=null}catch{}L.destroy(),L=null}W&&(W.destroy(!1),W=null),v=null},Te=(_,g)=>{const S=_.cellByPath.get(g);if(!S||!Xi(S))return null;const R=`${_.diffBase}::${g}`;let V=Q.get(R);if(!V){const X=S.sheet??0,ue=_.sheets.get(X);if(!ue)return null;let I,$=!1;if(ue.mode==="full")I=new ye.Texture({source:ue.texture.source,frame:new ye.Rectangle(S.x,S.y,S.w,S.h)});else{const de=Wo(ue.bitmap,S);I=ye.Texture.from(de),I.source.scaleMode="nearest",$=!0}V={texture:I,ownsSource:$},Q.set(R,V)}return{texture:V.texture,cell:S}},Z=(_,g,S,R)=>{if(!R||!S)return _.visible=!1,_.texture=ye.Texture.EMPTY,!1;const V=Te(S,R);if(!V)return _.visible=!1,_.texture=ye.Texture.EMPTY,!1;const X=Qi(S.atlasMeta,V.cell);return g.setThreshold(G),_.texture=V.texture,_.x=X.x,_.y=X.y,_.width=V.cell.w,_.height=V.cell.h,_.visible=!0,!0},b=_=>{if(!_||!N)return null;const g=P??new Set(N.cellByPath.keys());return pr(_,g)??(g.has(_)?_:null)},U=_=>{w.visible=!1,C();const g=b(_.mouthPath),S=_.expressionPath&&B?wr(_.expressionPath,R=>B.cellByPath.has(R)):null;g!==te?(Z(c,T,N,g),te=g):g?c.visible=!0:c.visible=!1,S!==le?(Z(f,h,B,S),le=S):S?f.visible=!0:f.visible=!1},Y=()=>{if(!(o||i||document.hidden))try{n.render()}catch{}};return{async loadAssets(_){if(o)return{width:ie,height:re,visemePaths:[]};const g=zt();if(g&&!_)throw new Error("Encrypted assets enabled but no key provided");const S=g?await ka(await Bt(ln(),_??"")):await us(ln());E&&E.destroy(!0),E=ye.Texture.from(S),E.source.scaleMode="linear";const R=Si();N=await ri(Ti(),R,g,r,_);try{B=await ri(ki(),R,g,r,_)}catch(X){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",X),B=null}const V=Yi(N.atlasMeta,S.width,S.height);return ge(V.width,V.height),G=Tn(N.atlasMeta),T.setThreshold(G),h.setThreshold(G),P=new Set(N.cellByPath.keys()),Q.clear(),C(),ce(),Y(),{width:V.width,height:V.height,visemePaths:[...N.cellByPath.keys()]}},getVisemeAtlasPaths(){return P},drawLiveFrame(_){o||i||!E||(z(),U(_),Y())},drawIdleVideo(_,g){o||i||document.hidden||g&&!g()||_.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(k=null,ce(),w.visible=!1,E&&(d.texture=E,A()),!W||v!==_?(ne(),L=new ye.VideoSource({resource:_,autoPlay:!1,updateFPS:0}),L.autoUpdate=!1,W=new ye.Texture({source:L}),v=_):W.source.update(),l.texture=W,q(),l.alpha=1,l.visible=!0,Y())},beginIdleToSilCrossfade:J,tickIdleToSilCrossfade:ee,finishIdleToSilCrossfade:z,isIdleToSilCrossfading(){return k!=null},renderSilOnly(){o||i||!E||(ce(),C(),Y())},blitBitmap(_){o||i||(z(),ce(),ae&&(ae.destroy(!0),ae=null),ae=ye.Texture.from(_),w.texture=ae,w.visible=!0,w.x=0,w.y=0,w.width=ie,w.height=re,d.visible=!1,Y())},async compositePrefetchFrame(_){return null},renderFrame:Y,isContextLost(){return i},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",u),oe(),ne(),ae&&(ae.destroy(!0),ae=null);for(const{texture:g,ownsSource:S}of Q.values())g.destroy(S);Q.clear(),E&&(E.destroy(!0),E=null);const _=g=>{g.mode==="full"?g.texture.destroy(!0):g.bitmap.close()};if(N)for(const g of N.sheets.values())_(g);if(B)for(const g of B.sheets.values())_(g);T.destroy(!0),h.destroy(!0),n.destroy({removeView:!1},{children:!0,texture:!0})}}}const ii=-1,sn=1e5,si=new Map;async function $o(e){let t=si.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),si.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function zo(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Jn(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 ai(e,t){let n=0,r=null;const i=Tr(async(s,o)=>(await Qn(),await Xn(e,s),i.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(s){const o=await Qn(s);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,i.reset(),await co(e)},drawLiveFrame(s,o,a,u){i.enqueue(o,a,u)},async compositePrefetchFrame(s,o){try{return await oo(s)}catch{return null}},blitBitmap(s,o){Jn(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 Xn(s,{mouthPath:Rt(o),expressionPath:null})},dispose(){n+=1,i.reset()}}}function jo(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=sn;const f=Tr(async(L,v,k)=>(d.set(v,{drawKey:k.drawKey,onDisplayed:k.onDisplayed}),await E({type:"drawFrame",diffPath:L.mouthPath,expressionDiffPath:L.expressionPath,liveSeq:v},void 0,!0),!1)),w=L=>{if(L===ii){let N=-1,B;for(const[ie,re]of d)ie>=N&&(N=ie,B=re);N>=0&&d.delete(N),B?.onDisplayed?.(B.drawKey);return}const v=-L,k=d.get(v);d.delete(v),k?.onDisplayed?.(k.drawKey)},T=new Map,h=(L,v)=>{a||!r||r.postMessage(L,[])},E=(L,v,k=!1)=>{if(a)return Promise.resolve();const N=i++;return new Promise((B,ie)=>{T.set(N,{resolve:re=>B(re),reject:ie,generation:typeof L.generation=="number"?L.generation:void 0,expectRenderDone:k}),h({...L,requestId:N})})},W=(async()=>{r=await $o(n),r.onmessage=L=>{if(a)return;const v=L.data;if(v.type==="status"){t.onStatus?.(v.label);return}if(v.type==="frame"){if(v.generation<=-sn){const B=-v.generation,ie=l.get(B);l.delete(B),ie?.resolve(v.bitmap);return}const N=v.generation<0;if(!N&&v.generation!==s){v.bitmap.close();return}if(N&&!(v.generation===ii)){const ie=-v.generation;if(!f.isLatestSeq(ie)){ut()?.onWorkerStale(),v.bitmap.close();return}}if(N&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){ut()?.onWorkerStale(),v.bitmap.close();return}Jn(e,v.bitmap),v.bitmap.close(),N&&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=L=>{if(a)return;const v=L.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(L){if(a)return{width:842,height:1264};if(await W,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await E({type:"loadAssets",keyHex:L,urls:Ws(yt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return u},async renderSilOnly(){if(a||(await W,a))return;s+=1,f.reset(),d.clear(),l.forEach(({resolve:v})=>v(null)),l.clear(),c=sn;const L=s;await E({type:"cancelLiveDraws"}),await E({type:"renderSil",generation:L},void 0,!0)},drawLiveFrame(L,v,k,N){a||W.then(()=>{a||f.enqueue(v,k,N)})},compositePrefetchFrame(L,v){return a?Promise.resolve(null):W.then(()=>{if(a)return null;const k=++c;return new Promise(N=>{l.set(k,{resolve:N}),E({type:"drawFrame",diffPath:L.mouthPath,expressionDiffPath:L.expressionPath,liveSeq:k},void 0,!0).catch(()=>{l.delete(k),N(null)})})})},blitBitmap(L,v){Jn(L,v)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(L,v,k={}){if(a||(await W,a))return;s+=1,f.reset(),d.clear();const N=s;try{await E({type:"cancelLiveDraws"}),await E({type:"renderViseme",generation:N,to:v,from:k.from,transitionDurationMs:k.transitionDurationMs,gapMs:k.gapMs,threshold:k.threshold},void 0,!0)}catch(B){if(B?.name==="AbortError")return;throw B}},dispose(){if(!a){a=!0,s+=1,f.reset(),d.clear(),l.forEach(({resolve:L})=>L(null)),l.clear(),c=sn;for(const[,L]of T)L.resolve();T.clear(),r?.terminate(),r=null}}}}async function Ko(e,t){const n=await Ho(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let r=0,i=null,s=!1;const o=Tr(async(a,u)=>s?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(ut()?.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:Rt(u),expressionPath:null})},dispose(){s||(s=!0,r+=1,o.reset(),n.dispose())}}}function oi(e,t){if(!zo())return ai(e,t);const n=Ts(t.workerScriptUrl);try{return jo(e,t,n)}catch{return ai(e,t)}}function Go(e,t={}){if(t.preferLegacyRenderer)return oi(e,t);let n=null,r=!1,i=null,s=!1;const o=()=>n?Promise.resolve(n):(i||(i=(async()=>{try{const a=await Ko(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=oi(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 qo extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Vn(e,t,n){return new Promise((r,i)=>{const s=globalThis.setTimeout(()=>{i(new qo(n,t))},t);e.then(o=>{globalThis.clearTimeout(s),r(o)},o=>{globalThis.clearTimeout(s),i(o)})})}const Yo={overflow:"hidden",position:"relative",display:"inline-block",lineHeight:0},Qo={display:"block",maxWidth:"100%",height:"auto"},Xo={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 Wn(e){return pi(e)?fr:gi(e)?pn:dr}function rt(e,t){return t?.isSpeaking()||t?.isWarmingUp()?t:e.isSpeaking()||e.isWarmingUp()?e:t?.isConnected()?t:e}const ds=m.forwardRef(function({id:t,avatarId:n,faceId:r,assets:i,authToken:s,apiBase:o,ttsEngineId:a,voiceId:u,language:d,speakingRate:l=Kt,className:c,style:f,canvasStyle:w,onStatusChange:T,onDisplayStatus:h,onError:E,onReady:W,showErrorOverlay:L=!0,loadingThumbnailUrl:v,onUserTranscript:k,onBotOutput:N,onRealtimeLipsyncDebug:B,onFrameRenderStats:ie,lipsyncBufferedPlayback:re=!0,lipsyncPlaybackWarmupMs:P=1500,idleHandoffHoldMs:G=So,pixiMaxTextureSize:Q,captions:te},le){const ae=m.useRef(null),oe=m.useRef(null),ge=m.useRef(null),ce=m.useRef(re);ce.current=re;const H=m.useRef(P);H.current=P;const A=m.useRef(G);A.current=G;const q=m.useRef(0),C=m.useRef(br()),z=m.useRef(Xa()),J=m.useRef(!1),ee=m.useRef(null),ne=m.useRef(null),Te=m.useRef(0),Z=m.useRef(0),b=m.useRef(0),U=m.useRef(null),Y=m.useRef(null),_=m.useRef(!1),g=m.useRef(!1),S=m.useRef(!1),R=m.useRef(!1),V=m.useRef(!1),X=m.useRef("sil"),ue=m.useRef(0),I=m.useRef(!1),$=m.useRef(null),de=m.useRef(!1),[Re,Ft]=m.useState("idle"),[vt,_t]=m.useState(null),[ct,kn]=m.useState(!1),[p,D]=m.useState(!1),[se,fe]=m.useState(!1),[_e,xe]=m.useState(),[Pe,$e]=m.useState({width:842,height:1264}),[Ue,Gt]=m.useState(null),[En,Lt]=m.useState(0),bt=m.useRef(!1),Ne=m.useRef(s??null),qe=o?.trim()||Dt,St=m.useRef(null),Ie=m.useRef(null),{ttsEngineId:Ce,voiceId:Ye}=m.useMemo(()=>{const y=st(a,u),x=y.ttsEngineId??ht;return{ttsEngineId:x,voiceId:y.voiceId??Wn(x)}},[a,u]),Ve=m.useCallback(y=>{const x=pi(y);C.current.holdPp=x,ge.current?.setHoldPp(x)},[]),We=m.useRef(!1),Ae=m.useRef({width:842,height:1264}),Be=m.useRef(null),ze=m.useRef("sil"),tt=m.useRef(""),je=m.useMemo(()=>uo(te),[te]),He=m.useCallback(()=>{tt.current="",Gt(null)},[]);m.useEffect(()=>{je.enabled||He()},[je.enabled,He]);const Tt=m.useCallback(y=>{if(!je.enabled)return;const x=y.isSpeaking(),F=y.isWarmingUp();if(!x||F){tt.current&&He();return}const M=lo(y.getWordQueue());if(!M){tt.current&&He();return}M!==tt.current&&(tt.current=M,Gt(M))},[je.enabled,He]),kt=m.useRef(void 0),xn=m.useRef(new Map),kr=m.useRef(W),Er=m.useRef(T),ke=m.useRef(h),xr=m.useRef(E),Ir=m.useRef(k),In=m.useRef(N),qt=m.useRef(B),Ar=m.useRef(ie),Et=m.useRef(bo());kr.current=W,Er.current=T,ke.current=h,xr.current=E,Ir.current=k,In.current=N,qt.current=B,Ar.current=ie,m.useEffect(()=>{const y=Et.current;return Xr(y),()=>Xr(null)},[]);const An=m.useCallback(y=>{const x=st(y?.ttsEngineId??a,y?.voiceId??u),F=x.ttsEngineId??Ie.current?.ttsEngineId??ht,M=x.voiceId??Ie.current?.voiceId??Wn(F);return{ttsEngineId:F,voiceId:M}},[a,u]),nt=m.useCallback(y=>{_t(y),fe(!0),xr.current?.(y)},[]),Ot=m.useCallback(y=>{Ft(y),Er.current?.(y)},[]),he=m.useRef(qn(Ot,qe,{onLipsyncDebug:y=>qt.current?.(y)})),we=m.useRef(null),Yt=m.useRef(!1),Mr=m.useRef(()=>{});m.useEffect(()=>(he.current=qn(Ot,qe,{onLipsyncDebug:y=>qt.current?.(y)}),s&&he.current.setDeveloperToken(s),he.current.setTtsEngineId(Ce),he.current.setMuted(Yt.current),()=>{he.current.stop();const y=we.current;y&&(y.disconnect(),we.current=null)}),[Ot,qe]);const Rr=m.useCallback(()=>(we.current||(we.current=qi(Ot,{speakingRate:l,language:d,onUserTranscript:(y,x)=>Ir.current?.(y,x),onBotOutput:y=>In.current?.(y),onLipsyncDebug:y=>qt.current?.(y)}),we.current.setTtsEngineId(Ce),we.current.setMuted(Yt.current),Mr.current(!0)),we.current),[Ot,l,d,Ce]),Le=m.useCallback(()=>{U.current!=null&&(clearTimeout(U.current),U.current=null)},[]),Fe=m.useCallback(()=>{Y.current!=null&&(clearTimeout(Y.current),Y.current=null),S.current=!1},[]),Mn=m.useCallback(()=>{V.current=!0,Fe(),$.current?.setLooping(!1)},[Fe]),Ke=m.useCallback(()=>{V.current=!1,$.current?.setLooping(!0)},[]),Nt=m.useCallback(()=>{if(R.current)return;const y=oe.current;if(R.current=!0,V.current=!0,Fe(),_.current=!1,g.current=!1,!de.current||!$.current){y?.renderSilOnly();return}const x=$.current;x.setLooping(!1),x.setActive(!1);const F=x.getVideo();if(F.ended||Number.isFinite(F.currentTime)&&F.currentTime<=Nn){try{(F.ended||F.currentTime>Nn)&&(F.currentTime=0)}catch{}y?.renderSilOnly(),y?.finishIdleToSilCrossfade();return}if(y?.usesPixi){y.drawIdleVideo(F),y.beginIdleToSilCrossfade(Zr);return}(async()=>{const j=ae.current;j&&await On(j,F,null,void 0,Ae.current).catch(()=>{}),await new Promise(ve=>setTimeout(ve,Zr)),R.current&&await y?.renderSilOnly()})()},[Fe]),Pr=m.useCallback(()=>{if(!(!de.current||!$.current)){if(R.current=!1,oe.current?.finishIdleToSilCrossfade(),oe.current?.renderSilOnly(),Fe(),V.current){S.current=!1;return}S.current=!0,Y.current=setTimeout(()=>{if(Y.current=null,rt(he.current,we.current).isSpeaking()){S.current=!1;return}if(_.current){S.current=!1;return}if(V.current){S.current=!1;return}const y=$.current;if(!y){S.current=!1;return}Ke(),y.setLooping(!0),y.restart(),y.setActive(!0);const x=y.getVideo();let F=!1;const M=()=>{F||(F=!0,x.removeEventListener("playing",j),S.current=!1)},j=()=>{M()};if(x.addEventListener("playing",j,{once:!0}),x.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!x.paused){M();return}setTimeout(M,300)},A.current)}},[Fe,Ke]),xt=m.useCallback(()=>{if(Le(),ke.current?.("sil"),_.current=!1,R.current=!1,!de.current||!$.current){S.current=!1,Ke();return}Pr()},[Le,Pr,Ke]),Rn=m.useCallback(async y=>{const x=Z.current,F=oe.current,M=ae.current,j=()=>{y?.fallbackOnly||(_.current=!1)};if(!F||!M||!ct){j();return}if(rt(he.current,we.current).isSpeaking()){j();return}if(y?.fallbackOnly){if(!_.current||(Oe(C.current),await F.renderSilOnly(),x!==Z.current)||rt(he.current,we.current).isSpeaking())return;xt();return}if(ei(C.current)){Oe(C.current),xt();return}if(ce.current&&F.supportsBufferedPlayback&&!y?.fallbackOnly){if(Oe(C.current),ge.current?.reset(),await F.renderSilOnly(),x!==Z.current||rt(he.current,we.current).isSpeaking())return;xt();return}const be=Ao(rt(he.current,we.current).getVisemeQueue(),ue.current,X.current),De=Mo(be,Be.current);if(Oe(C.current),!De){if(await F.renderSilOnly(),x!==Z.current||rt(he.current,we.current).isSpeaking())return;xt();return}try{await F.renderViseme(M,"sil",{from:be,transitionDurationMs:os})}catch(Ee){if(Ee?.name!=="AbortError")throw Ee}if(x!==Z.current){j();return}if(rt(he.current,we.current).isSpeaking()){j();return}xt()},[ct,xt]),dt=m.useCallback(()=>{if(g.current||_.current)return;g.current=!0,_.current=!0,Le();const y=Z.current;Rn().finally(()=>{g.current=!1}),U.current=setTimeout(()=>{U.current=null,y===Z.current&&Rn({fallbackOnly:!0})},Ro())},[Le,Rn]),Cr=m.useCallback(async()=>{const y=Math.floor(Date.now()/1e3);if(St.current&&y<St.current.expiresAt-60)return St.current.key;const x=Ne.current??await an();Ne.current=x,he.current.setDeveloperToken(x);const F=await Os(x,qe);return St.current={key:F.value,expiresAt:F.expiresAt},F.value},[qe]);m.useEffect(()=>{s&&(Ne.current=s,he.current.setDeveloperToken(s))},[s]),m.useEffect(()=>{he.current.setTtsEngineId(Ce),we.current?.setTtsEngineId(Ce),Ie.current&&(Ie.current.ttsEngineId=Ce),Ve(Ce)},[Ce,Ve]),m.useEffect(()=>{Ie.current&&(Ie.current.voiceId=Ye)},[Ye]);const Qe=m.useMemo(()=>vi(n,r),[n,r]),hs=m.useMemo(()=>i?JSON.stringify(i):Qe?`face:${Qe}`:`id:${t??""}`,[i,Qe,t]),ps=m.useMemo(()=>{const y=v?.trim();return y||(Fr(Qe)??Fr(_e)??Ps(i))},[v,Qe,_e,i]);return m.useEffect(()=>{if(!t&&!i&&!Qe){nt("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let y=!1;We.current=!1,kn(!1),D(!1),fe(!1),xe(Qe),_t(null),Ie.current=null,$.current=null,de.current=!1;const x=ae.current;if(!x)return;let F=null;return(async()=>{try{let M,j,ve,be,De;if(i)M=i,j=Ce,ve=Ye;else if(Qe)ke.current?.("loadFace"),M=Kn(Qe),j=Ce,ve=Ye;else{ke.current?.("getAiTwin");const K=await Vn(wi(t),3e4,"getAiTwin");if(y)return;if(!K.faceId?.trim())throw new Error("getAiTwin returned no faceId");xe(K.faceId.trim());const Se=st(a,u);j=Se.ttsEngineId??K.ttsEngineId,ve=Se.voiceId??K.voiceId??Wn(j),be=ir(K),De=sr(K),M=Kn(K.faceId)}Ie.current={ttsEngineId:j,voiceId:ve,brainId:be,brainUrl:De},_i(M),$.current=Ja();const Ee=!!(i&&!wt(i));F=Go(x,{preferLegacyRenderer:Ee,pixiMaxTextureSize:Q,onStatus:K=>{y||ke.current?.(K)},onError:K=>{y||nt(K)},shouldAcceptLiveFrame:()=>{if(J.current)return!0;if(_.current)return!1;const K=rt(he.current,we.current);return K.isSpeaking()||K.isWarmingUp()},onWebGlContextLost:()=>{y||bt.current||(bt.current=!0,queueMicrotask(()=>{y||Lt(K=>K+1)}))}}),oe.current=F,ge.current=Fo(F),Ve(j),bt.current=!1;const Xe=K=>{const Se=()=>{if(!K||H.current<=0)return!1;const Me=oe.current;return Me?ce.current&&Me.supportsBufferedPlayback?!0:Me.usesPixi:!1};he.current.setLipsyncWarmupHold(K,Se),we.current?.setLipsyncWarmupHold(K,Se)};Mr.current=Xe,Xe(!0),ke.current?.("auth");const Qt=Ne.current??s??await Vn(an(),3e4,"getAuthToken");if(y)return;Ne.current=Qt,he.current.setDeveloperToken(Qt),he.current.setTtsEngineId(j);const pe=zt()?await Cr():void 0;if(y)return;ke.current?.("loadAssets");const me=await Vn(F.loadAssets(pe),18e4,"load face assets");if(!y&&me.width>0&&me.height>0&&(Ae.current=me,$e(me)),y)return;Be.current=F.getVisemeAtlasPaths(),We.current=!0,kn(!0),kr.current?.(),F.renderSilOnly().then(()=>{y||ke.current?.("sil")}),(async()=>{try{const K=await Ia(pe);if(await $.current.load(K),y||(de.current=!0,D(!0),Oe(C.current),await F.renderSilOnly(),y)||(await new Promise(Me=>setTimeout(Me,A.current)),y))return;$.current.setActive(!0);const Se=$.current.getVideo();F.usesPixi?F.drawIdleVideo(Se):await On(x,Se,null,void 0,Ae.current)}catch(K){if(y)return;de.current=!1,D(!1),console.warn("[AiTwin] Idle video unavailable:",K)}finally{y||(fe(!0),ke.current?.("idle"))}})()}catch(M){if(y)return;if(M instanceof on){nt(M.message);return}nt(M instanceof Error?M.message:"Failed to load AI twin")}})(),()=>{y=!0,$.current?.dispose(),F?.dispose(),oe.current=null}},[hs,i,Qe,t,Ce,Ye,a,u,s,Q,Cr,nt,En,Ve]),m.useEffect(()=>{const y={current:!1},x=()=>{const F=ae.current,M=oe.current,j=rt(he.current,we.current);if(!F||!M||!ct){Te.current=requestAnimationFrame(x);return}if(document.hidden){$.current?.setActive(!1),Te.current=requestAnimationFrame(x);return}const ve=j.isSpeaking(),be=j.isWarmingUp(),De=ve&&!I.current,Ee=I.current&&!ve;De&&(Le(),Fe(),_.current=!1,g.current=!1,Oe(C.current),ge.current?.reset(),Et.current.reset(),kt.current=void 0,b.current=0,X.current="sil",ue.current=0,Nt()),Ee&&(z.current.reset(),$.current?.setActive(!1),ge.current?.reset(),M.finishIdleToSilCrossfade(),He(),V.current=!1,dt());const Xe=Ee||_.current||S.current||R.current,Qt=re&&M.supportsBufferedPlayback;if(V.current&&!ve&&!be&&!Ee&&!_.current&&!S.current){if(R.current){M.usesPixi&&M.isIdleToSilCrossfading()&&M.tickIdleToSilCrossfade(performance.now()),I.current=ve,Te.current=requestAnimationFrame(x);return}if(de.current&&$.current){const pe=$.current.getVideo();if(pe.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){const me=pe.duration,K=pe.currentTime,Se=pe.ended||Number.isFinite(K)&&K<=Nn,Me=Number.isFinite(me)&&me>0&&Number.isFinite(K)?Math.max(0,(me-K)*1e3):Number.POSITIVE_INFINITY;if(Se||Me<=To){Nt(),M.usesPixi&&M.isIdleToSilCrossfading()&&M.tickIdleToSilCrossfade(performance.now()),I.current=ve,Te.current=requestAnimationFrame(x);return}}}}if(be){if(Nt(),de.current&&$.current?.setActive(!1),M.usesPixi&&M.isIdleToSilCrossfading()){M.tickIdleToSilCrossfade(performance.now()),j.getVisemeQueue().length>0&&q.current===0&&(q.current=performance.now()),I.current=j.isSpeaking(),Te.current=requestAnimationFrame(x);return}const pe=j.getVisemeQueue();pe.length>0&&q.current===0&&(q.current=performance.now()),z.current.advance(performance.now());const me=z.current.getExpressionPath(),K=z.current.getDrawKey(),Se={queue:pe,elapsedMs:0,expressionPath:me,expressionDrawKey:K,availablePaths:Be.current};let Me=!1;Qt&&ge.current?(ge.current.warmupTick(Se),Me=ge.current.isWarmupReady(Se,H.current)):M.usesPixi&&ti(F,pe,0,me,K,C.current,(It,Xt,Pn,Jt)=>{M.drawLiveFrame(It,Xt,Pn,Je=>{Jt?.(Je),j.isWarmingUp()&&Je!==""&&!ei({lastDrawnKey:Je})&&(q.current=0,j.releaseWarmupHold())})},It=>{ke.current?.(It.label)},Be.current);const lt=q.current>0&&performance.now()-q.current>Es;ke.current?.(Me?"buffer ready":"buffering lipsync…"),(Me||lt)&&(q.current=0,j.releaseWarmupHold()),Tt(j),I.current=j.isSpeaking(),Te.current=requestAnimationFrame(x);return}if(ve){Nt(),de.current&&$.current?.setActive(!1),M.usesPixi&&M.isIdleToSilCrossfading()&&M.finishIdleToSilCrossfade();const pe=j.getVisemeQueue(),me=j.getPlaybackElapsedMs();ma(pe,me),ue.current=me;const K=pe.length>0?jt(pe,me):"sil";K!=="sil"&&(X.current=K);const Se=no(me,j.getSentenceEmotions(),j.getWordQueue(),j.getStreamMood());z.current.setTargetEmotion(Se),z.current.setTargetEyebrow(Ya(me,j.getWordQueue(),gt(Se))),z.current.advance(performance.now());const Me=z.current.getExpressionPath(),lt=z.current.getDrawKey(),It=(Je,Cn,Ut,Dn)=>{const Dr={label:ze.current,elapsedMs:me,mouthPath:Cn.mouthPath,transitionMeta:kt.current};xn.current.set(Ut,Dr),ge.current?.markExternallyDisplayed(Ut,Me),M.drawLiveFrame(Je,Cn,Ut,Zt=>{const gs=xn.current.get(Zt)??Dr;xn.current.delete(Zt),Et.current.onDrawDisplayed(gs,pe),ge.current?.markExternallyDisplayed(Zt,Me),Dn?.(Zt)})},Xt=Je=>{ze.current=Je.label,kt.current=Je.transitionMeta,ke.current?.(Je.label)},Pn=re&&M.supportsBufferedPlayback;let Jt=!1;Pn&&ge.current&&(Jt=ge.current.tick({canvas:F,queue:pe,elapsedMs:me,expressionPath:Me,expressionDrawKey:lt,playbackState:C.current,availablePaths:Be.current,onStatus:Xt,onDisplayed:(Cn,Ut,Dn)=>{Et.current.onDrawDisplayed({label:Dn,elapsedMs:me,mouthPath:Ut,transitionMeta:kt.current},pe)}}).usedBuffer),Jt||ti(F,pe,me,Me,lt,C.current,It,Xt,Be.current),Et.current.onRafTickSpeaking(),Ar.current?.(Et.current.snapshot(pe,me))}else if(!Xe&&J.current){$.current?.setActive(!1),z.current.advance(performance.now());const pe=z.current.getExpressionPath(),me=z.current.getDrawKey();Un(F,pe,me,C.current,(K,Se,Me,lt)=>M.drawLiveFrame(K,Se,Me,lt),K=>{if(ne.current){ke.current?.(ne.current);return}const Se=z.current.getTargetEmotion();ke.current?.(K==="sil"||K==="blink"?`${Se}${K==="blink"?" · blink":""}`:K)},null,ee.current)}else if(!Xe&&de.current&&$.current){const pe=$.current,me=pe.getVideo();if(me.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){pe.setActive(!0);const K=()=>!j.isSpeaking()&&!_.current&&!S.current&&!J.current;M.usesPixi?(M.drawIdleVideo(me,K),K()&&ke.current?.("idle")):y.current||(y.current=!0,On(F,me,null,void 0,Ae.current,K).then(()=>ke.current?.("idle")).finally(()=>{y.current=!1}))}else Un(F,null,"__sil__",C.current,(K,Se,Me,lt)=>M.drawLiveFrame(K,Se,Me,lt),K=>ke.current?.(K))}else Xe||Un(F,null,"__sil__",C.current,(pe,me,K,Se)=>M.drawLiveFrame(pe,me,K,Se),pe=>ke.current?.(pe));je.enabled&&Tt(j),I.current=ve,Te.current=requestAnimationFrame(x)};return Te.current=requestAnimationFrame(x),()=>{cancelAnimationFrame(Te.current),Le(),Fe(),he.current.stop(),we.current?.stop()}},[ct,p,dt,Le,Fe,Nt,Tt,He,je.enabled]),m.useImperativeHandle(le,()=>({speakText:async(y,x)=>{const F=y.trim();if(!F)return;const M=oe.current;if(!M||!We.current&&!ct)throw new Error("AI twin is not ready");const{ttsEngineId:j,voiceId:ve}=An(x);_t(null),He(),Z.current+=1,Le(),Fe(),_.current=!1,g.current=!1,X.current="sil",ue.current=0,Oe(C.current),Ve(j),J.current=!1,ee.current=null,ne.current=null,z.current.reset(),I.current=!1,Mn(),R.current=!1,M.finishIdleToSilCrossfade();try{await he.current.speak(F,{voiceId:ve,speakingRate:x?.speakingRate??l,ttsEngineId:j,language:x?.language??d})}catch(be){throw Ke(),R.current=!1,M.finishIdleToSilCrossfade(),dt(),nt(be instanceof Error?be.message:"TTS failed"),be}},speakWithReply:async(y,x)=>{const F=y.trim();if(!F)return{displayText:"",spokenText:""};const M=oe.current;if(!M||!We.current&&!ct)throw new Error("AI twin is not ready");const{ttsEngineId:j,voiceId:ve}=An(x);_t(null),He(),Z.current+=1,Le(),Fe(),_.current=!1,g.current=!1,X.current="sil",ue.current=0,Oe(C.current),Ve(j),J.current=!1,ee.current=null,ne.current=null,z.current.reset(),I.current=!1,Mn(),R.current=!1,M.finishIdleToSilCrossfade();const be=x?.brainId?.trim()||Ie.current?.brainId?.trim()||void 0,De=x?.brainUrl?.trim()||Ie.current?.brainUrl?.trim()||void 0;try{return await he.current.speakWithReply(F,{...x,voiceId:ve,speakingRate:x?.speakingRate??l,ttsEngineId:j,language:x?.language??d,brainId:be,brainUrl:De,onDisplayText:Ee=>{x?.onDisplayText?.(Ee),In.current?.(Ee)}})}catch(Ee){throw Ke(),R.current=!1,M.finishIdleToSilCrossfade(),dt(),nt(Ee instanceof Error?Ee.message:"speakWithReply failed"),Ee}},stop:()=>{Z.current+=1,Le(),Fe(),_.current=!1,g.current=!1,R.current=!1,Ke(),oe.current?.finishIdleToSilCrossfade(),he.current.stop(),we.current?.stop(),Oe(C.current),ge.current?.reset(),q.current=0,I.current=!1,He(),dt()},setTtsEngineId:y=>{he.current.setTtsEngineId(y),we.current?.setTtsEngineId(y),Ie.current&&(Ie.current.ttsEngineId=y),Ve(y)},renderViseme:async(y,x)=>{const F=oe.current,M=ae.current;if(!F||!M||!We.current)throw new Error("AI twin is not ready");await F.renderViseme(M,y,{from:x?.from,transitionDurationMs:x?.transitionDurationMs,gapMs:x?.gapMs,onStatus:j=>ke.current?.(j)})},setEmotion:y=>{if(!We.current)throw new Error("AI twin is not ready");const x=oe.current,F=ae.current;if(!x||!F)throw new Error("AI twin is not ready");Z.current+=1,Le(),Fe(),_.current=!1,g.current=!1,S.current=!1,R.current=!1,Ke(),he.current.stop(),we.current?.stop(),Oe(C.current),ge.current?.reset(),q.current=0,I.current=!1,x.finishIdleToSilCrossfade(),$.current?.setActive(!1);const M=it(y);J.current=!0,ee.current=null,ne.current=null,z.current.snapToEmotion(M);const j=z.current.getExpressionPath(),ve=z.current.getDrawKey(),be={mouthPath:null,expressionPath:j},De=$t(be,ve);C.current.lastDrawnKey="",x.drawLiveFrame(F,be,De,Xe=>{Xe===De&&(C.current.lastDrawnKey=De)});const Ee=gt(M);ke.current?.(j?`${M} · brow ${Ee>0?"+":""}${Ee}`:`${M} · brow 0 (sil base)`)},getEmotion:()=>J.current?z.current.getTargetEmotion():null,clearEmotionPreview:()=>{J.current=!1,ee.current=null,ne.current=null,z.current.reset(),Oe(C.current),ke.current?.("idle")},setViseme:y=>{if(!We.current)throw new Error("AI twin is not ready");const x=oe.current,F=ae.current;if(!x||!F)throw new Error("AI twin is not ready");Z.current+=1,Le(),Fe(),_.current=!1,g.current=!1,S.current=!1,R.current=!1,Ke(),he.current.stop(),we.current?.stop(),Oe(C.current),ge.current?.reset(),q.current=0,I.current=!1,x.finishIdleToSilCrossfade(),$.current?.setActive(!1);const M=wn(y);J.current=!0,ne.current=M,ee.current=M==="sil"?null:Rt(M),z.current.snapToEmotion("neutral");const j=z.current.getExpressionPath(),ve=z.current.getDrawKey(),De={mouthPath:ee.current,expressionPath:j},Ee=$t(De,ve);C.current.lastDrawnKey="",x.drawLiveFrame(F,De,Ee,Xe=>{Xe===Ee&&(C.current.lastDrawnKey=Ee)}),ke.current?.(M)},getViseme:()=>J.current?ne.current:null,isReady:()=>We.current,getStatus:()=>Re,connect:async(y={})=>{_t(null);try{let x=y.authToken?.trim();x||(x=Ne.current??s??await an(),Ne.current=x);const F=st(y.ttsEngineId??a,y.voiceId??u),M=F.voiceId??Ie.current?.voiceId,j=y.brainId?.trim()||y.personaId?.trim()||Ie.current?.brainId,ve=y.brainUrl?.trim()||Ie.current?.brainUrl,be=F.ttsEngineId??Ie.current?.ttsEngineId??Ce,De=Rr();be&&De.setTtsEngineId(be),be&&Ve(be),await De.unlockAudio(),await De.connect({...y,apiBase:y.apiBase?.trim()||qe,authToken:x,voiceId:M,brainId:j,brainUrl:ve,ttsEngineId:be,speakingRate:y.speakingRate??l,language:y.language??d})}catch(x){throw Wt(x)||nt(x instanceof Error?x.message:"Voice connect failed"),x}},disconnect:async()=>{const y=we.current;y&&(Z.current+=1,Le(),Fe(),_.current=!1,g.current=!1,R.current=!1,Ke(),oe.current?.finishIdleToSilCrossfade(),Oe(C.current),ge.current?.reset(),q.current=0,I.current=!1,await y.disconnect(),dt())},isConnected:()=>we.current?.isConnected()??!1,getVoiceStream:()=>we.current?.getVoiceStream()??he.current?.getVoiceStream()??null,setMuted:y=>{Yt.current=y,he.current?.setMuted(y),we.current?.setMuted(y)},isMuted:()=>Yt.current,getBrainId:()=>Ie.current?.brainId?.trim()||null,getPersonaId:()=>Ie.current?.brainId?.trim()||null,getBrainUrl:()=>Ie.current?.brainUrl?.trim()||null}),[ct,l,d,s,Ce,Ye,Le,Fe,dt,Mn,Ke,nt,An,Rr,Ve,Re,qe]),O.jsxs("div",{className:c,style:{...Yo,...f},children:[O.jsx("canvas",{ref:ae,width:Pe.width,height:Pe.height,style:{...Qo,...w},"aria-label":t?`AI twin ${t}`:"AI twin face"}),!se&&!vt?O.jsx(vo,{thumbnailUrl:ps}):null,L&&vt?O.jsx("div",{style:Xo,children:vt}):null,je.enabled&&Ue?O.jsx(po,{text:Ue,style:je.style},Ue):null]})});function Jo({muted:e}){return e?O.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[O.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),O.jsx("path",{d:"m16 9.5 5 5m0-5-5 5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]}):O.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[O.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),O.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 Zo(){return O.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:O.jsx("path",{d:"M8 5.5v13l11-6.5L8 5.5Z"})})}function ec(){return O.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:O.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"1.5"})})}function tc(){return O.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:O.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 nc({className:e}){return O.jsx("span",{className:e??"aitwin-widget__spinner","aria-hidden":!0,children:O.jsx("svg",{viewBox:"0 0 24 24",fill:"none",children:O.jsx("circle",{cx:"12",cy:"12",r:"9",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeDasharray:"40 20"})})})}function rc({muted:e,onToggle:t}){return O.jsx("button",{type:"button",className:"aitwin-widget__mute",onClick:t,"aria-label":e?"Unmute":"Mute","aria-pressed":e,children:O.jsx(Jo,{muted:e})})}function ic(e){const t=e.connecting||e.textSending||e.status==="loading"||e.status==="speaking",n=e.connecting?"Connecting...":e.connected?"End":"Talk",r=["aitwin-widget__action",e.textMode&&!e.connecting?"":"aitwin-widget__action--primary",e.connecting?"aitwin-widget__action--connecting":""].filter(Boolean).join(" ");return O.jsxs("div",{className:"aitwin-widget__controls",children:[O.jsxs("div",{className:"aitwin-widget__actions",children:[O.jsxs("button",{type:"button",className:r,onClick:e.onTalk,disabled:!e.ready||e.connecting||e.textSending,"aria-busy":e.connecting,children:[e.connecting?O.jsx(nc,{className:"aitwin-widget__spinner aitwin-widget__spinner--on-accent"}):e.connected?O.jsx(ec,{}):O.jsx(Zo,{}),O.jsx("span",{children:n})]}),O.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:[O.jsx(tc,{}),O.jsx("span",{children:"Text"})]})]}),e.textMode?O.jsxs("form",{className:"aitwin-widget__composer",onSubmit:i=>{i.preventDefault(),e.onSendText()},children:[O.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}),O.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?O.jsx("p",{className:"aitwin-widget__controls-error",role:"alert",children:e.error}):null]})}const ci=97,sc=3500;function ac(e,t){const n=Math.max(0,e),r=1-Math.exp(-n/sc);return Math.min(ci,Math.round(r*ci))}function oc(e){const[t,n]=m.useState(null),[r,i]=m.useState(()=>Date.now());return m.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:ac(r-t):100}const cc="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 lc({className:e="aitwin-widget__logo",strokeWidth:t=15,durationMs:n=2600,delayMs:r=0,loop:i=!1}){return O.jsx("svg",{viewBox:"0 0 1080 1080",className:e,role:"img","aria-label":"AITWIN logo",children:O.jsx("path",{className:i?"aitwin-widget__logo-draw aitwin-widget__logo-draw--loop":"aitwin-widget__logo-draw",d:cc,fill:"none",stroke:"currentColor",strokeWidth:t,strokeMiterlimit:10,pathLength:1,style:{animationDuration:`${n}ms`,animationDelay:`${r}ms`}})})}function uc({progress:e}){const t=Math.max(0,Math.min(100,Math.round(e)));return O.jsx("div",{className:"aitwin-widget__face-loading","aria-live":"polite","aria-label":`Loading ${t} percent`,children:O.jsxs("div",{className:"aitwin-widget__face-loading-content",children:[O.jsx(lc,{className:"aitwin-widget__logo",loop:!0,durationMs:2600}),O.jsxs("div",{className:"aitwin-widget__face-loading-bar-wrap",children:[O.jsx("div",{role:"progressbar","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":100,className:"aitwin-widget__face-loading-track",children:O.jsx("div",{className:"aitwin-widget__face-loading-fill",style:{width:`${t}%`}})}),O.jsxs("p",{className:"aitwin-widget__face-loading-pct",children:[t,"%"]})]})]})})}function li(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 dc(e){return[e.id??"",e.faceId??"",e.authToken?.slice(0,16)??"",e.voiceId??"",e.apiBase??"",String(e.speakingRate??"")].join("|")}const ui={display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",lineHeight:0},fc={display:"block",height:"100%",width:"100%",objectFit:"cover",objectPosition:"top"},mc=m.forwardRef(function({options:t},n){const r=m.useRef(null),i=m.useRef(t);i.current={...i.current,onReady:t.onReady,onStatusChange:t.onStatusChange,onError:t.onError,onUserTranscript:t.onUserTranscript,onBotOutput:t.onBotOutput};const[s,o]=m.useState(!!t.showControls),[a,u]=m.useState(()=>li(t)),[d,l]=m.useState(!1),[c,f]=m.useState(!1),[w,T]=m.useState(!1),[h,E]=m.useState(!1),[W,L]=m.useState("idle"),[v,k]=m.useState(null),[N,B]=m.useState(!1),[ie,re]=m.useState(!1),[P,G]=m.useState(""),[Q,te]=m.useState(!1),[le,ae]=m.useState([]),[oe,ge]=m.useState(t.brainId?.trim()||t.personaId?.trim()||void 0),[ce,H]=m.useState(t.brainUrl?.trim()||void 0),A=m.useCallback(I=>{i.current={...i.current,...I},I.showControls!==void 0&&o(!!I.showControls),(I.brainId!==void 0||I.personaId!==void 0)&&ge((I.brainId??I.personaId)?.trim()||void 0),I.brainUrl!==void 0&&H(I.brainUrl.trim()||void 0),u($=>li({id:I.id??$.id,faceId:I.faceId??I.avatarId??$.faceId,authToken:I.authToken??$.authToken,apiBase:I.apiBase??$.apiBase,voiceId:I.voiceId??$.voiceId,speakingRate:I.speakingRate??$.speakingRate,language:I.language??$.language}))},[]);m.useImperativeHandle(n,()=>({getTwin:()=>r.current,applyOptions:A}),[A]),m.useEffect(()=>{A(t)},[A,t.id,t.faceId,t.avatarId,t.authToken,t.apiBase,t.voiceId,t.speakingRate,t.showControls,t.brainId,t.personaId,t.brainUrl]);const q=m.useCallback(()=>{l(!0),k(null)},[]),C=m.useCallback(I=>{I==="idle"&&f(!0)},[]),z=m.useCallback(I=>{L(I),i.current.onStatusChange?.(I)},[]),J=m.useRef(!1);J.current=d&&c;const ee=m.useCallback(I=>{if(E(!1),Wt(I)){re(!0),k(null);return}k(I),J.current||(l(!1),f(!1)),i.current.onError?.(I)},[]),ne=m.useCallback((I,$)=>{i.current.onUserTranscript?.(I,$)},[]),Te=m.useCallback(I=>{i.current.onBotOutput?.(I)},[]);m.useEffect(()=>{if(!s)return;const I=window.setInterval(()=>{T(!!r.current?.isConnected())},400);return()=>window.clearInterval(I)},[s,a]);const Z=dc(a),b=!!(a.id||a.faceId),U=d&&c,Y=b&&!U&&!v,_=oc(Y),g=m.useRef(Z);m.useEffect(()=>{U&&i.current.onReady?.()},[U]),m.useEffect(()=>{U&&r.current?.setMuted(N)},[U,N,a]),m.useEffect(()=>{ae([])},[a.id,a.faceId]),m.useEffect(()=>{g.current!==Z&&(g.current=Z,l(!1),f(!1),k(null),E(!1),T(!1),L("idle"))},[Z]);const S=m.useCallback(()=>{re(!0),k(null),E(!1),T(!1)},[]),R=()=>{const I=r.current;if(!I?.isReady())return;if(k(null),I.isConnected()){E(!1),re(!1),I.disconnect().finally(()=>{T(!1)});return}E(!0);const $={authToken:a.authToken,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language,apiBase:a.apiBase,...oe?{brainId:oe}:{},...ce?{brainUrl:ce}:{}};(async()=>{if(await pa()){S();return}re(!1);try{await I.connect($),T(!!I.isConnected())}catch(de){if(Wt(de)){S();return}const Re=de instanceof Error?de.message:"Failed to connect voice.";k(Re),i.current.onError?.(Re)}finally{E(!1)}})()},V=()=>{re(I=>!I),k(null)},X=()=>{const I=P.trim(),$=r.current;!I||!$?.isReady()||Q||(k(null),G(""),te(!0),i.current.onUserTranscript?.(I,!0),(async()=>{try{const de=oe||$.getBrainId()?.trim()||void 0,Re=ce||$.getBrainUrl()?.trim()||void 0,Ft=await $.speakWithReply(I,{brainId:de,brainUrl:Re,history:le,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language});Ft.displayText&&ae(vt=>[...vt,{role:"user",content:I},{role:"assistant",content:Ft.displayText}])}catch(de){const Re=de instanceof Error?de.message:"Failed to get reply.";k(Re),i.current.onError?.(Re)}finally{te(!1)}})())},ue=()=>{const I=!N;B(I),r.current?.setMuted(I)};return O.jsxs("div",{className:"aitwin-widget__layout",children:[O.jsxs("div",{className:"aitwin-widget__stage",children:[b?O.jsx("div",{style:ui,children:O.jsx(ds,{ref:r,id:a.id,faceId:a.faceId,authToken:a.authToken,apiBase:a.apiBase,voiceId:a.voiceId,speakingRate:a.speakingRate,language:a.language,style:ui,canvasStyle:fc,onReady:q,onDisplayStatus:C,onStatusChange:z,onError:ee,onUserTranscript:ne,onBotOutput:Te,loadingThumbnailUrl:t.loadingThumbnailUrl},Z)}):O.jsx("p",{className:"aitwin-widget__hint",style:{padding:16},children:"Pass id or faceId to load a twin."}),Y?O.jsx(uc,{progress:_}):null,s?O.jsx(rc,{muted:N,onToggle:ue}):null]}),s?O.jsx(ic,{ready:U,connected:w,connecting:h,status:W,textMode:ie,textDraft:P,textSending:Q,error:v,onTalk:R,onTextMode:V,onTextDraftChange:G,onSendText:X}):null]})}),hc=".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(32px * 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--on-accent{color:#fff}@keyframes aitwin-widget-spin{to{transform:rotate(360deg)}}.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}",di="data-aitwin-widget-style";function fs(){if(typeof document>"u")return;const e=hc.trim();if(!e){console.warn("[AiTwinWidget] styles.css?inline resolved empty — chrome will be unstyled");return}const t=document.querySelector(`style[${di}]`);if(t){if((t.textContent??"").trim().length>0)return;t.textContent=e;return}const n=document.createElement("style");n.setAttribute(di,"1"),n.textContent=e,(document.head??document.documentElement).appendChild(n)}typeof document<"u"&&fs();const pc=m.forwardRef(function(t,n){fs();const r=m.useRef(null);m.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)},speakWithReply:async(s,o)=>{const a=r.current?.getTwin();if(!a)throw new Error("AiTwinWidget: twin is not mounted");return a.speakWithReply(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 O.jsx("div",{className:i?"aitwin-widget aitwin-widget--float":"aitwin-widget",children:O.jsx(mc,{ref:r,options:t})})}),gc=new Set([".png",".jpg",".jpeg",".webp"]);function ms(e=".png"){const t=e.toLowerCase();return gc.has(t)?`source${t}`:"source.png"}function wc(e,t=er,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${ms(n)}`}async function yc(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 vc(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()||Dt).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 yc(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:f}=await s.read();if(c)break;a+=o.decode(f,{stream:!0});const w=a.split(`
|
|
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 h=T.slice(6).trim();if(!h)continue;let E;try{E=JSON.parse(h)}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()}}exports.AI_TWIN_THUMBNAIL_FILENAME=ar;exports.AiTwin=ds;exports.AiTwinNotFoundError=on;exports.AiTwinWidget=pc;exports.CONSONANT_SKIP_GROUP=Ci;exports.DEFAULT_TTS_ENGINE_ID=ht;exports.DEFAULT_TTS_LANGUAGE=Ks;exports.EMOTION_TO_EYEBROW=ns;exports.EXPRESSION_ATLAS_EMOTIONS=Va;exports.MIC_SAMPLE_RATE=mr;exports.OCULUS_VISEME_IDS=Ai;exports.PLAYBACK_SAMPLE_RATE=hr;exports.SPEAKING_RATE_MAX=Sn;exports.SPEAKING_RATE_MIN=bn;exports.TTS_ENGINE_CARTESIA=at;exports.TTS_ENGINE_GOOGLE=nr;exports.TTS_ENGINE_INWORLD=hn;exports.TTS_ENGINE_VISEMETTS=ot;exports.TTS_LANGUAGE_CATALOG=pt;exports.TTS_LANGUAGE_CODES=Ei;exports.VISEME_IDS=Aa;exports.VISEME_SKIP_GAP_MS=Gn;exports.VISEME_TEST_CARTESIA_VOICE_ID=fr;exports.VISEME_TEST_SPEAKING_RATE=Kt;exports.VISEME_TEST_VISEMETTS_VOICE_ID=pn;exports.VISEME_TEST_VOICE_ID=dr;exports.VISEME_VTIME_GRID_MS=or;exports.VOWEL_SKIP_GROUP=Pi;exports.aiTwinSourceFilename=ms;exports.buildPlaybackTransitions=Ui;exports.buildPlaybackVisemeSeries=vn;exports.buildRawVisemeTransitions=Ni;exports.buildVoiceWebSocketUrl=Gi;exports.compactSkippableVisemes=lr;exports.createAvatarTtsLipsyncController=qn;exports.createRealtimeVoiceLipsyncController=qi;exports.emotionToEyebrow=gt;exports.faceAssetUrls=Kn;exports.fetchAiTwin=wi;exports.fetchAvatarReply=vc;exports.fetchDevAuthToken=an;exports.getAiTwinSourceUrl=wc;exports.getAiTwinThumbnailUrl=yi;exports.isTtsLanguageCode=xi;exports.isTtsLanguageSupported=qs;exports.listSkippedVisemeEntries=_n;exports.listSkippedVisemes=sa;exports.normalizeOculusViseme=wn;exports.normalizeStreamEmotion=it;exports.normalizeTtsLanguage=gn;exports.parsePackedVoiceId=mi;exports.parseTwinBrainUrl=Rs;exports.resolveDirectFaceId=vi;exports.resolveTwinBrainId=ir;exports.resolveTwinBrainUrl=sr;exports.resolveVisemeAtTime=jt;exports.resolveVisemeFromPlaybackSeries=Fi;exports.resolveWordAtTime=ha;exports.setActiveTwinAssets=_i;exports.snapVisemeQueueToGrid=cr;exports.snapVisemeVtimeToGrid=Di;exports.splitVoiceIdSpec=st;exports.ttsLanguagesForEngine=Gs;
|