@streamoji/aitwin 0.3.6 → 0.3.8

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