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