@streamoji/aitwin 0.6.8 → 0.7.0

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