@streamoji/aitwin 0.1.5 → 0.1.6
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/README.md +1 -1
- package/dist/aitwin.cjs +2 -2
- package/dist/aitwin.js +107 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ Provide **`id`** (cloud twin) **or** **`assets`** (fixed URLs). One is required.
|
|
|
53
53
|
| `id` | Twin id for `getAiTwin` (e.g. `olivia`) |
|
|
54
54
|
| `assets` | `{ twinBase, binBase, encrypted }` — skip `getAiTwin` (lab / custom CDN) |
|
|
55
55
|
| `authToken` | Bearer for TTS + encrypted assets; omitted → dev `getAuthToken` |
|
|
56
|
-
| `ttsEngineId` | TTS engine when using `assets` (default
|
|
56
|
+
| `ttsEngineId` | TTS engine when using `assets` (default Cartesia) |
|
|
57
57
|
| `voiceId` | Override TTS voice |
|
|
58
58
|
| `speakingRate` | Default `0.85` |
|
|
59
59
|
| `showErrorOverlay` | Canvas error overlay (default `true`) |
|
package/dist/aitwin.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Oe=require("react/jsx-runtime"),p=require("react");var Pe=typeof document<"u"?document.currentScript:null;const xt="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",lt={publicBase:xt},Ct="0.1.5",Mt={version:Ct},Ft={},Ae="https://ai.streamoji.com",Ot=`${lt.publicBase}/custom-faces`,Pt=`${lt.publicBase}/aitwin-workers/v${Mt.version}/visemeDiffPreview.worker.js`;function Lt(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Pe&&Pe.tagName.toUpperCase()==="SCRIPT"&&Pe.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Ft?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Pt}const Ut="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",re="eng_a7f2b9c1",we="eng_d4e8f3a2",ge="eng_c9b1e6d4",Ke=we,Nt=new Set([we,ge]),ft={[re]:"oculus_direct",[ge]:"oculus_direct",[we]:"inworld_word"},Je={google:re,inworld:we,cartesia:ge};function Bt(e){return ft[e]}function Vt(e){return e===ge}function $t(e){if(e.ttsEngineId&&e.ttsEngineId in ft)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Je?Je[t]:Ke}class ve extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function dt(e,t=Ut){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new ve;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const s=await r.json();if(!s.success)throw new ve(s.error??"AI twin not found");const{tts:i,...a}=s.data;return{...a,ttsEngineId:$t(s.data)}}const Ht="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",qt="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Wt="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Kt="6TNvp3SCs4Og0a1ijm9TommXLql1",Gt="Swaraj Mali";async function Ue(){const e=await fetch(Ht,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":qt,"Client-Secret":Wt},body:JSON.stringify({userId:Kt,userName:Gt})});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 jt(e,t=Ae){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 zt(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 Se(e){return Uint8Array.from(e)}function Qt(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Jt(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=Se(n.subarray(0,12)),s=Se(n.subarray(12,28)),i=Se(n.subarray(28)),a=Se(Qt(i,s)),c=await crypto.subtle.importKey("raw",zt(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},c,a)}let Ne=null;const Be=new Set;function Yt(e,t=Ot){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Xt(e){Ne=e;for(const t of Be)t()}function Zt(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return e;const r=s=>{try{return new URL(s,n).href.replace(/\/$/,"")}catch{return s}};return{twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted}}function se(){if(!Ne)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Ne}function en(e){return Be.add(e),()=>Be.delete(e)}function tn(){return`${se().twinBase}/sil.png`}function nn(){return`${se().twinBase}/idle.mp4`}function rn(){const{encrypted:e,binBase:t,twinBase:n}=se();return e?t:n}function ht(){return se().encrypted}function sn(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/atlas.bin`:`${t}/atlas.json`}function on(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/expression_atlas.bin`:`${t}/expression_atlas.json`}function an(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 _t=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],cn=new Map(_t.map(e=>[e.toLowerCase(),e]));function mt(e){const t=(e??"").trim();return t?cn.get(t.toLowerCase())??"sil":"sil"}const un={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 ln(e){if(!e)return["sil"];const t=e.toLowerCase();return un[t]??["sil"]}function fn(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 be(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function dn(e,t){const n=e.toLowerCase(),r=be(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 hn(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";const s=be(n,t);return s==="u"||s==="w"?"U":"O"}function _n(e,t){const n=e.toLowerCase(),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)||be(n,t)==="o"?"O":"U"}const Te={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function mn(e,t){const n=e.toLowerCase(),r=be(n,t);if(Te[r])return Te[r];for(let s=0;s<n.length;s++){const i=n[s];if(Te[i])return Te[i]}return"DD"}function wn(e,t,n){const r=ln(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 dn(s,a);case"o":return hn(s,a);case"qw":return _n(s,a);case"cdgknstxyz":return mn(s,a);default:return r[0]}}function gn(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}const yn=24e3;function pn(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Ye(e,t,n=yn){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 c=0;c<s.length;c++)i[c]=s[c]>=32768?-(65536-s[c])/32768:s[c]/32767;const a=e.createBuffer(1,i.length,n);return a.copyToChannel(i,0),a}function En(e){const t=gn(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 Sn(e,t){const n=En(t);if(pn(n)){const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return e.decodeAudioData(r)}if(n.length>=2&&n.length%2===0)return Ye(e,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(r)}catch{return Ye(e,n)}}function wt(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 gt(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Xe(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}const yt=.5,pt=1.5,Ge="Olivia",Et="f786b574-daa5-4673-aa0c-cbe3e8534c02",je=.85;function St(e,t=Ae){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],i=[];let a="neutral";const c=[],l=[];let d=null,m=!1,_=!1,I=!1,o=!1,x=0,w=0,u=0,g=0,E=null,R=1,$="",y=re,S=re,C=!1;const D=new Set,q=()=>{for(const h of l)h.playbackRate.value=R},W=()=>D.forEach(h=>h()),ae=()=>{E!=null&&(clearTimeout(E),E=null)},ye=()=>{for(const h of l)try{h.stop()}catch{}l.length=0},X=()=>{C=!0,ae(),ye(),c.length=0,m=!1,_=!1,I=!1,o=!1,r.length=0,s.length=0,i.length=0,a="neutral",u=0,g=0,w=0,e("idle"),W()},K=()=>{!o||m||l.length>0||c.length>0||(_=!1,ae(),e("done"),W())},pe=()=>{const h=Xe(r);if(h<=0){e("done"),W();return}_=!0,x=performance.now(),e("speaking"),W(),ae();const M=R>0?h/R:h;E=setTimeout(()=>{C||(_=!1,E=null,e("done"),W())},M)},xe=(h,M,B)=>{h.length!==0&&(B&&(u=M),h.forEach(P=>{const U=String(P.word??"").trim();if(!U)return;const Q=Math.round((P.start??0)*1e3),V=Math.round((P.duration??0)*1e3);s.push({word:U,wtime:u+Q,wduration:V,queueIndex:s.length})}))},ce=(h,M,B,P)=>{h.length!==0&&(B&&(u=M),h.forEach(k=>{const U=String(k.symbol??"").trim();if(!U)return;const Q=Math.round((k.start??0)*1e3),V=Math.max(1,Math.round((k.duration??0)*1e3)),L=u+Q;let F;if(Bt(P)==="oculus_direct")F=mt(U);else{const O=gt(s,L),J=O?fn(O,L):0;F=wn(U,O?.word??"",J)}r.push({viseme:F,weight:1,vtime:L,vduration:V})}),W())},ie=(h,M,B,P,k)=>{xe(M,B,P),ce(h,B,P,k)},Ee=async(h,M,B,P)=>{if(C||!h?.trim()){(M.length>0||B.length>0)&&!I&&ie(M,B,u,P,S);return}if(m){c.push({audio:h,visemes:M,words:B,isNewSegment:P});return}m=!0;try{const k=window.AudioContext||window.webkitAudioContext,U=d??new k;U.state==="suspended"&&await U.resume(),d=U;const Q=await Sn(U,h);I=!0;const V=U.currentTime;let L=g;const F=!_;L<V&&(L=V+.1),g=L+Q.duration;const O=U.createBufferSource();if(O.buffer=Q,O.playbackRate.value=R,O.connect(U.destination),l.push(O),C){l.pop();return}if(F){_=!0,e("speaking"),w=L,u=0,r.length=0,s.length=0;const H=(L-V)*1e3;x=performance.now()+H}O.onended=()=>{const H=l.indexOf(O);H>=0&&l.splice(H,1),K(),W()},O.start(L);const J=(L-w)*1e3;ie(M,B,J,P,S)}catch(k){console.error("[avatarTtsLipsync] audio chunk failed:",k)}finally{m=!1;const k=c.shift();k?await Ee(k.audio,k.visemes,k.words,k.isNewSegment):K()}},Z=()=>{if(o=!0,!I&&r.length>0){pe();return}K()};return{setDeveloperToken:h=>{$=h},setTtsEngineId:h=>{y=h},getTtsEngineId:()=>y,speak:async(h,M)=>{X(),C=!1,e("loading");const B=$.trim();if(!B)throw new Error("Developer token required for avatar_ttsWithPoses");const P=M?.ttsEngineId??y??Ke;S=P;const k=M?.voiceId??Ge,U=M?.speakingRate??je,Q=Math.max(yt,Math.min(pt,U)),V={user_query:h,ttsEngineId:P,speakingRate:Q};Nt.has(P)&&(V.voice_id=k);try{const L=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${B}`},body:JSON.stringify(V)});if(!L.ok)throw new Error(`avatar_ttsWithPoses failed (${L.status})`);const F=L.body;if(!F)throw new Error("No response body");const O=F.getReader(),J=new TextDecoder;let H="";const le=async fe=>{const f=an(fe);if(f){if(f.event==="audio"){const T=f.data.chunk,A=f.data.visemes??[],v=f.data.words??[],b=f.data.is_new_segment??!1;if(T)await Ee(T,A,v,b);else if(A.length>0||v.length>0){const G=b&&r.length>0?Xe(r):u;ie(A,v,G,b,P)}}else if(f.event==="metadata"){const T=f.data.mood;typeof T=="string"&&T.trim()&&(a=T.trim());const A=f.data.sentence_emotions;if(Array.isArray(A)){i.length=0;for(const v of A){if(!v||typeof v!="object")continue;const b=v;i.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??a),start_word:Number(b.start_word??0),end_word:Number(b.end_word??0)})}}W()}else if(f.event==="error")throw new Error(String(f.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:fe,value:f}=await O.read();f&&(H+=J.decode(f,{stream:!0}));const T=H.split(`
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Oe=require("react/jsx-runtime"),p=require("react");var Pe=typeof document<"u"?document.currentScript:null;const xt="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",lt={publicBase:xt},Ct="0.1.6",Mt={version:Ct},Ft={},ke="https://ai.streamoji.com",Ot=`${lt.publicBase}/custom-faces`,Pt=`${lt.publicBase}/aitwin-workers/v${Mt.version}/visemeDiffPreview.worker.js`;function Lt(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Pe&&Pe.tagName.toUpperCase()==="SCRIPT"&&Pe.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Ft?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Pt}const Ut="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Ke="eng_a7f2b9c1",Re="eng_d4e8f3a2",ae="eng_c9b1e6d4",re=ae,Nt=new Set([Re,ae]),ft={[Ke]:"oculus_direct",[ae]:"oculus_direct",[Re]:"inworld_word"},Je={google:Ke,inworld:Re,cartesia:ae};function Bt(e){return ft[e]}function Vt(e){return e===ae}function $t(e){if(e.ttsEngineId&&e.ttsEngineId in ft)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Je?Je[t]:re}class Ae extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function dt(e,t=Ut){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new Ae;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const s=await r.json();if(!s.success)throw new Ae(s.error??"AI twin not found");const{tts:i,...a}=s.data;return{...a,ttsEngineId:$t(s.data)}}const Ht="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",qt="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Wt="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Kt="6TNvp3SCs4Og0a1ijm9TommXLql1",Gt="Swaraj Mali";async function Ue(){const e=await fetch(Ht,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":qt,"Client-Secret":Wt},body:JSON.stringify({userId:Kt,userName:Gt})});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 jt(e,t=ke){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 zt(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 Ee(e){return Uint8Array.from(e)}function Qt(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Jt(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=Ee(n.subarray(0,12)),s=Ee(n.subarray(12,28)),i=Ee(n.subarray(28)),a=Ee(Qt(i,s)),c=await crypto.subtle.importKey("raw",zt(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},c,a)}let Ne=null;const Be=new Set;function Yt(e,t=Ot){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Xt(e){Ne=e;for(const t of Be)t()}function Zt(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return e;const r=s=>{try{return new URL(s,n).href.replace(/\/$/,"")}catch{return s}};return{twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted}}function se(){if(!Ne)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Ne}function en(e){return Be.add(e),()=>Be.delete(e)}function tn(){return`${se().twinBase}/sil.png`}function nn(){return`${se().twinBase}/idle.mp4`}function rn(){const{encrypted:e,binBase:t,twinBase:n}=se();return e?t:n}function ht(){return se().encrypted}function sn(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/atlas.bin`:`${t}/atlas.json`}function on(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/expression_atlas.bin`:`${t}/expression_atlas.json`}function an(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 _t=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],cn=new Map(_t.map(e=>[e.toLowerCase(),e]));function mt(e){const t=(e??"").trim();return t?cn.get(t.toLowerCase())??"sil":"sil"}const un={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 ln(e){if(!e)return["sil"];const t=e.toLowerCase();return un[t]??["sil"]}function fn(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 be(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function dn(e,t){const n=e.toLowerCase(),r=be(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 hn(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";const s=be(n,t);return s==="u"||s==="w"?"U":"O"}function _n(e,t){const n=e.toLowerCase(),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)||be(n,t)==="o"?"O":"U"}const Se={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function mn(e,t){const n=e.toLowerCase(),r=be(n,t);if(Se[r])return Se[r];for(let s=0;s<n.length;s++){const i=n[s];if(Se[i])return Se[i]}return"DD"}function wn(e,t,n){const r=ln(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 dn(s,a);case"o":return hn(s,a);case"qw":return _n(s,a);case"cdgknstxyz":return mn(s,a);default:return r[0]}}function gn(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}const yn=24e3;function pn(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Ye(e,t,n=yn){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 c=0;c<s.length;c++)i[c]=s[c]>=32768?-(65536-s[c])/32768:s[c]/32767;const a=e.createBuffer(1,i.length,n);return a.copyToChannel(i,0),a}function En(e){const t=gn(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 Sn(e,t){const n=En(t);if(pn(n)){const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return e.decodeAudioData(r)}if(n.length>=2&&n.length%2===0)return Ye(e,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(r)}catch{return Ye(e,n)}}function wt(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 gt(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Xe(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}const yt=.5,pt=1.5,Ge="Olivia",Et="f786b574-daa5-4673-aa0c-cbe3e8534c02",je=.85;function St(e,t=ke){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],i=[];let a="neutral";const c=[],l=[];let d=null,m=!1,_=!1,I=!1,o=!1,x=0,w=0,u=0,g=0,E=null,R=1,$="",y=re,S=re,C=!1;const D=new Set,q=()=>{for(const h of l)h.playbackRate.value=R},W=()=>D.forEach(h=>h()),ce=()=>{E!=null&&(clearTimeout(E),E=null)},ge=()=>{for(const h of l)try{h.stop()}catch{}l.length=0},X=()=>{C=!0,ce(),ge(),c.length=0,m=!1,_=!1,I=!1,o=!1,r.length=0,s.length=0,i.length=0,a="neutral",u=0,g=0,w=0,e("idle"),W()},K=()=>{!o||m||l.length>0||c.length>0||(_=!1,ce(),e("done"),W())},ye=()=>{const h=Xe(r);if(h<=0){e("done"),W();return}_=!0,x=performance.now(),e("speaking"),W(),ce();const M=R>0?h/R:h;E=setTimeout(()=>{C||(_=!1,E=null,e("done"),W())},M)},xe=(h,M,B)=>{h.length!==0&&(B&&(u=M),h.forEach(P=>{const U=String(P.word??"").trim();if(!U)return;const Q=Math.round((P.start??0)*1e3),V=Math.round((P.duration??0)*1e3);s.push({word:U,wtime:u+Q,wduration:V,queueIndex:s.length})}))},ue=(h,M,B,P)=>{h.length!==0&&(B&&(u=M),h.forEach(k=>{const U=String(k.symbol??"").trim();if(!U)return;const Q=Math.round((k.start??0)*1e3),V=Math.max(1,Math.round((k.duration??0)*1e3)),L=u+Q;let F;if(Bt(P)==="oculus_direct")F=mt(U);else{const O=gt(s,L),J=O?fn(O,L):0;F=wn(U,O?.word??"",J)}r.push({viseme:F,weight:1,vtime:L,vduration:V})}),W())},ie=(h,M,B,P,k)=>{xe(M,B,P),ue(h,B,P,k)},pe=async(h,M,B,P)=>{if(C||!h?.trim()){(M.length>0||B.length>0)&&!I&&ie(M,B,u,P,S);return}if(m){c.push({audio:h,visemes:M,words:B,isNewSegment:P});return}m=!0;try{const k=window.AudioContext||window.webkitAudioContext,U=d??new k;U.state==="suspended"&&await U.resume(),d=U;const Q=await Sn(U,h);I=!0;const V=U.currentTime;let L=g;const F=!_;L<V&&(L=V+.1),g=L+Q.duration;const O=U.createBufferSource();if(O.buffer=Q,O.playbackRate.value=R,O.connect(U.destination),l.push(O),C){l.pop();return}if(F){_=!0,e("speaking"),w=L,u=0,r.length=0,s.length=0;const H=(L-V)*1e3;x=performance.now()+H}O.onended=()=>{const H=l.indexOf(O);H>=0&&l.splice(H,1),K(),W()},O.start(L);const J=(L-w)*1e3;ie(M,B,J,P,S)}catch(k){console.error("[avatarTtsLipsync] audio chunk failed:",k)}finally{m=!1;const k=c.shift();k?await pe(k.audio,k.visemes,k.words,k.isNewSegment):K()}},Z=()=>{if(o=!0,!I&&r.length>0){ye();return}K()};return{setDeveloperToken:h=>{$=h},setTtsEngineId:h=>{y=h},getTtsEngineId:()=>y,speak:async(h,M)=>{X(),C=!1,e("loading");const B=$.trim();if(!B)throw new Error("Developer token required for avatar_ttsWithPoses");const P=M?.ttsEngineId??y??re;S=P;const k=M?.voiceId??Ge,U=M?.speakingRate??je,Q=Math.max(yt,Math.min(pt,U)),V={user_query:h,ttsEngineId:P,speakingRate:Q};Nt.has(P)&&(V.voice_id=k);try{const L=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${B}`},body:JSON.stringify(V)});if(!L.ok)throw new Error(`avatar_ttsWithPoses failed (${L.status})`);const F=L.body;if(!F)throw new Error("No response body");const O=F.getReader(),J=new TextDecoder;let H="";const fe=async de=>{const f=an(de);if(f){if(f.event==="audio"){const T=f.data.chunk,A=f.data.visemes??[],v=f.data.words??[],b=f.data.is_new_segment??!1;if(T)await pe(T,A,v,b);else if(A.length>0||v.length>0){const G=b&&r.length>0?Xe(r):u;ie(A,v,G,b,P)}}else if(f.event==="metadata"){const T=f.data.mood;typeof T=="string"&&T.trim()&&(a=T.trim());const A=f.data.sentence_emotions;if(Array.isArray(A)){i.length=0;for(const v of A){if(!v||typeof v!="object")continue;const b=v;i.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??a),start_word:Number(b.start_word??0),end_word:Number(b.end_word??0)})}}W()}else if(f.event==="error")throw new Error(String(f.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:de,value:f}=await O.read();f&&(H+=J.decode(f,{stream:!0}));const T=H.split(`
|
|
2
2
|
|
|
3
|
-
`);H=T.pop()??"";for(const A of T)await le(A);if(fe){H.trim()&&await le(H.trim()),C||Z();break}}}catch(L){throw console.error("[avatarTtsLipsync]",L),X(),e("error"),L}},stop:X,getVisemeQueue:()=>r,getWordQueue:()=>s,getSentenceEmotions:()=>i,getStreamMood:()=>a,getPlaybackElapsedMs:()=>_?I&&d&&w>0?Math.max(0,(d.currentTime-w)*1e3):Math.max(0,(performance.now()-x)*R):0,isSpeaking:()=>_,setPlaybackSpeed:h=>{R=Math.max(.1,Math.min(1,h)),q()},getPlaybackSpeed:()=>R,subscribe:h=>(D.add(h),()=>D.delete(h))}}function Tn(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function In(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 kn(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function Tt(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 Jt(r,t)}async function An(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await Tt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function vn(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})}function It(e,t){return`${e}/${t}_minus_sil.png`}const ze=15,Rn=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Ve=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],bn=Ve.length,Ze=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 et(e,t){return`${e}__${t}`}function tt(e,t){return`pairs/${e}/${t}_minus_sil.png`}function $e(e){return`${e}_minus_sil.png`}function Dn(e,t){if(e===t)return[];const n=[],r=et(e,t);if(Ze.has(r)){for(const i of Ve)n.push(tt(r,i));return n}const s=et(t,e);if(Ze.has(s)){for(let i=bn-1;i>=0;i--)n.push(tt(s,Ve[i]));return n}return[]}function xn(e){return e<16?[]:e<35?[2]:e<51?[0,4]:e<67?[0,2,4]:e<83?[0,1,2,3]:[0,1,2,3,4]}function Cn(e,t){return xn(t).map(r=>e[r]).filter(r=>r!=null)}function Mn(e,t,n,r){if(r<=0)return 0;const i=Math.max(1,n-t)/r,a=e-t,c=Math.floor(a/i);return Math.min(r-1,Math.max(0,c))}function Fn(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 On=[.32,.24,.16,.08,0],De=On.map(e=>`eyes_${e.toFixed(2)}`),Pn=["eyes_0.32","eyes_0.16","eyes_0.00"],Ln=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Un={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 oe(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?Un[n]??t:t}function z(e){return e==="neutral"?null:It(e,"eyes_standard")}function He(e,t){return!t||t==="eyes_standard"?z(e):e==="neutral"&&t==="eyes_standard"?null:It(e,t)}function Nn(e){if(!e)return"open";const t=e.match(/\/(eyes_[^/]+)_minus_sil\.png$/);if(!t?.[1])return"open";const n=t[1];return De.includes(n)?n:"open"}function Bn(e){return e==="open"?-1:De.indexOf(e)}function Vn(e,t){const n=[];for(const r of t)n.push(He(e,r));for(let r=t.length-2;r>=0;r--)n.push(He(e,t[r]));return n.push(z(e)),n}function $n(e,t){if(t==="open")return[z(e)];const n=Bn(t);if(n<0)return[z(e)];const r=[];for(let s=n;s>=0;s--)r.push(He(e,De[s]));return r.push(z(e)),r}const Hn=["t01_0.20","t02_0.40","t03_0.60","t04_0.80"];function qn(e,t){return`${e}__${t}`}function Wn(e,t,n){return`pairs/${qn(e,t)}/${n}_minus_sil.png`}function Kn(e,t){return Hn.map(n=>Wn(e,t,n))}function he(e,t){return e+Math.random()*(t-e)}function Ie(){return he(14,32)}function Gn(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:a=220,fullBlinkChance:c=.75,postEmotionChangeDelayMs:l=380,minDwellMs:d=550}=e;let m="neutral",_="neutral",I=0,o={kind:"idle",nextBlinkAt:performance.now()+t},x=null,w="__eyes_open__|neutral";function u(y,S){x=y,w=`${y??"__eyes_open__"}|${S}`}function g(y,S){o={kind:"idle",nextBlinkAt:y+he(n,r)},_=S,u(z(S),S)}function E(y,S,C){const D=C?Pn:Math.random()<c?De:Ln;o={kind:"playing",paths:Vn(S,D),index:0,holdUntil:y+Ie(),after:"idle",blinkEmotion:S},_=S,u(o.paths[0]??null,S)}function R(y,S,C){const D=Nn(x),q=[];if(D!=="open"){const W=$n(S,D);q.push(...W.slice(0,-1))}q.push(...Kn(S,C)),q.push(z(C)),o={kind:"emotionBlend",paths:q,index:0,holdUntil:y+Ie(),thenEmotion:C},u(q[0]??null,S)}function $(y){if(o.kind==="emotionBlend"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+Ie();const S=o.paths[o.index]??null;u(S,o.thenEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1&&(m=o.thenEmotion,_=o.thenEmotion,u(z(o.thenEmotion),o.thenEmotion),o={kind:"idle",nextBlinkAt:y+l});return}if(o.kind==="idle"){u(z(_),_),y>=o.nextBlinkAt&&E(y,_,!1);return}if(o.kind==="doublePause"){u(z(o.blinkEmotion),o.blinkEmotion),y>=o.resumeAt&&E(y,o.blinkEmotion,!0);return}if(o.kind==="playing"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+Ie();if(u(o.paths[o.index]??null,o.blinkEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1){if(o.after==="resumeIdle"){g(y+l,m);return}if(o.after==="doublePause"){o={kind:"doublePause",resumeAt:y+he(i,a),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}if(o.after==="idle"&&Math.random()<s){o={kind:"doublePause",resumeAt:y+he(i,a),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}g(y,o.blinkEmotion)}}}return{advance:$,setTargetEmotion(y){const S=oe(y,m);if(S===m&&o.kind!=="emotionBlend")return;const C=performance.now();if(d>0&&S!==m&&o.kind!=="emotionBlend"&&!(m==="neutral"&&S!=="neutral")&&C-I<d)return;const D=m;if(m=S,I=C,o.kind==="playing"){R(C,_,S);return}if(o.kind==="emotionBlend"){o={...o,thenEmotion:S};return}R(C,D,S)},getTargetEmotion:()=>m,getExpressionPath:()=>x,getDrawKey:()=>w,reset(){m="neutral",_="neutral",I=0,g(performance.now()+he(n,r),"neutral")}}}function jn(e){const t=document.createElement("video");t.muted=!0,t.playsInline=!0,t.preload="auto",t.setAttribute("playsinline",""),t.loop=!0;let n=!1;return{async load(){n||await new Promise((r,s)=>{const i=()=>{const a=t.duration;if(!Number.isFinite(a)||a<=0){s(new Error(`Idle video has invalid duration: ${e}`));return}n=!0,t.currentTime=0,r()};t.addEventListener("loadeddata",i,{once:!0}),t.addEventListener("error",()=>s(new Error(`Failed to load idle video: ${e}`)),{once:!0}),t.src=e,t.load()})},isReady(){return n},getVideo(){return t},setActive(r){n&&(r?t.paused&&t.play().catch(()=>{}):t.paused||t.pause())},restart(){n&&(t.currentTime=0)}}}const zn=50,kt=400;function Qn(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function Jn(e,t){const n=[];for(const r of e){const s=Qn(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-zn),endMs:a.wtime+a.wduration+kt})}return n.sort((r,s)=>r.startMs-s.startMs)}function Yn(e,t,n,r="neutral"){const s=oe(r);if(t.length===0)return s;if(n.length===0||e<n[0].wtime)return oe(t[0]?.emotion,s);const i=Jn(t,n);let a=null;for(const d of i)e>=d.startMs&&e<=d.endMs&&(a=d);if(a)return oe(a.sentence.emotion,s);const c=n[n.length-1],l=c.wtime+c.wduration;return e>l+kt?oe(t[t.length-1]?.emotion,s):s}function At(e,t,n,r,s=ze){const i=new OffscreenCanvas(n,r),a=i.getContext("2d",{willReadFrequently:!0});a.drawImage(e,0,0,n,r);const c=a.getImageData(0,0,n,r),l=a.createImageData(n,r);l.data.set(c.data);const m=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const _ of t){m.clearRect(0,0,n,r),m.drawImage(_,0,0,n,r);const I=m.getImageData(0,0,n,r);for(let o=0;o<l.data.length;o+=4){const x=I.data[o],w=I.data[o+1],u=I.data[o+2];Math.max(x,w,u)>s&&(l.data[o]=x,l.data[o+1]=w,l.data[o+2]=u,l.data[o+3]=255)}}return a.putImageData(l,0,0),i}let ne=null,_e=null;const Re=new Map;function Xn(){ne=null,_e=null,Re.clear()}en(Xn);function Zn(e){return e??_e??void 0}function Qe(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 nt(e,t,n,r){const s=n?await An(e,r):await fetch(e).then(d=>{if(!d.ok)throw new Error(`Failed to load ${e}`);return d.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const a=n?await vn(await Tt(Fn(t,i.path,n),r??"")):await Qe(`${t}/${i.path}`),c=new Map;for(const d of s.cells??[])d.path&&c.set(d.path,d);const l=new Map;for(const d of s.sheets??[])l.set(d.index,d);return{atlas:a,atlasMeta:s,cellByPath:c,sheetByIndex:l,diffBase:t}}async function qe(e){const t=Zn(e),n=ht();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(ne&&(!n||_e===(t??null))){const i=await ne;return me(i)}_e=t??null,Re.clear();const r=rn();ne=(async()=>{const i=await Qe(tn()),a=await nt(sn(),r,n,t);let c=null;try{c=await nt(on(),r,n,t)}catch{c=null}return{sil:i,viseme:a,expression:c}})();const s=await ne;return me(s)}async function vt(e){if(await qe(e),!ne)throw new Error("Assets not loaded");return ne}function me(e){return Tn(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function er(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 rt(e,t,n){const r=`${t.diffBase}::${n}`,s=Re.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 c=In(t.atlasMeta,a),l=me(e);if(kn(a)){const _=er(t,a),I=document.createElement("canvas");I.width=l.width,I.height=l.height;const o=I.getContext("2d");return o.fillStyle="#000",o.fillRect(0,0,l.width,l.height),o.drawImage(_,c.x,c.y),I}const d=`${t.diffBase}/${n}`,m=await Qe(d);if(m.naturalWidth===l.width&&m.naturalHeight===l.height)return m;throw new Error(`Diff PNG wrong size for ${n}`)})();return Re.set(r,i),i}async function st(e,t,n,r=ze,s,i){if(s){const{width:I,height:o}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const x=document.createElement("canvas");x.width=I,x.height=o;const w=x.getContext("2d");if(w.clearRect(0,0,I,o),w.drawImage(t,0,0,I,o),i&&!i())return;(e.width!==I||e.height!==o)&&(e.width=I,e.height=o);const u=e.getContext("2d");u.clearRect(0,0,I,o),u.drawImage(x,0,0);return}const a=await vt(),{width:c,height:l}=me(a);(e.width!==c||e.height!==l)&&(e.width=c,e.height=l);const d=[],m=e.getContext("2d");if(m.clearRect(0,0,c,l),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const I=a.sil;m.drawImage(I,0,0,c,l);return}if(d.length===0){m.drawImage(t,0,0,c,l);return}const _=At(t,d,c,l,r);m.drawImage(_,0,0)}async function We(e,t,n=ze){const r=await vt(_e??void 0),{width:s,height:i}=me(r);(e.width!==s||e.height!==i)&&(e.width=s,e.height=i);const a=[];t.mouthPath&&a.push(await rt(r,r.viseme,t.mouthPath)),t.expressionPath&&r.expression&&a.push(await rt(r,r.expression,t.expressionPath));const c=e.getContext("2d");if(c.clearRect(0,0,s,i),a.length===0){c.drawImage(r.sil,0,0,s,i);return}const l=At(r.sil,a,s,i,n);c.drawImage(l,0,0)}async function tr(e){await We(e,{mouthPath:null,expressionPath:null})}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 rr(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,c=t[r+1].vtime;s===i||c<=a||n.push({from:s,to:i,fromVtime:a,toVtime:c})}return n}function sr(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function ir(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const or=500,ar="__sil__";function cr(){return{lastDrawnKey:""}}function de(e){e.lastDrawnKey=""}function it(e){return e??ar}function ur(e,t){if(e.length===0)return{diffPath:null,label:"sil"};const n=rr(e),r=sr(n,t);if(r){const i=r.toVtime-r.fromVtime,a=ir(r.fromVtime,r.toVtime);if(t>=a.transStart&&t<r.toVtime){const c=Dn(r.from,r.to),l=Cn(c,i);if(l.length>0){const d=Mn(t,a.transStart,r.toVtime,l.length);return{diffPath:l[d]??l[l.length-1],label:`${r.from}→${r.to}`}}return{diffPath:$e(r.to),label:r.to}}}const s=wt(e,t);return s==="sil"?{diffPath:null,label:"sil"}:{diffPath:$e(s),label:s}}function Rt(e,t){const n=t??it(e.expressionPath);return`${it(e.mouthPath)}|${n}`}function lr(e,t,n,r,s,i,a,c){const l=ur(t,n),d={mouthPath:l.diffPath,expressionPath:r},m=Rt(d,s);m!==i.lastDrawnKey&&(c(l.label),a(e,d,m,_=>{_===m&&(i.lastDrawnKey=m)}))}function ot(e,t,n,r,s,i,a=null){const c={mouthPath:null,expressionPath:t},l=a!=null?`|idle@${Math.round(a*1e3)}`:"",d=Rt(c,n)+l;!(a!=null)&&d===r.lastDrawnKey||(i(a!=null?"idle":"sil"),s(e,c,d,_=>{_===d&&(r.lastDrawnKey=d)}))}function bt(e){let t=0,n=null,r=!1,s=!1;const i=async()=>{if(!r){r=!0;try{for(;n;){const c=n;n=null;const l=++t,d=await e(c.diffs,l,c);n||d&&l===t&&c.onDisplayed?.(c.drawKey)}}finally{r=!1,n&&i()}}},a=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(c,l,d){n={diffs:c,drawKey:l,onDisplayed:d},a()},reset(){t+=1,n=null},isLatestSeq(c){return c===t},getLatestSeq(){return t}}}const at=-1,ct=new Map;async function fr(e){let t=ct.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),ct.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function dr(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function hr(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 ut(e,t){let n=0;const r=bt(async(s,i)=>(await qe(),await We(e,s),r.isLatestSeq(i)));return{usesWorker:!1,async loadAssets(s){return await qe(s)},async renderSilOnly(){n+=1,r.reset(),await tr(e)},drawLiveFrame(s,i,a,c){r.enqueue(i,a,c)},async renderViseme(s,i){n+=1;const a=n;t.onStatus?.(i),await We(s,{mouthPath:$e(i),expressionPath:null})},dispose(){n+=1,r.reset()}}}function _r(e,t,n){let r=null,s=1,i=0,a=!1,c=!1;const l=new Map,d=bt(async(w,u,g)=>(l.set(u,{drawKey:g.drawKey,onDisplayed:g.onDisplayed}),await o({type:"drawFrame",diffPath:w.mouthPath,expressionDiffPath:w.expressionPath,liveSeq:u},void 0,!0),!1)),m=w=>{if(w===at){let E=-1,R;for(const[$,y]of l)$>=E&&(E=$,R=y);E>=0&&l.delete(E),R?.onDisplayed?.(R.drawKey);return}const u=-w,g=l.get(u);l.delete(u),g?.onDisplayed?.(g.drawKey)},_=new Map,I=(w,u)=>{c||!r||r.postMessage(w,[])},o=(w,u,g=!1)=>{if(c)return Promise.resolve();const E=s++;return new Promise((R,$)=>{_.set(E,{resolve:y=>R(y),reject:$,generation:typeof w.generation=="number"?w.generation:void 0,expectRenderDone:g}),I({...w,requestId:E})})},x=(async()=>{r=await fr(n),r.onmessage=w=>{if(c)return;const u=w.data;if(u.type==="status"){t.onStatus?.(u.label);return}if(u.type==="frame"){const E=u.generation<0;if(!E&&u.generation!==i){u.bitmap.close();return}if(E&&!(u.generation===at)){const $=-u.generation;if(!d.isLatestSeq($)){u.bitmap.close();return}}if(E&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){u.bitmap.close();return}hr(e,u.bitmap),u.bitmap.close(),E&&m(u.generation);return}const g=_.get(u.requestId);if(g)switch(u.type){case"ready":_.delete(u.requestId),g.resolve();break;case"loadAssetsDone":_.delete(u.requestId),g.resolve({width:u.width,height:u.height});break;case"renderDone":if(g.expectRenderDone&&g.generation!=null&&u.generation!==g.generation)return;_.delete(u.requestId),g.resolve();break;case"renderAborted":_.delete(u.requestId),g.resolve();break;case"error":_.delete(u.requestId),t.onError?.(u.message),g.reject(new Error(u.message));break}},r.onerror=w=>{if(c)return;const u=w.message||"Worker error";t.onError?.(u);for(const[,g]of _)g.reject(new Error(u));_.clear()},await o({type:"init"}),a=!0})();return{usesWorker:!0,async loadAssets(w){if(c)return{width:842,height:1264};if(await x,c)return{width:842,height:1264};if(!a)throw new Error("Worker init failed");return await o({type:"loadAssets",keyHex:w,urls:Zt(se())})??{width:842,height:1264}},async renderSilOnly(){if(c||(await x,c))return;i+=1,d.reset(),l.clear();const w=i;await o({type:"renderSil",generation:w},void 0,!0)},drawLiveFrame(w,u,g,E){c||x.then(()=>{c||d.enqueue(u,g,E)})},async renderViseme(w,u,g={}){if(c||(await x,c))return;i+=1;const E=i;try{await o({type:"renderViseme",generation:E,to:u,from:g.from,transitionDurationMs:g.transitionDurationMs,gapMs:g.gapMs,threshold:g.threshold},void 0,!0)}catch(R){if(R?.name==="AbortError")return;throw R}},dispose(){if(!c){c=!0,i+=1,d.reset(),l.clear();for(const[,w]of _)w.resolve();_.clear(),r?.terminate(),r=null}}}}function mr(e,t={}){if(!dr())return ut(e,t);const n=Lt(t.workerScriptUrl);try{return _r(e,t,n)}catch{return ut(e,t)}}class wr extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Le(e,t,n){return new Promise((r,s)=>{const i=globalThis.setTimeout(()=>{s(new wr(n,t))},t);e.then(a=>{globalThis.clearTimeout(i),r(a)},a=>{globalThis.clearTimeout(i),s(a)})})}const gr={position:"relative",display:"inline-block",lineHeight:0},yr={display:"block",maxWidth:"100%",height:"auto"},pr={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 ke(e){return Vt(e)?Et:Ge}const Er=p.forwardRef(function({id:t,assets:n,authToken:r,ttsEngineId:s=re,voiceId:i,speakingRate:a=je,className:c,style:l,canvasStyle:d,onStatusChange:m,onDisplayStatus:_,onError:I,onReady:o,showErrorOverlay:x=!0},w){const u=p.useRef(null),g=p.useRef(null),E=p.useRef(cr()),R=p.useRef(Gn()),$=p.useRef(0),y=p.useRef(0),S=p.useRef(null),C=p.useRef(!1),D=p.useRef(null),q=p.useRef(!1),[W,ae]=p.useState("idle"),[ye,X]=p.useState(null),[K,pe]=p.useState(!1),[xe,ce]=p.useState(!1),[ie,Ee]=p.useState({width:842,height:1264}),Z=p.useRef(r??null),ue=p.useRef(null),h=p.useRef(null),M=p.useRef(!1),B=p.useRef({width:842,height:1264}),P=p.useRef(o),k=p.useRef(_),U=p.useRef(I);P.current=o,k.current=_,U.current=I;const Q=p.useCallback(f=>{const T=f?.ttsEngineId??s??h.current?.ttsEngineId??re,A=f?.voiceId??i??h.current?.voiceId??ke(T);return{ttsEngineId:T,voiceId:A}},[s,i]),V=p.useCallback(f=>{X(f),U.current?.(f)},[]),L=p.useCallback(f=>{ae(f),m?.(f)},[m]),F=p.useRef(St(L,Ae)),O=p.useCallback(()=>{S.current!=null&&(clearTimeout(S.current),S.current=null)},[]),J=p.useCallback(async()=>{const f=y.current,T=g.current;!T||!K||F.current.isSpeaking()||(de(E.current),await T.renderSilOnly(),f===y.current&&(F.current.isSpeaking()||(k.current?.("sil"),q.current&&D.current&&(D.current.restart(),D.current.setActive(!0)))))},[K]),H=p.useCallback(()=>{O();const f=y.current;J(),S.current=setTimeout(()=>{S.current=null,f===y.current&&J()},or)},[O,J]),le=p.useCallback(async()=>{const f=Math.floor(Date.now()/1e3);if(ue.current&&f<ue.current.expiresAt-60)return ue.current.key;const T=Z.current??await Ue();Z.current=T,F.current.setDeveloperToken(T);const A=await jt(T,Ae);return ue.current={key:A.value,expiresAt:A.expiresAt},A.value},[]);p.useEffect(()=>{r&&(Z.current=r,F.current.setDeveloperToken(r))},[r]),p.useEffect(()=>{F.current.setTtsEngineId(s),h.current&&(h.current.ttsEngineId=s)},[s]),p.useEffect(()=>{const f=i??ke(s);h.current&&(h.current.voiceId=f)},[i,s]);const fe=p.useMemo(()=>n?JSON.stringify(n):`id:${t??""}`,[n,t]);return p.useEffect(()=>{if(!t&&!n){V("AiTwin requires either `id` or `assets`");return}let f=!1;M.current=!1,pe(!1),ce(!1),X(null),h.current=null,D.current=null,q.current=!1;const T=u.current;if(!T)return;let A=null;return(async()=>{try{let v,b,G;if(n)v=n,b=s,G=i??ke(b);else{k.current?.("getAiTwin");const N=await Le(dt(t),3e4,"getAiTwin");if(f)return;if(!N.faceId?.trim())throw new Error("getAiTwin returned no faceId");b=N.ttsEngineId,G=i??N.voiceId??ke(b),v=Yt(N.faceId)}h.current={ttsEngineId:b,voiceId:G},Xt(v),D.current=jn(nn()),A=mr(T,{onStatus:N=>{f||k.current?.(N)},onError:N=>{f||V(N)},shouldAcceptLiveFrame:()=>F.current.isSpeaking()}),g.current=A,k.current?.("auth");const Y=Z.current??r??await Le(Ue(),3e4,"getAuthToken");if(f)return;Z.current=Y,F.current.setDeveloperToken(Y),F.current.setTtsEngineId(b);const Ce=ht()?await le():void 0;if(f)return;k.current?.("loadAssets");const j=await Le(A.loadAssets(Ce),18e4,"load face assets");if(!f&&j.width>0&&j.height>0&&(B.current=j,Ee(j)),f)return;M.current=!0,pe(!0),P.current?.(),A.renderSilOnly().then(()=>{f||k.current?.("sil")}),(async()=>{try{if(await D.current.load(),f)return;q.current=!0,ce(!0),de(E.current),D.current.setActive(!0);const N=D.current.getVideo();await st(T,N,null,void 0,B.current),f||k.current?.("idle")}catch(N){if(f)return;q.current=!1,ce(!1),console.warn("[AiTwin] Idle video unavailable:",N)}})()}catch(v){if(f)return;if(v instanceof ve){V(v.message);return}V(v instanceof Error?v.message:"Failed to load AI twin")}})(),()=>{f=!0,A?.dispose(),g.current=null}},[fe,n,s,i,r,le,V]),p.useEffect(()=>{W==="done"&&K&&!F.current.isSpeaking()&&H()},[W,K,H]),p.useEffect(()=>{const f=F.current,T={current:!1},A=()=>{const v=u.current,b=g.current;if(!v||!b||!K){$.current=requestAnimationFrame(A);return}const G=f.isSpeaking(),Y=f.getPlaybackElapsedMs(),Ce=G?Yn(Y,f.getSentenceEmotions(),f.getWordQueue(),f.getStreamMood()):f.getStreamMood();if(G){if(q.current&&D.current?.setActive(!1),f.getVisemeQueue().length===0){$.current=requestAnimationFrame(A);return}R.current.setTargetEmotion(Ce),R.current.advance(performance.now());const N=R.current.getExpressionPath(),ee=R.current.getDrawKey();lr(v,f.getVisemeQueue(),Y,N,ee,E.current,(te,Me,Fe,Dt)=>b.drawLiveFrame(te,Me,Fe,Dt),te=>k.current?.(te))}else if(q.current&&D.current){const j=D.current,N=j.getVideo();N.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?(j.setActive(!0),T.current||(T.current=!0,st(v,N,null,void 0,B.current,()=>!f.isSpeaking()).then(()=>k.current?.("idle")).finally(()=>{T.current=!1}))):ot(v,null,"__sil__",E.current,(ee,te,Me,Fe)=>b.drawLiveFrame(ee,te,Me,Fe),ee=>k.current?.(ee))}else ot(v,null,"__sil__",E.current,(j,N,ee,te)=>b.drawLiveFrame(j,N,ee,te),j=>k.current?.(j));C.current&&!G&&(R.current.reset(),D.current?.setActive(!1),H()),C.current=G,$.current=requestAnimationFrame(A)};return $.current=requestAnimationFrame(A),()=>{cancelAnimationFrame($.current),O(),f.stop()}},[K,xe,H,O]),p.useImperativeHandle(w,()=>({speakText:async(f,T)=>{const A=f.trim();if(!A)return;const v=g.current;if(!v||!M.current&&!K)throw new Error("AI twin is not ready");const{ttsEngineId:b,voiceId:G}=Q(T);X(null),y.current+=1,O(),de(E.current),R.current.reset(),C.current=!1;try{q.current?(D.current?.setActive(!1),D.current?.restart(),de(E.current)):await v.renderSilOnly(),await F.current.speak(A,{voiceId:G,speakingRate:T?.speakingRate??a,ttsEngineId:b})}catch(Y){throw V(Y instanceof Error?Y.message:"TTS failed"),Y}},stop:()=>{y.current+=1,O(),F.current.stop(),de(E.current),C.current=!1,H()},setTtsEngineId:f=>{F.current.setTtsEngineId(f),h.current&&(h.current.ttsEngineId=f)},renderViseme:async(f,T)=>{const A=g.current,v=u.current;if(!A||!v||!M.current)throw new Error("AI twin is not ready");await A.renderViseme(v,f,{from:T?.from,transitionDurationMs:T?.transitionDurationMs,gapMs:T?.gapMs,onStatus:b=>k.current?.(b)})},isReady:()=>M.current,getStatus:()=>W}),[K,a,O,H,V,Q,W]),Oe.jsxs("div",{className:c,style:{...gr,...l},children:[Oe.jsx("canvas",{ref:u,width:ie.width,height:ie.height,style:{...yr,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),x&&ye?Oe.jsx("div",{style:pr,children:ye}):null]})});exports.AiTwin=Er;exports.AiTwinNotFoundError=ve;exports.DEFAULT_TTS_ENGINE_ID=Ke;exports.OCULUS_VISEME_IDS=_t;exports.SPEAKING_RATE_MAX=pt;exports.SPEAKING_RATE_MIN=yt;exports.TTS_ENGINE_CARTESIA=ge;exports.TTS_ENGINE_GOOGLE=re;exports.TTS_ENGINE_INWORLD=we;exports.VISEME_IDS=Rn;exports.VISEME_TEST_CARTESIA_VOICE_ID=Et;exports.VISEME_TEST_SPEAKING_RATE=je;exports.VISEME_TEST_VOICE_ID=Ge;exports.createAvatarTtsLipsyncController=St;exports.fetchAiTwin=dt;exports.fetchDevAuthToken=Ue;exports.normalizeOculusViseme=mt;exports.resolveVisemeAtTime=wt;exports.resolveWordAtTime=gt;
|
|
3
|
+
`);H=T.pop()??"";for(const A of T)await fe(A);if(de){H.trim()&&await fe(H.trim()),C||Z();break}}}catch(L){throw console.error("[avatarTtsLipsync]",L),X(),e("error"),L}},stop:X,getVisemeQueue:()=>r,getWordQueue:()=>s,getSentenceEmotions:()=>i,getStreamMood:()=>a,getPlaybackElapsedMs:()=>_?I&&d&&w>0?Math.max(0,(d.currentTime-w)*1e3):Math.max(0,(performance.now()-x)*R):0,isSpeaking:()=>_,setPlaybackSpeed:h=>{R=Math.max(.1,Math.min(1,h)),q()},getPlaybackSpeed:()=>R,subscribe:h=>(D.add(h),()=>D.delete(h))}}function Tn(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function In(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 kn(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function Tt(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 Jt(r,t)}async function An(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await Tt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function vn(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})}function It(e,t){return`${e}/${t}_minus_sil.png`}const ze=15,Rn=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Ve=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],bn=Ve.length,Ze=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 et(e,t){return`${e}__${t}`}function tt(e,t){return`pairs/${e}/${t}_minus_sil.png`}function $e(e){return`${e}_minus_sil.png`}function Dn(e,t){if(e===t)return[];const n=[],r=et(e,t);if(Ze.has(r)){for(const i of Ve)n.push(tt(r,i));return n}const s=et(t,e);if(Ze.has(s)){for(let i=bn-1;i>=0;i--)n.push(tt(s,Ve[i]));return n}return[]}function xn(e){return e<16?[]:e<35?[2]:e<51?[0,4]:e<67?[0,2,4]:e<83?[0,1,2,3]:[0,1,2,3,4]}function Cn(e,t){return xn(t).map(r=>e[r]).filter(r=>r!=null)}function Mn(e,t,n,r){if(r<=0)return 0;const i=Math.max(1,n-t)/r,a=e-t,c=Math.floor(a/i);return Math.min(r-1,Math.max(0,c))}function Fn(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 On=[.32,.24,.16,.08,0],De=On.map(e=>`eyes_${e.toFixed(2)}`),Pn=["eyes_0.32","eyes_0.16","eyes_0.00"],Ln=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Un={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 oe(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?Un[n]??t:t}function z(e){return e==="neutral"?null:It(e,"eyes_standard")}function He(e,t){return!t||t==="eyes_standard"?z(e):e==="neutral"&&t==="eyes_standard"?null:It(e,t)}function Nn(e){if(!e)return"open";const t=e.match(/\/(eyes_[^/]+)_minus_sil\.png$/);if(!t?.[1])return"open";const n=t[1];return De.includes(n)?n:"open"}function Bn(e){return e==="open"?-1:De.indexOf(e)}function Vn(e,t){const n=[];for(const r of t)n.push(He(e,r));for(let r=t.length-2;r>=0;r--)n.push(He(e,t[r]));return n.push(z(e)),n}function $n(e,t){if(t==="open")return[z(e)];const n=Bn(t);if(n<0)return[z(e)];const r=[];for(let s=n;s>=0;s--)r.push(He(e,De[s]));return r.push(z(e)),r}const Hn=["t01_0.20","t02_0.40","t03_0.60","t04_0.80"];function qn(e,t){return`${e}__${t}`}function Wn(e,t,n){return`pairs/${qn(e,t)}/${n}_minus_sil.png`}function Kn(e,t){return Hn.map(n=>Wn(e,t,n))}function _e(e,t){return e+Math.random()*(t-e)}function Te(){return _e(14,32)}function Gn(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:a=220,fullBlinkChance:c=.75,postEmotionChangeDelayMs:l=380,minDwellMs:d=550}=e;let m="neutral",_="neutral",I=0,o={kind:"idle",nextBlinkAt:performance.now()+t},x=null,w="__eyes_open__|neutral";function u(y,S){x=y,w=`${y??"__eyes_open__"}|${S}`}function g(y,S){o={kind:"idle",nextBlinkAt:y+_e(n,r)},_=S,u(z(S),S)}function E(y,S,C){const D=C?Pn:Math.random()<c?De:Ln;o={kind:"playing",paths:Vn(S,D),index:0,holdUntil:y+Te(),after:"idle",blinkEmotion:S},_=S,u(o.paths[0]??null,S)}function R(y,S,C){const D=Nn(x),q=[];if(D!=="open"){const W=$n(S,D);q.push(...W.slice(0,-1))}q.push(...Kn(S,C)),q.push(z(C)),o={kind:"emotionBlend",paths:q,index:0,holdUntil:y+Te(),thenEmotion:C},u(q[0]??null,S)}function $(y){if(o.kind==="emotionBlend"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+Te();const S=o.paths[o.index]??null;u(S,o.thenEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1&&(m=o.thenEmotion,_=o.thenEmotion,u(z(o.thenEmotion),o.thenEmotion),o={kind:"idle",nextBlinkAt:y+l});return}if(o.kind==="idle"){u(z(_),_),y>=o.nextBlinkAt&&E(y,_,!1);return}if(o.kind==="doublePause"){u(z(o.blinkEmotion),o.blinkEmotion),y>=o.resumeAt&&E(y,o.blinkEmotion,!0);return}if(o.kind==="playing"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+Te();if(u(o.paths[o.index]??null,o.blinkEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1){if(o.after==="resumeIdle"){g(y+l,m);return}if(o.after==="doublePause"){o={kind:"doublePause",resumeAt:y+_e(i,a),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}if(o.after==="idle"&&Math.random()<s){o={kind:"doublePause",resumeAt:y+_e(i,a),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}g(y,o.blinkEmotion)}}}return{advance:$,setTargetEmotion(y){const S=oe(y,m);if(S===m&&o.kind!=="emotionBlend")return;const C=performance.now();if(d>0&&S!==m&&o.kind!=="emotionBlend"&&!(m==="neutral"&&S!=="neutral")&&C-I<d)return;const D=m;if(m=S,I=C,o.kind==="playing"){R(C,_,S);return}if(o.kind==="emotionBlend"){o={...o,thenEmotion:S};return}R(C,D,S)},getTargetEmotion:()=>m,getExpressionPath:()=>x,getDrawKey:()=>w,reset(){m="neutral",_="neutral",I=0,g(performance.now()+_e(n,r),"neutral")}}}function jn(e){const t=document.createElement("video");t.muted=!0,t.playsInline=!0,t.preload="auto",t.setAttribute("playsinline",""),t.loop=!0;let n=!1;return{async load(){n||await new Promise((r,s)=>{const i=()=>{const a=t.duration;if(!Number.isFinite(a)||a<=0){s(new Error(`Idle video has invalid duration: ${e}`));return}n=!0,t.currentTime=0,r()};t.addEventListener("loadeddata",i,{once:!0}),t.addEventListener("error",()=>s(new Error(`Failed to load idle video: ${e}`)),{once:!0}),t.src=e,t.load()})},isReady(){return n},getVideo(){return t},setActive(r){n&&(r?t.paused&&t.play().catch(()=>{}):t.paused||t.pause())},restart(){n&&(t.currentTime=0)}}}const zn=50,kt=400;function Qn(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function Jn(e,t){const n=[];for(const r of e){const s=Qn(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-zn),endMs:a.wtime+a.wduration+kt})}return n.sort((r,s)=>r.startMs-s.startMs)}function Yn(e,t,n,r="neutral"){const s=oe(r);if(t.length===0)return s;if(n.length===0||e<n[0].wtime)return oe(t[0]?.emotion,s);const i=Jn(t,n);let a=null;for(const d of i)e>=d.startMs&&e<=d.endMs&&(a=d);if(a)return oe(a.sentence.emotion,s);const c=n[n.length-1],l=c.wtime+c.wduration;return e>l+kt?oe(t[t.length-1]?.emotion,s):s}function At(e,t,n,r,s=ze){const i=new OffscreenCanvas(n,r),a=i.getContext("2d",{willReadFrequently:!0});a.drawImage(e,0,0,n,r);const c=a.getImageData(0,0,n,r),l=a.createImageData(n,r);l.data.set(c.data);const m=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const _ of t){m.clearRect(0,0,n,r),m.drawImage(_,0,0,n,r);const I=m.getImageData(0,0,n,r);for(let o=0;o<l.data.length;o+=4){const x=I.data[o],w=I.data[o+1],u=I.data[o+2];Math.max(x,w,u)>s&&(l.data[o]=x,l.data[o+1]=w,l.data[o+2]=u,l.data[o+3]=255)}}return a.putImageData(l,0,0),i}let ne=null,me=null;const ve=new Map;function Xn(){ne=null,me=null,ve.clear()}en(Xn);function Zn(e){return e??me??void 0}function Qe(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 nt(e,t,n,r){const s=n?await An(e,r):await fetch(e).then(d=>{if(!d.ok)throw new Error(`Failed to load ${e}`);return d.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const a=n?await vn(await Tt(Fn(t,i.path,n),r??"")):await Qe(`${t}/${i.path}`),c=new Map;for(const d of s.cells??[])d.path&&c.set(d.path,d);const l=new Map;for(const d of s.sheets??[])l.set(d.index,d);return{atlas:a,atlasMeta:s,cellByPath:c,sheetByIndex:l,diffBase:t}}async function qe(e){const t=Zn(e),n=ht();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(ne&&(!n||me===(t??null))){const i=await ne;return we(i)}me=t??null,ve.clear();const r=rn();ne=(async()=>{const i=await Qe(tn()),a=await nt(sn(),r,n,t);let c=null;try{c=await nt(on(),r,n,t)}catch{c=null}return{sil:i,viseme:a,expression:c}})();const s=await ne;return we(s)}async function vt(e){if(await qe(e),!ne)throw new Error("Assets not loaded");return ne}function we(e){return Tn(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function er(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 rt(e,t,n){const r=`${t.diffBase}::${n}`,s=ve.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 c=In(t.atlasMeta,a),l=we(e);if(kn(a)){const _=er(t,a),I=document.createElement("canvas");I.width=l.width,I.height=l.height;const o=I.getContext("2d");return o.fillStyle="#000",o.fillRect(0,0,l.width,l.height),o.drawImage(_,c.x,c.y),I}const d=`${t.diffBase}/${n}`,m=await Qe(d);if(m.naturalWidth===l.width&&m.naturalHeight===l.height)return m;throw new Error(`Diff PNG wrong size for ${n}`)})();return ve.set(r,i),i}async function st(e,t,n,r=ze,s,i){if(s){const{width:I,height:o}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const x=document.createElement("canvas");x.width=I,x.height=o;const w=x.getContext("2d");if(w.clearRect(0,0,I,o),w.drawImage(t,0,0,I,o),i&&!i())return;(e.width!==I||e.height!==o)&&(e.width=I,e.height=o);const u=e.getContext("2d");u.clearRect(0,0,I,o),u.drawImage(x,0,0);return}const a=await vt(),{width:c,height:l}=we(a);(e.width!==c||e.height!==l)&&(e.width=c,e.height=l);const d=[],m=e.getContext("2d");if(m.clearRect(0,0,c,l),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const I=a.sil;m.drawImage(I,0,0,c,l);return}if(d.length===0){m.drawImage(t,0,0,c,l);return}const _=At(t,d,c,l,r);m.drawImage(_,0,0)}async function We(e,t,n=ze){const r=await vt(me??void 0),{width:s,height:i}=we(r);(e.width!==s||e.height!==i)&&(e.width=s,e.height=i);const a=[];t.mouthPath&&a.push(await rt(r,r.viseme,t.mouthPath)),t.expressionPath&&r.expression&&a.push(await rt(r,r.expression,t.expressionPath));const c=e.getContext("2d");if(c.clearRect(0,0,s,i),a.length===0){c.drawImage(r.sil,0,0,s,i);return}const l=At(r.sil,a,s,i,n);c.drawImage(l,0,0)}async function tr(e){await We(e,{mouthPath:null,expressionPath:null})}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 rr(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,c=t[r+1].vtime;s===i||c<=a||n.push({from:s,to:i,fromVtime:a,toVtime:c})}return n}function sr(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function ir(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const or=500,ar="__sil__";function cr(){return{lastDrawnKey:""}}function he(e){e.lastDrawnKey=""}function it(e){return e??ar}function ur(e,t){if(e.length===0)return{diffPath:null,label:"sil"};const n=rr(e),r=sr(n,t);if(r){const i=r.toVtime-r.fromVtime,a=ir(r.fromVtime,r.toVtime);if(t>=a.transStart&&t<r.toVtime){const c=Dn(r.from,r.to),l=Cn(c,i);if(l.length>0){const d=Mn(t,a.transStart,r.toVtime,l.length);return{diffPath:l[d]??l[l.length-1],label:`${r.from}→${r.to}`}}return{diffPath:$e(r.to),label:r.to}}}const s=wt(e,t);return s==="sil"?{diffPath:null,label:"sil"}:{diffPath:$e(s),label:s}}function Rt(e,t){const n=t??it(e.expressionPath);return`${it(e.mouthPath)}|${n}`}function lr(e,t,n,r,s,i,a,c){const l=ur(t,n),d={mouthPath:l.diffPath,expressionPath:r},m=Rt(d,s);m!==i.lastDrawnKey&&(c(l.label),a(e,d,m,_=>{_===m&&(i.lastDrawnKey=m)}))}function ot(e,t,n,r,s,i,a=null){const c={mouthPath:null,expressionPath:t},l=a!=null?`|idle@${Math.round(a*1e3)}`:"",d=Rt(c,n)+l;!(a!=null)&&d===r.lastDrawnKey||(i(a!=null?"idle":"sil"),s(e,c,d,_=>{_===d&&(r.lastDrawnKey=d)}))}function bt(e){let t=0,n=null,r=!1,s=!1;const i=async()=>{if(!r){r=!0;try{for(;n;){const c=n;n=null;const l=++t,d=await e(c.diffs,l,c);n||d&&l===t&&c.onDisplayed?.(c.drawKey)}}finally{r=!1,n&&i()}}},a=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(c,l,d){n={diffs:c,drawKey:l,onDisplayed:d},a()},reset(){t+=1,n=null},isLatestSeq(c){return c===t},getLatestSeq(){return t}}}const at=-1,ct=new Map;async function fr(e){let t=ct.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),ct.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function dr(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function hr(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 ut(e,t){let n=0;const r=bt(async(s,i)=>(await qe(),await We(e,s),r.isLatestSeq(i)));return{usesWorker:!1,async loadAssets(s){return await qe(s)},async renderSilOnly(){n+=1,r.reset(),await tr(e)},drawLiveFrame(s,i,a,c){r.enqueue(i,a,c)},async renderViseme(s,i){n+=1;const a=n;t.onStatus?.(i),await We(s,{mouthPath:$e(i),expressionPath:null})},dispose(){n+=1,r.reset()}}}function _r(e,t,n){let r=null,s=1,i=0,a=!1,c=!1;const l=new Map,d=bt(async(w,u,g)=>(l.set(u,{drawKey:g.drawKey,onDisplayed:g.onDisplayed}),await o({type:"drawFrame",diffPath:w.mouthPath,expressionDiffPath:w.expressionPath,liveSeq:u},void 0,!0),!1)),m=w=>{if(w===at){let E=-1,R;for(const[$,y]of l)$>=E&&(E=$,R=y);E>=0&&l.delete(E),R?.onDisplayed?.(R.drawKey);return}const u=-w,g=l.get(u);l.delete(u),g?.onDisplayed?.(g.drawKey)},_=new Map,I=(w,u)=>{c||!r||r.postMessage(w,[])},o=(w,u,g=!1)=>{if(c)return Promise.resolve();const E=s++;return new Promise((R,$)=>{_.set(E,{resolve:y=>R(y),reject:$,generation:typeof w.generation=="number"?w.generation:void 0,expectRenderDone:g}),I({...w,requestId:E})})},x=(async()=>{r=await fr(n),r.onmessage=w=>{if(c)return;const u=w.data;if(u.type==="status"){t.onStatus?.(u.label);return}if(u.type==="frame"){const E=u.generation<0;if(!E&&u.generation!==i){u.bitmap.close();return}if(E&&!(u.generation===at)){const $=-u.generation;if(!d.isLatestSeq($)){u.bitmap.close();return}}if(E&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){u.bitmap.close();return}hr(e,u.bitmap),u.bitmap.close(),E&&m(u.generation);return}const g=_.get(u.requestId);if(g)switch(u.type){case"ready":_.delete(u.requestId),g.resolve();break;case"loadAssetsDone":_.delete(u.requestId),g.resolve({width:u.width,height:u.height});break;case"renderDone":if(g.expectRenderDone&&g.generation!=null&&u.generation!==g.generation)return;_.delete(u.requestId),g.resolve();break;case"renderAborted":_.delete(u.requestId),g.resolve();break;case"error":_.delete(u.requestId),t.onError?.(u.message),g.reject(new Error(u.message));break}},r.onerror=w=>{if(c)return;const u=w.message||"Worker error";t.onError?.(u);for(const[,g]of _)g.reject(new Error(u));_.clear()},await o({type:"init"}),a=!0})();return{usesWorker:!0,async loadAssets(w){if(c)return{width:842,height:1264};if(await x,c)return{width:842,height:1264};if(!a)throw new Error("Worker init failed");return await o({type:"loadAssets",keyHex:w,urls:Zt(se())})??{width:842,height:1264}},async renderSilOnly(){if(c||(await x,c))return;i+=1,d.reset(),l.clear();const w=i;await o({type:"renderSil",generation:w},void 0,!0)},drawLiveFrame(w,u,g,E){c||x.then(()=>{c||d.enqueue(u,g,E)})},async renderViseme(w,u,g={}){if(c||(await x,c))return;i+=1;const E=i;try{await o({type:"renderViseme",generation:E,to:u,from:g.from,transitionDurationMs:g.transitionDurationMs,gapMs:g.gapMs,threshold:g.threshold},void 0,!0)}catch(R){if(R?.name==="AbortError")return;throw R}},dispose(){if(!c){c=!0,i+=1,d.reset(),l.clear();for(const[,w]of _)w.resolve();_.clear(),r?.terminate(),r=null}}}}function mr(e,t={}){if(!dr())return ut(e,t);const n=Lt(t.workerScriptUrl);try{return _r(e,t,n)}catch{return ut(e,t)}}class wr extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Le(e,t,n){return new Promise((r,s)=>{const i=globalThis.setTimeout(()=>{s(new wr(n,t))},t);e.then(a=>{globalThis.clearTimeout(i),r(a)},a=>{globalThis.clearTimeout(i),s(a)})})}const gr={position:"relative",display:"inline-block",lineHeight:0},yr={display:"block",maxWidth:"100%",height:"auto"},pr={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 Ie(e){return Vt(e)?Et:Ge}const Er=p.forwardRef(function({id:t,assets:n,authToken:r,ttsEngineId:s=re,voiceId:i,speakingRate:a=je,className:c,style:l,canvasStyle:d,onStatusChange:m,onDisplayStatus:_,onError:I,onReady:o,showErrorOverlay:x=!0},w){const u=p.useRef(null),g=p.useRef(null),E=p.useRef(cr()),R=p.useRef(Gn()),$=p.useRef(0),y=p.useRef(0),S=p.useRef(null),C=p.useRef(!1),D=p.useRef(null),q=p.useRef(!1),[W,ce]=p.useState("idle"),[ge,X]=p.useState(null),[K,ye]=p.useState(!1),[xe,ue]=p.useState(!1),[ie,pe]=p.useState({width:842,height:1264}),Z=p.useRef(r??null),le=p.useRef(null),h=p.useRef(null),M=p.useRef(!1),B=p.useRef({width:842,height:1264}),P=p.useRef(o),k=p.useRef(_),U=p.useRef(I);P.current=o,k.current=_,U.current=I;const Q=p.useCallback(f=>{const T=f?.ttsEngineId??s??h.current?.ttsEngineId??re,A=f?.voiceId??i??h.current?.voiceId??Ie(T);return{ttsEngineId:T,voiceId:A}},[s,i]),V=p.useCallback(f=>{X(f),U.current?.(f)},[]),L=p.useCallback(f=>{ce(f),m?.(f)},[m]),F=p.useRef(St(L,ke)),O=p.useCallback(()=>{S.current!=null&&(clearTimeout(S.current),S.current=null)},[]),J=p.useCallback(async()=>{const f=y.current,T=g.current;!T||!K||F.current.isSpeaking()||(he(E.current),await T.renderSilOnly(),f===y.current&&(F.current.isSpeaking()||(k.current?.("sil"),q.current&&D.current&&(D.current.restart(),D.current.setActive(!0)))))},[K]),H=p.useCallback(()=>{O();const f=y.current;J(),S.current=setTimeout(()=>{S.current=null,f===y.current&&J()},or)},[O,J]),fe=p.useCallback(async()=>{const f=Math.floor(Date.now()/1e3);if(le.current&&f<le.current.expiresAt-60)return le.current.key;const T=Z.current??await Ue();Z.current=T,F.current.setDeveloperToken(T);const A=await jt(T,ke);return le.current={key:A.value,expiresAt:A.expiresAt},A.value},[]);p.useEffect(()=>{r&&(Z.current=r,F.current.setDeveloperToken(r))},[r]),p.useEffect(()=>{F.current.setTtsEngineId(s),h.current&&(h.current.ttsEngineId=s)},[s]),p.useEffect(()=>{const f=i??Ie(s);h.current&&(h.current.voiceId=f)},[i,s]);const de=p.useMemo(()=>n?JSON.stringify(n):`id:${t??""}`,[n,t]);return p.useEffect(()=>{if(!t&&!n){V("AiTwin requires either `id` or `assets`");return}let f=!1;M.current=!1,ye(!1),ue(!1),X(null),h.current=null,D.current=null,q.current=!1;const T=u.current;if(!T)return;let A=null;return(async()=>{try{let v,b,G;if(n)v=n,b=s,G=i??Ie(b);else{k.current?.("getAiTwin");const N=await Le(dt(t),3e4,"getAiTwin");if(f)return;if(!N.faceId?.trim())throw new Error("getAiTwin returned no faceId");b=N.ttsEngineId,G=i??N.voiceId??Ie(b),v=Yt(N.faceId)}h.current={ttsEngineId:b,voiceId:G},Xt(v),D.current=jn(nn()),A=mr(T,{onStatus:N=>{f||k.current?.(N)},onError:N=>{f||V(N)},shouldAcceptLiveFrame:()=>F.current.isSpeaking()}),g.current=A,k.current?.("auth");const Y=Z.current??r??await Le(Ue(),3e4,"getAuthToken");if(f)return;Z.current=Y,F.current.setDeveloperToken(Y),F.current.setTtsEngineId(b);const Ce=ht()?await fe():void 0;if(f)return;k.current?.("loadAssets");const j=await Le(A.loadAssets(Ce),18e4,"load face assets");if(!f&&j.width>0&&j.height>0&&(B.current=j,pe(j)),f)return;M.current=!0,ye(!0),P.current?.(),A.renderSilOnly().then(()=>{f||k.current?.("sil")}),(async()=>{try{if(await D.current.load(),f)return;q.current=!0,ue(!0),he(E.current),D.current.setActive(!0);const N=D.current.getVideo();await st(T,N,null,void 0,B.current),f||k.current?.("idle")}catch(N){if(f)return;q.current=!1,ue(!1),console.warn("[AiTwin] Idle video unavailable:",N)}})()}catch(v){if(f)return;if(v instanceof Ae){V(v.message);return}V(v instanceof Error?v.message:"Failed to load AI twin")}})(),()=>{f=!0,A?.dispose(),g.current=null}},[de,n,s,i,r,fe,V]),p.useEffect(()=>{W==="done"&&K&&!F.current.isSpeaking()&&H()},[W,K,H]),p.useEffect(()=>{const f=F.current,T={current:!1},A=()=>{const v=u.current,b=g.current;if(!v||!b||!K){$.current=requestAnimationFrame(A);return}const G=f.isSpeaking(),Y=f.getPlaybackElapsedMs(),Ce=G?Yn(Y,f.getSentenceEmotions(),f.getWordQueue(),f.getStreamMood()):f.getStreamMood();if(G){if(q.current&&D.current?.setActive(!1),f.getVisemeQueue().length===0){$.current=requestAnimationFrame(A);return}R.current.setTargetEmotion(Ce),R.current.advance(performance.now());const N=R.current.getExpressionPath(),ee=R.current.getDrawKey();lr(v,f.getVisemeQueue(),Y,N,ee,E.current,(te,Me,Fe,Dt)=>b.drawLiveFrame(te,Me,Fe,Dt),te=>k.current?.(te))}else if(q.current&&D.current){const j=D.current,N=j.getVideo();N.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?(j.setActive(!0),T.current||(T.current=!0,st(v,N,null,void 0,B.current,()=>!f.isSpeaking()).then(()=>k.current?.("idle")).finally(()=>{T.current=!1}))):ot(v,null,"__sil__",E.current,(ee,te,Me,Fe)=>b.drawLiveFrame(ee,te,Me,Fe),ee=>k.current?.(ee))}else ot(v,null,"__sil__",E.current,(j,N,ee,te)=>b.drawLiveFrame(j,N,ee,te),j=>k.current?.(j));C.current&&!G&&(R.current.reset(),D.current?.setActive(!1),H()),C.current=G,$.current=requestAnimationFrame(A)};return $.current=requestAnimationFrame(A),()=>{cancelAnimationFrame($.current),O(),f.stop()}},[K,xe,H,O]),p.useImperativeHandle(w,()=>({speakText:async(f,T)=>{const A=f.trim();if(!A)return;const v=g.current;if(!v||!M.current&&!K)throw new Error("AI twin is not ready");const{ttsEngineId:b,voiceId:G}=Q(T);X(null),y.current+=1,O(),he(E.current),R.current.reset(),C.current=!1;try{q.current?(D.current?.setActive(!1),D.current?.restart(),he(E.current)):await v.renderSilOnly(),await F.current.speak(A,{voiceId:G,speakingRate:T?.speakingRate??a,ttsEngineId:b})}catch(Y){throw V(Y instanceof Error?Y.message:"TTS failed"),Y}},stop:()=>{y.current+=1,O(),F.current.stop(),he(E.current),C.current=!1,H()},setTtsEngineId:f=>{F.current.setTtsEngineId(f),h.current&&(h.current.ttsEngineId=f)},renderViseme:async(f,T)=>{const A=g.current,v=u.current;if(!A||!v||!M.current)throw new Error("AI twin is not ready");await A.renderViseme(v,f,{from:T?.from,transitionDurationMs:T?.transitionDurationMs,gapMs:T?.gapMs,onStatus:b=>k.current?.(b)})},isReady:()=>M.current,getStatus:()=>W}),[K,a,O,H,V,Q,W]),Oe.jsxs("div",{className:c,style:{...gr,...l},children:[Oe.jsx("canvas",{ref:u,width:ie.width,height:ie.height,style:{...yr,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),x&&ge?Oe.jsx("div",{style:pr,children:ge}):null]})});exports.AiTwin=Er;exports.AiTwinNotFoundError=Ae;exports.DEFAULT_TTS_ENGINE_ID=re;exports.OCULUS_VISEME_IDS=_t;exports.SPEAKING_RATE_MAX=pt;exports.SPEAKING_RATE_MIN=yt;exports.TTS_ENGINE_CARTESIA=ae;exports.TTS_ENGINE_GOOGLE=Ke;exports.TTS_ENGINE_INWORLD=Re;exports.VISEME_IDS=Rn;exports.VISEME_TEST_CARTESIA_VOICE_ID=Et;exports.VISEME_TEST_SPEAKING_RATE=je;exports.VISEME_TEST_VOICE_ID=Ge;exports.createAvatarTtsLipsyncController=St;exports.fetchAiTwin=dt;exports.fetchDevAuthToken=Ue;exports.normalizeOculusViseme=mt;exports.resolveVisemeAtTime=wt;exports.resolveWordAtTime=gt;
|
package/dist/aitwin.js
CHANGED
|
@@ -2,39 +2,39 @@ import { jsxs as Tt, jsx as je } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as vt, useRef as B, useState as _e, useCallback as ne, useEffect as oe, useMemo as It, useImperativeHandle as At } from "react";
|
|
3
3
|
const Rt = "https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev", ut = {
|
|
4
4
|
publicBase: Rt
|
|
5
|
-
}, bt = "0.1.
|
|
5
|
+
}, bt = "0.1.6", Dt = {
|
|
6
6
|
version: bt
|
|
7
|
-
}, xt = {},
|
|
7
|
+
}, xt = {}, Re = "https://ai.streamoji.com", Ct = `${ut.publicBase}/custom-faces`, Mt = `${ut.publicBase}/aitwin-workers/v${Dt.version}/visemeDiffPreview.worker.js`;
|
|
8
8
|
function Ft(e) {
|
|
9
9
|
if (e) return e;
|
|
10
10
|
const t = typeof import.meta < "u" ? xt?.VITE_AITWIN_WORKER_URL : void 0;
|
|
11
11
|
return t?.trim() ? t.trim() : Mt;
|
|
12
12
|
}
|
|
13
|
-
const Pt = "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const Pt = "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin", lt = "eng_a7f2b9c1", qe = "eng_d4e8f3a2", pe = "eng_c9b1e6d4", ce = pe, Ot = /* @__PURE__ */ new Set([
|
|
14
|
+
qe,
|
|
15
|
+
pe
|
|
16
16
|
]), ft = {
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[
|
|
17
|
+
[lt]: "oculus_direct",
|
|
18
|
+
[pe]: "oculus_direct",
|
|
19
|
+
[qe]: "inworld_word"
|
|
20
20
|
}, ze = {
|
|
21
|
-
google:
|
|
22
|
-
inworld:
|
|
23
|
-
cartesia:
|
|
21
|
+
google: lt,
|
|
22
|
+
inworld: qe,
|
|
23
|
+
cartesia: pe
|
|
24
24
|
};
|
|
25
25
|
function Lt(e) {
|
|
26
26
|
return ft[e];
|
|
27
27
|
}
|
|
28
28
|
function Ut(e) {
|
|
29
|
-
return e ===
|
|
29
|
+
return e === pe;
|
|
30
30
|
}
|
|
31
31
|
function Bt(e) {
|
|
32
32
|
if (e.ttsEngineId && e.ttsEngineId in ft)
|
|
33
33
|
return e.ttsEngineId;
|
|
34
34
|
const t = e.tts?.toLowerCase();
|
|
35
|
-
return t && t in ze ? ze[t] :
|
|
35
|
+
return t && t in ze ? ze[t] : ce;
|
|
36
36
|
}
|
|
37
|
-
class
|
|
37
|
+
class Le extends Error {
|
|
38
38
|
constructor(t = "AI twin not found") {
|
|
39
39
|
super(t), this.name = "AiTwinNotFoundError";
|
|
40
40
|
}
|
|
@@ -44,12 +44,12 @@ async function Nt(e, t = Pt) {
|
|
|
44
44
|
n.searchParams.set("id", e);
|
|
45
45
|
const r = await fetch(n.toString());
|
|
46
46
|
if (r.status === 404)
|
|
47
|
-
throw new
|
|
47
|
+
throw new Le();
|
|
48
48
|
if (!r.ok)
|
|
49
49
|
throw new Error(`getAiTwin failed (${r.status})`);
|
|
50
50
|
const i = await r.json();
|
|
51
51
|
if (!i.success)
|
|
52
|
-
throw new
|
|
52
|
+
throw new Le(i.error ?? "AI twin not found");
|
|
53
53
|
const { tts: s, ...a } = i.data;
|
|
54
54
|
return {
|
|
55
55
|
...a,
|
|
@@ -77,7 +77,7 @@ async function Qe() {
|
|
|
77
77
|
throw new Error("getAuthToken returned no token");
|
|
78
78
|
return n;
|
|
79
79
|
}
|
|
80
|
-
async function Kt(e, t =
|
|
80
|
+
async function Kt(e, t = Re) {
|
|
81
81
|
const n = await fetch(`${t.replace(/\/$/, "")}/api/session-value`, {
|
|
82
82
|
headers: { Authorization: `Bearer ${e}` }
|
|
83
83
|
});
|
|
@@ -95,7 +95,7 @@ function Gt(e) {
|
|
|
95
95
|
n[r / 2] = Number.parseInt(t.slice(r, r + 2), 16);
|
|
96
96
|
return n;
|
|
97
97
|
}
|
|
98
|
-
function
|
|
98
|
+
function Te(e) {
|
|
99
99
|
return Uint8Array.from(e);
|
|
100
100
|
}
|
|
101
101
|
function jt(e, t) {
|
|
@@ -106,7 +106,7 @@ async function zt(e, t) {
|
|
|
106
106
|
if (!t) throw new Error("Asset key is required for encrypted assets");
|
|
107
107
|
if (e.byteLength < 28)
|
|
108
108
|
throw new Error("Encrypted payload too small");
|
|
109
|
-
const n = new Uint8Array(e), r =
|
|
109
|
+
const n = new Uint8Array(e), r = Te(n.subarray(0, 12)), i = Te(n.subarray(12, 28)), s = Te(n.subarray(28)), a = Te(jt(s, i)), c = await crypto.subtle.importKey(
|
|
110
110
|
"raw",
|
|
111
111
|
Gt(t),
|
|
112
112
|
{ name: "AES-GCM" },
|
|
@@ -119,15 +119,15 @@ async function zt(e, t) {
|
|
|
119
119
|
a
|
|
120
120
|
);
|
|
121
121
|
}
|
|
122
|
-
let
|
|
123
|
-
const
|
|
122
|
+
let Ue = null;
|
|
123
|
+
const Be = /* @__PURE__ */ new Set();
|
|
124
124
|
function Qt(e, t = Ct) {
|
|
125
125
|
const n = `${t.replace(/\/$/, "")}/${e}`;
|
|
126
126
|
return { twinBase: n, binBase: n, encrypted: !0 };
|
|
127
127
|
}
|
|
128
128
|
function Jt(e) {
|
|
129
|
-
|
|
130
|
-
for (const t of
|
|
129
|
+
Ue = e;
|
|
130
|
+
for (const t of Be) t();
|
|
131
131
|
}
|
|
132
132
|
function Yt(e, t) {
|
|
133
133
|
const n = typeof globalThis.location < "u" ? globalThis.location.href : void 0;
|
|
@@ -146,12 +146,12 @@ function Yt(e, t) {
|
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
148
|
function ie() {
|
|
149
|
-
if (!
|
|
149
|
+
if (!Ue)
|
|
150
150
|
throw new Error("Twin assets not configured; call setActiveTwinAssets first");
|
|
151
|
-
return
|
|
151
|
+
return Ue;
|
|
152
152
|
}
|
|
153
153
|
function Xt(e) {
|
|
154
|
-
return
|
|
154
|
+
return Be.add(e), () => Be.delete(e);
|
|
155
155
|
}
|
|
156
156
|
function Zt() {
|
|
157
157
|
return `${ie().twinBase}/sil.png`;
|
|
@@ -237,12 +237,12 @@ function fn(e, t) {
|
|
|
237
237
|
const i = Math.max(0, Math.min(1, (t - e.wtime) / r));
|
|
238
238
|
return Math.min(n - 1, Math.floor(i * n));
|
|
239
239
|
}
|
|
240
|
-
function
|
|
240
|
+
function De(e, t) {
|
|
241
241
|
const n = Math.max(0, Math.min(e.length - 1, t));
|
|
242
242
|
return e[n] ?? "";
|
|
243
243
|
}
|
|
244
244
|
function dn(e, t) {
|
|
245
|
-
const n = e.toLowerCase(), r =
|
|
245
|
+
const n = e.toLowerCase(), r = De(n, t), i = n.slice(Math.max(0, t - 1), t + 2);
|
|
246
246
|
return r === "i" || r === "y" ? "I" : i.includes("ee") || r === "e" || n.includes("ea") ? "E" : "aa";
|
|
247
247
|
}
|
|
248
248
|
function hn(e, t) {
|
|
@@ -251,7 +251,7 @@ function hn(e, t) {
|
|
|
251
251
|
Math.min(n.length, t + 3)
|
|
252
252
|
);
|
|
253
253
|
if (/oo|ou|uw/.test(r)) return "U";
|
|
254
|
-
const i =
|
|
254
|
+
const i = De(n, t);
|
|
255
255
|
return i === "u" || i === "w" ? "U" : "O";
|
|
256
256
|
}
|
|
257
257
|
function _n(e, t) {
|
|
@@ -261,9 +261,9 @@ function _n(e, t) {
|
|
|
261
261
|
Math.max(0, t - 1),
|
|
262
262
|
Math.min(n.length, t + 3)
|
|
263
263
|
);
|
|
264
|
-
return /wo|wh/.test(i) ||
|
|
264
|
+
return /wo|wh/.test(i) || De(n, t) === "o" ? "O" : "U";
|
|
265
265
|
}
|
|
266
|
-
const
|
|
266
|
+
const ve = {
|
|
267
267
|
d: "DD",
|
|
268
268
|
t: "DD",
|
|
269
269
|
n: "DD",
|
|
@@ -276,11 +276,11 @@ const Te = {
|
|
|
276
276
|
j: "CH"
|
|
277
277
|
};
|
|
278
278
|
function mn(e, t) {
|
|
279
|
-
const n = e.toLowerCase(), r =
|
|
280
|
-
if (
|
|
279
|
+
const n = e.toLowerCase(), r = De(n, t);
|
|
280
|
+
if (ve[r]) return ve[r];
|
|
281
281
|
for (let i = 0; i < n.length; i++) {
|
|
282
282
|
const s = n[i];
|
|
283
|
-
if (
|
|
283
|
+
if (ve[s]) return ve[s];
|
|
284
284
|
}
|
|
285
285
|
return "DD";
|
|
286
286
|
}
|
|
@@ -371,7 +371,7 @@ function Ye(e) {
|
|
|
371
371
|
return t;
|
|
372
372
|
}
|
|
373
373
|
const vn = 0.5, In = 1.5, ht = "Olivia", An = "f786b574-daa5-4673-aa0c-cbe3e8534c02", _t = 0.85;
|
|
374
|
-
function Rn(e, t =
|
|
374
|
+
function Rn(e, t = Re) {
|
|
375
375
|
const n = `${t.replace(/\/$/, "")}/avatar_ttsWithPoses`, r = [], i = [], s = [];
|
|
376
376
|
let a = "neutral";
|
|
377
377
|
const c = [], l = [];
|
|
@@ -381,7 +381,7 @@ function Rn(e, t = Ae) {
|
|
|
381
381
|
h.playbackRate.value = A;
|
|
382
382
|
}, q = () => b.forEach((h) => h()), ue = () => {
|
|
383
383
|
p != null && (clearTimeout(p), p = null);
|
|
384
|
-
},
|
|
384
|
+
}, Ee = () => {
|
|
385
385
|
for (const h of l)
|
|
386
386
|
try {
|
|
387
387
|
h.stop();
|
|
@@ -389,10 +389,10 @@ function Rn(e, t = Ae) {
|
|
|
389
389
|
}
|
|
390
390
|
l.length = 0;
|
|
391
391
|
}, X = () => {
|
|
392
|
-
x = !0, ue(),
|
|
392
|
+
x = !0, ue(), Ee(), c.length = 0, m = !1, _ = !1, S = !1, o = !1, r.length = 0, i.length = 0, s.length = 0, a = "neutral", u = 0, g = 0, w = 0, e("idle"), q();
|
|
393
393
|
}, K = () => {
|
|
394
394
|
!o || m || l.length > 0 || c.length > 0 || (_ = !1, ue(), e("done"), q());
|
|
395
|
-
},
|
|
395
|
+
}, ke = () => {
|
|
396
396
|
const h = Ye(r);
|
|
397
397
|
if (h <= 0) {
|
|
398
398
|
e("done"), q();
|
|
@@ -403,7 +403,7 @@ function Rn(e, t = Ae) {
|
|
|
403
403
|
p = setTimeout(() => {
|
|
404
404
|
x || (_ = !1, p = null, e("done"), q());
|
|
405
405
|
}, C);
|
|
406
|
-
},
|
|
406
|
+
}, Ce = (h, C, N) => {
|
|
407
407
|
h.length !== 0 && (N && (u = C), h.forEach((P) => {
|
|
408
408
|
const L = String(P.word ?? "").trim();
|
|
409
409
|
if (!L) return;
|
|
@@ -442,8 +442,8 @@ function Rn(e, t = Ae) {
|
|
|
442
442
|
});
|
|
443
443
|
}), q());
|
|
444
444
|
}, se = (h, C, N, P, T) => {
|
|
445
|
-
|
|
446
|
-
},
|
|
445
|
+
Ce(C, N, P), le(h, N, P, T);
|
|
446
|
+
}, Se = async (h, C, N, P) => {
|
|
447
447
|
if (x || !h?.trim()) {
|
|
448
448
|
(C.length > 0 || N.length > 0) && !S && se(
|
|
449
449
|
C,
|
|
@@ -500,7 +500,7 @@ function Rn(e, t = Ae) {
|
|
|
500
500
|
} finally {
|
|
501
501
|
m = !1;
|
|
502
502
|
const T = c.shift();
|
|
503
|
-
T ? await
|
|
503
|
+
T ? await Se(
|
|
504
504
|
T.audio,
|
|
505
505
|
T.visemes,
|
|
506
506
|
T.words,
|
|
@@ -509,7 +509,7 @@ function Rn(e, t = Ae) {
|
|
|
509
509
|
}
|
|
510
510
|
}, Z = () => {
|
|
511
511
|
if (o = !0, !S && r.length > 0) {
|
|
512
|
-
|
|
512
|
+
ke();
|
|
513
513
|
return;
|
|
514
514
|
}
|
|
515
515
|
K();
|
|
@@ -527,7 +527,7 @@ function Rn(e, t = Ae) {
|
|
|
527
527
|
const N = V.trim();
|
|
528
528
|
if (!N)
|
|
529
529
|
throw new Error("Developer token required for avatar_ttsWithPoses");
|
|
530
|
-
const P = C?.ttsEngineId ?? y ??
|
|
530
|
+
const P = C?.ttsEngineId ?? y ?? ce;
|
|
531
531
|
E = P;
|
|
532
532
|
const T = C?.voiceId ?? ht, L = C?.speakingRate ?? _t, Q = Math.max(
|
|
533
533
|
vn,
|
|
@@ -559,7 +559,7 @@ function Rn(e, t = Ae) {
|
|
|
559
559
|
if (f.event === "audio") {
|
|
560
560
|
const k = f.data.chunk, v = f.data.visemes ?? [], I = f.data.words ?? [], R = f.data.is_new_segment ?? !1;
|
|
561
561
|
if (k)
|
|
562
|
-
await
|
|
562
|
+
await Se(k, v, I, R);
|
|
563
563
|
else if (v.length > 0 || I.length > 0) {
|
|
564
564
|
const G = R && r.length > 0 ? Ye(r) : u;
|
|
565
565
|
se(v, I, G, R, P);
|
|
@@ -682,13 +682,13 @@ const Ke = 15, Rr = [
|
|
|
682
682
|
"RR",
|
|
683
683
|
"kk",
|
|
684
684
|
"nn"
|
|
685
|
-
],
|
|
685
|
+
], Ne = [
|
|
686
686
|
"t01_0.17",
|
|
687
687
|
"t02_0.33",
|
|
688
688
|
"t03_0.50",
|
|
689
689
|
"t04_0.67",
|
|
690
690
|
"t05_0.83"
|
|
691
|
-
], Fn =
|
|
691
|
+
], Fn = Ne.length, Xe = /* @__PURE__ */ new Set([
|
|
692
692
|
"aa__kk",
|
|
693
693
|
"aa__nn",
|
|
694
694
|
"aa__sil",
|
|
@@ -801,21 +801,21 @@ function Ze(e, t) {
|
|
|
801
801
|
function et(e, t) {
|
|
802
802
|
return `pairs/${e}/${t}_minus_sil.png`;
|
|
803
803
|
}
|
|
804
|
-
function
|
|
804
|
+
function $e(e) {
|
|
805
805
|
return `${e}_minus_sil.png`;
|
|
806
806
|
}
|
|
807
807
|
function Pn(e, t) {
|
|
808
808
|
if (e === t) return [];
|
|
809
809
|
const n = [], r = Ze(e, t);
|
|
810
810
|
if (Xe.has(r)) {
|
|
811
|
-
for (const s of
|
|
811
|
+
for (const s of Ne)
|
|
812
812
|
n.push(et(r, s));
|
|
813
813
|
return n;
|
|
814
814
|
}
|
|
815
815
|
const i = Ze(t, e);
|
|
816
816
|
if (Xe.has(i)) {
|
|
817
817
|
for (let s = Fn - 1; s >= 0; s--)
|
|
818
|
-
n.push(et(i,
|
|
818
|
+
n.push(et(i, Ne[s]));
|
|
819
819
|
return n;
|
|
820
820
|
}
|
|
821
821
|
return [];
|
|
@@ -836,7 +836,7 @@ function Bn(e, t, n) {
|
|
|
836
836
|
const r = t.split("/").pop() ?? t, i = r.includes(".") ? r.slice(0, r.lastIndexOf(".")) : r;
|
|
837
837
|
return `${e}/${i}.bin`;
|
|
838
838
|
}
|
|
839
|
-
const Nn = [0.32, 0.24, 0.16, 0.08, 0],
|
|
839
|
+
const Nn = [0.32, 0.24, 0.16, 0.08, 0], xe = Nn.map(
|
|
840
840
|
(e) => `eyes_${e.toFixed(2)}`
|
|
841
841
|
), $n = [
|
|
842
842
|
"eyes_0.32",
|
|
@@ -877,7 +877,7 @@ function ae(e, t = "neutral") {
|
|
|
877
877
|
function z(e) {
|
|
878
878
|
return e === "neutral" ? null : wt(e, "eyes_standard");
|
|
879
879
|
}
|
|
880
|
-
function
|
|
880
|
+
function Ve(e, t) {
|
|
881
881
|
return !t || t === "eyes_standard" ? z(e) : e === "neutral" && t === "eyes_standard" ? null : wt(e, t);
|
|
882
882
|
}
|
|
883
883
|
function Wn(e) {
|
|
@@ -885,17 +885,17 @@ function Wn(e) {
|
|
|
885
885
|
const t = e.match(/\/(eyes_[^/]+)_minus_sil\.png$/);
|
|
886
886
|
if (!t?.[1]) return "open";
|
|
887
887
|
const n = t[1];
|
|
888
|
-
return
|
|
888
|
+
return xe.includes(n) ? n : "open";
|
|
889
889
|
}
|
|
890
890
|
function qn(e) {
|
|
891
|
-
return e === "open" ? -1 :
|
|
891
|
+
return e === "open" ? -1 : xe.indexOf(e);
|
|
892
892
|
}
|
|
893
893
|
function Kn(e, t) {
|
|
894
894
|
const n = [];
|
|
895
895
|
for (const r of t)
|
|
896
|
-
n.push(
|
|
896
|
+
n.push(Ve(e, r));
|
|
897
897
|
for (let r = t.length - 2; r >= 0; r--)
|
|
898
|
-
n.push(
|
|
898
|
+
n.push(Ve(e, t[r]));
|
|
899
899
|
return n.push(z(e)), n;
|
|
900
900
|
}
|
|
901
901
|
function Gn(e, t) {
|
|
@@ -904,7 +904,7 @@ function Gn(e, t) {
|
|
|
904
904
|
if (n < 0) return [z(e)];
|
|
905
905
|
const r = [];
|
|
906
906
|
for (let i = n; i >= 0; i--)
|
|
907
|
-
r.push(
|
|
907
|
+
r.push(Ve(e, xe[i]));
|
|
908
908
|
return r.push(z(e)), r;
|
|
909
909
|
}
|
|
910
910
|
const jn = [
|
|
@@ -927,7 +927,7 @@ function Jn(e, t) {
|
|
|
927
927
|
function we(e, t) {
|
|
928
928
|
return e + Math.random() * (t - e);
|
|
929
929
|
}
|
|
930
|
-
function
|
|
930
|
+
function Ie() {
|
|
931
931
|
return we(14, 32);
|
|
932
932
|
}
|
|
933
933
|
function Yn(e = {}) {
|
|
@@ -956,12 +956,12 @@ function Yn(e = {}) {
|
|
|
956
956
|
}, _ = E, u(z(E), E);
|
|
957
957
|
}
|
|
958
958
|
function p(y, E, x) {
|
|
959
|
-
const b = x ? $n : Math.random() < c ?
|
|
959
|
+
const b = x ? $n : Math.random() < c ? xe : Vn;
|
|
960
960
|
o = {
|
|
961
961
|
kind: "playing",
|
|
962
962
|
paths: Kn(E, b),
|
|
963
963
|
index: 0,
|
|
964
|
-
holdUntil: y +
|
|
964
|
+
holdUntil: y + Ie(),
|
|
965
965
|
after: "idle",
|
|
966
966
|
blinkEmotion: E
|
|
967
967
|
}, _ = E, u(o.paths[0] ?? null, E);
|
|
@@ -976,14 +976,14 @@ function Yn(e = {}) {
|
|
|
976
976
|
kind: "emotionBlend",
|
|
977
977
|
paths: W,
|
|
978
978
|
index: 0,
|
|
979
|
-
holdUntil: y +
|
|
979
|
+
holdUntil: y + Ie(),
|
|
980
980
|
thenEmotion: x
|
|
981
981
|
}, u(W[0] ?? null, E);
|
|
982
982
|
}
|
|
983
983
|
function V(y) {
|
|
984
984
|
if (o.kind === "emotionBlend") {
|
|
985
985
|
for (; y >= o.holdUntil && o.index < o.paths.length - 1; )
|
|
986
|
-
o.index += 1, o.holdUntil = y +
|
|
986
|
+
o.index += 1, o.holdUntil = y + Ie();
|
|
987
987
|
const E = o.paths[o.index] ?? null;
|
|
988
988
|
u(E, o.thenEmotion), y >= o.holdUntil && o.index >= o.paths.length - 1 && (m = o.thenEmotion, _ = o.thenEmotion, u(z(o.thenEmotion), o.thenEmotion), o = {
|
|
989
989
|
kind: "idle",
|
|
@@ -1001,7 +1001,7 @@ function Yn(e = {}) {
|
|
|
1001
1001
|
}
|
|
1002
1002
|
if (o.kind === "playing") {
|
|
1003
1003
|
for (; y >= o.holdUntil && o.index < o.paths.length - 1; )
|
|
1004
|
-
o.index += 1, o.holdUntil = y +
|
|
1004
|
+
o.index += 1, o.holdUntil = y + Ie();
|
|
1005
1005
|
if (u(o.paths[o.index] ?? null, o.blinkEmotion), y >= o.holdUntil && o.index >= o.paths.length - 1) {
|
|
1006
1006
|
if (o.after === "resumeIdle") {
|
|
1007
1007
|
g(y + l, m);
|
|
@@ -1156,9 +1156,9 @@ function yt(e, t, n, r, i = Ke) {
|
|
|
1156
1156
|
return a.putImageData(l, 0, 0), s;
|
|
1157
1157
|
}
|
|
1158
1158
|
let re = null, ge = null;
|
|
1159
|
-
const
|
|
1159
|
+
const be = /* @__PURE__ */ new Map();
|
|
1160
1160
|
function rr() {
|
|
1161
|
-
re = null, ge = null,
|
|
1161
|
+
re = null, ge = null, be.clear();
|
|
1162
1162
|
}
|
|
1163
1163
|
Xt(rr);
|
|
1164
1164
|
function ir(e) {
|
|
@@ -1189,7 +1189,7 @@ async function tt(e, t, n, r) {
|
|
|
1189
1189
|
l.set(d.index, d);
|
|
1190
1190
|
return { atlas: a, atlasMeta: i, cellByPath: c, sheetByIndex: l, diffBase: t };
|
|
1191
1191
|
}
|
|
1192
|
-
async function
|
|
1192
|
+
async function He(e) {
|
|
1193
1193
|
const t = ir(e), n = dt();
|
|
1194
1194
|
if (n && !t)
|
|
1195
1195
|
throw new Error("Encrypted assets enabled but no key provided");
|
|
@@ -1197,7 +1197,7 @@ async function We(e) {
|
|
|
1197
1197
|
const s = await re;
|
|
1198
1198
|
return ye(s);
|
|
1199
1199
|
}
|
|
1200
|
-
ge = t ?? null,
|
|
1200
|
+
ge = t ?? null, be.clear();
|
|
1201
1201
|
const r = tn();
|
|
1202
1202
|
re = (async () => {
|
|
1203
1203
|
const s = await Ge(Zt()), a = await tt(
|
|
@@ -1223,7 +1223,7 @@ async function We(e) {
|
|
|
1223
1223
|
return ye(i);
|
|
1224
1224
|
}
|
|
1225
1225
|
async function pt(e) {
|
|
1226
|
-
if (await
|
|
1226
|
+
if (await He(e), !re) throw new Error("Assets not loaded");
|
|
1227
1227
|
return re;
|
|
1228
1228
|
}
|
|
1229
1229
|
function ye(e) {
|
|
@@ -1238,7 +1238,7 @@ function sr(e, t) {
|
|
|
1238
1238
|
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;
|
|
1239
1239
|
}
|
|
1240
1240
|
async function nt(e, t, n) {
|
|
1241
|
-
const r = `${t.diffBase}::${n}`, i =
|
|
1241
|
+
const r = `${t.diffBase}::${n}`, i = be.get(r);
|
|
1242
1242
|
if (i) return i;
|
|
1243
1243
|
const s = (async () => {
|
|
1244
1244
|
const a = t.cellByPath.get(n);
|
|
@@ -1255,7 +1255,7 @@ async function nt(e, t, n) {
|
|
|
1255
1255
|
return m;
|
|
1256
1256
|
throw new Error(`Diff PNG wrong size for ${n}`);
|
|
1257
1257
|
})();
|
|
1258
|
-
return
|
|
1258
|
+
return be.set(r, s), s;
|
|
1259
1259
|
}
|
|
1260
1260
|
async function rt(e, t, n, r = Ke, i, s) {
|
|
1261
1261
|
if (i) {
|
|
@@ -1286,7 +1286,7 @@ async function rt(e, t, n, r = Ke, i, s) {
|
|
|
1286
1286
|
const _ = yt(t, d, c, l, r);
|
|
1287
1287
|
m.drawImage(_, 0, 0);
|
|
1288
1288
|
}
|
|
1289
|
-
async function
|
|
1289
|
+
async function We(e, t, n = Ke) {
|
|
1290
1290
|
const r = await pt(ge ?? void 0), { width: i, height: s } = ye(r);
|
|
1291
1291
|
(e.width !== i || e.height !== s) && (e.width = i, e.height = s);
|
|
1292
1292
|
const a = [];
|
|
@@ -1308,7 +1308,7 @@ async function qe(e, t, n = Ke) {
|
|
|
1308
1308
|
c.drawImage(l, 0, 0);
|
|
1309
1309
|
}
|
|
1310
1310
|
async function or(e) {
|
|
1311
|
-
await
|
|
1311
|
+
await We(e, { mouthPath: null, expressionPath: null });
|
|
1312
1312
|
}
|
|
1313
1313
|
function ar(e) {
|
|
1314
1314
|
const t = /* @__PURE__ */ new Map();
|
|
@@ -1360,11 +1360,11 @@ function _r(e, t) {
|
|
|
1360
1360
|
);
|
|
1361
1361
|
return { diffPath: l[d] ?? l[l.length - 1], label: `${r.from}→${r.to}` };
|
|
1362
1362
|
}
|
|
1363
|
-
return { diffPath:
|
|
1363
|
+
return { diffPath: $e(r.to), label: r.to };
|
|
1364
1364
|
}
|
|
1365
1365
|
}
|
|
1366
1366
|
const i = Sn(e, t);
|
|
1367
|
-
return i === "sil" ? { diffPath: null, label: "sil" } : { diffPath:
|
|
1367
|
+
return i === "sil" ? { diffPath: null, label: "sil" } : { diffPath: $e(i), label: i };
|
|
1368
1368
|
}
|
|
1369
1369
|
function Et(e, t) {
|
|
1370
1370
|
const n = t ?? it(e.expressionPath);
|
|
@@ -1447,11 +1447,11 @@ function yr(e, t) {
|
|
|
1447
1447
|
}
|
|
1448
1448
|
function ct(e, t) {
|
|
1449
1449
|
let n = 0;
|
|
1450
|
-
const r = kt(async (i, s) => (await
|
|
1450
|
+
const r = kt(async (i, s) => (await He(), await We(e, i), r.isLatestSeq(s)));
|
|
1451
1451
|
return {
|
|
1452
1452
|
usesWorker: !1,
|
|
1453
1453
|
async loadAssets(i) {
|
|
1454
|
-
return await
|
|
1454
|
+
return await He(i);
|
|
1455
1455
|
},
|
|
1456
1456
|
async renderSilOnly() {
|
|
1457
1457
|
n += 1, r.reset(), await or(e);
|
|
@@ -1462,8 +1462,8 @@ function ct(e, t) {
|
|
|
1462
1462
|
async renderViseme(i, s) {
|
|
1463
1463
|
n += 1;
|
|
1464
1464
|
const a = n;
|
|
1465
|
-
t.onStatus?.(s), await
|
|
1466
|
-
mouthPath:
|
|
1465
|
+
t.onStatus?.(s), await We(i, {
|
|
1466
|
+
mouthPath: $e(s),
|
|
1467
1467
|
expressionPath: null
|
|
1468
1468
|
});
|
|
1469
1469
|
},
|
|
@@ -1642,7 +1642,7 @@ class kr extends Error {
|
|
|
1642
1642
|
super(`${t} timed out after ${Math.round(n / 1e3)}s`), this.name = "LoadTimeoutError";
|
|
1643
1643
|
}
|
|
1644
1644
|
}
|
|
1645
|
-
function
|
|
1645
|
+
function Oe(e, t, n) {
|
|
1646
1646
|
return new Promise((r, i) => {
|
|
1647
1647
|
const s = globalThis.setTimeout(() => {
|
|
1648
1648
|
i(new kr(n, t));
|
|
@@ -1677,7 +1677,7 @@ const Sr = {
|
|
|
1677
1677
|
fontSize: "0.875rem",
|
|
1678
1678
|
textAlign: "center"
|
|
1679
1679
|
};
|
|
1680
|
-
function
|
|
1680
|
+
function Ae(e) {
|
|
1681
1681
|
return Ut(e) ? An : ht;
|
|
1682
1682
|
}
|
|
1683
1683
|
const br = vt(function({
|
|
@@ -1698,11 +1698,11 @@ const br = vt(function({
|
|
|
1698
1698
|
}, w) {
|
|
1699
1699
|
const u = B(null), g = B(null), p = B(hr()), A = B(Yn()), V = B(0), y = B(0), E = B(null), x = B(!1), b = B(
|
|
1700
1700
|
null
|
|
1701
|
-
), W = B(!1), [q, ue] = _e("idle"), [
|
|
1701
|
+
), W = B(!1), [q, ue] = _e("idle"), [Ee, X] = _e(null), [K, ke] = _e(!1), [Ce, le] = _e(!1), [se, Se] = _e({ width: 842, height: 1264 }), Z = B(r ?? null), fe = B(null), h = B(null), C = B(!1), N = B({ width: 842, height: 1264 }), P = B(o), T = B(_), L = B(S);
|
|
1702
1702
|
P.current = o, T.current = _, L.current = S;
|
|
1703
1703
|
const Q = ne(
|
|
1704
1704
|
(f) => {
|
|
1705
|
-
const k = f?.ttsEngineId ?? i ?? h.current?.ttsEngineId ?? ce, v = f?.voiceId ?? s ?? h.current?.voiceId ??
|
|
1705
|
+
const k = f?.ttsEngineId ?? i ?? h.current?.ttsEngineId ?? ce, v = f?.voiceId ?? s ?? h.current?.voiceId ?? Ae(k);
|
|
1706
1706
|
return { ttsEngineId: k, voiceId: v };
|
|
1707
1707
|
},
|
|
1708
1708
|
[i, s]
|
|
@@ -1714,7 +1714,7 @@ const br = vt(function({
|
|
|
1714
1714
|
},
|
|
1715
1715
|
[m]
|
|
1716
1716
|
), M = B(
|
|
1717
|
-
Rn(O,
|
|
1717
|
+
Rn(O, Re)
|
|
1718
1718
|
), F = ne(() => {
|
|
1719
1719
|
E.current != null && (clearTimeout(E.current), E.current = null);
|
|
1720
1720
|
}, []), J = ne(async () => {
|
|
@@ -1732,7 +1732,7 @@ const br = vt(function({
|
|
|
1732
1732
|
return fe.current.key;
|
|
1733
1733
|
const k = Z.current ?? await Qe();
|
|
1734
1734
|
Z.current = k, M.current.setDeveloperToken(k);
|
|
1735
|
-
const v = await Kt(k,
|
|
1735
|
+
const v = await Kt(k, Re);
|
|
1736
1736
|
return fe.current = {
|
|
1737
1737
|
key: v.value,
|
|
1738
1738
|
expiresAt: v.expiresAt
|
|
@@ -1743,7 +1743,7 @@ const br = vt(function({
|
|
|
1743
1743
|
}, [r]), oe(() => {
|
|
1744
1744
|
M.current.setTtsEngineId(i), h.current && (h.current.ttsEngineId = i);
|
|
1745
1745
|
}, [i]), oe(() => {
|
|
1746
|
-
const f = s ??
|
|
1746
|
+
const f = s ?? Ae(i);
|
|
1747
1747
|
h.current && (h.current.voiceId = f);
|
|
1748
1748
|
}, [s, i]);
|
|
1749
1749
|
const he = It(
|
|
@@ -1756,7 +1756,7 @@ const br = vt(function({
|
|
|
1756
1756
|
return;
|
|
1757
1757
|
}
|
|
1758
1758
|
let f = !1;
|
|
1759
|
-
C.current = !1,
|
|
1759
|
+
C.current = !1, ke(!1), le(!1), X(null), h.current = null, b.current = null, W.current = !1;
|
|
1760
1760
|
const k = u.current;
|
|
1761
1761
|
if (!k) return;
|
|
1762
1762
|
let v = null;
|
|
@@ -1764,10 +1764,10 @@ const br = vt(function({
|
|
|
1764
1764
|
try {
|
|
1765
1765
|
let I, R, G;
|
|
1766
1766
|
if (n)
|
|
1767
|
-
I = n, R = i, G = s ??
|
|
1767
|
+
I = n, R = i, G = s ?? Ae(R);
|
|
1768
1768
|
else {
|
|
1769
1769
|
T.current?.("getAiTwin");
|
|
1770
|
-
const U = await
|
|
1770
|
+
const U = await Oe(
|
|
1771
1771
|
Nt(t),
|
|
1772
1772
|
3e4,
|
|
1773
1773
|
"getAiTwin"
|
|
@@ -1775,7 +1775,7 @@ const br = vt(function({
|
|
|
1775
1775
|
if (f) return;
|
|
1776
1776
|
if (!U.faceId?.trim())
|
|
1777
1777
|
throw new Error("getAiTwin returned no faceId");
|
|
1778
|
-
R = U.ttsEngineId, G = s ?? U.voiceId ??
|
|
1778
|
+
R = U.ttsEngineId, G = s ?? U.voiceId ?? Ae(R), I = Qt(U.faceId);
|
|
1779
1779
|
}
|
|
1780
1780
|
h.current = { ttsEngineId: R, voiceId: G }, Jt(I), b.current = Xn(en()), v = Er(k, {
|
|
1781
1781
|
onStatus: (U) => {
|
|
@@ -1786,19 +1786,19 @@ const br = vt(function({
|
|
|
1786
1786
|
},
|
|
1787
1787
|
shouldAcceptLiveFrame: () => M.current.isSpeaking()
|
|
1788
1788
|
}), g.current = v, T.current?.("auth");
|
|
1789
|
-
const Y = Z.current ?? r ?? await
|
|
1789
|
+
const Y = Z.current ?? r ?? await Oe(Qe(), 3e4, "getAuthToken");
|
|
1790
1790
|
if (f) return;
|
|
1791
1791
|
Z.current = Y, M.current.setDeveloperToken(Y), M.current.setTtsEngineId(R);
|
|
1792
|
-
const
|
|
1792
|
+
const Me = dt() ? await de() : void 0;
|
|
1793
1793
|
if (f) return;
|
|
1794
1794
|
T.current?.("loadAssets");
|
|
1795
|
-
const j = await
|
|
1796
|
-
v.loadAssets(
|
|
1795
|
+
const j = await Oe(
|
|
1796
|
+
v.loadAssets(Me),
|
|
1797
1797
|
18e4,
|
|
1798
1798
|
"load face assets"
|
|
1799
1799
|
);
|
|
1800
|
-
if (!f && j.width > 0 && j.height > 0 && (N.current = j,
|
|
1801
|
-
C.current = !0,
|
|
1800
|
+
if (!f && j.width > 0 && j.height > 0 && (N.current = j, Se(j)), f) return;
|
|
1801
|
+
C.current = !0, ke(!0), P.current?.(), v.renderSilOnly().then(() => {
|
|
1802
1802
|
f || T.current?.("sil");
|
|
1803
1803
|
}), (async () => {
|
|
1804
1804
|
try {
|
|
@@ -1819,7 +1819,7 @@ const br = vt(function({
|
|
|
1819
1819
|
})();
|
|
1820
1820
|
} catch (I) {
|
|
1821
1821
|
if (f) return;
|
|
1822
|
-
if (I instanceof
|
|
1822
|
+
if (I instanceof Le) {
|
|
1823
1823
|
$(I.message);
|
|
1824
1824
|
return;
|
|
1825
1825
|
}
|
|
@@ -1837,7 +1837,7 @@ const br = vt(function({
|
|
|
1837
1837
|
V.current = requestAnimationFrame(v);
|
|
1838
1838
|
return;
|
|
1839
1839
|
}
|
|
1840
|
-
const G = f.isSpeaking(), Y = f.getPlaybackElapsedMs(),
|
|
1840
|
+
const G = f.isSpeaking(), Y = f.getPlaybackElapsedMs(), Me = G ? nr(
|
|
1841
1841
|
Y,
|
|
1842
1842
|
f.getSentenceEmotions(),
|
|
1843
1843
|
f.getWordQueue(),
|
|
@@ -1848,7 +1848,7 @@ const br = vt(function({
|
|
|
1848
1848
|
V.current = requestAnimationFrame(v);
|
|
1849
1849
|
return;
|
|
1850
1850
|
}
|
|
1851
|
-
A.current.setTargetEmotion(
|
|
1851
|
+
A.current.setTargetEmotion(Me), A.current.advance(performance.now());
|
|
1852
1852
|
const U = A.current.getExpressionPath(), ee = A.current.getDrawKey();
|
|
1853
1853
|
mr(
|
|
1854
1854
|
I,
|
|
@@ -1857,7 +1857,7 @@ const br = vt(function({
|
|
|
1857
1857
|
U,
|
|
1858
1858
|
ee,
|
|
1859
1859
|
p.current,
|
|
1860
|
-
(te,
|
|
1860
|
+
(te, Fe, Pe, St) => R.drawLiveFrame(te, Fe, Pe, St),
|
|
1861
1861
|
(te) => T.current?.(te)
|
|
1862
1862
|
);
|
|
1863
1863
|
} else if (W.current && b.current) {
|
|
@@ -1876,7 +1876,7 @@ const br = vt(function({
|
|
|
1876
1876
|
null,
|
|
1877
1877
|
"__sil__",
|
|
1878
1878
|
p.current,
|
|
1879
|
-
(ee, te,
|
|
1879
|
+
(ee, te, Fe, Pe) => R.drawLiveFrame(ee, te, Fe, Pe),
|
|
1880
1880
|
(ee) => T.current?.(ee)
|
|
1881
1881
|
);
|
|
1882
1882
|
} else
|
|
@@ -1893,7 +1893,7 @@ const br = vt(function({
|
|
|
1893
1893
|
return V.current = requestAnimationFrame(v), () => {
|
|
1894
1894
|
cancelAnimationFrame(V.current), F(), f.stop();
|
|
1895
1895
|
};
|
|
1896
|
-
}, [K,
|
|
1896
|
+
}, [K, Ce, H, F]), At(
|
|
1897
1897
|
w,
|
|
1898
1898
|
() => ({
|
|
1899
1899
|
speakText: async (f, k) => {
|
|
@@ -1954,19 +1954,19 @@ const br = vt(function({
|
|
|
1954
1954
|
"aria-label": t ? `AI twin ${t}` : "AI twin face"
|
|
1955
1955
|
}
|
|
1956
1956
|
),
|
|
1957
|
-
D &&
|
|
1957
|
+
D && Ee ? /* @__PURE__ */ je("div", { style: vr, children: Ee }) : null
|
|
1958
1958
|
] });
|
|
1959
1959
|
});
|
|
1960
1960
|
export {
|
|
1961
1961
|
br as AiTwin,
|
|
1962
|
-
|
|
1963
|
-
|
|
1962
|
+
Le as AiTwinNotFoundError,
|
|
1963
|
+
ce as DEFAULT_TTS_ENGINE_ID,
|
|
1964
1964
|
on as OCULUS_VISEME_IDS,
|
|
1965
1965
|
In as SPEAKING_RATE_MAX,
|
|
1966
1966
|
vn as SPEAKING_RATE_MIN,
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1967
|
+
pe as TTS_ENGINE_CARTESIA,
|
|
1968
|
+
lt as TTS_ENGINE_GOOGLE,
|
|
1969
|
+
qe as TTS_ENGINE_INWORLD,
|
|
1970
1970
|
Rr as VISEME_IDS,
|
|
1971
1971
|
An as VISEME_TEST_CARTESIA_VOICE_ID,
|
|
1972
1972
|
_t as VISEME_TEST_SPEAKING_RATE,
|