@streamoji/aitwin 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/aitwin.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const sr=require("react/jsx-runtime"),b=require("react"),cs=require("@pipecat-ai/client-js"),vr=require("@pipecat-ai/websocket-transport"),ne=require("pixi.js");var ir=typeof document<"u"?document.currentScript:null;const us="https://aitwin.bubu.social",pn={publicBase:us},ls="0.5.0",fs={version:ls},ds={},kt="https://ai.aitwin.me",br=`${pn.publicBase}/custom-faces`,ms=`${pn.publicBase}/aitwin-workers/v${fs.version}/visemeDiffPreview.worker.js`;function hs(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:ir&&ir.tagName.toUpperCase()==="SCRIPT"&&ir.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?ds?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():ms}const ps="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",ar=3e3,vt=16,qr=3e3,ws=4e3,gs=.85,ys=8,Tr=400,kr="eng_a7f2b9c1",jt="eng_d4e8f3a2",tt="eng_c9b1e6d4",Ze=tt,wn=new Set([jt,tt]),gn={[kr]:"oculus_direct",[tt]:"oculus_direct",[jt]:"inworld_word"},Gr={google:kr,inworld:jt,cartesia:tt};function _s(e){return gn[e]}function Ss(e){return e===tt}function vs(e){if(e.ttsEngineId&&e.ttsEngineId in gn)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Gr?Gr[t]:Ze}class Wt extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function yn(e,t=ps){const r=new URL(t);r.searchParams.set("id",e);const n=await fetch(r.toString());if(n.status===404)throw new Wt;if(!n.ok)throw new Error(`getAiTwin failed (${n.status})`);const s=await n.json();if(!s.success)throw new Wt(s.error??"AI twin not found");const{tts:i,token:o,...a}=s.data,u=String(a.authToken??o??"").trim()||void 0;return{...a,ttsEngineId:vs(s.data),authToken:u}}const bs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Ts="client_6TNvp3SCs4Og0a1ijm9TommXLql1",ks="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Es="6TNvp3SCs4Og0a1ijm9TommXLql1",Is="Swaraj Mali";async function Vt(){const e=await fetch(bs,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Ts,"Client-Secret":ks},body:JSON.stringify({userId:Es,userName:Is})});if(!e.ok)throw new Error(`getAuthToken failed (${e.status})`);const t=await e.json(),r=t.authToken??t.token??"";if(!r.trim())throw new Error("getAuthToken returned no token");return r}async function As(e,t=kt){const r=await fetch(`${t.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${e}`}});if(!r.ok)throw new Error(`/api/session-value failed (${r.status})`);const n=await r.json();if(!n.value)throw new Error("Session value response missing value");return n}function Ps(e){const t=e.trim();if(t.length%2!==0)throw new Error("Invalid hex key");const r=new Uint8Array(t.length/2);for(let n=0;n<t.length;n+=2)r[n/2]=Number.parseInt(t.slice(n,n+2),16);return r}function Ft(e){return Uint8Array.from(e)}function xs(e,t){const r=new Uint8Array(e.length+t.length);return r.set(e,0),r.set(t,e.length),r}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 r=new Uint8Array(e),n=Ft(r.subarray(0,12)),s=Ft(r.subarray(12,28)),i=Ft(r.subarray(28)),o=Ft(xs(i,s)),a=await crypto.subtle.importKey("raw",Ps(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:n,tagLength:128},a,o)}let dr=null;const mr=new Set;function Lt(e){return e.includes("/custom-faces/")}function $t(e){const t=e.binBase.trim().replace(/\/$/,""),r=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||Lt(t)||Lt(r)))return{twinBase:r,binBase:t,encrypted:!1};const s=Lt(t)?t:Lt(r)?r:t;return{twinBase:s,binBase:s,encrypted:!0}}function rt(e){return $t(e).encrypted}function hr(e,t=br){const r=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:r,binBase:r,encrypted:!0}}function _n(e,t){return(e??t)?.trim()||void 0}function Sn(e){dr=$t(e);for(const t of mr)t()}function Ms(e,t){const r=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!r)return $t(e);const n=s=>{try{return new URL(s,r).href.replace(/\/$/,"")}catch{return s}};return $t({twinBase:n(e.twinBase),binBase:n(e.binBase),encrypted:e.encrypted})}function nt(){if(!dr)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return dr}function vn(e){return mr.add(e),()=>mr.delete(e)}function Ht(){const e=nt();return rt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Cs(){const e=nt();return rt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function bn(){const e=nt();return rt(e)?e.binBase:e.twinBase}function Et(){return rt(nt())}function Tn(){const e=nt();return rt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function kn(){const e=nt();return rt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function En(e){const t=e.split(/\r?\n/);let r="",n="";for(const i of t)i.startsWith("event:")?r=i.slice(6).trim():i.startsWith("data:")&&(n=i.slice(5).trim());if(!r)return null;let s={};if(n)try{s=JSON.parse(n)}catch{s={raw:n}}return{event:r,data:s}}const In=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],Ds=new Map(In.map(e=>[e.toLowerCase(),e]));function An(e){const t=(e??"").trim();return t?Ds.get(t.toLowerCase())??"sil":"sil"}const Bs={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 Fs(e){if(!e)return["sil"];const t=e.toLowerCase();return Bs[t]??["sil"]}function Ls(e,t){const r=e.word.length;if(r<=0)return 0;const n=e.wduration;if(n<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/n));return Math.min(r-1,Math.floor(s*r))}function dt(e,t){const r=Math.max(0,Math.min(e.length-1,t));return e[r]??""}function Er(e,t){const r=e.toLowerCase().replace(/[^a-z']/g,"");return!r||dt(r,t)!=="w"||t>0&&dt(r,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(r)}function Os(e,t){const r=e.toLowerCase(),n=dt(r,t),s=r.slice(Math.max(0,t-1),t+2);return n==="i"||n==="y"?"I":s.includes("ee")||n==="e"||r.includes("ea")?"E":"aa"}function Ns(e,t){const r=e.toLowerCase(),n=r.slice(Math.max(0,t-1),Math.min(r.length,t+3));if(/oo|ou|uw/.test(n))return"U";if(Er(r,t))return"FF";const s=dt(r,t);return s==="u"||s==="w"?"U":"O"}function Us(e,t){const r=e.toLowerCase();if(Er(r,t))return"FF";const n=r.slice(Math.max(0,t-2),t+1);if(/qu/.test(n))return"U";const s=r.slice(Math.max(0,t-1),Math.min(r.length,t+3));return/wo|wh/.test(s)||dt(r,t)==="o"?"O":"U"}const Ot={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function Vs(e,t){const r=e.toLowerCase(),n=dt(r,t);if(Ot[n])return Ot[n];for(let s=0;s<r.length;s++){const i=r[s];if(Ot[i])return Ot[i]}return"DD"}function Ws(e,t,r){const n=Fs(e);if(n.length===1)return n[0];const s=t.trim();if(!s)return n[0];const i=(e??"").toLowerCase(),o=Math.max(0,r);switch(i){case"aei":return Os(s,o);case"o":return Ns(s,o);case"qw":return Us(s,o);case"cdgknstxyz":return Vs(s,o);default:return n[0]}}const pr=35,Pn=new Set(["aa","E","I"]),xn=new Set(["DD","SS","kk","CH"]),$s=[Pn,xn];function Hs(e){for(const t of $s)if(t.has(e))return t;return null}function Ks(e){return Hs(e)!=null}function Rn(e){const t=new Map;for(const r of e)t.has(r.vtime)||t.set(r.vtime,r);return[...t.values()].sort((r,n)=>r.vtime-n.vtime)}function Ir(e){if(e.length<=2)return[...e];const t=[e[0]];for(let r=1;r<e.length-1;r++){const n=e[r],s=e[r+1],i=t[t.length-1];if(!Ks(n.viseme)){t.push(n);continue}const o=n.vtime-i.vtime,a=s.vtime-n.vtime;o<pr||a<pr||t.push(n)}return t.push(e[e.length-1]),t}function Yt(e){return Ir(Rn(e))}function Mn(e,t){let r="sil";for(const n of e){if(n.vtime>t)break;n.viseme!=="sil"&&(r=n.viseme)}return r}function qs(e){const t=Rn(e),r=Ir(t),n=new Set(r.map(i=>i.vtime)),s=[];for(const i of t)n.has(i.vtime)||s.push(i.viseme);return s}const Gs=32,zr=48;function Cn(e){let t=0;for(const r of e)t=Math.max(t,r.vtime+r.vduration);return t}function Dn(e){let t=null,r=-1;for(const n of e){if(n.viseme==="sil")continue;const s=n.vtime+n.vduration;s>r&&(t=n,r=s)}return t}function zs(e){return Yt(e).find(r=>r.viseme!=="sil")??null}function Je(e){const t=Cn(e);return Dn(e)?t+Tr:t}function js(e){const t=[],r=zs(e);r&&r.vtime>0&&t.push({from:"sil",to:r.viseme,fromVtime:0,toVtime:r.vtime});const n=Dn(e),s=Cn(e);return n&&t.push({from:n.viseme,to:"sil",fromVtime:s,toVtime:s+Tr}),t}function Bn(e){const t=Yt(e),r=[];for(let n=0;n<t.length-1;n++){const s=t[n].viseme,i=t[n+1].viseme,o=t[n].vtime,a=t[n+1].vtime;s===i||a<=o||r.push({from:s,to:i,fromVtime:o,toVtime:a})}return r}function Fn(e){return e.length===0?[]:[...js(e),...Bn(e)]}function Ys(e,t){let r=null;for(const n of e){const{transStart:s,transEnd:i}=Ln(n.fromVtime,n.toVtime,n.from,n.to);t>=s&&t<i&&(r=n)}return r}function Ln(e,t,r,n){const s=Math.max(0,t-e);if((r==="PP"||n==="PP")&&s>zr){const f=zr,l=t,c=l-f;return{gapMs:s,effectiveGapMs:f,holdEnd:c,transStart:c,transEnd:l}}const o=s>0?Math.max(s,Gs):0,a=e,u=e+o;return{gapMs:s,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:u}}const Ar=16e3;function On(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Ar}function Xs(e){let t=e.trim();const r=t.indexOf(",");t.startsWith("data:")&&r>=0&&(t=t.slice(r+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const n=t.length%4;return n!==0&&(t+="=".repeat(4-n)),t}function Js(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function jr(e,t,r=Ar){const n=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(n.buffer,n.byteOffset,n.byteLength/2),i=new Float32Array(s.length);for(let a=0;a<s.length;a++)i[a]=s[a]>=32768?-(65536-s[a])/32768:s[a]/32767;const o=e.createBuffer(1,i.length,r);return o.copyToChannel(i,0),o}function Qs(e){const t=Xs(e),r=window.atob(t),n=new Uint8Array(r.length);for(let s=0;s<r.length;s++)n[s]=r.charCodeAt(s);return n}async function Yr(e,t,r=Ar){const n=Qs(t),s=On(r);if(Js(n)){const i=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return e.decodeAudioData(i)}if(n.length>=2&&n.length%2===0)return jr(e,n,s);try{const i=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(i)}catch{return jr(e,n,s)}}function Zs(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function Nn(e,t){const r=[],n=[];let s=null,i=!1,o=!1,a=!1,u=!1,f=0,l=0,c=0,d=null,w=1,T=t,h=!1,A=null,v=0,R=!1,g=!1,k=0,F=null,D=null,Y=null;const O=()=>({visemes:[],words:[],segmentOffsetMs:0}),E=()=>{g=!1,k=0},P=()=>{d!=null&&(clearTimeout(d),d=null)},M=()=>{for(const y of n){try{y.onended=null,y.stop(0)}catch{}try{y.disconnect()}catch{}}n.length=0},B=()=>{for(const y of n)y.playbackRate.value=w},ee=()=>{if(!(h||!u||i||g||n.length>0||r.length>0)){if(a&&s&&l>0){const y=(s.currentTime-l)*1e3;if(y<v){P();const I=w>0?(v-y)/w:v-y;d=setTimeout(()=>{h||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,I));return}}o=!1,P(),e.onSpeakingDone(),e.onNotify()}},V=y=>{const I=Je(y);if(I<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,f=performance.now(),e.onSpeakingStart(),e.onNotify(),P();const U=w>0?I/w:I;d=setTimeout(()=>{h||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},U)},te=(y,I,U,G)=>{I.length!==0&&(c=U,I.forEach($=>{const p=String($.word??"").trim();if(!p)return;const S=Math.round(($.start??0)*1e3),C=$.duration!=null?Math.round($.duration*1e3):$.end!=null?Math.max(1,Math.round(($.end-($.start??0))*1e3)):0;y.push({word:p,wtime:c+S,wduration:C,queueIndex:y.length,gesture:$.gesture??null,emphasis:$.emphasis===!0})}))},X=(y,I,U,G,$,H)=>{U.length!==0&&(c=G,U.forEach(p=>{const S=String(p.symbol??p.viseme??"").trim();if(!S)return;const C=Math.round((p.start??0)*1e3),le=Math.max(1,Math.round((p.duration??0)*1e3)),oe=c+C,pe=Zs(I,oe),ye=pe?Ls(pe,oe):0;let ve;_s(H)==="oculus_direct"?(ve=An(S),ve==="U"&&pe&&Er(pe.word,ye)&&(ve="FF")):ve=Ws(S,pe?.word??"",ye),y.push({viseme:ve,weight:1,vtime:oe,vduration:le})}),e.onNotify())},z=(y,I,U,G,$,H,p)=>{te(I,G,$),X(y,I,U,$,H,p)},me=(y,I,U)=>{Y===y&&y.visemes===I||(I.length=0,U.length=0,y.visemes=I,y.words=U,y.segmentOffsetMs=0,Y=y,c=0,v=0)},ae=async()=>{const y=window.AudioContext||window.webkitAudioContext;return s||(s=new y),s.state==="suspended"&&await s.resume(),A||(A=s.createMediaStreamDestination()),s},Q=(y,I)=>{if(!s)return 0;const U=s,G=U.currentTime,$=G+.02;if(I.isFirstAudio){l<=0&&(l=$);const p=($-G)*1e3;f=performance.now()+p}I.onBeforeStart?.($);const H=U.createBufferSource();return H.buffer=y,H.playbackRate.value=w,H.connect(U.destination),A&&H.connect(A),n.push(H),h?(n.pop(),$):(I.isFirstAudio&&(o=!0,e.onSpeakingStart()),H.onended=()=>{const p=n.indexOf(H);p>=0&&n.splice(p,1),e.onNotify(),!h&&(F&&D?de(F,D):ee())},H.start($),$)},de=async(y,I)=>{if(h||i||n.length>0)return;if(r.length===0){ee();return}i=!0;let U=!1;try{const G=await ae();if(h)return;const $=r[0];if(!$)return;const H=!o;if(R&&(e.shouldHoldForWarmup?.()??!1)&&(g||H&&$.newStream)||g){me($.utterance,y,I);for(const C of r){if(h)return;C.audioBuffer||(C.audioBuffer=await Yr(G,C.audio,C.sampleRate)),a=!0,g||(g=!0,k=0,C.newStream&&C.onNewStream?.()),C.visemesQueued||(z(y,I,C.visemes,C.words,k,!0,T),C.visemesQueued=!0,k+=Math.round(C.audioBuffer.duration*1e3),v=Math.max(v,Je(y)))}e.onNotify();return}const S=r.shift();if(!S||(S.audioBuffer||(S.audioBuffer=await Yr(G,S.audio,S.sampleRate)),h))return;a=!0,P(),me(S.utterance,y,I),S.visemesQueued=!1,S.newStream&&S.onNewStream?.(),Q(S.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:C=>{l=C,c=0,f=performance.now()+(C-G.currentTime)*1e3,z(y,I,S.visemes,S.words,0,!0,T),S.visemesQueued=!0,S.utterance.segmentOffsetMs=0}}),U=n.length>0,v=Je(y),e.onNotify()}catch(G){console.error("[avatarChunkPlayback] audio chunk failed:",G)}finally{if(i=!1,h)return;if(g){r.some($=>!$.audioBuffer||!$.visemesQueued)&&de(y,I);return}!U&&n.length===0&&r.length>0?de(y,I):n.length===0&&r.length===0&&ee()}};return{setStreamTtsEngineId:y=>{T=y},setPlaybackSpeed:y=>{w=Math.max(.1,Math.min(1,y)),B()},getPlaybackSpeed:()=>w,setLipsyncWarmupHoldEnabled:y=>{R=y,y||E()},isWarmingUp:()=>g,releaseWarmupHold:()=>{if(g){g=!1,k=0;for(const y of r)y.newStream=!1;F&&D&&de(F,D),e.onNotify()}},resetForNewStream:y=>{h=!1,u=!1,T=y,v=0},resumeBotStream:()=>{h=!1,u=!1},clearAborted:()=>{h=!1},primeAudioContext:async()=>{const y=window.AudioContext||window.webkitAudioContext;s||(s=new y),s.state==="suspended"&&await s.resume(),s&&!A&&(A=s.createMediaStreamDestination())},stop:()=>{h=!0,P(),M(),r.length=0,i=!1,o=!1,a=!1,u=!1,c=0,l=0,f=0,v=0,F=null,D=null,Y=null,E()},markStreamComplete:y=>{if(v=Math.max(v,Je(y)),u=!0,!a&&y.length>0){V(y);return}ee()},playAudioChunk:async(y,I,U,G,$,H,p)=>{if(h)return;F=y,D=I;const S=On(p?.sampleRate),C=p?.newStream===!0,le=O();if(!U?.trim()){if(G.length===0&&$.length===0)return;me(le,y,I),C&&p?.onNewStream?.(),z(y,I,G,$,0,!0,T),v=Je(y),!o&&v>0&&V(y),e.onNotify();return}r.push({audio:U,audioBuffer:null,utterance:le,visemes:G,words:$,isNewSegment:H,sampleRate:S,newStream:C,onNewStream:p?.onNewStream,visemesQueued:!1}),await de(y,I)},queueTimingsOnly:(y,I,U,G,$)=>{if(h)return;const H=O();me(H,y,I),z(y,I,U,G,0,!0,T),H.segmentOffsetMs=0,v=Je(y)},getPlaybackElapsedMs:()=>a&&s&&l>0?Math.max(0,(s.currentTime-l)*1e3):o?Math.max(0,(performance.now()-f)*w):0,isSpeaking:()=>o?!0:!a||!s||l<=0?!1:(s.currentTime-l)*1e3<v,getVoiceStream:()=>A?A.stream:null,getPlaybackStartPerf:()=>f,bargeIn:()=>{h=!0,u=!1,P(),M(),r.length=0,i=!1,o=!1,a=!1,c=0,l=0,f=0,v=0,F=null,D=null,Y=null,E()},interrupt:()=>{h=!0,u=!1,P(),M(),r.length=0,i=!1,o=!1,a=!1,c=0,l=0,f=0,v=0,F=null,D=null,Y=null,E()}}}function It(e,t){let r=null;for(const n of e)t<n.vtime||t>=n.vtime+n.vduration||(!r||n.vtime>=r.vtime)&&(r=n);return r?r.viseme:"sil"}function Un(e,t,r=120){const n=It(e,t);if(n!=="sil")return n;let s=null;for(const i of e){if(i.vtime>t)break;const o=i.vtime+i.vduration;o<=t&&t-o<=r&&(s=i)}return s?.viseme??"sil"}function ei(e,t,r=400){const n=t-r;let s=0;for(const i of e)if(i.vtime+i.vduration<n)s+=1;else break;s>0&&e.splice(0,s)}function ti(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function ri(e,t){const r=e.trim();if(!r)return null;try{const n=r.replace(/\s+/g,""),s=atob(n).length,i=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return s/2/i*1e3}catch{return null}}const Xt=.5,Jt=1.5,Pr="Olivia",xr="f786b574-daa5-4673-aa0c-cbe3e8534c02",At=.85;function wr(e,t=kt,r={}){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,s=[],i=[],o=[],a=[];let u="",f="neutral",l="",c=Ze;const d=new Set;let w=0,T=null;const h=()=>d.forEach(O=>O());let A=()=>!1;const v=Nn({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:h,shouldHoldForWarmup:()=>A()},Ze),R=()=>v.getPlaybackElapsedMs(),g=(O,E=u)=>{if(!r.onLipsyncDebug)return;const P=R(),M=s;r.onLipsyncDebug({event:O,spokenText:E,mood:f,playbackAnchorPerf:v.getPlaybackStartPerf(),playbackElapsedMs:P,queueLength:M.length,activeViseme:It(M,P),segments:a.map(B=>({...B,visemes:[...B.visemes]}))})},k=(O,E)=>{r.onLipsyncDebug&&(T={event:O,spokenText:E},w===0&&(w=requestAnimationFrame(()=>{w=0;const P=T;T=null,P&&g(P.event,P.spokenText)})))},F=(O,E,P,M,B)=>{if(!r.onLipsyncDebug)return;const ee=s.slice(E),V=P.filter(te=>String(te.symbol??te.viseme??"").trim());a.push({spokenText:O,audioOffsetMs:ee[0]?.vtime??0,isNewSegment:M,chunkDurationMs:B,receivedAtMs:performance.now(),visemes:ee.map((te,X)=>{const z=V[X];return{rawSymbol:String(z?.symbol??z?.viseme??te.viseme).trim(),viseme:te.viseme,startSec:Number(z?.start??0),durationSec:Number(z?.duration??0),vtimeMs:te.vtime,vdurationMs:te.vduration}})})},D=()=>{v.stop(),s.length=0,i.length=0,o.length=0,f="neutral",a.length=0,u="",e("idle"),k("reset"),h()};return{setDeveloperToken:O=>{l=O},setTtsEngineId:O=>{c=O},getTtsEngineId:()=>c,speak:async(O,E)=>{D(),e("loading"),u=O,a.length=0;const P=l.trim();if(!P)throw new Error("Developer token required for avatar_ttsWithPoses");const M=E?.ttsEngineId??c??Ze;v.resetForNewStream(M),v.setStreamTtsEngineId(M);const B=E?.voiceId??Pr,ee=E?.speakingRate??At,V=Math.max(Xt,Math.min(Jt,ee)),te={user_query:O,ttsEngineId:M,speakingRate:V,tenant:"aiTwin"};wn.has(M)&&(te.voice_id=B);try{const X=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${P}`},body:JSON.stringify(te)});if(!X.ok)throw new Error(`avatar_ttsWithPoses failed (${X.status})`);const z=X.body;if(!z)throw new Error("No response body");const me=z.getReader(),ae=new TextDecoder;let Q="",de=!0;const he=async Se=>{const j=En(Se);if(j){if(j.event==="audio"){const y=j.data.chunk,I=j.data.visemes??[],U=j.data.words??[],G=j.data.is_new_segment??!1,$=j.data.sample_rate,H=s.length;if(y){const p=de;de=!1,await v.playAudioChunk(s,i,y,I,U,G,{sampleRate:$,newStream:p}),F(O,H,I,G,ri(y,$)),k("audio_chunk",O)}else(I.length>0||U.length>0)&&(v.queueTimingsOnly(s,i,I,U,G),F(O,H,I,G,null),k("audio_chunk",O))}else if(j.event==="metadata"){const y=j.data.mood;typeof y=="string"&&y.trim()&&(f=y.trim());const I=j.data.sentence_emotions;if(Array.isArray(I)){o.length=0;for(const U of I){if(!U||typeof U!="object")continue;const G=U;o.push({sentence_index:Number(G.sentence_index??0),text:String(G.text??""),sentiment:typeof G.sentiment=="string"?G.sentiment:void 0,emotion:String(G.emotion??f),start_word:Number(G.start_word??0),end_word:Number(G.end_word??0)})}}h(),k("metadata",O)}else if(j.event==="error")throw new Error(String(j.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:Se,value:j}=await me.read();j&&(Q+=ae.decode(j,{stream:!0}));const y=Q.split(`
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ur=require("react/jsx-runtime"),T=require("react"),vs=require("@pipecat-ai/client-js"),kr=require("@pipecat-ai/websocket-transport"),ue=require("pixi.js");var cr=typeof document<"u"?document.currentScript:null;const bs="https://aitwin.bubu.social",bn={publicBase:bs},Ts="0.5.2",Es={version:Ts},ks={},kt="https://ai.aitwin.me",Ir=`${bn.publicBase}/custom-faces`,Is=`${bn.publicBase}/aitwin-workers/v${Es.version}/visemeDiffPreview.worker.js`;function As(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:cr&&cr.tagName.toUpperCase()==="SCRIPT"&&cr.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?ks?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Is}const Ps="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",lr=3e3,bt=16,Xr=3e3,xs=4e3,Ms=.85,Rs=8,Ar=400,Pr="eng_a7f2b9c1",Yt="eng_d4e8f3a2",et="eng_c9b1e6d4",Je=et,Tn=new Set([Yt,et]),En={[Pr]:"oculus_direct",[et]:"oculus_direct",[Yt]:"inworld_word"},Jr={google:Pr,inworld:Yt,cartesia:et};function kn(e){return En[e]}function Cs(e){return e===et}function Ds(e){if(e.ttsEngineId&&e.ttsEngineId in En)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Jr?Jr[t]:Je}class $t extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function In(e,t=Ps){const r=new URL(t);r.searchParams.set("id",e);const n=await fetch(r.toString());if(n.status===404)throw new $t;if(!n.ok)throw new Error(`getAiTwin failed (${n.status})`);const s=await n.json();if(!s.success)throw new $t(s.error??"AI twin not found");const{tts:i,token:o,...a}=s.data,l=String(a.authToken??o??"").trim()||void 0;return{...a,ttsEngineId:Ds(s.data),authToken:l}}const Fs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Bs="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Ls="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Os="6TNvp3SCs4Og0a1ijm9TommXLql1",Ns="Swaraj Mali";async function Wt(){const e=await fetch(Fs,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Bs,"Client-Secret":Ls},body:JSON.stringify({userId:Os,userName:Ns})});if(!e.ok)throw new Error(`getAuthToken failed (${e.status})`);const t=await e.json(),r=t.authToken??t.token??"";if(!r.trim())throw new Error("getAuthToken returned no token");return r}async function Vs(e,t=kt){const r=await fetch(`${t.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${e}`}});if(!r.ok)throw new Error(`/api/session-value failed (${r.status})`);const n=await r.json();if(!n.value)throw new Error("Session value response missing value");return n}function Us(e){const t=e.trim();if(t.length%2!==0)throw new Error("Invalid hex key");const r=new Uint8Array(t.length/2);for(let n=0;n<t.length;n+=2)r[n/2]=Number.parseInt(t.slice(n,n+2),16);return r}function Lt(e){return Uint8Array.from(e)}function Ws(e,t){const r=new Uint8Array(e.length+t.length);return r.set(e,0),r.set(t,e.length),r}async function $s(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 r=new Uint8Array(e),n=Lt(r.subarray(0,12)),s=Lt(r.subarray(12,28)),i=Lt(r.subarray(28)),o=Lt(Ws(i,s)),a=await crypto.subtle.importKey("raw",Us(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:n,tagLength:128},a,o)}let wr=null;const gr=new Set;function Ot(e){return e.includes("/custom-faces/")}function Ht(e){const t=e.binBase.trim().replace(/\/$/,""),r=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||Ot(t)||Ot(r)))return{twinBase:r,binBase:t,encrypted:!1};const s=Ot(t)?t:Ot(r)?r:t;return{twinBase:s,binBase:s,encrypted:!0}}function tt(e){return Ht(e).encrypted}function yr(e,t=Ir){const r=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:r,binBase:r,encrypted:!0}}function An(e,t){return(e??t)?.trim()||void 0}function Pn(e){wr=Ht(e);for(const t of gr)t()}function Hs(e,t){const r=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!r)return Ht(e);const n=s=>{try{return new URL(s,r).href.replace(/\/$/,"")}catch{return s}};return Ht({twinBase:n(e.twinBase),binBase:n(e.binBase),encrypted:e.encrypted})}function rt(){if(!wr)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return wr}function xn(e){return gr.add(e),()=>gr.delete(e)}function Kt(){const e=rt();return tt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function Ks(){const e=rt();return tt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Mn(){const e=rt();return tt(e)?e.binBase:e.twinBase}function It(){return tt(rt())}function Rn(){const e=rt();return tt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function Cn(){const e=rt();return tt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function Dn(e){const t=e.split(/\r?\n/);let r="",n="";for(const i of t)i.startsWith("event:")?r=i.slice(6).trim():i.startsWith("data:")&&(n=i.slice(5).trim());if(!r)return null;let s={};if(n)try{s=JSON.parse(n)}catch{s={raw:n}}return{event:r,data:s}}const Fn=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],qs=new Map(Fn.map(e=>[e.toLowerCase(),e]));function Qt(e){const t=(e??"").trim();return t?qs.get(t.toLowerCase())??"sil":"sil"}const Gs={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 zs(e){if(!e)return["sil"];const t=e.toLowerCase();return Gs[t]??["sil"]}function Bn(e,t){const r=e.word.length;if(r<=0)return 0;const n=e.wduration;if(n<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/n));return Math.min(r-1,Math.floor(s*r))}function ft(e,t){const r=Math.max(0,Math.min(e.length-1,t));return e[r]??""}function Xt(e,t){const r=e.toLowerCase().replace(/[^a-z']/g,"");return!r||ft(r,t)!=="w"||t>0&&ft(r,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(r)}function js(e,t){const r=e.toLowerCase(),n=ft(r,t),s=r.slice(Math.max(0,t-1),t+2);return n==="i"||n==="y"?"I":s.includes("ee")||n==="e"||r.includes("ea")?"E":"aa"}function Ys(e,t){const r=e.toLowerCase(),n=r.slice(Math.max(0,t-1),Math.min(r.length,t+3));if(/oo|ou|uw/.test(n))return"U";if(Xt(r,t))return"FF";const s=ft(r,t);return s==="u"||s==="w"?"U":"O"}function Qs(e,t){const r=e.toLowerCase();if(Xt(r,t))return"FF";const n=r.slice(Math.max(0,t-2),t+1);if(/qu/.test(n))return"U";const s=r.slice(Math.max(0,t-1),Math.min(r.length,t+3));return/wo|wh/.test(s)||ft(r,t)==="o"?"O":"U"}const Nt={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function Xs(e,t){const r=e.toLowerCase(),n=ft(r,t);if(Nt[n])return Nt[n];for(let s=0;s<r.length;s++){const i=r[s];if(Nt[i])return Nt[i]}return"DD"}function Ln(e,t,r){const n=zs(e);if(n.length===1)return n[0];const s=t.trim();if(!s)return n[0];const i=(e??"").toLowerCase(),o=Math.max(0,r);switch(i){case"aei":return js(s,o);case"o":return Ys(s,o);case"qw":return Qs(s,o);case"cdgknstxyz":return Xs(s,o);default:return n[0]}}const xr=16,_r=47,On=new Set(["aa","E","I"]),Nn=new Set(["DD","SS","kk","CH"]),Js=[On,Nn];function Zs(e){for(const t of Js)if(t.has(e))return t;return null}function ei(e){return Zs(e)!=null}function Vn(e,t=xr){return t<=0?e:Math.round(e/t)*t}function Mr(e,t=xr){return e.map(r=>({...r,vtime:Vn(r.vtime,t)}))}function Un(e){const t=new Map;for(const r of e)t.has(r.vtime)||t.set(r.vtime,r);return[...t.values()].sort((r,n)=>r.vtime-n.vtime)}function Rr(e){if(e.length<=2)return[...e];const t=[e[0]];for(let r=1;r<e.length-1;r++){const n=e[r],s=e[r+1],i=t[t.length-1];if(!ei(n.viseme)){t.push(n);continue}const o=n.vtime-i.vtime,a=s.vtime-n.vtime;o<_r||a<_r||t.push(n)}return t.push(e[e.length-1]),t}function Jt(e){return Rr(Un(Mr(e)))}function Wn(e,t){let r="sil";for(const n of e){if(n.vtime>t)break;n.viseme!=="sil"&&(r=n.viseme)}return r}function Zt(e){const t=Un(Mr(e)),r=Rr(t),n=new Set(r.map(i=>i.vtime)),s=[];for(const i of t)n.has(i.vtime)||s.push({viseme:i.viseme,vtime:i.vtime});return s}function ti(e){return Zt(e).map(t=>t.viseme)}const ri=32,Zr=48;function $n(e){let t=0;for(const r of e)t=Math.max(t,r.vtime+r.vduration);return t}function Hn(e){let t=null,r=-1;for(const n of e){if(n.viseme==="sil")continue;const s=n.vtime+n.vduration;s>r&&(t=n,r=s)}return t}function ni(e){return Jt(e).find(r=>r.viseme!=="sil")??null}function Qe(e){const t=$n(e);return Hn(e)?t+Ar:t}function si(e){const t=[],r=ni(e);r&&r.vtime>0&&t.push({from:"sil",to:r.viseme,fromVtime:0,toVtime:r.vtime});const n=Hn(e),s=$n(e);return n&&t.push({from:n.viseme,to:"sil",fromVtime:s,toVtime:s+Ar}),t}function Kn(e){const t=Jt(e),r=[];for(let n=0;n<t.length-1;n++){const s=t[n].viseme,i=t[n+1].viseme,o=t[n].vtime,a=t[n+1].vtime;s===i||a<=o||r.push({from:s,to:i,fromVtime:o,toVtime:a})}return r}function qn(e){return e.length===0?[]:[...si(e),...Kn(e)]}function ii(e,t){let r=null;for(const n of e){const{transStart:s,transEnd:i}=Gn(n.fromVtime,n.toVtime,n.from,n.to);t>=s&&t<i&&(r=n)}return r}function Gn(e,t,r,n){const s=Math.max(0,t-e);if((r==="PP"||n==="PP")&&s>Zr){const f=Zr,c=t,u=c-f;return{gapMs:s,effectiveGapMs:f,holdEnd:u,transStart:u,transEnd:c}}const o=s>0?Math.max(s,ri):0,a=e,l=e+o;return{gapMs:s,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:l}}function zn(e,t,r,n,s,i){n.forEach(o=>{const l=String(o.word??"").trim();if(!l)return;const f=Math.round((o.start??0)*1e3),c=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:l,wtime:s+f,wduration:c,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),r.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const l=Math.round((o.start??0)*1e3),f=Math.max(1,Math.round((o.duration??0)*1e3)),c=s+l,u=Qn(t,c),d=u?Bn(u,c):0;let p;kn(i)==="oculus_direct"?(p=Qt(a),p==="U"&&u&&Xt(u.word,d)&&(p="FF")):p=Ln(a,u?.word??"",d),e.push({viseme:p,weight:1,vtime:c,vduration:f})})}function jn(e,t){let r=t;for(const n of e){const s=Math.round((n.start??0)*1e3),i=Math.max(1,Math.round((n.duration??0)*1e3));r=Math.max(r,t+s+i)}return r}const Cr=16e3;function Yn(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Cr}function oi(e){let t=e.trim();const r=t.indexOf(",");t.startsWith("data:")&&r>=0&&(t=t.slice(r+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const n=t.length%4;return n!==0&&(t+="=".repeat(4-n)),t}function ai(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function en(e,t,r=Cr){const n=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(n.buffer,n.byteOffset,n.byteLength/2),i=new Float32Array(s.length);for(let a=0;a<s.length;a++)i[a]=s[a]>=32768?-(65536-s[a])/32768:s[a]/32767;const o=e.createBuffer(1,i.length,r);return o.copyToChannel(i,0),o}function ui(e){const t=oi(e),r=window.atob(t),n=new Uint8Array(r.length);for(let s=0;s<r.length;s++)n[s]=r.charCodeAt(s);return n}async function tn(e,t,r=Cr){const n=ui(t),s=Yn(r);if(ai(n)){const i=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return e.decodeAudioData(i)}if(n.length>=2&&n.length%2===0)return en(e,n,s);try{const i=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(i)}catch{return en(e,n,s)}}function Qn(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function Xn(e,t){const r=[],n=[];let s=null,i=!1,o=!1,a=!1,l=!1,f=0,c=0,u=0,d=null,p=1,E=t,m=!1,A=null,x=0,C=!1,w=!1,b=0,O=null,V=null,X=null;const fe=()=>({visemes:[],words:[],segmentOffsetMs:0}),P=()=>{w=!1,b=0},D=()=>{d!=null&&(clearTimeout(d),d=null)},N=()=>{for(const S of n){try{S.onended=null,S.stop(0)}catch{}try{S.disconnect()}catch{}}n.length=0},j=()=>{for(const S of n)S.playbackRate.value=p},F=()=>{if(!(m||!l||i||w||n.length>0||r.length>0)){if(a&&s&&c>0){const S=(s.currentTime-c)*1e3;if(S<x){D();const M=p>0?(x-S)/p:x-S;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,M));return}}o=!1,D(),e.onSpeakingDone(),e.onNotify()}},Y=S=>{const M=Qe(S);if(M<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,f=performance.now(),e.onSpeakingStart(),e.onNotify(),D();const G=p>0?M/p:M;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},G)},$=(S,M,G,z)=>{M.length!==0&&(u=G,M.forEach(I=>{const g=String(I.word??"").trim();if(!g)return;const _=Math.round((I.start??0)*1e3),y=I.duration!=null?Math.round(I.duration*1e3):I.end!=null?Math.max(1,Math.round((I.end-(I.start??0))*1e3)):0;S.push({word:g,wtime:u+_,wduration:y,queueIndex:S.length,gesture:I.gesture??null,emphasis:I.emphasis===!0})}))},q=(S,M,G,z,I,W)=>{G.length!==0&&(u=z,G.forEach(g=>{const _=String(g.symbol??g.viseme??"").trim();if(!_)return;const y=Math.round((g.start??0)*1e3),Z=Math.max(1,Math.round((g.duration??0)*1e3)),oe=u+y,ye=Qn(M,oe),Re=ye?Bn(ye,oe):0;let _e;kn(W)==="oculus_direct"?(_e=Qt(_),_e==="U"&&ye&&Xt(ye.word,Re)&&(_e="FF")):_e=Ln(_,ye?.word??"",Re),S.push({viseme:_e,weight:1,vtime:oe,vduration:Z})}),e.onNotify())},k=(S,M,G,z,I,W,g)=>{$(M,z,I),q(S,M,G,I,W,g)},ee=(S,M,G)=>{X===S&&S.visemes===M||(M.length=0,G.length=0,S.visemes=M,S.words=G,S.segmentOffsetMs=0,X=S,u=0,x=0)},he=async()=>{const S=window.AudioContext||window.webkitAudioContext;return s||(s=new S),s.state==="suspended"&&await s.resume(),A||(A=s.createMediaStreamDestination()),s},ce=(S,M)=>{if(!s)return 0;const G=s,z=G.currentTime,I=z+.02;if(M.isFirstAudio){c<=0&&(c=I);const g=(I-z)*1e3;f=performance.now()+g}M.onBeforeStart?.(I);const W=G.createBufferSource();return W.buffer=S,W.playbackRate.value=p,W.connect(G.destination),A&&W.connect(A),n.push(W),m?(n.pop(),I):(M.isFirstAudio&&(o=!0,e.onSpeakingStart()),W.onended=()=>{const g=n.indexOf(W);g>=0&&n.splice(g,1),e.onNotify(),!m&&(O&&V?te(O,V):F())},W.start(I),I)},te=async(S,M)=>{if(m||i||n.length>0)return;if(r.length===0){F();return}i=!0;let G=!1;try{const z=await he();if(m)return;const I=r[0];if(!I)return;const W=!o;if(C&&(e.shouldHoldForWarmup?.()??!1)&&(w||W&&I.newStream)||w){ee(I.utterance,S,M);for(const y of r){if(m)return;y.audioBuffer||(y.audioBuffer=await tn(z,y.audio,y.sampleRate)),a=!0,w||(w=!0,b=0,y.newStream&&y.onNewStream?.()),y.visemesQueued||(k(S,M,y.visemes,y.words,b,!0,E),y.visemesQueued=!0,b+=Math.round(y.audioBuffer.duration*1e3),x=Math.max(x,Qe(S)))}e.onNotify();return}const _=r.shift();if(!_||(_.audioBuffer||(_.audioBuffer=await tn(z,_.audio,_.sampleRate)),m))return;a=!0,D(),ee(_.utterance,S,M),_.visemesQueued=!1,_.newStream&&_.onNewStream?.(),ce(_.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:y=>{c=y,u=0,f=performance.now()+(y-z.currentTime)*1e3,k(S,M,_.visemes,_.words,0,!0,E),_.visemesQueued=!0,_.utterance.segmentOffsetMs=0}}),G=n.length>0,x=Qe(S),e.onNotify()}catch(z){console.error("[avatarChunkPlayback] audio chunk failed:",z)}finally{if(i=!1,m)return;if(w){r.some(I=>!I.audioBuffer||!I.visemesQueued)&&te(S,M);return}!G&&n.length===0&&r.length>0?te(S,M):n.length===0&&r.length===0&&F()}};return{setStreamTtsEngineId:S=>{E=S},setPlaybackSpeed:S=>{p=Math.max(.1,Math.min(1,S)),j()},getPlaybackSpeed:()=>p,setLipsyncWarmupHoldEnabled:S=>{C=S,S||P()},isWarmingUp:()=>w,releaseWarmupHold:()=>{if(w){w=!1,b=0;for(const S of r)S.newStream=!1;O&&V&&te(O,V),e.onNotify()}},resetForNewStream:S=>{m=!1,l=!1,E=S,x=0},resumeBotStream:()=>{m=!1,l=!1},clearAborted:()=>{m=!1},primeAudioContext:async()=>{const S=window.AudioContext||window.webkitAudioContext;s||(s=new S),s.state==="suspended"&&await s.resume(),s&&!A&&(A=s.createMediaStreamDestination())},stop:()=>{m=!0,D(),N(),r.length=0,i=!1,o=!1,a=!1,l=!1,u=0,c=0,f=0,x=0,O=null,V=null,X=null,P()},markStreamComplete:S=>{if(x=Math.max(x,Qe(S)),l=!0,!a&&S.length>0){Y(S);return}F()},playAudioChunk:async(S,M,G,z,I,W,g)=>{if(m)return;O=S,V=M;const _=Yn(g?.sampleRate),y=g?.newStream===!0,Z=fe();if(!G?.trim()){if(z.length===0&&I.length===0)return;ee(Z,S,M),y&&g?.onNewStream?.(),k(S,M,z,I,0,!0,E),x=Qe(S),!o&&x>0&&Y(S),e.onNotify();return}r.push({audio:G,audioBuffer:null,utterance:Z,visemes:z,words:I,isNewSegment:W,sampleRate:_,newStream:y,onNewStream:g?.onNewStream,visemesQueued:!1}),await te(S,M)},queueTimingsOnly:(S,M,G,z,I)=>{if(m)return;const W=fe();ee(W,S,M),k(S,M,G,z,0,!0,E),W.segmentOffsetMs=0,x=Qe(S)},getPlaybackElapsedMs:()=>a&&s&&c>0?Math.max(0,(s.currentTime-c)*1e3):o?Math.max(0,(performance.now()-f)*p):0,isSpeaking:()=>o?!0:!a||!s||c<=0?!1:(s.currentTime-c)*1e3<x,getVoiceStream:()=>A?A.stream:null,getPlaybackStartPerf:()=>f,bargeIn:()=>{m=!0,l=!1,D(),N(),r.length=0,i=!1,o=!1,a=!1,u=0,c=0,f=0,x=0,O=null,V=null,X=null,P()},interrupt:()=>{m=!0,l=!1,D(),N(),r.length=0,i=!1,o=!1,a=!1,u=0,c=0,f=0,x=0,O=null,V=null,X=null,P()}}}function At(e,t){let r=null;for(const n of e)t<n.vtime||t>=n.vtime+n.vduration||(!r||n.vtime>=r.vtime)&&(r=n);return r?r.viseme:"sil"}function Jn(e,t,r=120){const n=At(e,t);if(n!=="sil")return n;let s=null;for(const i of e){if(i.vtime>t)break;const o=i.vtime+i.vduration;o<=t&&t-o<=r&&(s=i)}return s?.viseme??"sil"}function ci(e,t,r=400){const n=t-r;let s=0;for(const i of e)if(i.vtime+i.vduration<n)s+=1;else break;s>0&&e.splice(0,s)}function li(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function rn(e,t){const r=e.trim();if(!r)return null;try{const n=r.replace(/\s+/g,""),s=atob(n).length,i=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return s/2/i*1e3}catch{return null}}const er=.5,tr=1.5,Dr="Olivia",Fr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Pt=.85;function Sr(e,t=kt,r={}){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,s=[],i=[],o=[],a=[];let l=0;const f=[],c=[];let u="",d="neutral",p="",E=Je;const m=new Set;let A=0,x=null;const C=()=>m.forEach(F=>F());let w=()=>!1;const b=Xn({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:C,shouldHoldForWarmup:()=>w()},Je),O=()=>b.getPlaybackElapsedMs(),V=(F,Y=u)=>{if(!r.onLipsyncDebug)return;const $=O(),q=s,k=Zt(o).map(ee=>({viseme:ee.viseme,vtimeMs:ee.vtime}));r.onLipsyncDebug({event:F,spokenText:Y,mood:d,playbackAnchorPerf:b.getPlaybackStartPerf(),playbackElapsedMs:$,queueLength:q.length,activeViseme:At(q,$),segments:c.map(ee=>({...ee,visemes:[...ee.visemes]})),fullQueueLength:o.length,compactionSkipped:k})},X=(F,Y)=>{r.onLipsyncDebug&&(x={event:F,spokenText:Y},A===0&&(A=requestAnimationFrame(()=>{A=0;const $=x;x=null,$&&V($.event,$.spokenText)})))},fe=(F,Y,$,q,k)=>{if(!r.onLipsyncDebug)return;const ee=s.slice(Y),he=$.filter(ce=>String(ce.symbol??ce.viseme??"").trim());c.push({spokenText:F,audioOffsetMs:ee[0]?.vtime??0,isNewSegment:q,chunkDurationMs:k,receivedAtMs:performance.now(),visemes:ee.map((ce,te)=>{const J=he[te];return{rawSymbol:String(J?.symbol??J?.viseme??ce.viseme).trim(),viseme:ce.viseme,startSec:Number(J?.start??0),durationSec:Number(J?.duration??0),vtimeMs:ce.vtime,vdurationMs:ce.vduration}})})},P=()=>{o.length=0,a.length=0,l=0},D=(F,Y,$,q,k)=>{if(F.length===0&&Y.length===0)return;zn(o,a,F,Y,l,k);const ee=jn(F,l),he=$?rn($,q):null;l=Math.max(ee,he!=null?l+he:l)},N=()=>{b.stop(),s.length=0,i.length=0,P(),f.length=0,d="neutral",c.length=0,u="",e("idle"),X("reset"),C()};return{setDeveloperToken:F=>{p=F},setTtsEngineId:F=>{E=F},getTtsEngineId:()=>E,speak:async(F,Y)=>{N(),e("loading"),u=F,c.length=0,P();const $=p.trim();if(!$)throw new Error("Developer token required for avatar_ttsWithPoses");const q=Y?.ttsEngineId??E??Je;b.resetForNewStream(q),b.setStreamTtsEngineId(q);const k=Y?.voiceId??Dr,ee=Y?.speakingRate??Pt,he=Math.max(er,Math.min(tr,ee)),ce={user_query:F,ttsEngineId:q,speakingRate:he,tenant:"aiTwin"};Tn.has(q)&&(ce.voice_id=k);try{const te=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${$}`},body:JSON.stringify(ce)});if(!te.ok)throw new Error(`avatar_ttsWithPoses failed (${te.status})`);const J=te.body;if(!J)throw new Error("No response body");const ke=J.getReader(),Me=new TextDecoder;let S="",M=!0;const G=async z=>{const I=Dn(z);if(I){if(I.event==="audio"){const W=I.data.chunk,g=I.data.visemes??[],_=I.data.words??[],y=I.data.is_new_segment??!1,Z=I.data.sample_rate,oe=s.length;if(D(g,_,W,Z,q),W){const ye=M;M=!1,await b.playAudioChunk(s,i,W,g,_,y,{sampleRate:Z,newStream:ye}),fe(F,oe,g,y,rn(W,Z)),X("audio_chunk",F)}else(g.length>0||_.length>0)&&(b.queueTimingsOnly(s,i,g,_,y),fe(F,oe,g,y,null),X("audio_chunk",F))}else if(I.event==="metadata"){const W=I.data.mood;typeof W=="string"&&W.trim()&&(d=W.trim());const g=I.data.sentence_emotions;if(Array.isArray(g)){f.length=0;for(const _ of g){if(!_||typeof _!="object")continue;const y=_;f.push({sentence_index:Number(y.sentence_index??0),text:String(y.text??""),sentiment:typeof y.sentiment=="string"?y.sentiment:void 0,emotion:String(y.emotion??d),start_word:Number(y.start_word??0),end_word:Number(y.end_word??0)})}}C(),X("metadata",F)}else if(I.event==="error")throw new Error(String(I.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:z,value:I}=await ke.read();I&&(S+=Me.decode(I,{stream:!0}));const W=S.split(`
|
|
2
2
|
|
|
3
|
-
`);
|
|
3
|
+
`);S=W.pop()??"";for(const g of W)await G(g);if(z){S.trim()&&await G(S.trim()),b.markStreamComplete(s),X("bot_stopped",F);break}}}catch(te){throw console.error("[avatarTtsLipsync]",te),N(),e("error"),te}},stop:N,getVisemeQueue:()=>s,getWordQueue:()=>i,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>f,getStreamMood:()=>d,getPlaybackElapsedMs:()=>b.getPlaybackElapsedMs(),isSpeaking:()=>b.isSpeaking(),isWarmingUp:()=>b.isWarmingUp(),releaseWarmupHold:()=>b.releaseWarmupHold(),setLipsyncWarmupHold:(F,Y)=>{Y&&(w=Y),b.setLipsyncWarmupHoldEnabled(F)},getVoiceStream:()=>b.getVoiceStream(),setPlaybackSpeed:F=>{b.setPlaybackSpeed(F)},getPlaybackSpeed:()=>b.getPlaybackSpeed(),subscribe:F=>(m.add(F),()=>m.delete(F))}}const Br=16e3,Lr=16e3;class fi extends kr.ProtobufFrameSerializer{async deserialize(t){try{return await super.deserialize(t)}catch(r){if(r instanceof Error&&r.message==="Unknown frame kind")return{type:"raw",message:null};throw r}}}class di extends kr.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,Br,Lr)}bufferBotAudio(t,r){}}const mi=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function hi(e){return mi.test(e.trim())}function pi(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function Zn(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 r=e.apiBase??kt,n=new URL(`${pi(r)}/ws/voice`);n.searchParams.set("authToken",t),n.searchParams.set("tenant","aiTwin");const s=e.voiceId?.trim();s&&hi(s)&&n.searchParams.set("voiceId",s);const i=e.personaId?.trim();i&&n.searchParams.set("personaId",i);const o=e.speakingRate??Pt;return n.searchParams.set("speaking_rate",String(Math.max(er,Math.min(tr,o)))),e.ttsStream===!1?n.searchParams.set("tts_stream","false"):n.searchParams.set("tts_stream","true"),n.toString()}function fr(e,t){if(!Array.isArray(e))return[];const r=[];for(const n of e)!n||typeof n!="object"||r.push({sentence_index:Number(n.sentence_index??0),text:String(n.text??""),sentiment:typeof n.sentiment=="string"?n.sentiment:void 0,emotion:String(n.emotion??t),start_word:Number(n.start_word??0),end_word:Number(n.end_word??0)});return r}function wi(e){if(!e||typeof e!="object")return null;const t=e,n=(t.data&&typeof t.data=="object"&&!Array.isArray(t.data)?t.data:null)||t;return{...n,type:String(n.type??t.type??"server-message")}}function dr(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function gi(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function es(e,t={}){const r=[],n=[],s=[],i=[];let o=0;const a=[],l=[];let f="",c="neutral",u=et,d=!1,p=null,E=null,m={...t},A=0,x=null;const C=new Set,w=[];let b=!1,O=null,V=!0,X="default";const fe=new Set;let P=null,D=0,N=!1,j=null,F=!1;const Y=()=>{j!=null&&(clearTimeout(j),j=null)},$=()=>C.forEach(h=>h());let q=()=>!1;const k=Xn({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{F=!1,e("done")},onNotify:$,shouldHoldForWarmup:()=>q()},u),ee=()=>{if(O)return O;const h=new MessageChannel;return h.port1.onmessage=()=>{const R=w.shift();R!==void 0&&Re(R),w.length>0?h.port2.postMessage(null):b=!1},O=h,h},he=h=>{w.push(h),!b&&(b=!0,ee().port2.postMessage(null))},ce=()=>k.getPlaybackElapsedMs(),te=(h,R=f)=>{if(!m.onLipsyncDebug)return;const Q=ce(),re=r,me=Zt(s).map(de=>({viseme:de.viseme,vtimeMs:de.vtime}));m.onLipsyncDebug({event:h,spokenText:R,mood:c,playbackAnchorPerf:k.getPlaybackStartPerf(),playbackElapsedMs:Q,queueLength:re.length,activeViseme:At(re,Q),segments:l.map(de=>({...de,visemes:[...de.visemes]})),fullQueueLength:s.length,compactionSkipped:me})},J=(h,R)=>{m.onLipsyncDebug&&(x={event:h,spokenText:R},A===0&&(A=requestAnimationFrame(()=>{A=0;const Q=x;x=null,Q&&te(Q.event,Q.spokenText)})))},ke=()=>{V=!0,fe.clear(),k.clearAborted()},Me=()=>{const h=gi(p);if(h){X=`bot-${Date.now()}`,h.interruptedTrackIds={[X]:!0};try{h.interrupt?.()}catch{}}const R=E;try{R?.interrupt?.()}catch{}},S=h=>{if(F&&k.isSpeaking())return!0;const R=h.context_id?.trim();return R&&fe.has(R)?!0:V?!1:!(h.type==="avatar_metadata"||dr(h))},M=h=>{V=!1,F=!1;const R=h.context_id?.trim();R&&fe.add(R),Y(),N=!1,w.length=0,b=!1,P?.abort(),P=null,D+=1,Me(),k.bargeIn(),G(),e("idle"),J("interrupt"),$()},G=()=>{r.length=0,n.length=0,s.length=0,i.length=0,o=0,l.length=0,f="",c="neutral",a.length=0},z=()=>{k.stop(),G(),J("reset"),$()},I=()=>{z(),e("idle"),$()},W=(h,R)=>{typeof h.mood=="string"&&h.mood.trim()&&(c=h.mood.trim()),Array.isArray(h.sentence_emotions)&&h.sentence_emotions.length>0&&(R&&(a.length=0),a.push(...fr(h.sentence_emotions,c)))},g=h=>{if(S({...h,type:"avatar_metadata"}))return;ke(),N=!0;const R=String(h.spoken_text??h.text??"").trim();R&&(f=R),k.resetForNewStream(u),typeof h.mood=="string"&&h.mood.trim()&&(c=h.mood.trim()),a.length=0,a.push(...fr(h.sentence_emotions,c)),Array.isArray(h.gestures)&&h.gestures,J("metadata",R),$()},_=(h,R,Q,re)=>{if(!m.onLipsyncDebug)return;const me=r.slice(Q),de=re.filter(pe=>String(pe.symbol??pe.viseme??"").trim());l.push({spokenText:R,audioOffsetMs:me[0]?.vtime??0,isNewSegment:!!h.is_new_segment,chunkDurationMs:h.chunk_duration_ms!=null?Number(h.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:me.map((pe,we)=>{const ve=de[we];return{rawSymbol:String(ve?.symbol??ve?.viseme??pe.viseme).trim(),viseme:pe.viseme,startSec:Number(ve?.start??0),durationSec:Number(ve?.duration??0),vtimeMs:pe.vtime,vdurationMs:pe.vduration}})})},y=(h,R,Q,re)=>{if(h.length===0&&R.length===0)return;zn(s,i,h,R,o,u);const me=jn(h,o);let de=null;const pe=Q.trim();if(pe)try{const we=atob(pe.replace(/\s+/g,"")).length,ve=Number.isFinite(re)&&(re??0)>0?Number(re):16e3;de=we/2/ve*1e3}catch{de=null}o=Math.max(me,de!=null?o+de:o)},Z=h=>{if(S(h))return;Y(),dr(h)&&ke();const R=String(h.spoken_text??h.text??"").trim(),Q=dr(h),re=h.visemes??[],me=h.words??[],de=String(h.chunk??"").trim(),pe=N;pe&&(N=!1),R&&(f=R),W(h,Q),pe?(k.resetForNewStream(u),s.length=0,i.length=0,o=0):Q&&k.resumeBotStream(),y(re,me,de,h.sample_rate);const we=r.length;k.playAudioChunk(r,n,de,re,me,Q,{sampleRate:h.sample_rate,newStream:pe,onNewStream:()=>{l.length=0}}).then(()=>{_(h,R,we,re),J("audio_chunk",R)})},oe=h=>{if(S(h))return;(h.is_new_segment||Number(h.audio_offset_ms??-1)===0)&&ke(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const R=String(h.spoken_text??h.text??"").trim();R&&(f=R),W(h,!!h.is_new_segment),y(h.visemes??[],h.words??[],"",void 0);const Q=r.length;k.queueTimingsOnly(r,n,h.visemes??[],h.words??[],!!h.is_new_segment),_(h,R,Q,h.visemes??[]),J("lipsync",R),$()},ye=async h=>{const R=String(h.text??"").trim();if(!R)return;const Q=m.authToken?.trim();if(!Q){console.error("[realtimeVoice] avatar_speak requires authToken");return}P?.abort();const re=new AbortController;P=re;const me=++D;ke(),k.resetForNewStream(u),f=R;const pe=`${(m.apiBase??kt).replace(/\/$/,"")}/avatar_ttsWithPoses`,we=m.voiceId?.trim()||Fr,ve=m.speakingRate??Pt,nt=Math.max(er,Math.min(tr,ve)),We={user_query:R,ttsEngineId:u,speakingRate:nt,tenant:"aiTwin"};Tn.has(u)&&(We.voice_id=we);try{const Ke=await fetch(pe,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Q}`},body:JSON.stringify(We),signal:re.signal});if(!Ke.ok)throw new Error(`avatar_ttsWithPoses failed (${Ke.status})`);const ze=Ke.body;if(!ze)throw new Error("No response body");const gt=ze.getReader(),Mt=new TextDecoder;let se="",yt=!0;const _t=async st=>{if(me!==D||re.signal.aborted||!V)return;const ge=Dn(st);if(ge){if(ge.event==="audio"){const Ce=ge.data.chunk,Te=ge.data.visemes??[],it=ge.data.words??[],Be=ge.data.is_new_segment??!1,je=ge.data.sample_rate;if(Ce){const ie=yt;yt=!1,await k.playAudioChunk(r,n,Ce,Te,it,Be,{sampleRate:je,newStream:ie})}else(Te.length>0||it.length>0)&&k.queueTimingsOnly(r,n,Te,it,Be)}else if(ge.event==="metadata"){const Ce=ge.data.mood;typeof Ce=="string"&&Ce.trim()&&(c=Ce.trim());const Te=ge.data.sentence_emotions;Array.isArray(Te)&&(a.length=0,a.push(...fr(Te,c))),$()}else if(ge.event==="error")throw new Error(String(ge.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(me!==D||re.signal.aborted||!V);){const{done:st,value:ge}=await gt.read();ge&&(se+=Mt.decode(ge,{stream:!0}));const Ce=se.split(`
|
|
4
4
|
|
|
5
|
-
`);Ve=Ae.pop()??"";for(const Ie of Ae)await ce(Ie);if(it){Ve.trim()&&await ce(Ve.trim()),_e===Y&&!ue.signal.aborted&&g&&V.markStreamComplete(r);break}}}catch(Be){if(ue.signal.aborted||!g)return;console.error("[realtimeVoice] avatar_speak failed:",Be),e("error"),B()}finally{D===ue&&(D=null)}},C=m=>{const x=ci(m);if(!x){console.warn("[realtimeVoice] server message with no payload",m);return}const J=String(x.type??"unknown");switch(J!=="avatar_metadata"&&J!=="avatar_audio_chunk"&&J!=="avatar_lipsync"&&J!=="avatar_interrupt"&&J!=="error"&&console.debug("[realtimeVoice] server message",J,x),J){case"avatar_metadata":G(x);break;case"avatar_audio_chunk":H(x);break;case"avatar_lipsync":p(x);break;case"avatar_interrupt":Se(x);break;case"error":{const ue=String(x.message??"Voice session error");console.error("[realtimeVoice] server error:",ue),e("error"),B();break}case"avatar_speak":S(x);break}},le=()=>l||(c=new si,l=new cs.PipecatClient({transport:new vr.WebSocketTransport({mediaManager:c,serializer:new ni,recorderSampleRate:Rr,playerSampleRate:Mr}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{f=!0,e("idle"),B()},onDisconnected:()=>{f=!1,I()},onError:m=>{const x=typeof m=="object"&&m!==null&&"data"in m?String(m.data??m):String(m);console.error("[realtimeVoice]",x,m),e("error"),B()},onTransportStateChanged:m=>{m==="error"&&(e("error"),B())},onServerMessage:m=>{X(m)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{Q(),ae("bot_started")},onBotStoppedSpeaking:()=>{g&&(M(),E=setTimeout(()=>{E=null,g&&(V.markStreamComplete(r),ae("bot_stopped"))},450))},onUserTranscript:m=>{String(m.text??""),d.onUserTranscript?.(m.text,!!m.final)},onBotOutput:m=>{d.onBotOutput?.(m.text)}}}),l);return{setDeveloperToken:m=>{},setTtsEngineId:m=>{u=m,V.setStreamTtsEngineId(m)},getTtsEngineId:()=>u,speak:async(m,x)=>{const J=m.trim();if(J){if(!l||!f)throw new Error("Realtime voice is not connected. Call connect() first.");y(),await l.sendText(J)}},stop:()=>{D?.abort(),D=null,Y+=1,Q(),y(),e("idle"),B()},connect:async m=>{if(m&&(d={...d,...m}),!d.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const x=le();await x.initDevices();const J=Vn(d);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",J);try{await x.connect({wsUrl:J})}catch(ue){f=!1,e("error"),B();const _e=ue instanceof Error?ue.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${_e} — ${J}`)}f=!0,e("idle"),B()},disconnect:async()=>{if(M(),O=!1,A.length=0,v=!1,D?.abort(),D=null,Y+=1,Q(),l)try{await l.disconnect()}catch(m){console.error("[realtimeVoice] disconnect failed:",m)}f=!1,I()},isConnected:()=>f,unlockAudio:async()=>{await V.primeAudioContext()},getVisemeQueue:()=>r,getWordQueue:()=>n,getSentenceEmotions:()=>s,getStreamMood:()=>a,getPlaybackElapsedMs:z,isSpeaking:()=>V.isSpeaking(),isWarmingUp:()=>V.isWarmingUp(),releaseWarmupHold:()=>V.releaseWarmupHold(),setLipsyncWarmupHold:(m,x)=>{x&&(ee=x),V.setLipsyncWarmupHoldEnabled(m)},getVoiceStream:()=>V.getVoiceStream(),setPlaybackSpeed:m=>{V.setPlaybackSpeed(m)},getPlaybackSpeed:()=>V.getPlaybackSpeed(),subscribe:m=>(h.add(m),()=>h.delete(m))}}function $n(e,t,r){return{width:e.crop?.source_width??t,height:e.crop?.source_height??r}}function Hn(e,t){const r=e.crop;return{x:t?.source_x??r?.x??0,y:t?.source_y??r?.y??0,width:t?.source_w??r?.width??e.frame_width??0,height:t?.source_h??r?.height??e.frame_height??0}}function Kn(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function pt(e,t){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const n=await r.arrayBuffer();return Rs(n,t)}async function qn(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const r=await pt(e,t),n=new TextDecoder().decode(r);return JSON.parse(n)}async function li(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function fi(e){const t=new Blob([e],{type:"image/webp"}),r=URL.createObjectURL(t);return new Promise((n,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(r),n(i)},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("Failed to decode decrypted image"))},i.src=r})}async function di(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function mi(e){const t=new Blob([e],{type:"image/png"}),r=URL.createObjectURL(t);return new Promise((n,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(r),n(i)},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("Failed to decode decrypted PNG"))},i.src=r})}function hi(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function pi(e){const t=Cs();if(!Et())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const r=await pt(t,e);return hi(r)}function ft(e,t){return`${e}/${t}_minus_sil.png`}const Gn=5;function Qt(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const r=e?.crop?.content_threshold;return typeof r=="number"&&r>0?r:Gn}const wi=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],gr=["t01_0.25","t02_0.50","t03_0.75"],gi=gr.length,Xr=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 Jr(e,t){return`${e}__${t}`}function Qr(e,t){return`pairs/${e}/${t}_minus_sil.png`}function bt(e){return`${e}_minus_sil.png`}function Cr(e,t){if(t.has(e))return e;const r=/^pairs\/([^/]+)\//.exec(e);if(!r)return null;const n=r[1].split("__")[1];if(!n||n==="sil")return null;const s=bt(n);return t.has(s)?s:null}function zn(e,t){return e.filter(r=>t.has(r))}function yi(e,t,r){const n=Dr(e,t);return zn(n,r).length>0}function Dr(e,t){if(e===t)return[];const r=[],n=Jr(e,t);if(Xr.has(n)){for(const i of gr)r.push(Qr(n,i));return r}const s=Jr(t,e);if(Xr.has(s)){for(let i=gi-1;i>=0;i--)r.push(Qr(s,gr[i]));return r}return[]}function _i(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function Si(e,t){return _i(t).map(n=>e[n]).filter(n=>n!=null)}function vi(e,t,r,n){if(n<=0)return 0;const i=Math.max(1,r-t)/n,o=e-t,a=Math.floor(o/i);return Math.min(n-1,Math.max(0,a))}function jn(e,t,r){if(!r)return`${e}/${t}`;const n=t.split("/").pop()??t,s=n.includes(".")?n.slice(0,n.lastIndexOf(".")):n;return`${e}/${s}.bin`}const bi=[.32,.24,.16,.08,0],Ti=bi.map(e=>`eyes_${e.toFixed(2)}`),ki=["eyes_0.32","eyes_0.16","eyes_0.00"],Ei=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],De=2,Ii=-30,Kt=20,Yn={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Tt(e){return`brow_${e}`}function et(e){return Yn[e]}function Oe(e){return Math.max(Ii,Math.min(Kt,e))}function Ai(e,t){if(e===t)return[];const r=e<t,n=r?De:-De,s=[];let i=e;if(i%De!==0){const o=r?Math.ceil(i/De)*De:Math.floor(i/De)*De,a=Oe(o);if(r?a>=t:a<=t)return[t];i=a,s.push(i)}for(;;){const o=i+n;if(r?o>=t:o<=t){t!==i&&s.push(t);break}i=o,s.push(i)}return s}function Zr(e){const t=Oe(e);if(t%De===0)return[t];const r=Math.floor(t/De)*De,n=Math.min(Kt,r+De),s=Oe(r);return t-s<=n-t?s===n?[s]:[s,n]:s===n?[n]:[n,s]}const Pi=["fear","anger","sad","neutral","love","happy","disgust"],xi={fear:"fear",afraid:"fear",anxiety:"fear",anger:"anger",angry:"anger",mad:"anger",sad:"sad",sadness:"sad",sorrow:"sad",neutral:"neutral",calm:"neutral",love:"love",loving:"love",affection:"love",happy:"happy",happiness:"happy",joy:"happy",joyful:"happy",excited:"happy",disgust:"disgust",disgusted:"disgust"};function qe(e,t="neutral"){const r=String(e??"").trim().toLowerCase();return r?xi[r]??t:t}function Xn(e){return e===0?null:ft(Tt(e),"eyes_standard")}function Jn(e){return Xn(et(e))}const Ri={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function Br(e,t){if(!e)return null;if(t(e))return e;const r=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const s=Number(r[1]),i=r[2];for(const a of Zr(s)){if(a===s)continue;const u=ft(Tt(a),i);if(t(u))return u}const o=Ri[s];if(o){const a=ft(o,i);if(t(a))return a}return null}const n=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const s=n[1],i=n[2],o=et(s);for(const a of[o,...Zr(o)]){const u=ft(Tt(a),i);if(t(u))return u}}return null}function en(e,t){const r=Tt(et(e));return!t||t==="eyes_standard"?Jn(e):e==="neutral"&&t==="eyes_standard"?null:ft(r,t)}function Mi(e,t){const r=[];for(const n of t)r.push(en(e,n));for(let n=t.length-2;n>=0;n--)r.push(en(e,t[n]));return r.push(Jn(e)),r}function Ci(e){return ft(Tt(e),"eyes_standard")}function Di(e,t){return Ai(e,t).map(Ci)}const Bi=6;function Fi(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function Li(e){const t=Oe(e);return t>=Kt?Kt:Oe(t+Bi)}function Oi(e,t,r){const n=Oe(r);return Fi(t,e)?.emphasis?Li(n):n}function tn(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const r=Number.parseInt(t[1],10);return Number.isFinite(r)?Oe(r):null}function lt(e,t){return e+Math.random()*(t-e)}function Nt(){return lt(14,32)}function Ni(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:r=2200,intervalMaxMs:n=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:u=380,minDwellMs:f=550}=e;let l="neutral",c="neutral",d=0,w=0,T=0,h={kind:"idle",nextBlinkAt:performance.now()+t},A=null,v="__eyes_open__|neutral|brow:0";function R(E=l){v=`${A??"__eyes_open__"}|${E}|brow:${w}`}function g(E,P=l){A=E;const M=tn(E);M!=null?w=M:E==null&&(w=0),R(P)}function k(E){return Xn(E)}function F(E,P,M){const B=Oe(P),ee=Oe(M);if(d=ee,B===ee){g(k(ee));return}const V=[...Di(B,ee),k(ee)];h={kind:"browBlend",paths:V,index:0,holdUntil:E+Nt(),targetBrow:ee},g(V[0]??null)}function D(E,P){h={kind:"idle",nextBlinkAt:E+lt(r,n)},c=P,g(k(d),P)}function Y(E,P,M){const B=M?ki:Math.random()<a?Ti:Ei;h={kind:"playing",paths:Mi(P,B),index:0,holdUntil:E+Nt(),after:"idle",blinkEmotion:P},c=P,g(h.paths[0]??null,P)}function O(E){if(h.kind==="browBlend"){for(;E>=h.holdUntil&&h.index<h.paths.length-1;)h.index+=1,h.holdUntil=E+Nt();const P=h.paths[h.index]??null;g(P),E>=h.holdUntil&&h.index>=h.paths.length-1&&(w=h.targetBrow,d=h.targetBrow,g(k(h.targetBrow)),h={kind:"idle",nextBlinkAt:E+u});return}if(h.kind==="idle"){g(k(d),c),E>=h.nextBlinkAt&&Y(E,c,!1);return}if(h.kind==="doublePause"){g(k(d),h.blinkEmotion),E>=h.resumeAt&&Y(E,h.blinkEmotion,!0);return}if(h.kind==="playing"){for(;E>=h.holdUntil&&h.index<h.paths.length-1;)h.index+=1,h.holdUntil=E+Nt();if(g(h.paths[h.index]??null,h.blinkEmotion),E>=h.holdUntil&&h.index>=h.paths.length-1){if(h.after==="resumeIdle"){D(E+u,l);return}if(h.after==="doublePause"){h={kind:"doublePause",resumeAt:E+lt(i,o),blinkEmotion:h.blinkEmotion},g(k(d),h.blinkEmotion);return}if(h.after==="idle"&&Math.random()<s){h={kind:"doublePause",resumeAt:E+lt(i,o),blinkEmotion:h.blinkEmotion},g(k(d),h.blinkEmotion);return}D(E,h.blinkEmotion)}}}return{advance:O,setTargetEmotion(E,P){const M=qe(E,l);if(M===l)return;const B=performance.now();!P?.force&&f>0&&!(l==="neutral"&&M!=="neutral")&&B-T<f||(l=M,c=M,T=B)},setTargetEyebrow(E){const P=Oe(E);if(P===d)return;const M=performance.now(),B=h.kind==="browBlend"?tn(A)??w:w;d=P,!(P===B&&h.kind!=="browBlend")&&(h.kind==="playing"||h.kind==="doublePause"||F(M,B,P))},snapToEmotion(E){const P=qe(E),M=et(P);l=P,c=P,d=M,w=M,T=performance.now(),h={kind:"idle",nextBlinkAt:performance.now()+lt(4e3,7e3)},g(k(M),P)},getTargetEmotion:()=>l,getTargetEyebrow:()=>d,getExpressionPath:()=>A,getDrawKey:()=>v,reset(){l="neutral",c="neutral",d=0,w=0,T=0,D(performance.now()+lt(r,n),"neutral")}}}function Ui(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,r=null,n="";const s=()=>{r&&(URL.revokeObjectURL(r),r=null)};return{async load(i){t&&n===i||(s(),t=!1,n=i,i.startsWith("blob:")&&(r=i),await new Promise((o,a)=>{const u=()=>{const f=e.duration;if(!Number.isFinite(f)||f<=0){a(new Error(`Idle video has invalid duration: ${i}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",u,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${i}`)),{once:!0}),e.src=i,e.load()}))},isReady(){return t},getVideo(){return e},setActive(i){t&&(i?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),s(),t=!1,n=""}}}const Vi=50,Qn=400;function Wi(e,t,r){return e.filter(n=>{const s=n.queueIndex??-1;return s>=t&&s<=r})}function $i(e,t){const r=[];for(const n of e){const s=Wi(t,n.start_word,n.end_word);if(s.length===0)continue;const i=s[0],o=s[s.length-1];r.push({sentence:n,startMs:Math.max(0,i.wtime-Vi),endMs:o.wtime+o.wduration+Qn})}return r.sort((n,s)=>n.startMs-s.startMs)}function Hi(e,t,r,n="neutral"){const s=qe(n);if(t.length===0)return s;if(r.length===0||e<r[0].wtime)return qe(t[0]?.emotion,s);const i=$i(t,r);let o=null;for(const f of i)e>=f.startMs&&e<=f.endMs&&(o=f);if(o)return qe(o.sentence.emotion,s);const a=r[r.length-1],u=a.wtime+a.wduration;return e>u+Qn?qe(t[t.length-1]?.emotion,s):s}function Fr(e,t,r,n,s=Gn){const i=new OffscreenCanvas(r,n),o=i.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,r,n);const a=o.getImageData(0,0,r,n),u=o.createImageData(r,n);u.data.set(a.data);const l=new OffscreenCanvas(r,n).getContext("2d",{willReadFrequently:!0});for(const c of t){l.clearRect(0,0,r,n),l.drawImage(c,0,0,r,n);const d=l.getImageData(0,0,r,n);for(let w=0;w<u.data.length;w+=4){const T=d.data[w],h=d.data[w+1],A=d.data[w+2];Math.max(T,h,A)>s&&(u.data[w]=T,u.data[w+1]=h,u.data[w+2]=A,u.data[w+3]=255)}}return o.putImageData(u,0,0),i}let Qe=null,mt=null;const qt=new Map;function Ki(){Qe=null,mt=null,qt.clear()}vn(Ki);function qi(e){return e??mt??void 0}function Lr(e){return new Promise((t,r)=>{const n=new Image;n.decoding="async",n.onload=()=>t(n),n.onerror=()=>r(new Error(`Failed to load image: ${e}`)),n.src=e})}async function Gi(e){return Et()?mi(await pt(Ht(),e??"")):Lr(Ht())}async function rn(e,t,r,n){const s=r?await qn(e,n):await fetch(e).then(f=>{if(!f.ok)throw new Error(`Failed to load ${e}`);return f.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const o=r?await fi(await pt(jn(t,i.path,r),n??"")):await Lr(`${t}/${i.path}`),a=new Map;for(const f of s.cells??[])f.path&&a.set(f.path,f);const u=new Map;for(const f of s.sheets??[])u.set(f.index,f);return{atlas:o,atlasMeta:s,cellByPath:a,sheetByIndex:u,diffBase:t}}async function yr(e){const t=qi(e),r=Et();if(r&&!t)throw new Error("Encrypted assets enabled but no key provided");if(Qe&&(!r||mt===(t??null))){const i=await Qe;return{...ht(i),visemePaths:[...i.viseme.cellByPath.keys()]}}mt=t??null,qt.clear();const n=bn();Qe=(async()=>{const i=await Gi(t),o=await rn(Tn(),n,r,t);let a=null;try{a=await rn(kn(),n,r,t)}catch{a=null}return{sil:i,viseme:o,expression:a}})();const s=await Qe;return{...ht(s),visemePaths:[...s.viseme.cellByPath.keys()]}}async function Or(e){if(await yr(e),!Qe)throw new Error("Assets not loaded");return Qe}function ht(e){return $n(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function zi(e,t){const r=document.createElement("canvas");return r.width=t.w,r.height=t.h,r.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}async function Gt(e,t,r){const n=`${t.diffBase}::${r}`,s=qt.get(n);if(s)return s;const i=(async()=>{const o=t.cellByPath.get(r);if(!o)throw new Error(`No atlas cell for path: ${r}`);const a=Hn(t.atlasMeta,o),u=ht(e);if(Kn(o)){const c=zi(t,o),d=document.createElement("canvas");d.width=u.width,d.height=u.height;const w=d.getContext("2d");return w.fillStyle="#000",w.fillRect(0,0,u.width,u.height),w.drawImage(c,a.x,a.y),d}const f=`${t.diffBase}/${r}`,l=await Lr(f);if(l.naturalWidth===u.width&&l.naturalHeight===u.height)return l;throw new Error(`Diff PNG wrong size for ${r}`)})();return qt.set(n,i),i}async function ur(e,t,r,n,s,i){if(s){const{width:w,height:T}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const h=document.createElement("canvas");h.width=w,h.height=T;const A=h.getContext("2d");if(A.clearRect(0,0,w,T),A.drawImage(t,0,0,w,T),i&&!i())return;(e.width!==w||e.height!==T)&&(e.width=w,e.height=T);const v=e.getContext("2d");v.clearRect(0,0,w,T),v.drawImage(h,0,0);return}const o=await Or(),a=Qt(o.viseme.atlasMeta),{width:u,height:f}=ht(o);(e.width!==u||e.height!==f)&&(e.width=u,e.height=f);const l=[],c=e.getContext("2d");if(c.clearRect(0,0,u,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const w=o.sil;c.drawImage(w,0,0,u,f);return}if(l.length===0){c.drawImage(t,0,0,u,f);return}const d=Fr(t,l,u,f,a);c.drawImage(d,0,0)}async function _r(e,t,r){const n=await Or(mt??void 0),s=Qt(n.viseme.atlasMeta),{width:i,height:o}=ht(n);(e.width!==i||e.height!==o)&&(e.width=i,e.height=o);const a=[];if(t.mouthPath){const l=new Set(n.viseme.cellByPath.keys()),c=Cr(t.mouthPath,l)??(l.has(t.mouthPath)?t.mouthPath:null);c&&a.push(await Gt(n,n.viseme,c))}if(t.expressionPath&&n.expression){const l=Br(t.expressionPath,c=>n.expression.cellByPath.has(c));l&&a.push(await Gt(n,n.expression,l))}const u=e.getContext("2d");if(u.clearRect(0,0,i,o),a.length===0){u.drawImage(n.sil,0,0,i,o);return}const f=Fr(n.sil,a,i,o,s);u.drawImage(f,0,0)}async function ji(e,t){const r=await Or(mt??void 0),n=Qt(r.viseme.atlasMeta),{width:s,height:i}=ht(r),o=[];if(e.mouthPath){const l=new Set(r.viseme.cellByPath.keys()),c=Cr(e.mouthPath,l)??(l.has(e.mouthPath)?e.mouthPath:null);c&&o.push(await Gt(r,r.viseme,c))}if(e.expressionPath&&r.expression){const l=Br(e.expressionPath,c=>r.expression.cellByPath.has(c));l&&o.push(await Gt(r,r.expression,l))}const a=new OffscreenCanvas(s,i),u=a.getContext("2d");if(o.length===0)return u.drawImage(r.sil,0,0,s,i),a.transferToImageBitmap();const f=Fr(r.sil,o,s,i,n);return u.drawImage(f,0,0),a.transferToImageBitmap()}async function Yi(e){await _r(e,{mouthPath:null,expressionPath:null})}let Zn=null;function nn(e){Zn=e}function Ye(){return Zn}function Xi(e){return`${e.from}→${e.to}@${e.fromVtime}`}function sn(){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 Ji(){let e=sn();const t=new Set,r=new Set,n=new Set;let s="",i=-1,o="";const a=()=>{e=sn(),t.clear(),r.clear(),n.clear(),s="",i=-1,o=""},u=l=>{t.add(l)},f=l=>{l&&n.add(l)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(l,c){const d=Xi(l);e.transitionFramesSampled+=1,d!==s&&(s=d,i=-1,o!==d&&(o=d,e.rifeFramesOmittedByGap+=l.omittedByGap)),c&&r.add(c),i>=0&&l.frameIdx>i+1&&(e.transitionFramesMissed+=l.frameIdx-i-1),i=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),f(l.mouthPath);return}if(l.label.includes("→")){e.transitionFramesDisplayed+=1;return}const d=l.label.trim();if(!(!d||d==="sil")){for(const w of c)if(w.viseme===d&&l.elapsedMs>=w.vtime&&l.elapsedMs<w.vtime+w.vduration){u(w.vtime);break}}},snapshot(l,c){let d=0,w=0;for(const R of l)if(R.viseme!=="sil"){if(R.vtime>=c)break;d+=1,t.has(R.vtime)&&(w+=1)}const T=d>0?Math.round(w/d*100):100,h=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),A=d-w,v=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:v,renderLoss:h,visemeSlotsTotal:d,visemeSlotsCovered:w,visemeCoveragePct:T,transitionFramesUniqueSampled:r.size,transitionFramesUniquePainted:n.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+h,visemesShown:w,visemesSkipped:A,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const es=Tr,Qi=200,an=300,Zi=100,ea=600,ts="__sil__";function on(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===ts:!1}function Nr(){return{lastDrawnKey:""}}function Me(e){e.lastDrawnKey="",e.transitionCache=void 0}function ta(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const r=Fn(e);return t&&(t.transitionCache={queueLength:e.length,transitions:r}),r}function ra(e,t){let r="sil";for(const n of e)n.viseme!=="sil"&&(t!=null&&n.vtime>t||(r=n.viseme));return r}function na(e,t,r,n=120){if(r!=="sil")return r;const s=Un(e,t,n);return s!=="sil"?s:ra(e,t)}function sa(e,t){return e==="sil"?!1:t?yi(e,"sil",t):Dr(e,"sil").length>0}function ia(){return es+ea}function zt(e){return e??ts}function Ur(e,t,r,n,s=Zi){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=Je(e))return{diffPath:null,label:"sil"};const i=ta(e,n),o=Ys(i,t);if(o){const f=Ln(o.fromVtime,o.toVtime,o.from,o.to);if(t>=f.transStart&&t<f.transEnd){let l=Dr(o.from,o.to);r&&(l=zn(l,r));const c=Si(l,f.effectiveGapMs);if(c.length>0){const d=vi(t,f.transStart,f.transEnd,c.length);return{diffPath:c[d]??c[c.length-1],label:`${o.from}→${o.to}`,transitionMeta:{from:o.from,to:o.to,fromVtime:o.fromVtime,toVtime:o.toVtime,frameIdx:d,frameCount:c.length,fullFrameCount:l.length,omittedByGap:Math.max(0,l.length-c.length)}}}return{diffPath:bt(o.to),label:o.to}}}const a=Yt(e);let u=Mn(a,t);return u==="sil"&&(u=Un(e,t,s)),u==="sil"?{diffPath:null,label:"sil"}:{diffPath:bt(u),label:u}}function Zt(e,t){const r=t??zt(e.expressionPath);return`${zt(e.mouthPath)}|${r}`}function cn(e,t,r,n,s,i,o,a,u,f){const l=Ur(t,r,u,i),c={mouthPath:l.diffPath,expressionPath:n},d=Zt(c,s),w=Ye();if(l.transitionMeta&&w?.onTransitionSample(l.transitionMeta,l.diffPath),d===i.lastDrawnKey){w?.onDrawDeduped();return}w?.onDrawRequested(),a(l),i.lastDrawnKey=d,o(e,c,d,T=>{T===d&&(i.lastDrawnKey=d)})}function lr(e,t,r,n,s,i,o=null){const a={mouthPath:null,expressionPath:t},u=o!=null?`|idle@${Math.round(o*1e3)}`:"",f=Zt(a,r)+u;!(o!=null)&&f===n.lastDrawnKey||(i(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),s(e,a,f,c=>{c===f&&(n.lastDrawnKey=f)}))}function rs(e,t,r,n,s=vt,i){if(r<=t||e.length===0)return[];const o=i??Nr(),a=[];let u="";for(let f=t;f<r;f+=s){const l=Ur(e,f,n,o),c=zt(l.diffPath);c!==u&&(u=c,a.push({displayAtMs:f,mouthPath:l.diffPath,mouthKey:c,label:l.label}))}return a}const aa=3;function Vr(e){let t=0;const r=[];let n=!1,s=!1;const i=async()=>{if(!n){n=!0;try{for(;r.length>0;){const a=r.shift(),u=++t;await e(a.diffs,u,a)&&u===t&&a.onDisplayed?.(a.drawKey)}}finally{n=!1,r.length>0&&i()}}},o=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(a,u,f){const l=r.findIndex(c=>c.drawKey===u);l>=0?r[l]={diffs:a,drawKey:u,onDisplayed:f}:(r.length>=aa&&(r.shift(),Ye()?.onQueueSuperseded()),r.push({diffs:a,drawKey:u,onDisplayed:f})),o()},reset(){t+=1,r.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function oa(e,t=2){const r=[],n=new Set;let s=0,i=!1,o=0;const a=(f,l)=>`${f}|${l}`,u=async()=>{if(!i){i=!0;try{for(;s<t&&r.length>0;){const f=r.shift(),l=a(f.displayAtMs,f.drawKey);if(n.has(l))continue;n.add(l),s+=1;const c=o;try{await e(f)}finally{if(n.delete(l),s-=1,c!==o)return}}}finally{i=!1,r.length>0&&s<t&&u()}}};return{enqueue(f){const l=a(f.displayAtMs,f.drawKey);n.has(l)||r.some(c=>a(c.displayAtMs,c.drawKey)===l)||(r.push(f),u())},isQueuedOrInflight(f,l){const c=a(f,l);return n.has(c)?!0:r.some(d=>a(d.displayAtMs,d.drawKey)===c)},reset(){o+=1,r.length=0,n.clear(),s=0},pendingCount(){return r.length+s}}}function ca(){const e=new Map,t=r=>{r.bitmap.close()};return{has(r,n){return e.has(n)},markRendered(r,n,s,i,o){const a=e.get(n);a&&t(a),e.set(n,{displayAtMs:r,mouthKey:n,label:s,mouthPath:i,bitmap:o})},findForMouthKey(r){return e.get(r)??null},removeThrough(r){},pruneBefore(r){},reset(){for(const r of e.values())t(r);e.clear()},size(){return e.size}}}function ua(e,t,r,n,s,i){const o=rs(t,r,n,s,vt,i);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 la(e){const t=ca(),r=Nr(),n=new Set;let s="",i=null;const o=oa(async c=>{try{if(!e.supportsBufferedPlayback)return;const d=await e.compositePrefetchFrame(c.diffs,c.mouthKey);if(!d)return;t.markRendered(c.displayAtMs,c.mouthKey,c.label,c.mouthPath,d),Ye()?.onBufferPrefetched()}finally{n.delete(c.mouthKey)}},ys),a=c=>{for(const d of c)t.has(d.displayAtMs,d.mouthKey)||n.has(d.mouthKey)||o.isQueuedOrInflight(0,d.mouthKey)||(n.add(d.mouthKey),o.enqueue({...d,displayAtMs:0,drawKey:d.mouthKey,diffs:{mouthPath:d.mouthPath,expressionPath:null}}))},u=(c,d,w,T=ar)=>{if(!e.supportsBufferedPlayback)return;const h=Math.max(0,d-vt*4),A=rs(c,h,d+T,w,vt,r);a(A)},f=(c,d)=>{s=c,i=d},l=(c,d)=>!(s!==c||i!==d);return{reset(){t.reset(),o.reset(),n.clear(),Me(r),s="",i=null,Ye()?.onBufferReset()},markExternallyDisplayed(c,d){f(c.split("|")[0]??c,d)},warmupTick(c){e.supportsBufferedPlayback&&u(c.queue,0,c.availablePaths,Math.max(qr,ar))},isWarmupReady(c,d=qr){if(!e.supportsBufferedPlayback)return!0;const{ready:w,total:T}=ua(t,c.queue,0,d,c.availablePaths,r);return T===0?!1:w/T>=gs},getBufferedFrameCount:()=>t.size(),tick(c){const d=Ye();d?.onBufferTick(),u(c.queue,c.elapsedMs,c.availablePaths),t.pruneBefore(c.elapsedMs-ar);const w=Ur(c.queue,c.elapsedMs,c.availablePaths,r),T=zt(w.diffPath),h=Zt({mouthPath:w.diffPath,expressionPath:c.expressionPath},c.expressionDrawKey),A=()=>(f(T,c.expressionPath),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(l(T,c.expressionPath)||c.playbackState.lastDrawnKey===h)return A();const v=t.findForMouthKey(T,c.elapsedMs,vt);return v&&c.expressionPath!=null?(d?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):v?(e.blitBitmap(c.canvas,v.bitmap),f(v.mouthKey,c.expressionPath),c.playbackState.lastDrawnKey=h,c.onStatus({diffPath:v.mouthPath,label:v.label}),c.onDisplayed(h,v.mouthPath,v.label),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(d?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const fa=`
|
|
5
|
+
`);se=Ce.pop()??"";for(const Te of Ce)await _t(Te);if(st){se.trim()&&await _t(se.trim()),me===D&&!re.signal.aborted&&V&&k.markStreamComplete(r);break}}}catch(Ke){if(re.signal.aborted||!V)return;console.error("[realtimeVoice] avatar_speak failed:",Ke),e("error"),$()}finally{P===re&&(P=null)}},Re=h=>{const R=wi(h);if(!R){console.warn("[realtimeVoice] server message with no payload",h);return}const Q=String(R.type??"unknown");switch(Q!=="avatar_metadata"&&Q!=="avatar_audio_chunk"&&Q!=="avatar_lipsync"&&Q!=="avatar_interrupt"&&Q!=="error"&&console.debug("[realtimeVoice] server message",Q,R),Q){case"avatar_metadata":g(R);break;case"avatar_audio_chunk":Z(R);break;case"avatar_lipsync":oe(R);break;case"avatar_interrupt":M(R);break;case"error":{const re=String(R.message??"Voice session error");console.error("[realtimeVoice] server error:",re),e("error"),$();break}case"avatar_speak":ye(R);break}},_e=()=>p||(E=new di,p=new vs.PipecatClient({transport:new kr.WebSocketTransport({mediaManager:E,serializer:new fi,recorderSampleRate:Br,playerSampleRate:Lr}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{d=!0,e("idle"),$()},onDisconnected:()=>{d=!1,I()},onError:h=>{const R=typeof h=="object"&&h!==null&&"data"in h?String(h.data??h):String(h);console.error("[realtimeVoice]",R,h),e("error"),$()},onTransportStateChanged:h=>{h==="error"&&(e("error"),$())},onServerMessage:h=>{he(h)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{ke(),J("bot_started")},onBotStoppedSpeaking:()=>{V&&(Y(),j=setTimeout(()=>{j=null,V&&(k.markStreamComplete(r),J("bot_stopped"))},450))},onUserTranscript:h=>{String(h.text??""),m.onUserTranscript?.(h.text,!!h.final)},onBotOutput:h=>{m.onBotOutput?.(h.text)}}}),p);return{setDeveloperToken:h=>{},setTtsEngineId:h=>{u=h,k.setStreamTtsEngineId(h)},getTtsEngineId:()=>u,speak:async(h,R)=>{const Q=h.trim();if(Q){if(!p||!d)throw new Error("Realtime voice is not connected. Call connect() first.");z(),await p.sendText(Q)}},stop:()=>{P?.abort(),P=null,D+=1,ke(),z(),e("idle"),$()},connect:async h=>{if(h&&(m={...m,...h}),!m.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const R=_e();await R.initDevices();const Q=Zn(m);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",Q);try{await R.connect({wsUrl:Q})}catch(re){d=!1,e("error"),$();const me=re instanceof Error?re.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${me} — ${Q}`)}d=!0,e("idle"),$()},disconnect:async()=>{if(Y(),N=!1,w.length=0,b=!1,P?.abort(),P=null,D+=1,ke(),p)try{await p.disconnect()}catch(h){console.error("[realtimeVoice] disconnect failed:",h)}d=!1,I()},isConnected:()=>d,unlockAudio:async()=>{await k.primeAudioContext()},getVisemeQueue:()=>r,getWordQueue:()=>n,getFullVisemeQueue:()=>s,getFullWordQueue:()=>i,getSentenceEmotions:()=>a,getStreamMood:()=>c,getPlaybackElapsedMs:ce,isSpeaking:()=>k.isSpeaking(),isWarmingUp:()=>k.isWarmingUp(),releaseWarmupHold:()=>k.releaseWarmupHold(),setLipsyncWarmupHold:(h,R)=>{R&&(q=R),k.setLipsyncWarmupHoldEnabled(h)},getVoiceStream:()=>k.getVoiceStream(),setPlaybackSpeed:h=>{k.setPlaybackSpeed(h)},getPlaybackSpeed:()=>k.getPlaybackSpeed(),subscribe:h=>(C.add(h),()=>C.delete(h))}}function ts(e,t,r){return{width:e.crop?.source_width??t,height:e.crop?.source_height??r}}function rs(e,t){const r=e.crop;return{x:t?.source_x??r?.x??0,y:t?.source_y??r?.y??0,width:t?.source_w??r?.width??e.frame_width??0,height:t?.source_h??r?.height??e.frame_height??0}}function ns(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function pt(e,t){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const n=await r.arrayBuffer();return $s(n,t)}async function ss(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const r=await pt(e,t),n=new TextDecoder().decode(r);return JSON.parse(n)}async function yi(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function _i(e){const t=new Blob([e],{type:"image/webp"}),r=URL.createObjectURL(t);return new Promise((n,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(r),n(i)},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("Failed to decode decrypted image"))},i.src=r})}async function Si(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function vi(e){const t=new Blob([e],{type:"image/png"}),r=URL.createObjectURL(t);return new Promise((n,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(r),n(i)},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("Failed to decode decrypted PNG"))},i.src=r})}function bi(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Ti(e){const t=Ks();if(!It())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const r=await pt(t,e);return bi(r)}function lt(e,t){return`${e}/${t}_minus_sil.png`}const is=5;function rr(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const r=e?.crop?.content_threshold;return typeof r=="number"&&r>0?r:is}const Ei=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],vr=["t01_0.25","t02_0.50","t03_0.75"],ki=vr.length,nn=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 sn(e,t){return`${e}__${t}`}function on(e,t){return`pairs/${e}/${t}_minus_sil.png`}function dt(e){return`${e}_minus_sil.png`}function Or(e,t){if(t.has(e))return e;const r=/^pairs\/([^/]+)\//.exec(e);if(!r)return null;const n=r[1].split("__")[1];if(!n||n==="sil")return null;const s=dt(n);return t.has(s)?s:null}function os(e,t){return e.filter(r=>t.has(r))}function Ii(e,t,r){const n=Nr(e,t);return os(n,r).length>0}function Nr(e,t){if(e===t)return[];const r=[],n=sn(e,t);if(nn.has(n)){for(const i of vr)r.push(on(n,i));return r}const s=sn(t,e);if(nn.has(s)){for(let i=ki-1;i>=0;i--)r.push(on(s,vr[i]));return r}return[]}function Ai(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function Pi(e,t){return Ai(t).map(n=>e[n]).filter(n=>n!=null)}function xi(e,t,r,n){if(n<=0)return 0;const i=Math.max(1,r-t)/n,o=e-t,a=Math.floor(o/i);return Math.min(n-1,Math.max(0,a))}function as(e,t,r){if(!r)return`${e}/${t}`;const n=t.split("/").pop()??t,s=n.includes(".")?n.slice(0,n.lastIndexOf(".")):n;return`${e}/${s}.bin`}const Mi=[.32,.24,.16,.08,0],Ri=Mi.map(e=>`eyes_${e.toFixed(2)}`),Ci=["eyes_0.32","eyes_0.16","eyes_0.00"],Di=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Le=2,Fi=-20,qt=16,us={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Tt(e){return`brow_${e}`}function Ze(e){return us[e]}function Ue(e){return Math.max(Fi,Math.min(qt,e))}function Bi(e,t){if(e===t)return[];const r=e<t,n=r?Le:-Le,s=[];let i=e;if(i%Le!==0){const o=r?Math.ceil(i/Le)*Le:Math.floor(i/Le)*Le,a=Ue(o);if(r?a>=t:a<=t)return[t];i=a,s.push(i)}for(;;){const o=i+n;if(r?o>=t:o<=t){t!==i&&s.push(t);break}i=o,s.push(i)}return s}function an(e){const t=Ue(e);if(t%Le===0)return[t];const r=Math.floor(t/Le)*Le,n=Math.min(qt,r+Le),s=Ue(r);return t-s<=n-t?s===n?[s]:[s,n]:s===n?[n]:[n,s]}const Li=["fear","anger","sad","neutral","love","happy","disgust"],Oi={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 He(e,t="neutral"){const r=String(e??"").trim().toLowerCase();return r?Oi[r]??t:t}function cs(e){return e===0?null:lt(Tt(e),"eyes_standard")}function ls(e){return cs(Ze(e))}const Ni={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function Vr(e,t){if(!e)return null;if(t(e))return e;const r=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const s=Number(r[1]),i=r[2];for(const a of an(s)){if(a===s)continue;const l=lt(Tt(a),i);if(t(l))return l}const o=Ni[s];if(o){const a=lt(o,i);if(t(a))return a}return null}const n=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const s=n[1],i=n[2],o=Ze(s);for(const a of[o,...an(o)]){const l=lt(Tt(a),i);if(t(l))return l}}return null}function un(e,t){const r=Tt(Ze(e));return!t||t==="eyes_standard"?ls(e):e==="neutral"&&t==="eyes_standard"?null:lt(r,t)}function Vi(e,t){const r=[];for(const n of t)r.push(un(e,n));for(let n=t.length-2;n>=0;n--)r.push(un(e,t[n]));return r.push(ls(e)),r}function Ui(e){return lt(Tt(e),"eyes_standard")}function Wi(e,t){return Bi(e,t).map(Ui)}const $i=6;function Hi(e,t){for(const r of e)if(t>=r.wtime&&t<r.wtime+r.wduration)return r;return null}function Ki(e){const t=Ue(e);return t>=qt?qt:Ue(t+$i)}function qi(e,t,r){const n=Ue(r);return Hi(t,e)?.emphasis?Ki(n):n}function cn(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const r=Number.parseInt(t[1],10);return Number.isFinite(r)?Ue(r):null}function ct(e,t){return e+Math.random()*(t-e)}function Vt(){return ct(14,32)}function Gi(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:r=2200,intervalMaxMs:n=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:l=380,minDwellMs:f=550}=e;let c="neutral",u="neutral",d=0,p=0,E=0,m={kind:"idle",nextBlinkAt:performance.now()+t},A=null,x="__eyes_open__|neutral|brow:0";function C(P=c){x=`${A??"__eyes_open__"}|${P}|brow:${p}`}function w(P,D=c){A=P;const N=cn(P);N!=null?p=N:P==null&&(p=0),C(D)}function b(P){return cs(P)}function O(P,D,N){const j=Ue(D),F=Ue(N);if(d=F,j===F){w(b(F));return}const Y=[...Wi(j,F),b(F)];m={kind:"browBlend",paths:Y,index:0,holdUntil:P+Vt(),targetBrow:F},w(Y[0]??null)}function V(P,D){m={kind:"idle",nextBlinkAt:P+ct(r,n)},u=D,w(b(d),D)}function X(P,D,N){const j=N?Ci:Math.random()<a?Ri:Di;m={kind:"playing",paths:Vi(D,j),index:0,holdUntil:P+Vt(),after:"idle",blinkEmotion:D},u=D,w(m.paths[0]??null,D)}function fe(P){if(m.kind==="browBlend"){for(;P>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=P+Vt();const D=m.paths[m.index]??null;w(D),P>=m.holdUntil&&m.index>=m.paths.length-1&&(p=m.targetBrow,d=m.targetBrow,w(b(m.targetBrow)),m={kind:"idle",nextBlinkAt:P+l});return}if(m.kind==="idle"){w(b(d),u),P>=m.nextBlinkAt&&X(P,u,!1);return}if(m.kind==="doublePause"){w(b(d),m.blinkEmotion),P>=m.resumeAt&&X(P,m.blinkEmotion,!0);return}if(m.kind==="playing"){for(;P>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=P+Vt();if(w(m.paths[m.index]??null,m.blinkEmotion),P>=m.holdUntil&&m.index>=m.paths.length-1){if(m.after==="resumeIdle"){V(P+l,c);return}if(m.after==="doublePause"){m={kind:"doublePause",resumeAt:P+ct(i,o),blinkEmotion:m.blinkEmotion},w(b(d),m.blinkEmotion);return}if(m.after==="idle"&&Math.random()<s){m={kind:"doublePause",resumeAt:P+ct(i,o),blinkEmotion:m.blinkEmotion},w(b(d),m.blinkEmotion);return}V(P,m.blinkEmotion)}}}return{advance:fe,setTargetEmotion(P,D){const N=He(P,c);if(N===c)return;const j=performance.now();!D?.force&&f>0&&!(c==="neutral"&&N!=="neutral")&&j-E<f||(c=N,u=N,E=j)},setTargetEyebrow(P){const D=Ue(P);if(D===d)return;const N=performance.now(),j=m.kind==="browBlend"?cn(A)??p:p;d=D,!(D===j&&m.kind!=="browBlend")&&(m.kind==="playing"||m.kind==="doublePause"||O(N,j,D))},snapToEmotion(P){const D=He(P),N=Ze(D);c=D,u=D,d=N,p=N,E=performance.now(),m={kind:"idle",nextBlinkAt:performance.now()+ct(4e3,7e3)},w(b(N),D)},getTargetEmotion:()=>c,getTargetEyebrow:()=>d,getExpressionPath:()=>A,getDrawKey:()=>x,reset(){c="neutral",u="neutral",d=0,p=0,E=0,V(performance.now()+ct(r,n),"neutral")}}}function zi(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,r=null,n="";const s=()=>{r&&(URL.revokeObjectURL(r),r=null)};return{async load(i){t&&n===i||(s(),t=!1,n=i,i.startsWith("blob:")&&(r=i),await new Promise((o,a)=>{const l=()=>{const f=e.duration;if(!Number.isFinite(f)||f<=0){a(new Error(`Idle video has invalid duration: ${i}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",l,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${i}`)),{once:!0}),e.src=i,e.load()}))},isReady(){return t},getVideo(){return e},setActive(i){t&&(i?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),s(),t=!1,n=""}}}const ji=50,fs=400;function Yi(e,t,r){return e.filter(n=>{const s=n.queueIndex??-1;return s>=t&&s<=r})}function Qi(e,t){const r=[];for(const n of e){const s=Yi(t,n.start_word,n.end_word);if(s.length===0)continue;const i=s[0],o=s[s.length-1];r.push({sentence:n,startMs:Math.max(0,i.wtime-ji),endMs:o.wtime+o.wduration+fs})}return r.sort((n,s)=>n.startMs-s.startMs)}function Xi(e,t,r,n="neutral"){const s=He(n);if(t.length===0)return s;if(r.length===0||e<r[0].wtime)return He(t[0]?.emotion,s);const i=Qi(t,r);let o=null;for(const f of i)e>=f.startMs&&e<=f.endMs&&(o=f);if(o)return He(o.sentence.emotion,s);const a=r[r.length-1],l=a.wtime+a.wduration;return e>l+fs?He(t[t.length-1]?.emotion,s):s}function Ur(e,t,r,n,s=is){const i=new OffscreenCanvas(r,n),o=i.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,r,n);const a=o.getImageData(0,0,r,n),l=o.createImageData(r,n);l.data.set(a.data);const c=new OffscreenCanvas(r,n).getContext("2d",{willReadFrequently:!0});for(const u of t){c.clearRect(0,0,r,n),c.drawImage(u,0,0,r,n);const d=c.getImageData(0,0,r,n);for(let p=0;p<l.data.length;p+=4){const E=d.data[p],m=d.data[p+1],A=d.data[p+2];Math.max(E,m,A)>s&&(l.data[p]=E,l.data[p+1]=m,l.data[p+2]=A,l.data[p+3]=255)}}return o.putImageData(l,0,0),i}let Xe=null,mt=null;const Gt=new Map;function Ji(){Xe=null,mt=null,Gt.clear()}xn(Ji);function Zi(e){return e??mt??void 0}function Wr(e){return new Promise((t,r)=>{const n=new Image;n.decoding="async",n.onload=()=>t(n),n.onerror=()=>r(new Error(`Failed to load image: ${e}`)),n.src=e})}async function eo(e){return It()?vi(await pt(Kt(),e??"")):Wr(Kt())}async function ln(e,t,r,n){const s=r?await ss(e,n):await fetch(e).then(f=>{if(!f.ok)throw new Error(`Failed to load ${e}`);return f.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const o=r?await _i(await pt(as(t,i.path,r),n??"")):await Wr(`${t}/${i.path}`),a=new Map;for(const f of s.cells??[])f.path&&a.set(f.path,f);const l=new Map;for(const f of s.sheets??[])l.set(f.index,f);return{atlas:o,atlasMeta:s,cellByPath:a,sheetByIndex:l,diffBase:t}}async function br(e){const t=Zi(e),r=It();if(r&&!t)throw new Error("Encrypted assets enabled but no key provided");if(Xe&&(!r||mt===(t??null))){const i=await Xe;return{...ht(i),visemePaths:[...i.viseme.cellByPath.keys()]}}mt=t??null,Gt.clear();const n=Mn();Xe=(async()=>{const i=await eo(t),o=await ln(Rn(),n,r,t);let a=null;try{a=await ln(Cn(),n,r,t)}catch{a=null}return{sil:i,viseme:o,expression:a}})();const s=await Xe;return{...ht(s),visemePaths:[...s.viseme.cellByPath.keys()]}}async function $r(e){if(await br(e),!Xe)throw new Error("Assets not loaded");return Xe}function ht(e){return ts(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function to(e,t){const r=document.createElement("canvas");return r.width=t.w,r.height=t.h,r.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}async function zt(e,t,r){const n=`${t.diffBase}::${r}`,s=Gt.get(n);if(s)return s;const i=(async()=>{const o=t.cellByPath.get(r);if(!o)throw new Error(`No atlas cell for path: ${r}`);const a=rs(t.atlasMeta,o),l=ht(e);if(ns(o)){const u=to(t,o),d=document.createElement("canvas");d.width=l.width,d.height=l.height;const p=d.getContext("2d");return p.fillStyle="#000",p.fillRect(0,0,l.width,l.height),p.drawImage(u,a.x,a.y),d}const f=`${t.diffBase}/${r}`,c=await Wr(f);if(c.naturalWidth===l.width&&c.naturalHeight===l.height)return c;throw new Error(`Diff PNG wrong size for ${r}`)})();return Gt.set(n,i),i}async function mr(e,t,r,n,s,i){if(s){const{width:p,height:E}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const m=document.createElement("canvas");m.width=p,m.height=E;const A=m.getContext("2d");if(A.clearRect(0,0,p,E),A.drawImage(t,0,0,p,E),i&&!i())return;(e.width!==p||e.height!==E)&&(e.width=p,e.height=E);const x=e.getContext("2d");x.clearRect(0,0,p,E),x.drawImage(m,0,0);return}const o=await $r(),a=rr(o.viseme.atlasMeta),{width:l,height:f}=ht(o);(e.width!==l||e.height!==f)&&(e.width=l,e.height=f);const c=[],u=e.getContext("2d");if(u.clearRect(0,0,l,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const p=o.sil;u.drawImage(p,0,0,l,f);return}if(c.length===0){u.drawImage(t,0,0,l,f);return}const d=Ur(t,c,l,f,a);u.drawImage(d,0,0)}async function Tr(e,t,r){const n=await $r(mt??void 0),s=rr(n.viseme.atlasMeta),{width:i,height:o}=ht(n);(e.width!==i||e.height!==o)&&(e.width=i,e.height=o);const a=[];if(t.mouthPath){const c=new Set(n.viseme.cellByPath.keys()),u=Or(t.mouthPath,c)??(c.has(t.mouthPath)?t.mouthPath:null);u&&a.push(await zt(n,n.viseme,u))}if(t.expressionPath&&n.expression){const c=Vr(t.expressionPath,u=>n.expression.cellByPath.has(u));c&&a.push(await zt(n,n.expression,c))}const l=e.getContext("2d");if(l.clearRect(0,0,i,o),a.length===0){l.drawImage(n.sil,0,0,i,o);return}const f=Ur(n.sil,a,i,o,s);l.drawImage(f,0,0)}async function ro(e,t){const r=await $r(mt??void 0),n=rr(r.viseme.atlasMeta),{width:s,height:i}=ht(r),o=[];if(e.mouthPath){const c=new Set(r.viseme.cellByPath.keys()),u=Or(e.mouthPath,c)??(c.has(e.mouthPath)?e.mouthPath:null);u&&o.push(await zt(r,r.viseme,u))}if(e.expressionPath&&r.expression){const c=Vr(e.expressionPath,u=>r.expression.cellByPath.has(u));c&&o.push(await zt(r,r.expression,c))}const a=new OffscreenCanvas(s,i),l=a.getContext("2d");if(o.length===0)return l.drawImage(r.sil,0,0,s,i),a.transferToImageBitmap();const f=Ur(r.sil,o,s,i,n);return l.drawImage(f,0,0),a.transferToImageBitmap()}async function no(e){await Tr(e,{mouthPath:null,expressionPath:null})}let ds=null;function fn(e){ds=e}function Ge(){return ds}function so(e){return`${e.from}→${e.to}@${e.fromVtime}`}function dn(){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 io(){let e=dn();const t=new Set,r=new Set,n=new Set;let s="",i=-1,o="";const a=()=>{e=dn(),t.clear(),r.clear(),n.clear(),s="",i=-1,o=""},l=c=>{t.add(c)},f=c=>{c&&n.add(c)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(c,u){const d=so(c);e.transitionFramesSampled+=1,d!==s&&(s=d,i=-1,o!==d&&(o=d,e.rifeFramesOmittedByGap+=c.omittedByGap)),u&&r.add(u),i>=0&&c.frameIdx>i+1&&(e.transitionFramesMissed+=c.frameIdx-i-1),i=c.frameIdx},onBufferTick(){e.bufferTicks+=1},onBufferHit(){e.bufferHits+=1},onBufferUnderrun(){e.bufferUnderruns+=1},onBufferPrefetched(){e.bufferPrefetched+=1},onBufferReset(){},onDrawDisplayed(c,u){if(e.drawsDisplayed+=1,c.transitionMeta){e.transitionFramesDisplayed+=1;const p=c.transitionMeta;l(p.fromVtime),l(p.toVtime),f(c.mouthPath);return}if(c.label.includes("→")){e.transitionFramesDisplayed+=1;return}const d=c.label.trim();if(!(!d||d==="sil")){for(const p of u)if(p.viseme===d&&c.elapsedMs>=p.vtime&&c.elapsedMs<p.vtime+p.vduration){l(p.vtime);break}}},snapshot(c,u){let d=0,p=0;for(const C of c)if(C.viseme!=="sil"){if(C.vtime>=u)break;d+=1,t.has(C.vtime)&&(p+=1)}const E=d>0?Math.round(p/d*100):100,m=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),A=d-p,x=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:x,renderLoss:m,visemeSlotsTotal:d,visemeSlotsCovered:p,visemeCoveragePct:E,transitionFramesUniqueSampled:r.size,transitionFramesUniquePainted:n.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+m,visemesShown:p,visemesSkipped:A,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const ms=Ar,oo=200,mn=300,ao=100,uo=600,hs="__sil__";function hn(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===hs:!1}function Hr(){return{lastDrawnKey:""}}function xe(e){e.lastDrawnKey="",e.transitionCache=void 0}function co(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const r=qn(e);return t&&(t.transitionCache={queueLength:e.length,transitions:r}),r}function lo(e,t){let r="sil";for(const n of e)n.viseme!=="sil"&&(t!=null&&n.vtime>t||(r=n.viseme));return r}function fo(e,t,r,n=120){if(r!=="sil")return r;const s=Jn(e,t,n);return s!=="sil"?s:lo(e,t)}function mo(e,t){return e==="sil"?!1:t?Ii(e,"sil",t):Nr(e,"sil").length>0}function ho(){return ms+uo}function jt(e){return e??hs}function Kr(e,t,r,n,s=ao){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=Qe(e))return{diffPath:null,label:"sil"};const i=co(e,n),o=ii(i,t);if(o){const f=Gn(o.fromVtime,o.toVtime,o.from,o.to);if(t>=f.transStart&&t<f.transEnd){let c=Nr(o.from,o.to);r&&(c=os(c,r));const u=Pi(c,f.effectiveGapMs);if(u.length>0){const d=xi(t,f.transStart,f.transEnd,u.length);return{diffPath:u[d]??u[u.length-1],label:`${o.from}→${o.to}`,transitionMeta:{from:o.from,to:o.to,fromVtime:o.fromVtime,toVtime:o.toVtime,frameIdx:d,frameCount:u.length,fullFrameCount:c.length,omittedByGap:Math.max(0,c.length-u.length)}}}return{diffPath:dt(o.to),label:o.to}}}const a=Jt(e);let l=Wn(a,t);return l==="sil"&&(l=Jn(e,t,s)),l==="sil"?{diffPath:null,label:"sil"}:{diffPath:dt(l),label:l}}function Et(e,t){const r=t??jt(e.expressionPath);return`${jt(e.mouthPath)}|${r}`}function pn(e,t,r,n,s,i,o,a,l,f){const c=Kr(t,r,l,i),u={mouthPath:c.diffPath,expressionPath:n},d=Et(u,s),p=Ge();if(c.transitionMeta&&p?.onTransitionSample(c.transitionMeta,c.diffPath),d===i.lastDrawnKey){p?.onDrawDeduped();return}p?.onDrawRequested(),a(c),i.lastDrawnKey=d,o(e,u,d,E=>{E===d&&(i.lastDrawnKey=d)})}function hr(e,t,r,n,s,i,o=null,a=null){const l={mouthPath:a,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",c=Et(l,r)+f;!(o!=null)&&c===n.lastDrawnKey||(i(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),s(e,l,c,d=>{d===c&&(n.lastDrawnKey=c)}))}function ps(e,t,r,n,s=bt,i){if(r<=t||e.length===0)return[];const o=i??Hr(),a=[];let l="";for(let f=t;f<r;f+=s){const c=Kr(e,f,n,o),u=jt(c.diffPath);u!==l&&(l=u,a.push({displayAtMs:f,mouthPath:c.diffPath,mouthKey:u,label:c.label}))}return a}const po=3;function qr(e){let t=0;const r=[];let n=!1,s=!1;const i=async()=>{if(!n){n=!0;try{for(;r.length>0;){const a=r.shift(),l=++t;await e(a.diffs,l,a)&&l===t&&a.onDisplayed?.(a.drawKey)}}finally{n=!1,r.length>0&&i()}}},o=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(a,l,f){const c=r.findIndex(u=>u.drawKey===l);c>=0?r[c]={diffs:a,drawKey:l,onDisplayed:f}:(r.length>=po&&(r.shift(),Ge()?.onQueueSuperseded()),r.push({diffs:a,drawKey:l,onDisplayed:f})),o()},reset(){t+=1,r.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function wo(e,t=2){const r=[],n=new Set;let s=0,i=!1,o=0;const a=(f,c)=>`${f}|${c}`,l=async()=>{if(!i){i=!0;try{for(;s<t&&r.length>0;){const f=r.shift(),c=a(f.displayAtMs,f.drawKey);if(n.has(c))continue;n.add(c),s+=1;const u=o;try{await e(f)}finally{if(n.delete(c),s-=1,u!==o)return}}}finally{i=!1,r.length>0&&s<t&&l()}}};return{enqueue(f){const c=a(f.displayAtMs,f.drawKey);n.has(c)||r.some(u=>a(u.displayAtMs,u.drawKey)===c)||(r.push(f),l())},isQueuedOrInflight(f,c){const u=a(f,c);return n.has(u)?!0:r.some(d=>a(d.displayAtMs,d.drawKey)===u)},reset(){o+=1,r.length=0,n.clear(),s=0},pendingCount(){return r.length+s}}}function go(){const e=new Map,t=r=>{r.bitmap.close()};return{has(r,n){return e.has(n)},markRendered(r,n,s,i,o){const a=e.get(n);a&&t(a),e.set(n,{displayAtMs:r,mouthKey:n,label:s,mouthPath:i,bitmap:o})},findForMouthKey(r){return e.get(r)??null},removeThrough(r){},pruneBefore(r){},reset(){for(const r of e.values())t(r);e.clear()},size(){return e.size}}}function yo(e,t,r,n,s,i){const o=ps(t,r,n,s,bt,i);if(o.length===0)return{ready:0,total:0};let a=0;for(const l of o)e.has(l.displayAtMs,l.mouthKey)&&(a+=1);return{ready:a,total:o.length}}function _o(e){const t=go(),r=Hr(),n=new Set;let s="",i=null;const o=wo(async u=>{try{if(!e.supportsBufferedPlayback)return;const d=await e.compositePrefetchFrame(u.diffs,u.mouthKey);if(!d)return;t.markRendered(u.displayAtMs,u.mouthKey,u.label,u.mouthPath,d),Ge()?.onBufferPrefetched()}finally{n.delete(u.mouthKey)}},Rs),a=u=>{for(const d of u)t.has(d.displayAtMs,d.mouthKey)||n.has(d.mouthKey)||o.isQueuedOrInflight(0,d.mouthKey)||(n.add(d.mouthKey),o.enqueue({...d,displayAtMs:0,drawKey:d.mouthKey,diffs:{mouthPath:d.mouthPath,expressionPath:null}}))},l=(u,d,p,E=lr)=>{if(!e.supportsBufferedPlayback)return;const m=Math.max(0,d-bt*4),A=ps(u,m,d+E,p,bt,r);a(A)},f=(u,d)=>{s=u,i=d},c=(u,d)=>!(s!==u||i!==d);return{reset(){t.reset(),o.reset(),n.clear(),xe(r),s="",i=null,Ge()?.onBufferReset()},markExternallyDisplayed(u,d){f(u.split("|")[0]??u,d)},warmupTick(u){e.supportsBufferedPlayback&&l(u.queue,0,u.availablePaths,Math.max(Xr,lr))},isWarmupReady(u,d=Xr){if(!e.supportsBufferedPlayback)return!0;const{ready:p,total:E}=yo(t,u.queue,0,d,u.availablePaths,r);return E===0?!1:p/E>=Ms},getBufferedFrameCount:()=>t.size(),tick(u){const d=Ge();d?.onBufferTick(),l(u.queue,u.elapsedMs,u.availablePaths),t.pruneBefore(u.elapsedMs-lr);const p=Kr(u.queue,u.elapsedMs,u.availablePaths,r),E=jt(p.diffPath),m=Et({mouthPath:p.diffPath,expressionPath:u.expressionPath},u.expressionDrawKey),A=()=>(f(E,u.expressionPath),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(c(E,u.expressionPath)||u.playbackState.lastDrawnKey===m)return A();const x=t.findForMouthKey(E,u.elapsedMs,bt);return x&&u.expressionPath!=null?(d?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):x?(e.blitBitmap(u.canvas,x.bitmap),f(x.mouthKey,u.expressionPath),u.playbackState.lastDrawnKey=m,u.onStatus({diffPath:x.mouthPath,label:x.label}),u.onDisplayed(m,x.mouthPath,x.label),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(d?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const So=`
|
|
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
|
+
`,vo=`
|
|
34
34
|
in vec2 vTextureCoord;
|
|
35
35
|
out vec4 finalColor;
|
|
36
36
|
|
|
@@ -44,4 +44,4 @@ void main(void)
|
|
|
44
44
|
float keep = step(uThreshold + 1e-6, peak);
|
|
45
45
|
finalColor = vec4(color.rgb, keep);
|
|
46
46
|
}
|
|
47
|
-
`;function un(e=5){const t=new ne.Filter({glProgram:ne.GlProgram.from({vertex:fa,fragment:da,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=r=>{t.resources.thresholdUniforms.uniforms.uThreshold=r/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function ma(e,t,r){return e>r||t>r}function ha(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function pa(e,t){return t!=null&&t>0?Math.floor(t):ha(e)}function wa(e,t){const r=document.createElement("canvas");r.width=t.w,r.height=t.h;const n=r.getContext("2d");if(!n)throw new Error("Failed to acquire 2d context for atlas cell crop");return n.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}function ns(e){return fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load image: ${e}`);return t.blob()}).then(t=>createImageBitmap(t))}async function ln(e,t,r,n,s){const i=r?await qn(e,s):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),o=i.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,u=async(c,d)=>{const w=jn(t,d,r),T=r?await li(await pt(w,s??"")):await ns(w);if(ma(T.width,T.height,n))return console.info(`[PixiVisemeCompositor] Sheet ${d} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${n}; using per-cell crops.`),{mode:"cells",bitmap:T};const h=ne.Texture.from(T);return h.source.scaleMode="nearest",{mode:"full",texture:h}};a.set(o.index,await u(o.index,o.path));for(const c of i.sheets??[])c.index!==o.index&&c.path&&a.set(c.index,await u(c.index,c.path));const f=new Map;for(const c of i.cells??[])c.path&&f.set(c.path,c);const l=new Map;for(const c of i.sheets??[])l.set(c.index,c);return{atlasMeta:i,cellByPath:f,sheetByIndex:l,diffBase:t,sheets:a}}async function ga(e,t={}){const r=new ne.Application;try{await r.init({canvas:e,width:842,height:1264,preference:"webgl",autoStart:!1,antialias:!1,resolution:1,autoDensity:!1,backgroundAlpha:1,backgroundColor:0,powerPreference:"high-performance"})}catch(p){throw r.destroy({removeView:!1}),p}if(r.renderer.type!==ne.RendererType.WEBGL)throw r.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const n=pa(r.renderer.gl,t.maxTextureSize);let s=!1,i=!1,o=!1;const a=r.canvas,u=()=>{s=!0,!i&&!o&&(i=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",u);const f=new ne.Sprite(ne.Texture.EMPTY),l=new ne.Sprite(ne.Texture.EMPTY);l.visible=!1,l.alpha=0;const c=new ne.Sprite(ne.Texture.EMPTY),d=new ne.Sprite(ne.Texture.EMPTY),w=new ne.Sprite(ne.Texture.EMPTY);w.visible=!1;const T=un(5),h=un(5);c.filters=[T],d.filters=[h],r.stage.addChild(f),r.stage.addChild(l),r.stage.addChild(c),r.stage.addChild(d),r.stage.addChild(w);let A=null,v=null,R=null,g=null,k=null,F=null,D=null,Y=842,O=1264,E=null,P=5;const M=new Map;let B=null,ee=null,V=null;const te=vn(()=>{M.clear(),F=null,D=null,A=null,E=null}),X=(p,S)=>{Y=p,O=S,r.renderer.resize(p,S),(e.width!==p||e.height!==S)&&(e.width=p,e.height=S)},z=()=>{c.visible=!1,d.visible=!1,c.texture=ne.Texture.EMPTY,d.texture=ne.Texture.EMPTY,B=null,ee=null},me=()=>{k=null,l.visible=!1,l.alpha=0},ae=()=>{f.visible=!0,f.width=Y,f.height=O,f.x=0,f.y=0},Q=()=>{l.width=Y,l.height=O,l.x=0,l.y=0},de=()=>{w.visible=!1,me(),A&&(f.texture=A,ae())},he=()=>{!k&&!l.visible||de()},Se=p=>{if(o||s||!A){de();return}const S=Math.max(0,p);if(!v||S<=0){de();return}z(),w.visible=!1,f.texture=v,ae(),l.texture=A,Q(),l.alpha=0,l.visible=!0,k={startMs:performance.now(),durationMs:S},H()},j=(p=performance.now())=>{if(!k)return!1;if(o||s)return he(),!1;const S=(p-k.startMs)/Math.max(1,k.durationMs);if(S>=1)return de(),H(),!1;const C=Math.min(1,Math.max(0,S)),le=C*C*(3-2*C);return l.alpha=le,l.visible=!0,H(),!0},y=()=>{if(R){try{R.resource=null}catch{}R.destroy(),R=null}v&&(v.destroy(!1),v=null),g=null},I=(p,S)=>{const C=p.cellByPath.get(S);if(!C||!Kn(C))return null;const le=`${p.diffBase}::${S}`;let oe=M.get(le);if(!oe){const pe=C.sheet??0,ye=p.sheets.get(pe);if(!ye)return null;let ve,wt=!1;if(ye.mode==="full")ve=new ne.Texture({source:ye.texture.source,frame:new ne.Rectangle(C.x,C.y,C.w,C.h)});else{const m=wa(ye.bitmap,C);ve=ne.Texture.from(m),ve.source.scaleMode="nearest",wt=!0}oe={texture:ve,ownsSource:wt},M.set(le,oe)}return{texture:oe.texture,cell:C}},U=(p,S,C,le)=>{if(!le||!C)return p.visible=!1,p.texture=ne.Texture.EMPTY,!1;const oe=I(C,le);if(!oe)return p.visible=!1,p.texture=ne.Texture.EMPTY,!1;const pe=Hn(C.atlasMeta,oe.cell);return S.setThreshold(P),p.texture=oe.texture,p.x=pe.x,p.y=pe.y,p.width=oe.cell.w,p.height=oe.cell.h,p.visible=!0,!0},G=p=>{if(!p||!F)return null;const S=E??new Set(F.cellByPath.keys());return Cr(p,S)??(S.has(p)?p:null)},$=p=>{w.visible=!1,de();const S=G(p.mouthPath),C=p.expressionPath&&D?Br(p.expressionPath,le=>D.cellByPath.has(le)):null;S!==B?(U(c,T,F,S),B=S):S?c.visible=!0:c.visible=!1,C!==ee?(U(d,h,D,C),ee=C):C?d.visible=!0:d.visible=!1},H=()=>{if(!(o||s||document.hidden))try{r.render()}catch{}};return{async loadAssets(p){if(o)return{width:Y,height:O,visemePaths:[]};const S=Et();if(S&&!p)throw new Error("Encrypted assets enabled but no key provided");const C=S?await di(await pt(Ht(),p??"")):await ns(Ht());A&&A.destroy(!0),A=ne.Texture.from(C),A.source.scaleMode="linear";const le=bn();F=await ln(Tn(),le,S,n,p);try{D=await ln(kn(),le,S,n,p)}catch(pe){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",pe),D=null}const oe=$n(F.atlasMeta,C.width,C.height);return X(oe.width,oe.height),P=Qt(F.atlasMeta),T.setThreshold(P),h.setThreshold(P),E=new Set(F.cellByPath.keys()),M.clear(),de(),z(),H(),{width:oe.width,height:oe.height,visemePaths:[...F.cellByPath.keys()]}},getVisemeAtlasPaths(){return E},drawLiveFrame(p){o||s||!A||(he(),$(p),H())},drawIdleVideo(p,S){o||s||document.hidden||S&&!S()||p.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(me(),z(),w.visible=!1,!v||g!==p?(y(),R=new ne.VideoSource({resource:p,autoPlay:!1,updateFPS:0}),R.autoUpdate=!1,v=new ne.Texture({source:R}),g=p):v.source.update(),f.texture=v,ae(),H())},beginIdleToSilCrossfade:Se,tickIdleToSilCrossfade:j,finishIdleToSilCrossfade:he,isIdleToSilCrossfading(){return k!=null},renderSilOnly(){o||s||!A||(z(),de(),H())},blitBitmap(p){o||s||(he(),z(),V&&(V.destroy(!0),V=null),V=ne.Texture.from(p),w.texture=V,w.visible=!0,w.x=0,w.y=0,w.width=Y,w.height=O,f.visible=!1,H())},async compositePrefetchFrame(p){return null},renderFrame:H,isContextLost(){return s},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",u),te(),y(),V&&(V.destroy(!0),V=null);for(const{texture:S,ownsSource:C}of M.values())S.destroy(C);M.clear(),A&&(A.destroy(!0),A=null);const p=S=>{S.mode==="full"?S.texture.destroy(!0):S.bitmap.close()};if(F)for(const S of F.sheets.values())p(S);if(D)for(const S of D.sheets.values())p(S);T.destroy(!0),h.destroy(!0),r.destroy({removeView:!1},{children:!0,texture:!0})}}}const fn=-1,Ut=1e5,dn=new Map;async function ya(e){let t=dn.get(e);if(!t){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch worker script (${r.status}): ${e}`);const n=await r.blob();t=URL.createObjectURL(n),dn.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function _a(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Sr(e,t){(e.width!==t.width||e.height!==t.height)&&(e.width=t.width,e.height=t.height);const r=e.getContext("2d");r&&r.drawImage(t,0,0)}function mn(e,t){let r=0,n=null;const s=Vr(async(i,o)=>(await yr(),await _r(e,i),s.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(i){const o=await yr(i);return n=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return n},async renderSilOnly(){r+=1,s.reset(),await Yi(e)},drawLiveFrame(i,o,a,u){s.enqueue(o,a,u)},async compositePrefetchFrame(i,o){try{return await ji(i)}catch{return null}},blitBitmap(i,o){Sr(i,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(i,o){r+=1;const a=r;t.onStatus?.(o),await _r(i,{mouthPath:bt(o),expressionPath:null})},dispose(){r+=1,s.reset()}}}function Sa(e,t,r){let n=null,s=1,i=0,o=!1,a=!1,u=null;const f=new Map,l=new Map;let c=Ut;const d=Vr(async(R,g,k)=>(f.set(g,{drawKey:k.drawKey,onDisplayed:k.onDisplayed}),await A({type:"drawFrame",diffPath:R.mouthPath,expressionDiffPath:R.expressionPath,liveSeq:g},void 0,!0),!1)),w=R=>{if(R===fn){let F=-1,D;for(const[Y,O]of f)Y>=F&&(F=Y,D=O);F>=0&&f.delete(F),D?.onDisplayed?.(D.drawKey);return}const g=-R,k=f.get(g);f.delete(g),k?.onDisplayed?.(k.drawKey)},T=new Map,h=(R,g)=>{a||!n||n.postMessage(R,[])},A=(R,g,k=!1)=>{if(a)return Promise.resolve();const F=s++;return new Promise((D,Y)=>{T.set(F,{resolve:O=>D(O),reject:Y,generation:typeof R.generation=="number"?R.generation:void 0,expectRenderDone:k}),h({...R,requestId:F})})},v=(async()=>{n=await ya(r),n.onmessage=R=>{if(a)return;const g=R.data;if(g.type==="status"){t.onStatus?.(g.label);return}if(g.type==="frame"){if(g.generation<=-Ut){const D=-g.generation,Y=l.get(D);l.delete(D),Y?.resolve(g.bitmap);return}const F=g.generation<0;if(!F&&g.generation!==i){g.bitmap.close();return}if(F&&!(g.generation===fn)){const Y=-g.generation;if(!d.isLatestSeq(Y)){Ye()?.onWorkerStale(),g.bitmap.close();return}}if(F&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){Ye()?.onWorkerStale(),g.bitmap.close();return}Sr(e,g.bitmap),g.bitmap.close(),F&&w(g.generation);return}const k=T.get(g.requestId);if(k)switch(g.type){case"ready":T.delete(g.requestId),k.resolve();break;case"loadAssetsDone":T.delete(g.requestId),u=g.visemePaths?.length?new Set(g.visemePaths):null,k.resolve({width:g.width,height:g.height,visemePaths:g.visemePaths});break;case"renderDone":if(k.expectRenderDone&&k.generation!=null&&g.generation!==k.generation)return;T.delete(g.requestId),k.resolve();break;case"renderAborted":T.delete(g.requestId),k.resolve();break;case"error":T.delete(g.requestId),t.onError?.(g.message),k.reject(new Error(g.message));break}},n.onerror=R=>{if(a)return;const g=R.message||"Worker error";t.onError?.(g);for(const[,k]of T)k.reject(new Error(g));T.clear()},await A({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(R){if(a)return{width:842,height:1264};if(await v,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await A({type:"loadAssets",keyHex:R,urls:Ms(nt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return u},async renderSilOnly(){if(a||(await v,a))return;i+=1,d.reset(),f.clear(),l.forEach(({resolve:g})=>g(null)),l.clear(),c=Ut;const R=i;await A({type:"cancelLiveDraws"}),await A({type:"renderSil",generation:R},void 0,!0)},drawLiveFrame(R,g,k,F){a||v.then(()=>{a||d.enqueue(g,k,F)})},compositePrefetchFrame(R,g){return a?Promise.resolve(null):v.then(()=>{if(a)return null;const k=++c;return new Promise(F=>{l.set(k,{resolve:F}),A({type:"drawFrame",diffPath:R.mouthPath,expressionDiffPath:R.expressionPath,liveSeq:k},void 0,!0).catch(()=>{l.delete(k),F(null)})})})},blitBitmap(R,g){Sr(R,g)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(R,g,k={}){if(a||(await v,a))return;i+=1,d.reset(),f.clear();const F=i;try{await A({type:"cancelLiveDraws"}),await A({type:"renderViseme",generation:F,to:g,from:k.from,transitionDurationMs:k.transitionDurationMs,gapMs:k.gapMs,threshold:k.threshold},void 0,!0)}catch(D){if(D?.name==="AbortError")return;throw D}},dispose(){if(!a){a=!0,i+=1,d.reset(),f.clear(),l.forEach(({resolve:R})=>R(null)),l.clear(),c=Ut;for(const[,R]of T)R.resolve();T.clear(),n?.terminate(),n=null}}}}async function va(e,t){const r=await ga(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let n=0,s=null,i=!1;const o=Vr(async(a,u)=>i?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(Ye()?.onWorkerStale(),!1):(r.drawLiveFrame(a),o.isLatestSeq(u)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(i)return{width:842,height:1264};const u=await r.loadAssets(a);return s=u.visemePaths?.length?new Set(u.visemePaths):null,u},getVisemeAtlasPaths(){return s},async renderSilOnly(){i||(n+=1,o.reset(),r.renderSilOnly())},drawLiveFrame(a,u,f,l){i||o.enqueue(u,f,l)},async compositePrefetchFrame(a,u){if(i)return null;try{return await r.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,u){i||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||r.blitBitmap(u)},drawIdleVideo(a,u){i||r.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){i||r.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return i?!1:r.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){i||r.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return i?!1:r.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,u){if(i)return;n+=1;const f=n;o.reset(),t.onStatus?.(u),r.drawLiveFrame({mouthPath:bt(u),expressionPath:null})},dispose(){i||(i=!0,n+=1,o.reset(),r.dispose())}}}function hn(e,t){if(!_a())return mn(e,t);const r=hs(t.workerScriptUrl);try{return Sa(e,t,r)}catch{return mn(e,t)}}function ba(e,t={}){if(t.preferLegacyRenderer)return hn(e,t);let r=null,n=!1,s=null,i=!1;const o=()=>r?Promise.resolve(r):(s||(s=(async()=>{try{const a=await va(e,t);if(i)throw a.dispose(),new Error("Renderer disposed during Pixi init");return n=!0,r=a,a}catch(a){if(i)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),r=hn(e,t),n=!1,r}})()),s);return{get usesWorker(){return r?.usesWorker??!1},get usesPixi(){return n},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return r?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,u,f,l){o().then(c=>{i||c.drawLiveFrame(a,u,f,l)})},async compositePrefetchFrame(a,u){return(await o()).compositePrefetchFrame(a,u)},blitBitmap(a,u){r&&r.blitBitmap(a,u)},drawIdleVideo(a,u){r?.usesPixi&&r.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){r?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return r?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){r?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return r?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return r?.supportsBufferedPlayback??!1},async renderViseme(a,u,f){return(await o()).renderViseme(a,u,f)},dispose(){i=!0,s=null,r?.dispose(),r=null}}}class Ta extends Error{constructor(t,r){super(`${t} timed out after ${Math.round(r/1e3)}s`),this.name="LoadTimeoutError"}}function fr(e,t,r){return new Promise((n,s)=>{const i=globalThis.setTimeout(()=>{s(new Ta(r,t))},t);e.then(o=>{globalThis.clearTimeout(i),n(o)},o=>{globalThis.clearTimeout(i),s(o)})})}const ka={position:"relative",display:"inline-block",lineHeight:0},Ea={display:"block",maxWidth:"100%",height:"auto"},Ia={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 St(e){return Ss(e)?xr:Pr}function Ke(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const Aa=b.forwardRef(function({id:t,avatarId:r,faceId:n,assets:s,authToken:i,apiBase:o,ttsEngineId:a=Ze,voiceId:u,speakingRate:f=At,className:l,style:c,canvasStyle:d,onStatusChange:w,onDisplayStatus:T,onError:h,onReady:A,showErrorOverlay:v=!0,onUserTranscript:R,onBotOutput:g,onRealtimeLipsyncDebug:k,onFrameRenderStats:F,lipsyncBufferedPlayback:D=!0,lipsyncPlaybackWarmupMs:Y=1500,pixiMaxTextureSize:O},E){const P=b.useRef(null),M=b.useRef(null),B=b.useRef(null),ee=b.useRef(D);ee.current=D;const V=b.useRef(Y);V.current=Y;const te=b.useRef(0),X=b.useRef(Nr()),z=b.useRef(Ni()),me=b.useRef(!1),ae=b.useRef(0),Q=b.useRef(0),de=b.useRef(0),he=b.useRef(null),Se=b.useRef(null),j=b.useRef(!1),y=b.useRef(!1),I=b.useRef(!1),U=b.useRef(!1),G=b.useRef("sil"),$=b.useRef(0),H=b.useRef(!1),p=b.useRef(null),S=b.useRef(!1),[C,le]=b.useState("idle"),[oe,pe]=b.useState(null),[ye,ve]=b.useState(!1),[wt,m]=b.useState(!1),[x,J]=b.useState({width:842,height:1264}),[ue,_e]=b.useState(0),Ge=b.useRef(!1),fe=b.useRef(i??null),Ee=o?.trim()||kt,Ce=b.useRef(null),be=b.useRef(null),Ne=b.useRef(!1),Be=b.useRef({width:842,height:1264}),Ue=b.useRef(null),Pt=b.useRef("sil"),st=b.useRef(void 0),Ve=b.useRef(new Map),gt=b.useRef(A),ce=b.useRef(T),it=b.useRef(h),we=b.useRef(R),Ae=b.useRef(g),Ie=b.useRef(k),at=b.useRef(F),We=b.useRef(Ji());gt.current=A,ce.current=T,it.current=h,we.current=R,Ae.current=g,Ie.current=k,at.current=F,b.useEffect(()=>{const _=We.current;return nn(_),()=>nn(null)},[]);const xt=b.useCallback(_=>{const L=_?.ttsEngineId??a??be.current?.ttsEngineId??Ze,W=_?.voiceId??u??be.current?.voiceId??St(L);return{ttsEngineId:L,voiceId:W}},[a,u]),Fe=b.useCallback(_=>{pe(_),it.current?.(_)},[]),yt=b.useCallback(_=>{le(_),w?.(_)},[w]),se=b.useRef(wr(yt,Ee,{onLipsyncDebug:_=>Ie.current?.(_)})),ie=b.useRef(null);b.useEffect(()=>(se.current=wr(yt,Ee,{onLipsyncDebug:_=>Ie.current?.(_)}),i&&se.current.setDeveloperToken(i),se.current.setTtsEngineId(a),()=>{se.current.stop();const _=ie.current;_&&(_.disconnect(),ie.current=null)}),[yt,i,a,Ee]);const Wr=b.useCallback(()=>(ie.current||(ie.current=Wn(yt,{speakingRate:f,onUserTranscript:(_,L)=>we.current?.(_,L),onBotOutput:_=>Ae.current?.(_),onLipsyncDebug:_=>Ie.current?.(_)}),ie.current.setTtsEngineId(a)),ie.current),[yt,f,a]),Pe=b.useCallback(()=>{he.current!=null&&(clearTimeout(he.current),he.current=null)},[]),xe=b.useCallback(()=>{Se.current!=null&&(clearTimeout(Se.current),Se.current=null),I.current=!1},[]),Rt=b.useCallback(()=>{if(U.current)return;const _=M.current;if(U.current=!0,xe(),j.current=!1,y.current=!1,!S.current||!p.current){_?.renderSilOnly();return}p.current.setActive(!1);const L=p.current.getVideo();if(_?.usesPixi){_.drawIdleVideo(L),_.beginIdleToSilCrossfade(an);return}(async()=>{const W=P.current;W&&await ur(W,L,null,void 0,Be.current).catch(()=>{}),await new Promise(N=>setTimeout(N,an)),U.current&&await _?.renderSilOnly()})()},[xe]),$r=b.useCallback(()=>{!S.current||!p.current||(U.current=!1,M.current?.finishIdleToSilCrossfade(),xe(),I.current=!0,Se.current=setTimeout(()=>{if(Se.current=null,Ke(se.current,ie.current).isSpeaking()){I.current=!1;return}if(j.current){I.current=!1;return}const _=p.current;if(!_){I.current=!1;return}_.restart(),_.setActive(!0);const L=_.getVideo();let W=!1;const N=()=>{W||(W=!0,L.removeEventListener("playing",q),I.current=!1)},q=()=>{N()};if(L.addEventListener("playing",q,{once:!0}),L.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!L.paused){N();return}setTimeout(N,300)},Qi))},[xe]),ot=b.useCallback(()=>{if(Pe(),ce.current?.("sil"),j.current=!1,U.current=!1,!S.current||!p.current){I.current=!1;return}$r()},[Pe,$r]),er=b.useCallback(async _=>{const L=Q.current,W=M.current,N=P.current,q=()=>{_?.fallbackOnly||(j.current=!1)};if(!W||!N||!ye){q();return}if(Ke(se.current,ie.current).isSpeaking()){q();return}if(_?.fallbackOnly){if(!j.current||(Me(X.current),await W.renderSilOnly(),L!==Q.current)||Ke(se.current,ie.current).isSpeaking())return;ot();return}if(on(X.current)){Me(X.current),ot();return}if(ee.current&&W.supportsBufferedPlayback&&!_?.fallbackOnly){if(Me(X.current),B.current?.reset(),await W.renderSilOnly(),L!==Q.current||Ke(se.current,ie.current).isSpeaking())return;ot();return}const ke=na(Ke(se.current,ie.current).getVisemeQueue(),$.current,G.current),$e=sa(ke,Ue.current);if(Me(X.current),!$e){if(await W.renderSilOnly(),L!==Q.current||Ke(se.current,ie.current).isSpeaking())return;ot();return}try{await W.renderViseme(N,"sil",{from:ke,transitionDurationMs:es})}catch(He){if(He?.name!=="AbortError")throw He}if(L!==Q.current){q();return}if(Ke(se.current,ie.current).isSpeaking()){q();return}ot()},[ye,ot]),ct=b.useCallback(()=>{if(y.current||j.current)return;y.current=!0,j.current=!0,Pe();const _=Q.current;er().finally(()=>{y.current=!1}),he.current=setTimeout(()=>{he.current=null,_===Q.current&&er({fallbackOnly:!0})},ia())},[Pe,er]),Hr=b.useCallback(async()=>{const _=Math.floor(Date.now()/1e3);if(Ce.current&&_<Ce.current.expiresAt-60)return Ce.current.key;const L=fe.current??await Vt();fe.current=L,se.current.setDeveloperToken(L);const W=await As(L,Ee);return Ce.current={key:W.value,expiresAt:W.expiresAt},W.value},[Ee]);b.useEffect(()=>{i&&(fe.current=i,se.current.setDeveloperToken(i))},[i]),b.useEffect(()=>{se.current.setTtsEngineId(a),ie.current?.setTtsEngineId(a),be.current&&(be.current.ttsEngineId=a)},[a]),b.useEffect(()=>{const _=u??St(a);be.current&&(be.current.voiceId=_)},[u,a]);const Xe=b.useMemo(()=>_n(r,n),[r,n]),as=b.useMemo(()=>s?JSON.stringify(s):Xe?`face:${Xe}`:`id:${t??""}`,[s,Xe,t]);return b.useEffect(()=>{if(!t&&!s&&!Xe){Fe("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let _=!1;Ne.current=!1,ve(!1),m(!1),pe(null),be.current=null,p.current=null,S.current=!1;const L=P.current;if(!L)return;let W=null;return(async()=>{try{let N,q,Te,ke;if(s)N=s,q=a,Te=u??St(q);else if(Xe)ce.current?.("loadFace"),N=hr(Xe),q=a,Te=u??St(q);else{ce.current?.("getAiTwin");const K=await fr(yn(t),3e4,"getAiTwin");if(_)return;if(!K.faceId?.trim())throw new Error("getAiTwin returned no faceId");q=K.ttsEngineId,Te=u??K.voiceId??St(q),ke=K.knowledgeContextId?.trim()||void 0,N=hr(K.faceId)}be.current={ttsEngineId:q,voiceId:Te,personaId:ke},Sn(N),p.current=Ui();const $e=!!(s&&!rt(s));W=ba(L,{preferLegacyRenderer:$e,pixiMaxTextureSize:O,onStatus:K=>{_||ce.current?.(K)},onError:K=>{_||Fe(K)},shouldAcceptLiveFrame:()=>{if(me.current)return!0;if(j.current)return!1;const K=Ke(se.current,ie.current);return K.isSpeaking()||K.isWarmingUp()},onWebGlContextLost:()=>{_||Ge.current||(Ge.current=!0,queueMicrotask(()=>{_||_e(K=>K+1)}))}}),M.current=W,B.current=la(W),Ge.current=!1,(K=>{const Z=()=>{if(!K||V.current<=0)return!1;const ge=M.current;return ge?ee.current&&ge.supportsBufferedPlayback?!0:ge.usesPixi:!1};se.current.setLipsyncWarmupHold(K,Z),ie.current?.setLipsyncWarmupHold(K,Z)})(!0),ce.current?.("auth");const ze=fe.current??i??await fr(Vt(),3e4,"getAuthToken");if(_)return;fe.current=ze,se.current.setDeveloperToken(ze),se.current.setTtsEngineId(q);const Mt=Et()?await Hr():void 0;if(_)return;ce.current?.("loadAssets");const re=await fr(W.loadAssets(Mt),18e4,"load face assets");if(!_&&re.width>0&&re.height>0&&(Be.current=re,J(re)),_)return;Ue.current=W.getVisemeAtlasPaths(),Ne.current=!0,ve(!0),gt.current?.(),W.renderSilOnly().then(()=>{_||ce.current?.("sil")}),(async()=>{try{const K=await pi(Mt);if(await p.current.load(K),_)return;S.current=!0,m(!0),Me(X.current),p.current.setActive(!0);const Z=p.current.getVideo();W.usesPixi?W.drawIdleVideo(Z):await ur(L,Z,null,void 0,Be.current),_||ce.current?.("idle")}catch(K){if(_)return;S.current=!1,m(!1),console.warn("[AiTwin] Idle video unavailable:",K)}})()}catch(N){if(_)return;if(N instanceof Wt){Fe(N.message);return}Fe(N instanceof Error?N.message:"Failed to load AI twin")}})(),()=>{_=!0,p.current?.dispose(),W?.dispose(),M.current=null}},[as,s,Xe,t,a,u,i,O,Hr,Fe,ue]),b.useEffect(()=>{const _={current:!1},L=()=>{const W=P.current,N=M.current,q=Ke(se.current,ie.current);if(!W||!N||!ye){ae.current=requestAnimationFrame(L);return}if(document.hidden){p.current?.setActive(!1),ae.current=requestAnimationFrame(L);return}const Te=q.isSpeaking(),ke=q.isWarmingUp(),$e=Te&&!H.current,He=H.current&&!Te;$e&&(Pe(),xe(),j.current=!1,y.current=!1,Me(X.current),B.current?.reset(),We.current.reset(),st.current=void 0,de.current=0,G.current="sil",$.current=0,Rt()),He&&(z.current.reset(),p.current?.setActive(!1),B.current?.reset(),N.finishIdleToSilCrossfade(),ct());const ze=He||j.current||I.current||U.current,Mt=D&&N.supportsBufferedPlayback;if(ke){if(Rt(),S.current&&p.current?.setActive(!1),N.usesPixi&&N.isIdleToSilCrossfading()){N.tickIdleToSilCrossfade(performance.now()),q.getVisemeQueue().length>0&&te.current===0&&(te.current=performance.now()),H.current=q.isSpeaking(),ae.current=requestAnimationFrame(L);return}const re=q.getVisemeQueue();re.length>0&&te.current===0&&(te.current=performance.now()),z.current.advance(performance.now());const K=z.current.getExpressionPath(),Z=z.current.getDrawKey(),ge={queue:re,elapsedMs:0,expressionPath:K,expressionDrawKey:Z,availablePaths:Ue.current};let Re=!1;Mt&&B.current?(B.current.warmupTick(ge),Re=B.current.isWarmupReady(ge,V.current)):N.usesPixi&&cn(W,re,0,K,Z,X.current,(ut,Ct,tr,Dt)=>{N.drawLiveFrame(ut,Ct,tr,Le=>{Dt?.(Le),q.isWarmingUp()&&Le!==""&&!on({lastDrawnKey:Le})&&(te.current=0,q.releaseWarmupHold())})},ut=>{ce.current?.(ut.label)},Ue.current);const je=te.current>0&&performance.now()-te.current>ws;ce.current?.(Re?"buffer ready":"buffering lipsync…"),(Re||je)&&(te.current=0,q.releaseWarmupHold()),H.current=q.isSpeaking(),ae.current=requestAnimationFrame(L);return}if(Te){Rt(),S.current&&p.current?.setActive(!1),N.usesPixi&&N.isIdleToSilCrossfading()&&N.finishIdleToSilCrossfade();const re=q.getVisemeQueue(),K=q.getPlaybackElapsedMs();ei(re,K),$.current=K;const Z=re.length>0?It(re,K):"sil";Z!=="sil"&&(G.current=Z);const ge=Hi(K,q.getSentenceEmotions(),q.getWordQueue(),q.getStreamMood());z.current.setTargetEmotion(ge),z.current.setTargetEyebrow(Oi(K,q.getWordQueue(),et(ge))),z.current.advance(performance.now());const Re=z.current.getExpressionPath(),je=z.current.getDrawKey(),ut=(Le,rr,_t,nr)=>{const Kr={label:Pt.current,elapsedMs:K,mouthPath:rr.mouthPath,transitionMeta:st.current};Ve.current.set(_t,Kr),B.current?.markExternallyDisplayed(_t,Re),N.drawLiveFrame(Le,rr,_t,Bt=>{const os=Ve.current.get(Bt)??Kr;Ve.current.delete(Bt),We.current.onDrawDisplayed(os,re),B.current?.markExternallyDisplayed(Bt,Re),nr?.(Bt)})},Ct=Le=>{Pt.current=Le.label,st.current=Le.transitionMeta,ce.current?.(Le.label)},tr=D&&N.supportsBufferedPlayback;let Dt=!1;tr&&B.current&&(Dt=B.current.tick({canvas:W,queue:re,elapsedMs:K,expressionPath:Re,expressionDrawKey:je,playbackState:X.current,availablePaths:Ue.current,onStatus:Ct,onDisplayed:(rr,_t,nr)=>{We.current.onDrawDisplayed({label:nr,elapsedMs:K,mouthPath:_t,transitionMeta:st.current},re)}}).usedBuffer),Dt||cn(W,re,K,Re,je,X.current,ut,Ct,Ue.current),We.current.onRafTickSpeaking(),at.current?.(We.current.snapshot(re,K))}else if(!ze&&me.current){p.current?.setActive(!1),z.current.advance(performance.now());const re=z.current.getExpressionPath(),K=z.current.getDrawKey();lr(W,re,K,X.current,(Z,ge,Re,je)=>N.drawLiveFrame(Z,ge,Re,je),Z=>{const ge=z.current.getTargetEmotion();ce.current?.(Z==="sil"||Z==="blink"?`${ge}${Z==="blink"?" · blink":""}`:Z)})}else if(!ze&&S.current&&p.current){const re=p.current,K=re.getVideo();if(K.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){re.setActive(!0);const Z=()=>!q.isSpeaking()&&!j.current&&!I.current&&!me.current;N.usesPixi?(N.drawIdleVideo(K,Z),Z()&&ce.current?.("idle")):_.current||(_.current=!0,ur(W,K,null,void 0,Be.current,Z).then(()=>ce.current?.("idle")).finally(()=>{_.current=!1}))}else lr(W,null,"__sil__",X.current,(Z,ge,Re,je)=>N.drawLiveFrame(Z,ge,Re,je),Z=>ce.current?.(Z))}else ze||lr(W,null,"__sil__",X.current,(re,K,Z,ge)=>N.drawLiveFrame(re,K,Z,ge),re=>ce.current?.(re));H.current=Te,ae.current=requestAnimationFrame(L)};return ae.current=requestAnimationFrame(L),()=>{cancelAnimationFrame(ae.current),Pe(),xe(),se.current.stop(),ie.current?.stop()}},[ye,wt,ct,Pe,xe,Rt]),b.useImperativeHandle(E,()=>({speakText:async(_,L)=>{const W=_.trim();if(!W)return;const N=M.current;if(!N||!Ne.current&&!ye)throw new Error("AI twin is not ready");const{ttsEngineId:q,voiceId:Te}=xt(L);pe(null),Q.current+=1,Pe(),xe(),j.current=!1,y.current=!1,G.current="sil",$.current=0,Me(X.current),me.current=!1,z.current.reset(),H.current=!1,U.current=!1,N.finishIdleToSilCrossfade();try{await se.current.speak(W,{voiceId:Te,speakingRate:L?.speakingRate??f,ttsEngineId:q})}catch(ke){throw U.current=!1,N.finishIdleToSilCrossfade(),ct(),Fe(ke instanceof Error?ke.message:"TTS failed"),ke}},stop:()=>{Q.current+=1,Pe(),xe(),j.current=!1,y.current=!1,U.current=!1,M.current?.finishIdleToSilCrossfade(),se.current.stop(),ie.current?.stop(),Me(X.current),B.current?.reset(),te.current=0,H.current=!1,ct()},setTtsEngineId:_=>{se.current.setTtsEngineId(_),ie.current?.setTtsEngineId(_),be.current&&(be.current.ttsEngineId=_)},renderViseme:async(_,L)=>{const W=M.current,N=P.current;if(!W||!N||!Ne.current)throw new Error("AI twin is not ready");await W.renderViseme(N,_,{from:L?.from,transitionDurationMs:L?.transitionDurationMs,gapMs:L?.gapMs,onStatus:q=>ce.current?.(q)})},setEmotion:_=>{if(!Ne.current)throw new Error("AI twin is not ready");const L=M.current,W=P.current;if(!L||!W)throw new Error("AI twin is not ready");Q.current+=1,Pe(),xe(),j.current=!1,y.current=!1,I.current=!1,U.current=!1,se.current.stop(),ie.current?.stop(),Me(X.current),B.current?.reset(),te.current=0,H.current=!1,L.finishIdleToSilCrossfade(),p.current?.setActive(!1);const N=qe(_);me.current=!0,z.current.snapToEmotion(N);const q=z.current.getExpressionPath(),Te=z.current.getDrawKey(),ke={mouthPath:null,expressionPath:q},$e=Zt(ke,Te);X.current.lastDrawnKey="",L.drawLiveFrame(W,ke,$e,ze=>{ze===$e&&(X.current.lastDrawnKey=$e)});const He=et(N);ce.current?.(q?`${N} · brow ${He>0?"+":""}${He}`:`${N} · brow 0 (sil base)`)},getEmotion:()=>me.current?z.current.getTargetEmotion():null,clearEmotionPreview:()=>{me.current=!1,z.current.reset(),Me(X.current),ce.current?.("idle")},isReady:()=>Ne.current,getStatus:()=>C,connect:async(_={})=>{pe(null);try{let L=_.authToken?.trim();L||(L=fe.current??i??await Vt(),fe.current=L);const W=_.voiceId?.trim()??u??be.current?.voiceId,N=_.personaId?.trim()??be.current?.personaId,q=Wr();await q.unlockAudio(),await q.connect({..._,apiBase:_.apiBase?.trim()||Ee,authToken:L,voiceId:W,personaId:N,speakingRate:_.speakingRate??f})}catch(L){throw Fe(L instanceof Error?L.message:"Voice connect failed"),L}},disconnect:async()=>{const _=ie.current;_&&(Q.current+=1,Pe(),xe(),j.current=!1,y.current=!1,U.current=!1,M.current?.finishIdleToSilCrossfade(),Me(X.current),B.current?.reset(),te.current=0,H.current=!1,await _.disconnect(),ct())},isConnected:()=>ie.current?.isConnected()??!1,getVoiceStream:()=>ie.current?.getVoiceStream()??se.current?.getVoiceStream()??null}),[ye,f,i,u,Pe,xe,ct,Fe,xt,Wr,C,Ee]),sr.jsxs("div",{className:l,style:{...ka,...c},children:[sr.jsx("canvas",{ref:P,width:x.width,height:x.height,style:{...Ea,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),v&&oe?sr.jsx("div",{style:Ia,children:oe}):null]})}),ss="thumbnail.webp";function Pa(e,t=br){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${ss}`}const xa=new Set([".png",".jpg",".jpeg",".webp"]);function is(e=".png"){const t=e.toLowerCase();return xa.has(t)?`source${t}`:"source.png"}function Ra(e,t=br,r=".png"){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${is(r)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=ss;exports.AiTwin=Aa;exports.AiTwinNotFoundError=Wt;exports.CONSONANT_SKIP_GROUP=xn;exports.DEFAULT_TTS_ENGINE_ID=Ze;exports.EMOTION_TO_EYEBROW=Yn;exports.EXPRESSION_ATLAS_EMOTIONS=Pi;exports.MIC_SAMPLE_RATE=Rr;exports.OCULUS_VISEME_IDS=In;exports.PLAYBACK_SAMPLE_RATE=Mr;exports.SPEAKING_RATE_MAX=Jt;exports.SPEAKING_RATE_MIN=Xt;exports.TTS_ENGINE_CARTESIA=tt;exports.TTS_ENGINE_GOOGLE=kr;exports.TTS_ENGINE_INWORLD=jt;exports.VISEME_IDS=wi;exports.VISEME_SKIP_GAP_MS=pr;exports.VISEME_TEST_CARTESIA_VOICE_ID=xr;exports.VISEME_TEST_SPEAKING_RATE=At;exports.VISEME_TEST_VOICE_ID=Pr;exports.VOWEL_SKIP_GROUP=Pn;exports.aiTwinSourceFilename=is;exports.buildPlaybackTransitions=Fn;exports.buildPlaybackVisemeSeries=Yt;exports.buildRawVisemeTransitions=Bn;exports.buildVoiceWebSocketUrl=Vn;exports.compactSkippableVisemes=Ir;exports.createAvatarTtsLipsyncController=wr;exports.createRealtimeVoiceLipsyncController=Wn;exports.emotionToEyebrow=et;exports.faceAssetUrls=hr;exports.fetchAiTwin=yn;exports.fetchDevAuthToken=Vt;exports.getAiTwinSourceUrl=Ra;exports.getAiTwinThumbnailUrl=Pa;exports.listSkippedVisemes=qs;exports.normalizeOculusViseme=An;exports.normalizeStreamEmotion=qe;exports.resolveDirectFaceId=_n;exports.resolveVisemeAtTime=It;exports.resolveVisemeFromPlaybackSeries=Mn;exports.resolveWordAtTime=ti;exports.setActiveTwinAssets=Sn;
|
|
47
|
+
`;function wn(e=5){const t=new ue.Filter({glProgram:ue.GlProgram.from({vertex:So,fragment:vo,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=r=>{t.resources.thresholdUniforms.uniforms.uThreshold=r/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function bo(e,t,r){return e>r||t>r}function To(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function Eo(e,t){return t!=null&&t>0?Math.floor(t):To(e)}function ko(e,t){const r=document.createElement("canvas");r.width=t.w,r.height=t.h;const n=r.getContext("2d");if(!n)throw new Error("Failed to acquire 2d context for atlas cell crop");return n.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),r}function ws(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 gn(e,t,r,n,s){const i=r?await ss(e,s):await fetch(e).then(u=>{if(!u.ok)throw new Error(`Failed to load ${e}`);return u.json()}),o=i.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,l=async(u,d)=>{const p=as(t,d,r),E=r?await yi(await pt(p,s??"")):await ws(p);if(bo(E.width,E.height,n))return console.info(`[PixiVisemeCompositor] Sheet ${d} (${E.width}x${E.height}) exceeds MAX_TEXTURE_SIZE=${n}; using per-cell crops.`),{mode:"cells",bitmap:E};const m=ue.Texture.from(E);return m.source.scaleMode="nearest",{mode:"full",texture:m}};a.set(o.index,await l(o.index,o.path));for(const u of i.sheets??[])u.index!==o.index&&u.path&&a.set(u.index,await l(u.index,u.path));const f=new Map;for(const u of i.cells??[])u.path&&f.set(u.path,u);const c=new Map;for(const u of i.sheets??[])c.set(u.index,u);return{atlasMeta:i,cellByPath:f,sheetByIndex:c,diffBase:t,sheets:a}}async function Io(e,t={}){const r=new ue.Application;try{await r.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(g){throw r.destroy({removeView:!1}),g}if(r.renderer.type!==ue.RendererType.WEBGL)throw r.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const n=Eo(r.renderer.gl,t.maxTextureSize);let s=!1,i=!1,o=!1;const a=r.canvas,l=()=>{s=!0,!i&&!o&&(i=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",l);const f=new ue.Sprite(ue.Texture.EMPTY),c=new ue.Sprite(ue.Texture.EMPTY);c.visible=!1,c.alpha=0;const u=new ue.Sprite(ue.Texture.EMPTY),d=new ue.Sprite(ue.Texture.EMPTY),p=new ue.Sprite(ue.Texture.EMPTY);p.visible=!1;const E=wn(5),m=wn(5);u.filters=[E],d.filters=[m],r.stage.addChild(f),r.stage.addChild(c),r.stage.addChild(u),r.stage.addChild(d),r.stage.addChild(p);let A=null,x=null,C=null,w=null,b=null,O=null,V=null,X=842,fe=1264,P=null,D=5;const N=new Map;let j=null,F=null,Y=null;const $=xn(()=>{N.clear(),O=null,V=null,A=null,P=null}),q=(g,_)=>{X=g,fe=_,r.renderer.resize(g,_),(e.width!==g||e.height!==_)&&(e.width=g,e.height=_)},k=()=>{u.visible=!1,d.visible=!1,u.texture=ue.Texture.EMPTY,d.texture=ue.Texture.EMPTY,j=null,F=null},ee=()=>{b=null,c.visible=!1,c.alpha=0},he=()=>{f.visible=!0,f.width=X,f.height=fe,f.x=0,f.y=0},ce=()=>{c.width=X,c.height=fe,c.x=0,c.y=0},te=()=>{p.visible=!1,ee(),A&&(f.texture=A,he())},J=()=>{!b&&!c.visible||te()},ke=g=>{if(o||s||!A){te();return}const _=Math.max(0,g);if(!x||_<=0){te();return}k(),p.visible=!1,f.texture=x,he(),c.texture=A,ce(),c.alpha=0,c.visible=!0,b={startMs:performance.now(),durationMs:_},W()},Me=(g=performance.now())=>{if(!b)return!1;if(o||s)return J(),!1;const _=(g-b.startMs)/Math.max(1,b.durationMs);if(_>=1)return te(),W(),!1;const y=Math.min(1,Math.max(0,_)),Z=y*y*(3-2*y);return c.alpha=Z,c.visible=!0,W(),!0},S=()=>{if(C){try{C.resource=null}catch{}C.destroy(),C=null}x&&(x.destroy(!1),x=null),w=null},M=(g,_)=>{const y=g.cellByPath.get(_);if(!y||!ns(y))return null;const Z=`${g.diffBase}::${_}`;let oe=N.get(Z);if(!oe){const ye=y.sheet??0,Re=g.sheets.get(ye);if(!Re)return null;let _e,Oe=!1;if(Re.mode==="full")_e=new ue.Texture({source:Re.texture.source,frame:new ue.Rectangle(y.x,y.y,y.w,y.h)});else{const wt=ko(Re.bitmap,y);_e=ue.Texture.from(wt),_e.source.scaleMode="nearest",Oe=!0}oe={texture:_e,ownsSource:Oe},N.set(Z,oe)}return{texture:oe.texture,cell:y}},G=(g,_,y,Z)=>{if(!Z||!y)return g.visible=!1,g.texture=ue.Texture.EMPTY,!1;const oe=M(y,Z);if(!oe)return g.visible=!1,g.texture=ue.Texture.EMPTY,!1;const ye=rs(y.atlasMeta,oe.cell);return _.setThreshold(D),g.texture=oe.texture,g.x=ye.x,g.y=ye.y,g.width=oe.cell.w,g.height=oe.cell.h,g.visible=!0,!0},z=g=>{if(!g||!O)return null;const _=P??new Set(O.cellByPath.keys());return Or(g,_)??(_.has(g)?g:null)},I=g=>{p.visible=!1,te();const _=z(g.mouthPath),y=g.expressionPath&&V?Vr(g.expressionPath,Z=>V.cellByPath.has(Z)):null;_!==j?(G(u,E,O,_),j=_):_?u.visible=!0:u.visible=!1,y!==F?(G(d,m,V,y),F=y):y?d.visible=!0:d.visible=!1},W=()=>{if(!(o||s||document.hidden))try{r.render()}catch{}};return{async loadAssets(g){if(o)return{width:X,height:fe,visemePaths:[]};const _=It();if(_&&!g)throw new Error("Encrypted assets enabled but no key provided");const y=_?await Si(await pt(Kt(),g??"")):await ws(Kt());A&&A.destroy(!0),A=ue.Texture.from(y),A.source.scaleMode="linear";const Z=Mn();O=await gn(Rn(),Z,_,n,g);try{V=await gn(Cn(),Z,_,n,g)}catch(ye){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",ye),V=null}const oe=ts(O.atlasMeta,y.width,y.height);return q(oe.width,oe.height),D=rr(O.atlasMeta),E.setThreshold(D),m.setThreshold(D),P=new Set(O.cellByPath.keys()),N.clear(),te(),k(),W(),{width:oe.width,height:oe.height,visemePaths:[...O.cellByPath.keys()]}},getVisemeAtlasPaths(){return P},drawLiveFrame(g){o||s||!A||(J(),I(g),W())},drawIdleVideo(g,_){o||s||document.hidden||_&&!_()||g.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(ee(),k(),p.visible=!1,!x||w!==g?(S(),C=new ue.VideoSource({resource:g,autoPlay:!1,updateFPS:0}),C.autoUpdate=!1,x=new ue.Texture({source:C}),w=g):x.source.update(),f.texture=x,he(),W())},beginIdleToSilCrossfade:ke,tickIdleToSilCrossfade:Me,finishIdleToSilCrossfade:J,isIdleToSilCrossfading(){return b!=null},renderSilOnly(){o||s||!A||(k(),te(),W())},blitBitmap(g){o||s||(J(),k(),Y&&(Y.destroy(!0),Y=null),Y=ue.Texture.from(g),p.texture=Y,p.visible=!0,p.x=0,p.y=0,p.width=X,p.height=fe,f.visible=!1,W())},async compositePrefetchFrame(g){return null},renderFrame:W,isContextLost(){return s},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",l),$(),S(),Y&&(Y.destroy(!0),Y=null);for(const{texture:_,ownsSource:y}of N.values())_.destroy(y);N.clear(),A&&(A.destroy(!0),A=null);const g=_=>{_.mode==="full"?_.texture.destroy(!0):_.bitmap.close()};if(O)for(const _ of O.sheets.values())g(_);if(V)for(const _ of V.sheets.values())g(_);E.destroy(!0),m.destroy(!0),r.destroy({removeView:!1},{children:!0,texture:!0})}}}const yn=-1,Ut=1e5,_n=new Map;async function Ao(e){let t=_n.get(e);if(!t){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch worker script (${r.status}): ${e}`);const n=await r.blob();t=URL.createObjectURL(n),_n.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function Po(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Er(e,t){(e.width!==t.width||e.height!==t.height)&&(e.width=t.width,e.height=t.height);const r=e.getContext("2d");r&&r.drawImage(t,0,0)}function Sn(e,t){let r=0,n=null;const s=qr(async(i,o)=>(await br(),await Tr(e,i),s.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(i){const o=await br(i);return n=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return n},async renderSilOnly(){r+=1,s.reset(),await no(e)},drawLiveFrame(i,o,a,l){s.enqueue(o,a,l)},async compositePrefetchFrame(i,o){try{return await ro(i)}catch{return null}},blitBitmap(i,o){Er(i,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(i,o){r+=1;const a=r;t.onStatus?.(o),await Tr(i,{mouthPath:dt(o),expressionPath:null})},dispose(){r+=1,s.reset()}}}function xo(e,t,r){let n=null,s=1,i=0,o=!1,a=!1,l=null;const f=new Map,c=new Map;let u=Ut;const d=qr(async(C,w,b)=>(f.set(w,{drawKey:b.drawKey,onDisplayed:b.onDisplayed}),await A({type:"drawFrame",diffPath:C.mouthPath,expressionDiffPath:C.expressionPath,liveSeq:w},void 0,!0),!1)),p=C=>{if(C===yn){let O=-1,V;for(const[X,fe]of f)X>=O&&(O=X,V=fe);O>=0&&f.delete(O),V?.onDisplayed?.(V.drawKey);return}const w=-C,b=f.get(w);f.delete(w),b?.onDisplayed?.(b.drawKey)},E=new Map,m=(C,w)=>{a||!n||n.postMessage(C,[])},A=(C,w,b=!1)=>{if(a)return Promise.resolve();const O=s++;return new Promise((V,X)=>{E.set(O,{resolve:fe=>V(fe),reject:X,generation:typeof C.generation=="number"?C.generation:void 0,expectRenderDone:b}),m({...C,requestId:O})})},x=(async()=>{n=await Ao(r),n.onmessage=C=>{if(a)return;const w=C.data;if(w.type==="status"){t.onStatus?.(w.label);return}if(w.type==="frame"){if(w.generation<=-Ut){const V=-w.generation,X=c.get(V);c.delete(V),X?.resolve(w.bitmap);return}const O=w.generation<0;if(!O&&w.generation!==i){w.bitmap.close();return}if(O&&!(w.generation===yn)){const X=-w.generation;if(!d.isLatestSeq(X)){Ge()?.onWorkerStale(),w.bitmap.close();return}}if(O&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){Ge()?.onWorkerStale(),w.bitmap.close();return}Er(e,w.bitmap),w.bitmap.close(),O&&p(w.generation);return}const b=E.get(w.requestId);if(b)switch(w.type){case"ready":E.delete(w.requestId),b.resolve();break;case"loadAssetsDone":E.delete(w.requestId),l=w.visemePaths?.length?new Set(w.visemePaths):null,b.resolve({width:w.width,height:w.height,visemePaths:w.visemePaths});break;case"renderDone":if(b.expectRenderDone&&b.generation!=null&&w.generation!==b.generation)return;E.delete(w.requestId),b.resolve();break;case"renderAborted":E.delete(w.requestId),b.resolve();break;case"error":E.delete(w.requestId),t.onError?.(w.message),b.reject(new Error(w.message));break}},n.onerror=C=>{if(a)return;const w=C.message||"Worker error";t.onError?.(w);for(const[,b]of E)b.reject(new Error(w));E.clear()},await A({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(C){if(a)return{width:842,height:1264};if(await x,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await A({type:"loadAssets",keyHex:C,urls:Hs(rt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return l},async renderSilOnly(){if(a||(await x,a))return;i+=1,d.reset(),f.clear(),c.forEach(({resolve:w})=>w(null)),c.clear(),u=Ut;const C=i;await A({type:"cancelLiveDraws"}),await A({type:"renderSil",generation:C},void 0,!0)},drawLiveFrame(C,w,b,O){a||x.then(()=>{a||d.enqueue(w,b,O)})},compositePrefetchFrame(C,w){return a?Promise.resolve(null):x.then(()=>{if(a)return null;const b=++u;return new Promise(O=>{c.set(b,{resolve:O}),A({type:"drawFrame",diffPath:C.mouthPath,expressionDiffPath:C.expressionPath,liveSeq:b},void 0,!0).catch(()=>{c.delete(b),O(null)})})})},blitBitmap(C,w){Er(C,w)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(C,w,b={}){if(a||(await x,a))return;i+=1,d.reset(),f.clear();const O=i;try{await A({type:"cancelLiveDraws"}),await A({type:"renderViseme",generation:O,to:w,from:b.from,transitionDurationMs:b.transitionDurationMs,gapMs:b.gapMs,threshold:b.threshold},void 0,!0)}catch(V){if(V?.name==="AbortError")return;throw V}},dispose(){if(!a){a=!0,i+=1,d.reset(),f.clear(),c.forEach(({resolve:C})=>C(null)),c.clear(),u=Ut;for(const[,C]of E)C.resolve();E.clear(),n?.terminate(),n=null}}}}async function Mo(e,t){const r=await Io(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let n=0,s=null,i=!1;const o=qr(async(a,l)=>i?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(Ge()?.onWorkerStale(),!1):(r.drawLiveFrame(a),o.isLatestSeq(l)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(i)return{width:842,height:1264};const l=await r.loadAssets(a);return s=l.visemePaths?.length?new Set(l.visemePaths):null,l},getVisemeAtlasPaths(){return s},async renderSilOnly(){i||(n+=1,o.reset(),r.renderSilOnly())},drawLiveFrame(a,l,f,c){i||o.enqueue(l,f,c)},async compositePrefetchFrame(a,l){if(i)return null;try{return await r.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,l){i||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||r.blitBitmap(l)},drawIdleVideo(a,l){i||r.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){i||r.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return i?!1:r.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){i||r.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return i?!1:r.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,l){if(i)return;n+=1;const f=n;o.reset(),t.onStatus?.(l),r.drawLiveFrame({mouthPath:dt(l),expressionPath:null})},dispose(){i||(i=!0,n+=1,o.reset(),r.dispose())}}}function vn(e,t){if(!Po())return Sn(e,t);const r=As(t.workerScriptUrl);try{return xo(e,t,r)}catch{return Sn(e,t)}}function Ro(e,t={}){if(t.preferLegacyRenderer)return vn(e,t);let r=null,n=!1,s=null,i=!1;const o=()=>r?Promise.resolve(r):(s||(s=(async()=>{try{const a=await Mo(e,t);if(i)throw a.dispose(),new Error("Renderer disposed during Pixi init");return n=!0,r=a,a}catch(a){if(i)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),r=vn(e,t),n=!1,r}})()),s);return{get usesWorker(){return r?.usesWorker??!1},get usesPixi(){return n},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return r?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,l,f,c){o().then(u=>{i||u.drawLiveFrame(a,l,f,c)})},async compositePrefetchFrame(a,l){return(await o()).compositePrefetchFrame(a,l)},blitBitmap(a,l){r&&r.blitBitmap(a,l)},drawIdleVideo(a,l){r?.usesPixi&&r.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){r?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return r?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){r?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return r?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return r?.supportsBufferedPlayback??!1},async renderViseme(a,l,f){return(await o()).renderViseme(a,l,f)},dispose(){i=!0,s=null,r?.dispose(),r=null}}}class Co extends Error{constructor(t,r){super(`${t} timed out after ${Math.round(r/1e3)}s`),this.name="LoadTimeoutError"}}function pr(e,t,r){return new Promise((n,s)=>{const i=globalThis.setTimeout(()=>{s(new Co(r,t))},t);e.then(o=>{globalThis.clearTimeout(i),n(o)},o=>{globalThis.clearTimeout(i),s(o)})})}const Do={position:"relative",display:"inline-block",lineHeight:0},Fo={display:"block",maxWidth:"100%",height:"auto"},Bo={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 vt(e){return Cs(e)?Fr:Dr}function $e(e,t){return t?.isSpeaking()?t:e.isSpeaking()?e:t?.isConnected()?t:e}const Lo=T.forwardRef(function({id:t,avatarId:r,faceId:n,assets:s,authToken:i,apiBase:o,ttsEngineId:a=Je,voiceId:l,speakingRate:f=Pt,className:c,style:u,canvasStyle:d,onStatusChange:p,onDisplayStatus:E,onError:m,onReady:A,showErrorOverlay:x=!0,onUserTranscript:C,onBotOutput:w,onRealtimeLipsyncDebug:b,onFrameRenderStats:O,lipsyncBufferedPlayback:V=!0,lipsyncPlaybackWarmupMs:X=1500,pixiMaxTextureSize:fe},P){const D=T.useRef(null),N=T.useRef(null),j=T.useRef(null),F=T.useRef(V);F.current=V;const Y=T.useRef(X);Y.current=X;const $=T.useRef(0),q=T.useRef(Hr()),k=T.useRef(Gi()),ee=T.useRef(!1),he=T.useRef(null),ce=T.useRef(null),te=T.useRef(0),J=T.useRef(0),ke=T.useRef(0),Me=T.useRef(null),S=T.useRef(null),M=T.useRef(!1),G=T.useRef(!1),z=T.useRef(!1),I=T.useRef(!1),W=T.useRef("sil"),g=T.useRef(0),_=T.useRef(!1),y=T.useRef(null),Z=T.useRef(!1),[oe,ye]=T.useState("idle"),[Re,_e]=T.useState(null),[Oe,wt]=T.useState(!1),[Gr,xt]=T.useState(!1),[nr,h]=T.useState({width:842,height:1264}),[R,Q]=T.useState(0),re=T.useRef(!1),me=T.useRef(i??null),de=o?.trim()||kt,pe=T.useRef(null),we=T.useRef(null),ve=T.useRef(!1),nt=T.useRef({width:842,height:1264}),We=T.useRef(null),Ke=T.useRef("sil"),ze=T.useRef(void 0),gt=T.useRef(new Map),Mt=T.useRef(A),se=T.useRef(E),yt=T.useRef(m),_t=T.useRef(C),st=T.useRef(w),ge=T.useRef(b),Ce=T.useRef(O),Te=T.useRef(io());Mt.current=A,se.current=E,yt.current=m,_t.current=C,st.current=w,ge.current=b,Ce.current=O,T.useEffect(()=>{const v=Te.current;return fn(v),()=>fn(null)},[]);const it=T.useCallback(v=>{const B=v?.ttsEngineId??a??we.current?.ttsEngineId??Je,U=v?.voiceId??l??we.current?.voiceId??vt(B);return{ttsEngineId:B,voiceId:U}},[a,l]),Be=T.useCallback(v=>{_e(v),yt.current?.(v)},[]),je=T.useCallback(v=>{ye(v),p?.(v)},[p]),ie=T.useRef(Sr(je,de,{onLipsyncDebug:v=>ge.current?.(v)})),le=T.useRef(null);T.useEffect(()=>(ie.current=Sr(je,de,{onLipsyncDebug:v=>ge.current?.(v)}),i&&ie.current.setDeveloperToken(i),ie.current.setTtsEngineId(a),()=>{ie.current.stop();const v=le.current;v&&(v.disconnect(),le.current=null)}),[je,i,a,de]);const zr=T.useCallback(()=>(le.current||(le.current=es(je,{speakingRate:f,onUserTranscript:(v,B)=>_t.current?.(v,B),onBotOutput:v=>st.current?.(v),onLipsyncDebug:v=>ge.current?.(v)}),le.current.setTtsEngineId(a)),le.current),[je,f,a]),Ie=T.useCallback(()=>{Me.current!=null&&(clearTimeout(Me.current),Me.current=null)},[]),Ae=T.useCallback(()=>{S.current!=null&&(clearTimeout(S.current),S.current=null),z.current=!1},[]),Rt=T.useCallback(()=>{if(I.current)return;const v=N.current;if(I.current=!0,Ae(),M.current=!1,G.current=!1,!Z.current||!y.current){v?.renderSilOnly();return}y.current.setActive(!1);const B=y.current.getVideo();if(v?.usesPixi){v.drawIdleVideo(B),v.beginIdleToSilCrossfade(mn);return}(async()=>{const U=D.current;U&&await mr(U,B,null,void 0,nt.current).catch(()=>{}),await new Promise(L=>setTimeout(L,mn)),I.current&&await v?.renderSilOnly()})()},[Ae]),jr=T.useCallback(()=>{!Z.current||!y.current||(I.current=!1,N.current?.finishIdleToSilCrossfade(),Ae(),z.current=!0,S.current=setTimeout(()=>{if(S.current=null,$e(ie.current,le.current).isSpeaking()){z.current=!1;return}if(M.current){z.current=!1;return}const v=y.current;if(!v){z.current=!1;return}v.restart(),v.setActive(!0);const B=v.getVideo();let U=!1;const L=()=>{U||(U=!0,B.removeEventListener("playing",H),z.current=!1)},H=()=>{L()};if(B.addEventListener("playing",H,{once:!0}),B.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!B.paused){L();return}setTimeout(L,300)},oo))},[Ae]),ot=T.useCallback(()=>{if(Ie(),se.current?.("sil"),M.current=!1,I.current=!1,!Z.current||!y.current){z.current=!1;return}jr()},[Ie,jr]),sr=T.useCallback(async v=>{const B=J.current,U=N.current,L=D.current,H=()=>{v?.fallbackOnly||(M.current=!1)};if(!U||!L||!Oe){H();return}if($e(ie.current,le.current).isSpeaking()){H();return}if(v?.fallbackOnly){if(!M.current||(xe(q.current),await U.renderSilOnly(),B!==J.current)||$e(ie.current,le.current).isSpeaking())return;ot();return}if(hn(q.current)){xe(q.current),ot();return}if(F.current&&U.supportsBufferedPlayback&&!v?.fallbackOnly){if(xe(q.current),j.current?.reset(),await U.renderSilOnly(),B!==J.current||$e(ie.current,le.current).isSpeaking())return;ot();return}const Ee=fo($e(ie.current,le.current).getVisemeQueue(),g.current,W.current),De=mo(Ee,We.current);if(xe(q.current),!De){if(await U.renderSilOnly(),B!==J.current||$e(ie.current,le.current).isSpeaking())return;ot();return}try{await U.renderViseme(L,"sil",{from:Ee,transitionDurationMs:ms})}catch(Pe){if(Pe?.name!=="AbortError")throw Pe}if(B!==J.current){H();return}if($e(ie.current,le.current).isSpeaking()){H();return}ot()},[Oe,ot]),at=T.useCallback(()=>{if(G.current||M.current)return;G.current=!0,M.current=!0,Ie();const v=J.current;sr().finally(()=>{G.current=!1}),Me.current=setTimeout(()=>{Me.current=null,v===J.current&&sr({fallbackOnly:!0})},ho())},[Ie,sr]),Yr=T.useCallback(async()=>{const v=Math.floor(Date.now()/1e3);if(pe.current&&v<pe.current.expiresAt-60)return pe.current.key;const B=me.current??await Wt();me.current=B,ie.current.setDeveloperToken(B);const U=await Vs(B,de);return pe.current={key:U.value,expiresAt:U.expiresAt},U.value},[de]);T.useEffect(()=>{i&&(me.current=i,ie.current.setDeveloperToken(i))},[i]),T.useEffect(()=>{ie.current.setTtsEngineId(a),le.current?.setTtsEngineId(a),we.current&&(we.current.ttsEngineId=a)},[a]),T.useEffect(()=>{const v=l??vt(a);we.current&&(we.current.voiceId=v)},[l,a]);const Ye=T.useMemo(()=>An(r,n),[r,n]),_s=T.useMemo(()=>s?JSON.stringify(s):Ye?`face:${Ye}`:`id:${t??""}`,[s,Ye,t]);return T.useEffect(()=>{if(!t&&!s&&!Ye){Be("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let v=!1;ve.current=!1,wt(!1),xt(!1),_e(null),we.current=null,y.current=null,Z.current=!1;const B=D.current;if(!B)return;let U=null;return(async()=>{try{let L,H,be,Ee;if(s)L=s,H=a,be=l??vt(H);else if(Ye)se.current?.("loadFace"),L=yr(Ye),H=a,be=l??vt(H);else{se.current?.("getAiTwin");const K=await pr(In(t),3e4,"getAiTwin");if(v)return;if(!K.faceId?.trim())throw new Error("getAiTwin returned no faceId");H=K.ttsEngineId,be=l??K.voiceId??vt(H),Ee=K.knowledgeContextId?.trim()||void 0,L=yr(K.faceId)}we.current={ttsEngineId:H,voiceId:be,personaId:Ee},Pn(L),y.current=zi();const De=!!(s&&!tt(s));U=Ro(B,{preferLegacyRenderer:De,pixiMaxTextureSize:fe,onStatus:K=>{v||se.current?.(K)},onError:K=>{v||Be(K)},shouldAcceptLiveFrame:()=>{if(ee.current)return!0;if(M.current)return!1;const K=$e(ie.current,le.current);return K.isSpeaking()||K.isWarmingUp()},onWebGlContextLost:()=>{v||re.current||(re.current=!0,queueMicrotask(()=>{v||Q(K=>K+1)}))}}),N.current=U,j.current=_o(U),re.current=!1,(K=>{const ne=()=>{if(!K||Y.current<=0)return!1;const Se=N.current;return Se?F.current&&Se.supportsBufferedPlayback?!0:Se.usesPixi:!1};ie.current.setLipsyncWarmupHold(K,ne),le.current?.setLipsyncWarmupHold(K,ne)})(!0),se.current?.("auth");const Ne=me.current??i??await pr(Wt(),3e4,"getAuthToken");if(v)return;me.current=Ne,ie.current.setDeveloperToken(Ne),ie.current.setTtsEngineId(H);const Ct=It()?await Yr():void 0;if(v)return;se.current?.("loadAssets");const ae=await pr(U.loadAssets(Ct),18e4,"load face assets");if(!v&&ae.width>0&&ae.height>0&&(nt.current=ae,h(ae)),v)return;We.current=U.getVisemeAtlasPaths(),ve.current=!0,wt(!0),Mt.current?.(),U.renderSilOnly().then(()=>{v||se.current?.("sil")}),(async()=>{try{const K=await Ti(Ct);if(await y.current.load(K),v)return;Z.current=!0,xt(!0),xe(q.current),y.current.setActive(!0);const ne=y.current.getVideo();U.usesPixi?U.drawIdleVideo(ne):await mr(B,ne,null,void 0,nt.current),v||se.current?.("idle")}catch(K){if(v)return;Z.current=!1,xt(!1),console.warn("[AiTwin] Idle video unavailable:",K)}})()}catch(L){if(v)return;if(L instanceof $t){Be(L.message);return}Be(L instanceof Error?L.message:"Failed to load AI twin")}})(),()=>{v=!0,y.current?.dispose(),U?.dispose(),N.current=null}},[_s,s,Ye,t,a,l,i,fe,Yr,Be,R]),T.useEffect(()=>{const v={current:!1},B=()=>{const U=D.current,L=N.current,H=$e(ie.current,le.current);if(!U||!L||!Oe){te.current=requestAnimationFrame(B);return}if(document.hidden){y.current?.setActive(!1),te.current=requestAnimationFrame(B);return}const be=H.isSpeaking(),Ee=H.isWarmingUp(),De=be&&!_.current,Pe=_.current&&!be;De&&(Ie(),Ae(),M.current=!1,G.current=!1,xe(q.current),j.current?.reset(),Te.current.reset(),ze.current=void 0,ke.current=0,W.current="sil",g.current=0,Rt()),Pe&&(k.current.reset(),y.current?.setActive(!1),j.current?.reset(),L.finishIdleToSilCrossfade(),at());const Ne=Pe||M.current||z.current||I.current,Ct=V&&L.supportsBufferedPlayback;if(Ee){if(Rt(),Z.current&&y.current?.setActive(!1),L.usesPixi&&L.isIdleToSilCrossfading()){L.tickIdleToSilCrossfade(performance.now()),H.getVisemeQueue().length>0&&$.current===0&&($.current=performance.now()),_.current=H.isSpeaking(),te.current=requestAnimationFrame(B);return}const ae=H.getVisemeQueue();ae.length>0&&$.current===0&&($.current=performance.now()),k.current.advance(performance.now());const K=k.current.getExpressionPath(),ne=k.current.getDrawKey(),Se={queue:ae,elapsedMs:0,expressionPath:K,expressionDrawKey:ne,availablePaths:We.current};let Fe=!1;Ct&&j.current?(j.current.warmupTick(Se),Fe=j.current.isWarmupReady(Se,Y.current)):L.usesPixi&&pn(U,ae,0,K,ne,q.current,(ut,Dt,ir,Ft)=>{L.drawLiveFrame(ut,Dt,ir,Ve=>{Ft?.(Ve),H.isWarmingUp()&&Ve!==""&&!hn({lastDrawnKey:Ve})&&($.current=0,H.releaseWarmupHold())})},ut=>{se.current?.(ut.label)},We.current);const qe=$.current>0&&performance.now()-$.current>xs;se.current?.(Fe?"buffer ready":"buffering lipsync…"),(Fe||qe)&&($.current=0,H.releaseWarmupHold()),_.current=H.isSpeaking(),te.current=requestAnimationFrame(B);return}if(be){Rt(),Z.current&&y.current?.setActive(!1),L.usesPixi&&L.isIdleToSilCrossfading()&&L.finishIdleToSilCrossfade();const ae=H.getVisemeQueue(),K=H.getPlaybackElapsedMs();ci(ae,K),g.current=K;const ne=ae.length>0?At(ae,K):"sil";ne!=="sil"&&(W.current=ne);const Se=Xi(K,H.getSentenceEmotions(),H.getWordQueue(),H.getStreamMood());k.current.setTargetEmotion(Se),k.current.setTargetEyebrow(qi(K,H.getWordQueue(),Ze(Se))),k.current.advance(performance.now());const Fe=k.current.getExpressionPath(),qe=k.current.getDrawKey(),ut=(Ve,or,St,ar)=>{const Qr={label:Ke.current,elapsedMs:K,mouthPath:or.mouthPath,transitionMeta:ze.current};gt.current.set(St,Qr),j.current?.markExternallyDisplayed(St,Fe),L.drawLiveFrame(Ve,or,St,Bt=>{const Ss=gt.current.get(Bt)??Qr;gt.current.delete(Bt),Te.current.onDrawDisplayed(Ss,ae),j.current?.markExternallyDisplayed(Bt,Fe),ar?.(Bt)})},Dt=Ve=>{Ke.current=Ve.label,ze.current=Ve.transitionMeta,se.current?.(Ve.label)},ir=V&&L.supportsBufferedPlayback;let Ft=!1;ir&&j.current&&(Ft=j.current.tick({canvas:U,queue:ae,elapsedMs:K,expressionPath:Fe,expressionDrawKey:qe,playbackState:q.current,availablePaths:We.current,onStatus:Dt,onDisplayed:(or,St,ar)=>{Te.current.onDrawDisplayed({label:ar,elapsedMs:K,mouthPath:St,transitionMeta:ze.current},ae)}}).usedBuffer),Ft||pn(U,ae,K,Fe,qe,q.current,ut,Dt,We.current),Te.current.onRafTickSpeaking(),Ce.current?.(Te.current.snapshot(ae,K))}else if(!Ne&&ee.current){y.current?.setActive(!1),k.current.advance(performance.now());const ae=k.current.getExpressionPath(),K=k.current.getDrawKey();hr(U,ae,K,q.current,(ne,Se,Fe,qe)=>L.drawLiveFrame(ne,Se,Fe,qe),ne=>{if(ce.current){se.current?.(ce.current);return}const Se=k.current.getTargetEmotion();se.current?.(ne==="sil"||ne==="blink"?`${Se}${ne==="blink"?" · blink":""}`:ne)},null,he.current)}else if(!Ne&&Z.current&&y.current){const ae=y.current,K=ae.getVideo();if(K.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){ae.setActive(!0);const ne=()=>!H.isSpeaking()&&!M.current&&!z.current&&!ee.current;L.usesPixi?(L.drawIdleVideo(K,ne),ne()&&se.current?.("idle")):v.current||(v.current=!0,mr(U,K,null,void 0,nt.current,ne).then(()=>se.current?.("idle")).finally(()=>{v.current=!1}))}else hr(U,null,"__sil__",q.current,(ne,Se,Fe,qe)=>L.drawLiveFrame(ne,Se,Fe,qe),ne=>se.current?.(ne))}else Ne||hr(U,null,"__sil__",q.current,(ae,K,ne,Se)=>L.drawLiveFrame(ae,K,ne,Se),ae=>se.current?.(ae));_.current=be,te.current=requestAnimationFrame(B)};return te.current=requestAnimationFrame(B),()=>{cancelAnimationFrame(te.current),Ie(),Ae(),ie.current.stop(),le.current?.stop()}},[Oe,Gr,at,Ie,Ae,Rt]),T.useImperativeHandle(P,()=>({speakText:async(v,B)=>{const U=v.trim();if(!U)return;const L=N.current;if(!L||!ve.current&&!Oe)throw new Error("AI twin is not ready");const{ttsEngineId:H,voiceId:be}=it(B);_e(null),J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,W.current="sil",g.current=0,xe(q.current),ee.current=!1,he.current=null,ce.current=null,k.current.reset(),_.current=!1,I.current=!1,L.finishIdleToSilCrossfade();try{await ie.current.speak(U,{voiceId:be,speakingRate:B?.speakingRate??f,ttsEngineId:H})}catch(Ee){throw I.current=!1,L.finishIdleToSilCrossfade(),at(),Be(Ee instanceof Error?Ee.message:"TTS failed"),Ee}},stop:()=>{J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,I.current=!1,N.current?.finishIdleToSilCrossfade(),ie.current.stop(),le.current?.stop(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,at()},setTtsEngineId:v=>{ie.current.setTtsEngineId(v),le.current?.setTtsEngineId(v),we.current&&(we.current.ttsEngineId=v)},renderViseme:async(v,B)=>{const U=N.current,L=D.current;if(!U||!L||!ve.current)throw new Error("AI twin is not ready");await U.renderViseme(L,v,{from:B?.from,transitionDurationMs:B?.transitionDurationMs,gapMs:B?.gapMs,onStatus:H=>se.current?.(H)})},setEmotion:v=>{if(!ve.current)throw new Error("AI twin is not ready");const B=N.current,U=D.current;if(!B||!U)throw new Error("AI twin is not ready");J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,z.current=!1,I.current=!1,ie.current.stop(),le.current?.stop(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,B.finishIdleToSilCrossfade(),y.current?.setActive(!1);const L=He(v);ee.current=!0,he.current=null,ce.current=null,k.current.snapToEmotion(L);const H=k.current.getExpressionPath(),be=k.current.getDrawKey(),Ee={mouthPath:null,expressionPath:H},De=Et(Ee,be);q.current.lastDrawnKey="",B.drawLiveFrame(U,Ee,De,Ne=>{Ne===De&&(q.current.lastDrawnKey=De)});const Pe=Ze(L);se.current?.(H?`${L} · brow ${Pe>0?"+":""}${Pe}`:`${L} · brow 0 (sil base)`)},getEmotion:()=>ee.current?k.current.getTargetEmotion():null,clearEmotionPreview:()=>{ee.current=!1,he.current=null,ce.current=null,k.current.reset(),xe(q.current),se.current?.("idle")},setViseme:v=>{if(!ve.current)throw new Error("AI twin is not ready");const B=N.current,U=D.current;if(!B||!U)throw new Error("AI twin is not ready");J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,z.current=!1,I.current=!1,ie.current.stop(),le.current?.stop(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,B.finishIdleToSilCrossfade(),y.current?.setActive(!1);const L=Qt(v);ee.current=!0,ce.current=L,he.current=L==="sil"?null:dt(L),k.current.snapToEmotion("neutral");const H=k.current.getExpressionPath(),be=k.current.getDrawKey(),De={mouthPath:he.current,expressionPath:H},Pe=Et(De,be);q.current.lastDrawnKey="",B.drawLiveFrame(U,De,Pe,Ne=>{Ne===Pe&&(q.current.lastDrawnKey=Pe)}),se.current?.(L)},getViseme:()=>ee.current?ce.current:null,isReady:()=>ve.current,getStatus:()=>oe,connect:async(v={})=>{_e(null);try{let B=v.authToken?.trim();B||(B=me.current??i??await Wt(),me.current=B);const U=v.voiceId?.trim()??l??we.current?.voiceId,L=v.personaId?.trim()??we.current?.personaId,H=zr();await H.unlockAudio(),await H.connect({...v,apiBase:v.apiBase?.trim()||de,authToken:B,voiceId:U,personaId:L,speakingRate:v.speakingRate??f})}catch(B){throw Be(B instanceof Error?B.message:"Voice connect failed"),B}},disconnect:async()=>{const v=le.current;v&&(J.current+=1,Ie(),Ae(),M.current=!1,G.current=!1,I.current=!1,N.current?.finishIdleToSilCrossfade(),xe(q.current),j.current?.reset(),$.current=0,_.current=!1,await v.disconnect(),at())},isConnected:()=>le.current?.isConnected()??!1,getVoiceStream:()=>le.current?.getVoiceStream()??ie.current?.getVoiceStream()??null}),[Oe,f,i,l,Ie,Ae,at,Be,it,zr,oe,de]),ur.jsxs("div",{className:c,style:{...Do,...u},children:[ur.jsx("canvas",{ref:D,width:nr.width,height:nr.height,style:{...Fo,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),x&&Re?ur.jsx("div",{style:Bo,children:Re}):null]})}),gs="thumbnail.webp";function Oo(e,t=Ir){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${gs}`}const No=new Set([".png",".jpg",".jpeg",".webp"]);function ys(e=".png"){const t=e.toLowerCase();return No.has(t)?`source${t}`:"source.png"}function Vo(e,t=Ir,r=".png"){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${ys(r)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=gs;exports.AiTwin=Lo;exports.AiTwinNotFoundError=$t;exports.CONSONANT_SKIP_GROUP=Nn;exports.DEFAULT_TTS_ENGINE_ID=Je;exports.EMOTION_TO_EYEBROW=us;exports.EXPRESSION_ATLAS_EMOTIONS=Li;exports.MIC_SAMPLE_RATE=Br;exports.OCULUS_VISEME_IDS=Fn;exports.PLAYBACK_SAMPLE_RATE=Lr;exports.SPEAKING_RATE_MAX=tr;exports.SPEAKING_RATE_MIN=er;exports.TTS_ENGINE_CARTESIA=et;exports.TTS_ENGINE_GOOGLE=Pr;exports.TTS_ENGINE_INWORLD=Yt;exports.VISEME_IDS=Ei;exports.VISEME_SKIP_GAP_MS=_r;exports.VISEME_TEST_CARTESIA_VOICE_ID=Fr;exports.VISEME_TEST_SPEAKING_RATE=Pt;exports.VISEME_TEST_VOICE_ID=Dr;exports.VISEME_VTIME_GRID_MS=xr;exports.VOWEL_SKIP_GROUP=On;exports.aiTwinSourceFilename=ys;exports.buildPlaybackTransitions=qn;exports.buildPlaybackVisemeSeries=Jt;exports.buildRawVisemeTransitions=Kn;exports.buildVoiceWebSocketUrl=Zn;exports.compactSkippableVisemes=Rr;exports.createAvatarTtsLipsyncController=Sr;exports.createRealtimeVoiceLipsyncController=es;exports.emotionToEyebrow=Ze;exports.faceAssetUrls=yr;exports.fetchAiTwin=In;exports.fetchDevAuthToken=Wt;exports.getAiTwinSourceUrl=Vo;exports.getAiTwinThumbnailUrl=Oo;exports.listSkippedVisemeEntries=Zt;exports.listSkippedVisemes=ti;exports.normalizeOculusViseme=Qt;exports.normalizeStreamEmotion=He;exports.resolveDirectFaceId=An;exports.resolveVisemeAtTime=At;exports.resolveVisemeFromPlaybackSeries=Wn;exports.resolveWordAtTime=li;exports.setActiveTwinAssets=Pn;exports.snapVisemeQueueToGrid=Mr;exports.snapVisemeVtimeToGrid=Vn;
|