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