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