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