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