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