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