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