@streamoji/aitwin 0.7.3 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aitwin.cjs +1 -1
- package/dist/aitwin.js +1 -1
- package/package.json +1 -1
package/dist/aitwin.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),m=require("react"),ys=require("@pipecat-ai/client-js"),Zn=require("@pipecat-ai/websocket-transport"),ve=require("pixi.js");var Bn=typeof document<"u"?document.currentScript:null;const vs="https://aitwin.bubu.social",mi={publicBase:vs},_s="0.7.3",bs={version:_s},Ss={},Bt="https://ai.aitwin.me",er=`${mi.publicBase}/custom-faces`,Ts=`${mi.publicBase}/aitwin-workers/v${bs.version}/visemeDiffPreview.worker.js`;function ks(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Bn&&Bn.tagName.toUpperCase()==="SCRIPT"&&Bn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Ss?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Ts}const xs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Fn=3e3,Wt=16,Br=3e3,Es=4e3,Is=.85,As=8,tr=400,nr="eng_a7f2b9c1",pn="eng_d4e8f3a2",ut="eng_c9b1e6d4",dt="visemetts",gt=ut,wn="eve",jn=new Set([pn,ut,dt]),rr={[nr]:"oculus_direct",[ut]:"oculus_direct",[dt]:"oculus_direct",[pn]:"inworld_word"},zn={google:nr,inworld:pn,cartesia:ut,visemetts:dt};function Ms(e){const t=e.trim();if(t)return t in rr?t:zn[t.toLowerCase()]}function hi(e){const t=e?.trim();if(!t)return{};const n=t.indexOf(":");if(n<=0)return{voiceId:t};const r=Ms(t.slice(0,n));if(!r)return{voiceId:t};const i=t.slice(n+1).trim();return{ttsEngineId:r,voiceId:i||void 0}}function lt(e,t){const n=hi(t);return{ttsEngineId:n.ttsEngineId??e,voiceId:n.voiceId}}function pi(e){return rr[e]}function wi(e){return e===ut}function gi(e){return e===dt}function Rs(e){if(e.ttsEngineId&&e.ttsEngineId in rr)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in zn?zn[t]:gt}class cn extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}function ir(e,...t){const n=typeof e=="string"?e:e?.brainId?.trim()||e?.knowledgeContextId?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}function sr(e,...t){const n=typeof e=="string"?e:e?.brainUrl?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}function Ps(e){const t=(e??"").trim();if(!t)return;let n;try{n=new URL(t)}catch{throw new Error("brainUrl must be an http or https URL")}if(n.protocol!=="http:"&&n.protocol!=="https:")throw new Error("brainUrl must be an http or https URL");if(!n.host)throw new Error("brainUrl must be an http or https URL");if(n.hash)throw new Error("brainUrl must not include a fragment");return t}async function yi(e,t=xs){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new cn;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new cn(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,u=String(a.authToken??o??"").trim()||void 0,d=ir(a),l=sr(a);return{...a,ttsEngineId:Rs(i.data),authToken:u,brainId:d,knowledgeContextId:d,brainUrl:l}}const ar="thumbnail.webp";function vi(e,t=er){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${ar}`}function Fr(e){const t=e?.trim();if(!t)return null;try{return vi(t)}catch{return null}}function Cs(e){if(!e)return null;const t=(e.binBase||e.twinBase).trim().replace(/\/$/,"");return t?`${t}/${ar}`:null}const Ds="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Bs="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Fs="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Ls="6TNvp3SCs4Og0a1ijm9TommXLql1",Ns="Swaraj Mali";async function on(){const e=await fetch(Ds,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Bs,"Client-Secret":Fs},body:JSON.stringify({userId:Ls,userName:Ns})});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 Os(e,t=Bt){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 Us(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 tn(e){return Uint8Array.from(e)}function Vs(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Ws(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=tn(n.subarray(0,12)),i=tn(n.subarray(12,28)),s=tn(n.subarray(28)),o=tn(Vs(s,i)),a=await crypto.subtle.importKey("raw",Us(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let Hn=null;const $n=new Set;function nn(e){return e.includes("/custom-faces/")}function ln(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||nn(t)||nn(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=nn(t)?t:nn(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function _t(e){return ln(e).encrypted}function Kn(e,t=er){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function _i(e,t){return(e??t)?.trim()||void 0}function bi(e){Hn=ln(e);for(const t of $n)t()}function js(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return ln(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return ln({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function bt(){if(!Hn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Hn}function Si(e){return $n.add(e),()=>$n.delete(e)}function un(){const e=bt();return _t(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function zs(){const e=bt();return _t(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Ti(){const e=bt();return _t(e)?e.binBase:e.twinBase}function $t(){return _t(bt())}function ki(){const e=bt();return _t(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function xi(){const e=bt();return _t(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}const yt=[{code:"en",label:"English",visemetts:!0,cartesia:!0},{code:"es",label:"Spanish",visemetts:!0,cartesia:!0},{code:"es-MX",label:"Spanish (Mexico)",visemetts:!0,cartesia:!0},{code:"es-ES",label:"Spanish (Spain)",visemetts:!0,cartesia:!0},{code:"pt",label:"Portuguese",visemetts:!0,cartesia:!0},{code:"pt-BR",label:"Portuguese (Brazil)",visemetts:!0,cartesia:!0},{code:"pt-PT",label:"Portuguese (Portugal)",visemetts:!0,cartesia:!0},{code:"fr",label:"French",visemetts:!0,cartesia:!0},{code:"de",label:"German",visemetts:!0,cartesia:!0},{code:"it",label:"Italian",visemetts:!0,cartesia:!0},{code:"zh",label:"Chinese",visemetts:!0,cartesia:!0},{code:"ja",label:"Japanese",visemetts:!0,cartesia:!0},{code:"hi",label:"Hindi",visemetts:!0,cartesia:!0},{code:"ko",label:"Korean",visemetts:!0,cartesia:!0},{code:"ru",label:"Russian",visemetts:!0,cartesia:!0},{code:"tr",label:"Turkish",visemetts:!0,cartesia:!0},{code:"id",label:"Indonesian",visemetts:!0,cartesia:!0},{code:"ar",label:"Arabic",visemetts:!0,cartesia:!0},{code:"ar-EG",label:"Arabic (Egypt)",visemetts:!0,cartesia:!0},{code:"ar-AE",label:"Arabic (UAE)",visemetts:!0,cartesia:!0},{code:"vi",label:"Vietnamese",visemetts:!0,cartesia:!0},{code:"bn",label:"Bengali",visemetts:!0,cartesia:!0},{code:"auto",label:"Auto-detect",visemetts:!0,cartesia:!1},{code:"nl",label:"Dutch",visemetts:!1,cartesia:!0},{code:"pl",label:"Polish",visemetts:!1,cartesia:!0},{code:"sv",label:"Swedish",visemetts:!1,cartesia:!0},{code:"tl",label:"Tagalog",visemetts:!1,cartesia:!0},{code:"bg",label:"Bulgarian",visemetts:!1,cartesia:!0},{code:"ro",label:"Romanian",visemetts:!1,cartesia:!0},{code:"cs",label:"Czech",visemetts:!1,cartesia:!0},{code:"el",label:"Greek",visemetts:!1,cartesia:!0},{code:"fi",label:"Finnish",visemetts:!1,cartesia:!0},{code:"hr",label:"Croatian",visemetts:!1,cartesia:!0},{code:"ms",label:"Malay",visemetts:!1,cartesia:!0},{code:"sk",label:"Slovak",visemetts:!1,cartesia:!0},{code:"da",label:"Danish",visemetts:!1,cartesia:!0},{code:"ta",label:"Tamil",visemetts:!1,cartesia:!0},{code:"uk",label:"Ukrainian",visemetts:!1,cartesia:!0},{code:"hu",label:"Hungarian",visemetts:!1,cartesia:!0},{code:"no",label:"Norwegian",visemetts:!1,cartesia:!0},{code:"th",label:"Thai",visemetts:!1,cartesia:!0},{code:"he",label:"Hebrew",visemetts:!1,cartesia:!0},{code:"ka",label:"Georgian",visemetts:!1,cartesia:!0},{code:"te",label:"Telugu",visemetts:!1,cartesia:!0},{code:"gu",label:"Gujarati",visemetts:!1,cartesia:!0},{code:"kn",label:"Kannada",visemetts:!1,cartesia:!0},{code:"ml",label:"Malayalam",visemetts:!1,cartesia:!0},{code:"mr",label:"Marathi",visemetts:!1,cartesia:!0},{code:"pa",label:"Punjabi",visemetts:!1,cartesia:!0}],Ei=yt.map(e=>e.code),Hs=new Set(Ei),$s=new Set(yt.filter(e=>e.visemetts).map(e=>e.code)),Ks=new Set(yt.filter(e=>e.cartesia).map(e=>e.code)),Gs="en";function Ii(e){return Hs.has(e)}function gn(e){const t=e?.trim();if(t)return t}function qs(e){return e===dt?yt.filter(t=>t.visemetts).map(t=>t.code):e===ut?yt.filter(t=>t.cartesia).map(t=>t.code):yt.filter(t=>t.visemetts&&t.cartesia).map(t=>t.code)}function Ys(e,t){const n=t.trim();return n?e===dt?$s.has(n):e===ut?Ks.has(n):Ii(n):!1}function Ai(e){const t=e.split(/\r?\n/);let n="",r="";for(const s of t)s.startsWith("event:")?n=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());if(!n)return null;let i={};if(r)try{i=JSON.parse(r)}catch{i={raw:r}}return{event:n,data:i}}const Mi=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],Qs=new Map(Mi.map(e=>[e.toLowerCase(),e]));function yn(e){const t=(e??"").trim();return t?Qs.get(t.toLowerCase())??"sil":"sil"}const Xs={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 Js(e){if(!e)return["sil"];const t=e.toLowerCase();return Xs[t]??["sil"]}function Ri(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const i=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(i*n))}function Rt(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function vn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||Rt(n,t)!=="w"||t>0&&Rt(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function Zs(e,t){const n=e.toLowerCase(),r=Rt(n,t),i=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":i.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function ea(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";if(vn(n,t))return"FF";const i=Rt(n,t);return i==="u"||i==="w"?"U":"O"}function ta(e,t){const n=e.toLowerCase();if(vn(n,t))return"FF";const r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const i=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(i)||Rt(n,t)==="o"?"O":"U"}const rn={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function na(e,t){const n=e.toLowerCase(),r=Rt(n,t);if(rn[r])return rn[r];for(let i=0;i<n.length;i++){const s=n[i];if(rn[s])return rn[s]}return"DD"}function Pi(e,t,n){const r=Js(e);if(r.length===1)return r[0];const i=t.trim();if(!i)return r[0];const s=(e??"").toLowerCase(),o=Math.max(0,n);switch(s){case"aei":return Zs(i,o);case"o":return ea(i,o);case"qw":return ta(i,o);case"cdgknstxyz":return na(i,o);default:return r[0]}}const or=16,Gn=47,Ci=new Set(["aa","E","I"]),Di=new Set(["DD","SS","kk","CH"]),ra=[Ci,Di];function ia(e){for(const t of ra)if(t.has(e))return t;return null}function sa(e){return ia(e)!=null}function Bi(e,t=or){return t<=0?e:Math.round(e/t)*t}function cr(e,t=or){return e.map(n=>({...n,vtime:Bi(n.vtime,t)}))}function Fi(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 lr(e){if(e.length<=2)return[...e];const t=[e[0]];for(let n=1;n<e.length-1;n++){const r=e[n],i=e[n+1],s=t[t.length-1];if(!sa(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<Gn||a<Gn||t.push(r)}return t.push(e[e.length-1]),t}function _n(e){return lr(Fi(cr(e)))}function Li(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function bn(e){const t=Fi(cr(e)),n=lr(t),r=new Set(n.map(s=>s.vtime)),i=[];for(const s of t)r.has(s.vtime)||i.push({viseme:s.viseme,vtime:s.vtime});return i}function aa(e){return bn(e).map(t=>t.viseme)}const oa=32,Lr=48;function Ni(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function Oi(e){let t=null,n=-1;for(const r of e){if(r.viseme==="sil")continue;const i=r.vtime+r.vduration;i>n&&(t=r,n=i)}return t}function ca(e){return _n(e).find(n=>n.viseme!=="sil")??null}function pt(e){const t=Ni(e);return Oi(e)?t+tr:t}function la(e){const t=[],n=ca(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=Oi(e),i=Ni(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+tr}),t}function Ui(e){const t=_n(e),n=[];for(let r=0;r<t.length-1;r++){const i=t[r].viseme,s=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;i===s||a<=o||n.push({from:i,to:s,fromVtime:o,toVtime:a})}return n}function Vi(e){return e.length===0?[]:[...la(e),...Ui(e)]}function ua(e,t,n=!1){let r=null;for(const i of e){const{transStart:s,transEnd:o}=Wi(i.fromVtime,i.toVtime,i.from,i.to,n);t>=s&&t<o&&(r=i)}return r}function Wi(e,t,n,r,i=!1){const s=Math.max(0,t-e);if(i&&(n==="PP"||r==="PP")&&s>Lr){const l=Lr,c=t,f=c-l;return{gapMs:s,effectiveGapMs:l,holdEnd:f,transStart:f,transEnd:c}}const a=s>0?Math.max(s,oa):0,u=e,d=e+a;return{gapMs:s,effectiveGapMs:a,holdEnd:e,transStart:u,transEnd:d}}function ji(e,t,n,r,i,s){r.forEach(o=>{const u=String(o.word??"").trim();if(!u)return;const d=Math.round((o.start??0)*1e3),l=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:u,wtime:i+d,wduration:l,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),n.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const u=Math.round((o.start??0)*1e3),d=Math.max(1,Math.round((o.duration??0)*1e3)),l=i+u,c=$i(t,l),f=c?Ri(c,l):0;let g;pi(s)==="oculus_direct"?(g=yn(a),g==="U"&&c&&vn(c.word,f)&&(g="FF")):g=Pi(a,c?.word??"",f),e.push({viseme:g,weight:1,vtime:l,vduration:d})})}function zi(e,t){let n=t;for(const r of e){const i=Math.round((r.start??0)*1e3),s=Math.max(1,Math.round((r.duration??0)*1e3));n=Math.max(n,t+i+s)}return n}const ur=16e3;function Hi(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:ur}function da(e){let t=e.trim();const n=t.indexOf(",");t.startsWith("data:")&&n>=0&&(t=t.slice(n+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const r=t.length%4;return r!==0&&(t+="=".repeat(4-r)),t}function fa(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Nr(e,t,n=ur){const r=t.byteOffset%2===0?t:t.slice(),i=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),s=new Float32Array(i.length);for(let a=0;a<i.length;a++)s[a]=i[a]>=32768?-(65536-i[a])/32768:i[a]/32767;const o=e.createBuffer(1,s.length,n);return o.copyToChannel(s,0),o}function ma(e){const t=da(e),n=window.atob(t),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return r}async function Or(e,t,n=ur){const r=ma(t),i=Hi(n);if(fa(r)){const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(s)}if(r.length>=2&&r.length%2===0)return Nr(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return Nr(e,r,i)}}function $i(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Ki(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,u=!1,d=0,l=0,c=0,f=null,g=1,T=t,h=!1,x=null,W=null,N=!1,v=0,k=!1,O=!1,F=0,ie=null,re=null,C=null;const G=()=>({visemes:[],words:[],segmentOffsetMs:0}),Q=()=>{O=!1,F=0},te=()=>{f!=null&&(clearTimeout(f),f=null)},le=()=>{for(const b of r){try{b.onended=null,b.stop(0)}catch{}try{b.disconnect()}catch{}}r.length=0},ae=()=>{for(const b of r)b.playbackRate.value=g},oe=()=>{if(!(h||!u||s||O||r.length>0||n.length>0)){if(a&&i&&l>0){const b=(i.currentTime-l)*1e3;if(b<v){te();const U=g>0?(v-b)/g:v-b;f=setTimeout(()=>{h||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,U));return}}o=!1,te(),e.onSpeakingDone(),e.onNotify()}},ge=b=>{const U=pt(b);if(U<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,d=performance.now(),e.onSpeakingStart(),e.onNotify(),te();const Y=g>0?U/g:U;f=setTimeout(()=>{h||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},Y)},ce=(b,U,Y,_)=>{U.length!==0&&(c=Y,U.forEach(w=>{const P=String(w.word??"").trim();if(!P)return;const V=Math.round((w.start??0)*1e3),K=w.duration!=null?Math.round(w.duration*1e3):w.end!=null?Math.max(1,Math.round((w.end-(w.start??0))*1e3)):0;b.push({word:P,wtime:c+V,wduration:K,queueIndex:b.length,gesture:w.gesture??null,emphasis:w.emphasis===!0})}))},j=(b,U,Y,_,w,S)=>{Y.length!==0&&(c=_,Y.forEach(P=>{const V=String(P.symbol??P.viseme??"").trim();if(!V)return;const K=Math.round((P.start??0)*1e3),ue=Math.max(1,Math.round((P.duration??0)*1e3)),me=c+K,ee=$i(U,me),R=ee?Ri(ee,me):0;let we;pi(S)==="oculus_direct"?(we=yn(V),we==="U"&&ee&&vn(ee.word,R)&&(we="FF")):we=Pi(V,ee?.word??"",R),b.push({viseme:we,weight:1,vtime:me,vduration:ue})}),e.onNotify())},I=(b,U,Y,_,w,S,P)=>{ce(U,_,w),j(b,U,Y,w,S,P)},q=(b,U,Y)=>{C===b&&b.visemes===U||(U.length=0,Y.length=0,b.visemes=U,b.words=Y,b.segmentOffsetMs=0,C=b,c=0,v=0)},D=b=>(W||(W=b.createGain(),W.gain.value=N?0:1,W.connect(b.destination)),W),z=async()=>{const b=window.AudioContext||window.webkitAudioContext;return i||(i=new b,W=null,x=null),i.state==="suspended"&&await i.resume(),D(i),x||(x=i.createMediaStreamDestination()),i},X=(b,U)=>{if(!i)return 0;const Y=i,_=Y.currentTime,w=_+.02;if(U.isFirstAudio){l<=0&&(l=w);const P=(w-_)*1e3;d=performance.now()+P}U.onBeforeStart?.(w);const S=Y.createBufferSource();return S.buffer=b,S.playbackRate.value=g,S.connect(D(Y)),x&&S.connect(x),r.push(S),h?(r.pop(),w):(U.isFirstAudio&&(o=!0,e.onSpeakingStart()),S.onended=()=>{const P=r.indexOf(S);P>=0&&r.splice(P,1),e.onNotify(),!h&&(ie&&re?Z(ie,re):oe())},S.start(w),w)},Z=async(b,U)=>{if(h||s||r.length>0)return;if(n.length===0){oe();return}s=!0;let Y=!1;try{const _=await z();if(h)return;const w=n[0];if(!w)return;const S=!o;if(k&&(e.shouldHoldForWarmup?.()??!1)&&(O||S&&w.newStream)||O){q(w.utterance,b,U);for(const K of n){if(h)return;K.audioBuffer||(K.audioBuffer=await Or(_,K.audio,K.sampleRate)),a=!0,O||(O=!0,F=0,K.newStream&&K.onNewStream?.()),K.visemesQueued||(I(b,U,K.visemes,K.words,F,!0,T),K.visemesQueued=!0,F+=Math.round(K.audioBuffer.duration*1e3),v=Math.max(v,pt(b)))}e.onNotify();return}const V=n.shift();if(!V||(V.audioBuffer||(V.audioBuffer=await Or(_,V.audio,V.sampleRate)),h))return;a=!0,te(),q(V.utterance,b,U),V.visemesQueued=!1,V.newStream&&V.onNewStream?.(),X(V.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:K=>{l=K,c=0,d=performance.now()+(K-_.currentTime)*1e3,b.length=0,U.length=0,I(b,U,V.visemes,V.words,0,!0,T),V.visemesQueued=!0,V.utterance.segmentOffsetMs=0}}),Y=r.length>0,v=pt(b),e.onNotify()}catch(_){console.error("[avatarChunkPlayback] audio chunk failed:",_)}finally{if(s=!1,h)return;if(O){n.some(w=>!w.audioBuffer||!w.visemesQueued)&&Z(b,U);return}!Y&&r.length===0&&n.length>0?Z(b,U):r.length===0&&n.length===0&&oe()}};return{setStreamTtsEngineId:b=>{T=b},setPlaybackSpeed:b=>{g=Math.max(.1,Math.min(1,b)),ae()},getPlaybackSpeed:()=>g,setMuted:b=>{N=b,W&&(W.gain.value=b?0:1)},isMuted:()=>N,setLipsyncWarmupHoldEnabled:b=>{k=b,b||Q()},isWarmingUp:()=>O,releaseWarmupHold:()=>{if(O){O=!1,F=0;for(const b of n)b.newStream=!1;ie&&re&&Z(ie,re),e.onNotify()}},resetForNewStream:b=>{h=!1,u=!1,T=b,v=0},resumeBotStream:()=>{h=!1,u=!1},clearAborted:()=>{h=!1},primeAudioContext:async()=>{const b=window.AudioContext||window.webkitAudioContext;i||(i=new b,W=null,x=null),i.state==="suspended"&&await i.resume(),D(i),x||(x=i.createMediaStreamDestination())},stop:()=>{h=!0,te(),le(),n.length=0,s=!1,o=!1,a=!1,u=!1,c=0,l=0,d=0,v=0,ie=null,re=null,C=null,Q()},markStreamComplete:b=>{if(v=Math.max(v,pt(b)),u=!0,!a&&b.length>0){ge(b);return}oe()},playAudioChunk:async(b,U,Y,_,w,S,P)=>{if(h)return;ie=b,re=U;const V=Hi(P?.sampleRate),K=P?.newStream===!0,ue=G();if(!Y?.trim()){if(_.length===0&&w.length===0)return;q(ue,b,U),K&&P?.onNewStream?.(),I(b,U,_,w,0,!0,T),v=pt(b),!o&&v>0&&ge(b),e.onNotify();return}n.push({audio:Y,audioBuffer:null,utterance:ue,visemes:_,words:w,isNewSegment:S,sampleRate:V,newStream:K,onNewStream:P?.onNewStream,visemesQueued:!1}),await Z(b,U)},queueTimingsOnly:(b,U,Y,_,w,S)=>{if(h)return;const P=G();q(P,b,U),I(b,U,Y,_,0,!0,T),P.segmentOffsetMs=0,v=pt(b)},getPlaybackElapsedMs:()=>a&&i&&l>0?Math.max(0,(i.currentTime-l)*1e3*g):o?Math.max(0,(performance.now()-d)*g):0,isSpeaking:()=>o?!0:!a||!i||l<=0?!1:(i.currentTime-l)*1e3<v,getVoiceStream:()=>x?x.stream:null,getPlaybackStartPerf:()=>d,bargeIn:()=>{h=!0,u=!1,te(),le(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,v=0,ie=null,re=null,C=null,Q()},interrupt:()=>{h=!0,u=!1,te(),le(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,v=0,ie=null,re=null,C=null,Q()}}}function Kt(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 Gi(e,t,n=120){const r=Kt(e,t);if(r!=="sil")return r;let i=null;for(const s of e){if(s.vtime>t)break;const o=s.vtime+s.vduration;o<=t&&t-o<=n&&(i=s)}return i?.viseme??"sil"}function ha(e,t,n=400){const r=t-n;let i=0;for(const s of e)if(s.vtime+s.vduration<r)i+=1;else break;i>0&&e.splice(0,i)}function pa(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Ur(e,t){const n=e.trim();if(!n)return null;try{const r=n.replace(/\s+/g,""),i=atob(r).length,s=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return i/2/s*1e3}catch{return null}}const Sn=.5,Tn=1.5,dr="Olivia",fr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Gt=.85;function qn(e,t=Bt,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let u=0;const d=[],l=[];let c="",f="neutral",g="",T=gt;const h=new Set;let x=0,W=null,N=0,v=null;const k=()=>h.forEach(j=>j());let O=()=>!1;const F=Ki({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:k,shouldHoldForWarmup:()=>O()},gt),ie=()=>F.getPlaybackElapsedMs(),re=(j,I=c)=>{if(!n.onLipsyncDebug)return;const q=ie(),D=i,z=bn(o).map(X=>({viseme:X.viseme,vtimeMs:X.vtime}));n.onLipsyncDebug({event:j,spokenText:I,mood:f,playbackAnchorPerf:F.getPlaybackStartPerf(),playbackElapsedMs:q,queueLength:D.length,activeViseme:Kt(D,q),segments:l.map(X=>({...X,visemes:[...X.visemes]})),fullQueueLength:o.length,compactionSkipped:z})},C=(j,I)=>{n.onLipsyncDebug&&(W={event:j,spokenText:I},x===0&&(x=requestAnimationFrame(()=>{x=0;const q=W;W=null,q&&re(q.event,q.spokenText)})))},G=(j,I,q,D,z)=>{if(!n.onLipsyncDebug)return;const X=i.slice(I),Z=q.filter(ne=>String(ne.symbol??ne.viseme??"").trim());l.push({spokenText:j,audioOffsetMs:X[0]?.vtime??0,isNewSegment:D,chunkDurationMs:z,receivedAtMs:performance.now(),visemes:X.map((ne,ke)=>{const J=Z[ke];return{rawSymbol:String(J?.symbol??J?.viseme??ne.viseme).trim(),viseme:ne.viseme,startSec:Number(J?.start??0),durationSec:Number(J?.duration??0),vtimeMs:ne.vtime,vdurationMs:ne.vduration}})})},Q=()=>{o.length=0,a.length=0,u=0},te=(j,I,q,D,z)=>{if(j.length===0&&I.length===0)return;ji(o,a,j,I,u,z);const X=zi(j,u),Z=q?Ur(q,D):null;u=Math.max(X,Z!=null?u+Z:u)},le=()=>{N+=1,v?.abort(),v=null,F.stop(),i.length=0,s.length=0,Q(),d.length=0,f="neutral",l.length=0,c="",e("idle"),C("reset"),k()},ae=j=>{const I=lt(j?.ttsEngineId,j?.voiceId),q=I.ttsEngineId??T??gt,D=I.voiceId??(q===dt?wn:dr),z=j?.speakingRate??Gt,X=Math.max(Sn,Math.min(Tn,z));return{engineId:q,voiceId:D,speakingRate:X,language:gn(j?.language)}},oe=async j=>{le();const I=N;v=new AbortController,e("loading"),c=j.debugSpokenFallback,l.length=0,Q();const q=g.trim();if(!q)throw new Error("Developer token required for avatar_ttsWithPoses");F.resetForNewStream(j.engineId),F.setStreamTtsEngineId(j.engineId);let D="",z="";try{const X=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${q}`,Accept:"text/event-stream"},body:JSON.stringify(j.requestBody),signal:v.signal});if(!X.ok)throw new Error(`avatar_ttsWithPoses failed (${X.status})`);const Z=X.body;if(!Z)throw new Error("No response body");const ne=Z.getReader(),ke=new TextDecoder;let J="",b=!0;const U=()=>D||j.debugSpokenFallback,Y=async _=>{if(I!==N)return;const w=Ai(_);if(w){if(w.event==="spokenText"){const S=typeof w.data.text=="string"?w.data.text.trim():"";S&&(D=S,c=S,j.onSpokenText?.(S),k());return}if(w.event==="displayText"){const S=typeof w.data.text=="string"?w.data.text.trim():"";S&&(z=S,j.onDisplayText?.(S),k());return}if(w.event!=="done"){if(w.event==="audio"){const S=w.data.chunk,P=w.data.visemes??[],V=w.data.words??[],K=w.data.is_new_segment??!1,ue=w.data.sample_rate,me=Number(w.data.audio_offset_ms??0),ee=i.length,R=U();if(te(P,V,S,ue,j.engineId),S){const we=b;b=!1,await F.playAudioChunk(i,s,S,P,V,K,{sampleRate:ue,newStream:we,audioOffsetMs:me}),G(R,ee,P,K,Ur(S,ue)),C("audio_chunk",R)}else(P.length>0||V.length>0)&&(F.queueTimingsOnly(i,s,P,V,K,{audioOffsetMs:me,newStream:b}),G(R,ee,P,K,null),C("audio_chunk",R))}else if(w.event==="metadata"){const S=w.data.mood;typeof S=="string"&&S.trim()&&(f=S.trim());const P=w.data.spoken_text??w.data.text;typeof P=="string"&&P.trim()&&!D&&(D=P.trim(),c=D);const V=w.data.sentence_emotions;if(Array.isArray(V)){d.length=0;for(const K of V){if(!K||typeof K!="object")continue;const ue=K;d.push({sentence_index:Number(ue.sentence_index??0),text:String(ue.text??""),sentiment:typeof ue.sentiment=="string"?ue.sentiment:void 0,emotion:String(ue.emotion??f),start_word:Number(ue.start_word??0),end_word:Number(ue.end_word??0)})}}k(),C("metadata",U())}else if(w.event==="error")throw new Error(String(w.data.message??"avatar_ttsWithPoses stream error"))}}};for(;;){if(I!==N)return{displayText:z,spokenText:D,aborted:!0};const{done:_,value:w}=await ne.read();w&&(J+=ke.decode(w,{stream:!0}));const S=J.split(`
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),m=require("react"),ys=require("@pipecat-ai/client-js"),Zn=require("@pipecat-ai/websocket-transport"),ve=require("pixi.js");var Bn=typeof document<"u"?document.currentScript:null;const vs="https://aitwin.bubu.social",mi={publicBase:vs},_s="0.7.4",bs={version:_s},Ss={},Bt="https://ai.aitwin.me",er=`${mi.publicBase}/custom-faces`,Ts=`${mi.publicBase}/aitwin-workers/v${bs.version}/visemeDiffPreview.worker.js`;function ks(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Bn&&Bn.tagName.toUpperCase()==="SCRIPT"&&Bn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Ss?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Ts}const xs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Fn=3e3,Wt=16,Br=3e3,Es=4e3,Is=.85,As=8,tr=400,nr="eng_a7f2b9c1",pn="eng_d4e8f3a2",ut="eng_c9b1e6d4",dt="visemetts",gt=ut,wn="eve",jn=new Set([pn,ut,dt]),rr={[nr]:"oculus_direct",[ut]:"oculus_direct",[dt]:"oculus_direct",[pn]:"inworld_word"},zn={google:nr,inworld:pn,cartesia:ut,visemetts:dt};function Ms(e){const t=e.trim();if(t)return t in rr?t:zn[t.toLowerCase()]}function hi(e){const t=e?.trim();if(!t)return{};const n=t.indexOf(":");if(n<=0)return{voiceId:t};const r=Ms(t.slice(0,n));if(!r)return{voiceId:t};const i=t.slice(n+1).trim();return{ttsEngineId:r,voiceId:i||void 0}}function lt(e,t){const n=hi(t);return{ttsEngineId:n.ttsEngineId??e,voiceId:n.voiceId}}function pi(e){return rr[e]}function wi(e){return e===ut}function gi(e){return e===dt}function Rs(e){if(e.ttsEngineId&&e.ttsEngineId in rr)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in zn?zn[t]:gt}class cn extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}function ir(e,...t){const n=typeof e=="string"?e:e?.brainId?.trim()||e?.knowledgeContextId?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}function sr(e,...t){const n=typeof e=="string"?e:e?.brainUrl?.trim();for(const r of[n,...t]){const i=r?.trim();if(i)return i}}function Ps(e){const t=(e??"").trim();if(!t)return;let n;try{n=new URL(t)}catch{throw new Error("brainUrl must be an http or https URL")}if(n.protocol!=="http:"&&n.protocol!=="https:")throw new Error("brainUrl must be an http or https URL");if(!n.host)throw new Error("brainUrl must be an http or https URL");if(n.hash)throw new Error("brainUrl must not include a fragment");return t}async function yi(e,t=xs){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new cn;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new cn(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,u=String(a.authToken??o??"").trim()||void 0,d=ir(a),l=sr(a);return{...a,ttsEngineId:Rs(i.data),authToken:u,brainId:d,knowledgeContextId:d,brainUrl:l}}const ar="thumbnail.webp";function vi(e,t=er){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${ar}`}function Fr(e){const t=e?.trim();if(!t)return null;try{return vi(t)}catch{return null}}function Cs(e){if(!e)return null;const t=(e.binBase||e.twinBase).trim().replace(/\/$/,"");return t?`${t}/${ar}`:null}const Ds="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Bs="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Fs="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Ls="6TNvp3SCs4Og0a1ijm9TommXLql1",Ns="Swaraj Mali";async function on(){const e=await fetch(Ds,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Bs,"Client-Secret":Fs},body:JSON.stringify({userId:Ls,userName:Ns})});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 Os(e,t=Bt){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 Us(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 tn(e){return Uint8Array.from(e)}function Vs(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Ws(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=tn(n.subarray(0,12)),i=tn(n.subarray(12,28)),s=tn(n.subarray(28)),o=tn(Vs(s,i)),a=await crypto.subtle.importKey("raw",Us(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let Hn=null;const $n=new Set;function nn(e){return e.includes("/custom-faces/")}function ln(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||nn(t)||nn(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=nn(t)?t:nn(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function _t(e){return ln(e).encrypted}function Kn(e,t=er){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function _i(e,t){return(e??t)?.trim()||void 0}function bi(e){Hn=ln(e);for(const t of $n)t()}function js(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return ln(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return ln({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function bt(){if(!Hn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Hn}function Si(e){return $n.add(e),()=>$n.delete(e)}function un(){const e=bt();return _t(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function zs(){const e=bt();return _t(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Ti(){const e=bt();return _t(e)?e.binBase:e.twinBase}function $t(){return _t(bt())}function ki(){const e=bt();return _t(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function xi(){const e=bt();return _t(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}const yt=[{code:"en",label:"English",visemetts:!0,cartesia:!0},{code:"es",label:"Spanish",visemetts:!0,cartesia:!0},{code:"es-MX",label:"Spanish (Mexico)",visemetts:!0,cartesia:!0},{code:"es-ES",label:"Spanish (Spain)",visemetts:!0,cartesia:!0},{code:"pt",label:"Portuguese",visemetts:!0,cartesia:!0},{code:"pt-BR",label:"Portuguese (Brazil)",visemetts:!0,cartesia:!0},{code:"pt-PT",label:"Portuguese (Portugal)",visemetts:!0,cartesia:!0},{code:"fr",label:"French",visemetts:!0,cartesia:!0},{code:"de",label:"German",visemetts:!0,cartesia:!0},{code:"it",label:"Italian",visemetts:!0,cartesia:!0},{code:"zh",label:"Chinese",visemetts:!0,cartesia:!0},{code:"ja",label:"Japanese",visemetts:!0,cartesia:!0},{code:"hi",label:"Hindi",visemetts:!0,cartesia:!0},{code:"ko",label:"Korean",visemetts:!0,cartesia:!0},{code:"ru",label:"Russian",visemetts:!0,cartesia:!0},{code:"tr",label:"Turkish",visemetts:!0,cartesia:!0},{code:"id",label:"Indonesian",visemetts:!0,cartesia:!0},{code:"ar",label:"Arabic",visemetts:!0,cartesia:!0},{code:"ar-EG",label:"Arabic (Egypt)",visemetts:!0,cartesia:!0},{code:"ar-AE",label:"Arabic (UAE)",visemetts:!0,cartesia:!0},{code:"vi",label:"Vietnamese",visemetts:!0,cartesia:!0},{code:"bn",label:"Bengali",visemetts:!0,cartesia:!0},{code:"auto",label:"Auto-detect",visemetts:!0,cartesia:!1},{code:"nl",label:"Dutch",visemetts:!1,cartesia:!0},{code:"pl",label:"Polish",visemetts:!1,cartesia:!0},{code:"sv",label:"Swedish",visemetts:!1,cartesia:!0},{code:"tl",label:"Tagalog",visemetts:!1,cartesia:!0},{code:"bg",label:"Bulgarian",visemetts:!1,cartesia:!0},{code:"ro",label:"Romanian",visemetts:!1,cartesia:!0},{code:"cs",label:"Czech",visemetts:!1,cartesia:!0},{code:"el",label:"Greek",visemetts:!1,cartesia:!0},{code:"fi",label:"Finnish",visemetts:!1,cartesia:!0},{code:"hr",label:"Croatian",visemetts:!1,cartesia:!0},{code:"ms",label:"Malay",visemetts:!1,cartesia:!0},{code:"sk",label:"Slovak",visemetts:!1,cartesia:!0},{code:"da",label:"Danish",visemetts:!1,cartesia:!0},{code:"ta",label:"Tamil",visemetts:!1,cartesia:!0},{code:"uk",label:"Ukrainian",visemetts:!1,cartesia:!0},{code:"hu",label:"Hungarian",visemetts:!1,cartesia:!0},{code:"no",label:"Norwegian",visemetts:!1,cartesia:!0},{code:"th",label:"Thai",visemetts:!1,cartesia:!0},{code:"he",label:"Hebrew",visemetts:!1,cartesia:!0},{code:"ka",label:"Georgian",visemetts:!1,cartesia:!0},{code:"te",label:"Telugu",visemetts:!1,cartesia:!0},{code:"gu",label:"Gujarati",visemetts:!1,cartesia:!0},{code:"kn",label:"Kannada",visemetts:!1,cartesia:!0},{code:"ml",label:"Malayalam",visemetts:!1,cartesia:!0},{code:"mr",label:"Marathi",visemetts:!1,cartesia:!0},{code:"pa",label:"Punjabi",visemetts:!1,cartesia:!0}],Ei=yt.map(e=>e.code),Hs=new Set(Ei),$s=new Set(yt.filter(e=>e.visemetts).map(e=>e.code)),Ks=new Set(yt.filter(e=>e.cartesia).map(e=>e.code)),Gs="en";function Ii(e){return Hs.has(e)}function gn(e){const t=e?.trim();if(t)return t}function qs(e){return e===dt?yt.filter(t=>t.visemetts).map(t=>t.code):e===ut?yt.filter(t=>t.cartesia).map(t=>t.code):yt.filter(t=>t.visemetts&&t.cartesia).map(t=>t.code)}function Ys(e,t){const n=t.trim();return n?e===dt?$s.has(n):e===ut?Ks.has(n):Ii(n):!1}function Ai(e){const t=e.split(/\r?\n/);let n="",r="";for(const s of t)s.startsWith("event:")?n=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());if(!n)return null;let i={};if(r)try{i=JSON.parse(r)}catch{i={raw:r}}return{event:n,data:i}}const Mi=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],Qs=new Map(Mi.map(e=>[e.toLowerCase(),e]));function yn(e){const t=(e??"").trim();return t?Qs.get(t.toLowerCase())??"sil":"sil"}const Xs={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 Js(e){if(!e)return["sil"];const t=e.toLowerCase();return Xs[t]??["sil"]}function Ri(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const i=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(i*n))}function Rt(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function vn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||Rt(n,t)!=="w"||t>0&&Rt(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function Zs(e,t){const n=e.toLowerCase(),r=Rt(n,t),i=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":i.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function ea(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";if(vn(n,t))return"FF";const i=Rt(n,t);return i==="u"||i==="w"?"U":"O"}function ta(e,t){const n=e.toLowerCase();if(vn(n,t))return"FF";const r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const i=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(i)||Rt(n,t)==="o"?"O":"U"}const rn={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function na(e,t){const n=e.toLowerCase(),r=Rt(n,t);if(rn[r])return rn[r];for(let i=0;i<n.length;i++){const s=n[i];if(rn[s])return rn[s]}return"DD"}function Pi(e,t,n){const r=Js(e);if(r.length===1)return r[0];const i=t.trim();if(!i)return r[0];const s=(e??"").toLowerCase(),o=Math.max(0,n);switch(s){case"aei":return Zs(i,o);case"o":return ea(i,o);case"qw":return ta(i,o);case"cdgknstxyz":return na(i,o);default:return r[0]}}const or=16,Gn=47,Ci=new Set(["aa","E","I"]),Di=new Set(["DD","SS","kk","CH"]),ra=[Ci,Di];function ia(e){for(const t of ra)if(t.has(e))return t;return null}function sa(e){return ia(e)!=null}function Bi(e,t=or){return t<=0?e:Math.round(e/t)*t}function cr(e,t=or){return e.map(n=>({...n,vtime:Bi(n.vtime,t)}))}function Fi(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 lr(e){if(e.length<=2)return[...e];const t=[e[0]];for(let n=1;n<e.length-1;n++){const r=e[n],i=e[n+1],s=t[t.length-1];if(!sa(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<Gn||a<Gn||t.push(r)}return t.push(e[e.length-1]),t}function _n(e){return lr(Fi(cr(e)))}function Li(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function bn(e){const t=Fi(cr(e)),n=lr(t),r=new Set(n.map(s=>s.vtime)),i=[];for(const s of t)r.has(s.vtime)||i.push({viseme:s.viseme,vtime:s.vtime});return i}function aa(e){return bn(e).map(t=>t.viseme)}const oa=32,Lr=48;function Ni(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function Oi(e){let t=null,n=-1;for(const r of e){if(r.viseme==="sil")continue;const i=r.vtime+r.vduration;i>n&&(t=r,n=i)}return t}function ca(e){return _n(e).find(n=>n.viseme!=="sil")??null}function pt(e){const t=Ni(e);return Oi(e)?t+tr:t}function la(e){const t=[],n=ca(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=Oi(e),i=Ni(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+tr}),t}function Ui(e){const t=_n(e),n=[];for(let r=0;r<t.length-1;r++){const i=t[r].viseme,s=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;i===s||a<=o||n.push({from:i,to:s,fromVtime:o,toVtime:a})}return n}function Vi(e){return e.length===0?[]:[...la(e),...Ui(e)]}function ua(e,t,n=!1){let r=null;for(const i of e){const{transStart:s,transEnd:o}=Wi(i.fromVtime,i.toVtime,i.from,i.to,n);t>=s&&t<o&&(r=i)}return r}function Wi(e,t,n,r,i=!1){const s=Math.max(0,t-e);if(i&&(n==="PP"||r==="PP")&&s>Lr){const l=Lr,c=t,f=c-l;return{gapMs:s,effectiveGapMs:l,holdEnd:f,transStart:f,transEnd:c}}const a=s>0?Math.max(s,oa):0,u=e,d=e+a;return{gapMs:s,effectiveGapMs:a,holdEnd:e,transStart:u,transEnd:d}}function ji(e,t,n,r,i,s){r.forEach(o=>{const u=String(o.word??"").trim();if(!u)return;const d=Math.round((o.start??0)*1e3),l=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:u,wtime:i+d,wduration:l,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),n.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const u=Math.round((o.start??0)*1e3),d=Math.max(1,Math.round((o.duration??0)*1e3)),l=i+u,c=$i(t,l),f=c?Ri(c,l):0;let g;pi(s)==="oculus_direct"?(g=yn(a),g==="U"&&c&&vn(c.word,f)&&(g="FF")):g=Pi(a,c?.word??"",f),e.push({viseme:g,weight:1,vtime:l,vduration:d})})}function zi(e,t){let n=t;for(const r of e){const i=Math.round((r.start??0)*1e3),s=Math.max(1,Math.round((r.duration??0)*1e3));n=Math.max(n,t+i+s)}return n}const ur=16e3;function Hi(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:ur}function da(e){let t=e.trim();const n=t.indexOf(",");t.startsWith("data:")&&n>=0&&(t=t.slice(n+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const r=t.length%4;return r!==0&&(t+="=".repeat(4-r)),t}function fa(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Nr(e,t,n=ur){const r=t.byteOffset%2===0?t:t.slice(),i=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),s=new Float32Array(i.length);for(let a=0;a<i.length;a++)s[a]=i[a]>=32768?-(65536-i[a])/32768:i[a]/32767;const o=e.createBuffer(1,s.length,n);return o.copyToChannel(s,0),o}function ma(e){const t=da(e),n=window.atob(t),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return r}async function Or(e,t,n=ur){const r=ma(t),i=Hi(n);if(fa(r)){const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(s)}if(r.length>=2&&r.length%2===0)return Nr(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return Nr(e,r,i)}}function $i(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Ki(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,u=!1,d=0,l=0,c=0,f=null,g=1,T=t,h=!1,x=null,W=null,N=!1,v=0,k=!1,O=!1,F=0,ie=null,re=null,C=null;const G=()=>({visemes:[],words:[],segmentOffsetMs:0}),Q=()=>{O=!1,F=0},te=()=>{f!=null&&(clearTimeout(f),f=null)},le=()=>{for(const b of r){try{b.onended=null,b.stop(0)}catch{}try{b.disconnect()}catch{}}r.length=0},ae=()=>{for(const b of r)b.playbackRate.value=g},oe=()=>{if(!(h||!u||s||O||r.length>0||n.length>0)){if(a&&i&&l>0){const b=(i.currentTime-l)*1e3;if(b<v){te();const U=g>0?(v-b)/g:v-b;f=setTimeout(()=>{h||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,U));return}}o=!1,te(),e.onSpeakingDone(),e.onNotify()}},ge=b=>{const U=pt(b);if(U<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,d=performance.now(),e.onSpeakingStart(),e.onNotify(),te();const Y=g>0?U/g:U;f=setTimeout(()=>{h||(o=!1,f=null,e.onSpeakingDone(),e.onNotify())},Y)},ce=(b,U,Y,_)=>{U.length!==0&&(c=Y,U.forEach(w=>{const P=String(w.word??"").trim();if(!P)return;const V=Math.round((w.start??0)*1e3),K=w.duration!=null?Math.round(w.duration*1e3):w.end!=null?Math.max(1,Math.round((w.end-(w.start??0))*1e3)):0;b.push({word:P,wtime:c+V,wduration:K,queueIndex:b.length,gesture:w.gesture??null,emphasis:w.emphasis===!0})}))},j=(b,U,Y,_,w,S)=>{Y.length!==0&&(c=_,Y.forEach(P=>{const V=String(P.symbol??P.viseme??"").trim();if(!V)return;const K=Math.round((P.start??0)*1e3),ue=Math.max(1,Math.round((P.duration??0)*1e3)),me=c+K,ee=$i(U,me),R=ee?Ri(ee,me):0;let we;pi(S)==="oculus_direct"?(we=yn(V),we==="U"&&ee&&vn(ee.word,R)&&(we="FF")):we=Pi(V,ee?.word??"",R),b.push({viseme:we,weight:1,vtime:me,vduration:ue})}),e.onNotify())},I=(b,U,Y,_,w,S,P)=>{ce(U,_,w),j(b,U,Y,w,S,P)},q=(b,U,Y)=>{C===b&&b.visemes===U||(U.length=0,Y.length=0,b.visemes=U,b.words=Y,b.segmentOffsetMs=0,C=b,c=0,v=0)},D=b=>(W||(W=b.createGain(),W.gain.value=N?0:1,W.connect(b.destination)),W),z=async()=>{const b=window.AudioContext||window.webkitAudioContext;return i||(i=new b,W=null,x=null),i.state==="suspended"&&await i.resume(),D(i),x||(x=i.createMediaStreamDestination()),i},X=(b,U)=>{if(!i)return 0;const Y=i,_=Y.currentTime,w=_+.02;if(U.isFirstAudio){l<=0&&(l=w);const P=(w-_)*1e3;d=performance.now()+P}U.onBeforeStart?.(w);const S=Y.createBufferSource();return S.buffer=b,S.playbackRate.value=g,S.connect(D(Y)),x&&S.connect(x),r.push(S),h?(r.pop(),w):(U.isFirstAudio&&(o=!0,e.onSpeakingStart()),S.onended=()=>{const P=r.indexOf(S);P>=0&&r.splice(P,1),e.onNotify(),!h&&(ie&&re?Z(ie,re):oe())},S.start(w),w)},Z=async(b,U)=>{if(h||s||r.length>0)return;if(n.length===0){oe();return}s=!0;let Y=!1;try{const _=await z();if(h)return;const w=n[0];if(!w)return;const S=!o;if(k&&(e.shouldHoldForWarmup?.()??!1)&&(O||S&&w.newStream)||O){q(w.utterance,b,U);for(const K of n){if(h)return;K.audioBuffer||(K.audioBuffer=await Or(_,K.audio,K.sampleRate)),a=!0,O||(O=!0,F=0,K.newStream&&K.onNewStream?.()),K.visemesQueued||(I(b,U,K.visemes,K.words,F,!0,T),K.visemesQueued=!0,F+=Math.round(K.audioBuffer.duration*1e3),v=Math.max(v,pt(b)))}e.onNotify();return}const V=n.shift();if(!V||(V.audioBuffer||(V.audioBuffer=await Or(_,V.audio,V.sampleRate)),h))return;a=!0,te(),q(V.utterance,b,U),V.visemesQueued=!1,V.newStream&&V.onNewStream?.(),X(V.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:K=>{l=K,c=0,d=performance.now()+(K-_.currentTime)*1e3,b.length=0,U.length=0,I(b,U,V.visemes,V.words,0,!0,T),V.visemesQueued=!0,V.utterance.segmentOffsetMs=0}}),Y=r.length>0,v=pt(b),e.onNotify()}catch(_){console.error("[avatarChunkPlayback] audio chunk failed:",_)}finally{if(s=!1,h)return;if(O){n.some(w=>!w.audioBuffer||!w.visemesQueued)&&Z(b,U);return}!Y&&r.length===0&&n.length>0?Z(b,U):r.length===0&&n.length===0&&oe()}};return{setStreamTtsEngineId:b=>{T=b},setPlaybackSpeed:b=>{g=Math.max(.1,Math.min(1,b)),ae()},getPlaybackSpeed:()=>g,setMuted:b=>{N=b,W&&(W.gain.value=b?0:1)},isMuted:()=>N,setLipsyncWarmupHoldEnabled:b=>{k=b,b||Q()},isWarmingUp:()=>O,releaseWarmupHold:()=>{if(O){O=!1,F=0;for(const b of n)b.newStream=!1;ie&&re&&Z(ie,re),e.onNotify()}},resetForNewStream:b=>{h=!1,u=!1,T=b,v=0},resumeBotStream:()=>{h=!1,u=!1},clearAborted:()=>{h=!1},primeAudioContext:async()=>{const b=window.AudioContext||window.webkitAudioContext;i||(i=new b,W=null,x=null),i.state==="suspended"&&await i.resume(),D(i),x||(x=i.createMediaStreamDestination())},stop:()=>{h=!0,te(),le(),n.length=0,s=!1,o=!1,a=!1,u=!1,c=0,l=0,d=0,v=0,ie=null,re=null,C=null,Q()},markStreamComplete:b=>{if(v=Math.max(v,pt(b)),u=!0,!a&&b.length>0){ge(b);return}oe()},playAudioChunk:async(b,U,Y,_,w,S,P)=>{if(h)return;ie=b,re=U;const V=Hi(P?.sampleRate),K=P?.newStream===!0,ue=G();if(!Y?.trim()){if(_.length===0&&w.length===0)return;q(ue,b,U),K&&P?.onNewStream?.(),I(b,U,_,w,0,!0,T),v=pt(b),!o&&v>0&&ge(b),e.onNotify();return}n.push({audio:Y,audioBuffer:null,utterance:ue,visemes:_,words:w,isNewSegment:S,sampleRate:V,newStream:K,onNewStream:P?.onNewStream,visemesQueued:!1}),await Z(b,U)},queueTimingsOnly:(b,U,Y,_,w,S)=>{if(h)return;const P=G();q(P,b,U),I(b,U,Y,_,0,!0,T),P.segmentOffsetMs=0,v=pt(b)},getPlaybackElapsedMs:()=>a&&i&&l>0?Math.max(0,(i.currentTime-l)*1e3*g):o?Math.max(0,(performance.now()-d)*g):0,isSpeaking:()=>o?!0:!a||!i||l<=0?!1:(i.currentTime-l)*1e3<v,getVoiceStream:()=>x?x.stream:null,getPlaybackStartPerf:()=>d,bargeIn:()=>{h=!0,u=!1,te(),le(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,v=0,ie=null,re=null,C=null,Q()},interrupt:()=>{h=!0,u=!1,te(),le(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,d=0,v=0,ie=null,re=null,C=null,Q()}}}function Kt(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 Gi(e,t,n=120){const r=Kt(e,t);if(r!=="sil")return r;let i=null;for(const s of e){if(s.vtime>t)break;const o=s.vtime+s.vduration;o<=t&&t-o<=n&&(i=s)}return i?.viseme??"sil"}function ha(e,t,n=400){const r=t-n;let i=0;for(const s of e)if(s.vtime+s.vduration<r)i+=1;else break;i>0&&e.splice(0,i)}function pa(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Ur(e,t){const n=e.trim();if(!n)return null;try{const r=n.replace(/\s+/g,""),i=atob(r).length,s=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return i/2/s*1e3}catch{return null}}const Sn=.5,Tn=1.5,dr="Olivia",fr="f786b574-daa5-4673-aa0c-cbe3e8534c02",Gt=.85;function qn(e,t=Bt,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let u=0;const d=[],l=[];let c="",f="neutral",g="",T=gt;const h=new Set;let x=0,W=null,N=0,v=null;const k=()=>h.forEach(j=>j());let O=()=>!1;const F=Ki({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:k,shouldHoldForWarmup:()=>O()},gt),ie=()=>F.getPlaybackElapsedMs(),re=(j,I=c)=>{if(!n.onLipsyncDebug)return;const q=ie(),D=i,z=bn(o).map(X=>({viseme:X.viseme,vtimeMs:X.vtime}));n.onLipsyncDebug({event:j,spokenText:I,mood:f,playbackAnchorPerf:F.getPlaybackStartPerf(),playbackElapsedMs:q,queueLength:D.length,activeViseme:Kt(D,q),segments:l.map(X=>({...X,visemes:[...X.visemes]})),fullQueueLength:o.length,compactionSkipped:z})},C=(j,I)=>{n.onLipsyncDebug&&(W={event:j,spokenText:I},x===0&&(x=requestAnimationFrame(()=>{x=0;const q=W;W=null,q&&re(q.event,q.spokenText)})))},G=(j,I,q,D,z)=>{if(!n.onLipsyncDebug)return;const X=i.slice(I),Z=q.filter(ne=>String(ne.symbol??ne.viseme??"").trim());l.push({spokenText:j,audioOffsetMs:X[0]?.vtime??0,isNewSegment:D,chunkDurationMs:z,receivedAtMs:performance.now(),visemes:X.map((ne,ke)=>{const J=Z[ke];return{rawSymbol:String(J?.symbol??J?.viseme??ne.viseme).trim(),viseme:ne.viseme,startSec:Number(J?.start??0),durationSec:Number(J?.duration??0),vtimeMs:ne.vtime,vdurationMs:ne.vduration}})})},Q=()=>{o.length=0,a.length=0,u=0},te=(j,I,q,D,z)=>{if(j.length===0&&I.length===0)return;ji(o,a,j,I,u,z);const X=zi(j,u),Z=q?Ur(q,D):null;u=Math.max(X,Z!=null?u+Z:u)},le=()=>{N+=1,v?.abort(),v=null,F.stop(),i.length=0,s.length=0,Q(),d.length=0,f="neutral",l.length=0,c="",e("idle"),C("reset"),k()},ae=j=>{const I=lt(j?.ttsEngineId,j?.voiceId),q=I.ttsEngineId??T??gt,D=I.voiceId??(q===dt?wn:dr),z=j?.speakingRate??Gt,X=Math.max(Sn,Math.min(Tn,z));return{engineId:q,voiceId:D,speakingRate:X,language:gn(j?.language)}},oe=async j=>{le();const I=N;v=new AbortController,e("loading"),c=j.debugSpokenFallback,l.length=0,Q();const q=g.trim();if(!q)throw new Error("Developer token required for avatar_ttsWithPoses");F.resetForNewStream(j.engineId),F.setStreamTtsEngineId(j.engineId);let D="",z="";try{const X=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${q}`,Accept:"text/event-stream"},body:JSON.stringify(j.requestBody),signal:v.signal});if(!X.ok)throw new Error(`avatar_ttsWithPoses failed (${X.status})`);const Z=X.body;if(!Z)throw new Error("No response body");const ne=Z.getReader(),ke=new TextDecoder;let J="",b=!0;const U=()=>D||j.debugSpokenFallback,Y=async _=>{if(I!==N)return;const w=Ai(_);if(w){if(w.event==="spokenText"){const S=typeof w.data.text=="string"?w.data.text.trim():"";S&&(D=S,c=S,j.onSpokenText?.(S),k());return}if(w.event==="displayText"){const S=typeof w.data.text=="string"?w.data.text.trim():"";S&&(z=S,j.onDisplayText?.(S),k());return}if(w.event!=="done"){if(w.event==="audio"){const S=w.data.chunk,P=w.data.visemes??[],V=w.data.words??[],K=w.data.is_new_segment??!1,ue=w.data.sample_rate,me=Number(w.data.audio_offset_ms??0),ee=i.length,R=U();if(te(P,V,S,ue,j.engineId),S){const we=b;b=!1,await F.playAudioChunk(i,s,S,P,V,K,{sampleRate:ue,newStream:we,audioOffsetMs:me}),G(R,ee,P,K,Ur(S,ue)),C("audio_chunk",R)}else(P.length>0||V.length>0)&&(F.queueTimingsOnly(i,s,P,V,K,{audioOffsetMs:me,newStream:b}),G(R,ee,P,K,null),C("audio_chunk",R))}else if(w.event==="metadata"){const S=w.data.mood;typeof S=="string"&&S.trim()&&(f=S.trim());const P=w.data.spoken_text??w.data.text;typeof P=="string"&&P.trim()&&!D&&(D=P.trim(),c=D);const V=w.data.sentence_emotions;if(Array.isArray(V)){d.length=0;for(const K of V){if(!K||typeof K!="object")continue;const ue=K;d.push({sentence_index:Number(ue.sentence_index??0),text:String(ue.text??""),sentiment:typeof ue.sentiment=="string"?ue.sentiment:void 0,emotion:String(ue.emotion??f),start_word:Number(ue.start_word??0),end_word:Number(ue.end_word??0)})}}k(),C("metadata",U())}else if(w.event==="error")throw new Error(String(w.data.message??"avatar_ttsWithPoses stream error"))}}};for(;;){if(I!==N)return{displayText:z,spokenText:D,aborted:!0};const{done:_,value:w}=await ne.read();w&&(J+=ke.decode(w,{stream:!0}));const S=J.split(`
|
|
2
2
|
|
|
3
3
|
`);J=S.pop()??"";for(const P of S)await Y(P);if(_){J.trim()&&await Y(J.trim()),F.markStreamComplete(i),C("bot_stopped",U());break}}}catch(X){if(I!==N)return{displayText:z,spokenText:D,aborted:!0};if(X instanceof DOMException&&X.name==="AbortError")return{displayText:z,spokenText:D,aborted:!0};throw console.error("[avatarTtsLipsync]",X),le(),e("error"),X}return{displayText:z,spokenText:D}};return{setDeveloperToken:j=>{g=j},setTtsEngineId:j=>{T=j},getTtsEngineId:()=>T,speak:async(j,I)=>{const{engineId:q,voiceId:D,speakingRate:z,language:X}=ae(I),Z={user_query:j,ttsEngineId:q,speakingRate:z,tenant:"aiTwin"};jn.has(q)&&(Z.voice_id=D),X&&(Z.language=X),await oe({requestBody:Z,engineId:q,debugSpokenFallback:j})},speakWithReply:async(j,I)=>{const q=j.trim();if(!q)throw new Error("Message is required");const{engineId:D,voiceId:z,speakingRate:X,language:Z}=ae(I),ne={generateReply:!0,message:q,ttsEngineId:D,speakingRate:X,tenant:"aiTwin",history:I?.history??[]};jn.has(D)&&(ne.voice_id=z),Z&&(ne.language=Z);const ke=I?.brainId?.trim();ke&&(ne.brainId=ke);const J=I?.brainUrl?.trim();J&&(ne.brainUrl=J);const b=await oe({requestBody:ne,engineId:D,debugSpokenFallback:q,onSpokenText:I?.onSpokenText,onDisplayText:I?.onDisplayText});if(b.aborted)return{spokenText:b.spokenText,displayText:b.displayText};if(!b.spokenText&&!b.displayText)throw new Error("avatar_ttsWithPoses generateReply stream missing spokenText or displayText");return{spokenText:b.spokenText||b.displayText,displayText:b.displayText||b.spokenText}},stop:le,getVisemeQueue:()=>i,getWordQueue:()=>s,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>d,getStreamMood:()=>f,getPlaybackElapsedMs:()=>F.getPlaybackElapsedMs(),isSpeaking:()=>F.isSpeaking(),isWarmingUp:()=>F.isWarmingUp(),releaseWarmupHold:()=>F.releaseWarmupHold(),setLipsyncWarmupHold:(j,I)=>{I&&(O=I),F.setLipsyncWarmupHoldEnabled(j)},getVoiceStream:()=>F.getVoiceStream(),setMuted:j=>{F.setMuted(j)},isMuted:()=>F.isMuted(),setPlaybackSpeed:j=>{F.setPlaybackSpeed(j)},getPlaybackSpeed:()=>F.getPlaybackSpeed(),subscribe:j=>(h.add(j),()=>h.delete(j))}}function jt(e){if(e==null)return!1;if(typeof e=="object"){const r=e;if(r.type==="permissions"||r.name==="NotAllowedError"||r.name==="PermissionDeniedError")return!0}const n=(e instanceof Error?`${e.name} ${e.message}`:typeof e=="string"?e:String(e)).toLowerCase();return!!(n.includes("notallowederror")||n.includes("permissiondeniederror")||n.includes("permission denied")||n.includes("permissions denied")||n.includes("microphone access denied")||(n.includes("microphone")||n.includes(" mic"))&&(n.includes("denied")||n.includes("blocked")||n.includes("not allowed")||n.includes("permission")))}async function wa(){if(typeof navigator>"u"||!navigator.permissions?.query)return!1;try{return(await navigator.permissions.query({name:"microphone"})).state==="denied"}catch{return!1}}const mr=16e3,hr=16e3;class ga extends Zn.ProtobufFrameSerializer{async deserialize(t){try{return await super.deserialize(t)}catch(n){if(n instanceof Error&&n.message==="Unknown frame kind")return{type:"raw",message:null};throw n}}}class ya extends Zn.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,mr,hr)}bufferBotAudio(t,n){}}const va=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Vr(e){return va.test(e.trim())}function _a(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function qi(e){if(e.wsUrl?.trim())return e.wsUrl.trim();const t=e.authToken?.trim();if(!t)throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");const n=e.apiBase??Bt,r=new URL(`${_a(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const i=lt(e.ttsEngineId,e.voiceId),s=i.ttsEngineId;s&&r.searchParams.set("ttsEngineId",s);const o=i.voiceId?.trim();o&&(s&&gi(s)?Vr(o)||r.searchParams.set("voiceId",o):Vr(o)&&r.searchParams.set("voiceId",o));const a=gn(e.language);a&&r.searchParams.set("language",a);const u=e.brainId?.trim()||e.personaId?.trim();u&&r.searchParams.set("brainId",u);const d=e.brainUrl?.trim();d&&r.searchParams.set("brainUrl",d);const l=e.speakingRate??Gt;r.searchParams.set("speaking_rate",String(Math.max(Sn,Math.min(Tn,l)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),e.speakOnlyWhenSpokenTo&&r.searchParams.set("speakOnlyWhenSpokenTo","true");const c=e.avatarName?.trim();return c&&r.searchParams.set("avatarName",c),r.toString()}function Ln(e,t){if(!Array.isArray(e))return[];const n=[];for(const r of e)!r||typeof r!="object"||n.push({sentence_index:Number(r.sentence_index??0),text:String(r.text??""),sentiment:typeof r.sentiment=="string"?r.sentiment:void 0,emotion:String(r.emotion??t),start_word:Number(r.start_word??0),end_word:Number(r.end_word??0)});return n}function ba(e){if(!e||typeof e!="object")return null;const t=e,r=(t.data&&typeof t.data=="object"&&!Array.isArray(t.data)?t.data:null)||t;return{...r,type:String(r.type??t.type??"server-message")}}function Wr(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function Sa(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function Yi(e,t={}){const n=[],r=[],i=[],s=[];let o=0;const a=[],u=[];let d="",l="neutral",c=ut,f=!1,g=null,T=null,h={...t},x=0,W=null;const N=new Set,v=[];let k=!1,O=null,F=!0,ie="default";const re=new Set;let C=null,G=0,Q=!1,te=!1,le=null,ae=!1;const oe=()=>{le!=null&&(clearTimeout(le),le=null)},ge=()=>{oe(),le=setTimeout(()=>{le=null,F&&(I.markStreamComplete(n),Z("bot_stopped"))},450)},ce=()=>N.forEach(p=>p());let j=()=>!1;const I=Ki({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{ae=!1,te=!1,e("done")},onNotify:ce,shouldHoldForWarmup:()=>j()},c),q=()=>{if(O)return O;const p=new MessageChannel;return p.port1.onmessage=()=>{const B=v.shift();B!==void 0&&ee(B),v.length>0?p.port2.postMessage(null):k=!1},O=p,p},D=p=>{v.push(p),!k&&(k=!0,q().port2.postMessage(null))},z=()=>I.getPlaybackElapsedMs(),X=(p,B=d)=>{if(!h.onLipsyncDebug)return;const se=z(),de=n,be=bn(i).map(Ie=>({viseme:Ie.viseme,vtimeMs:Ie.vtime}));h.onLipsyncDebug({event:p,spokenText:B,mood:l,playbackAnchorPerf:I.getPlaybackStartPerf(),playbackElapsedMs:se,queueLength:de.length,activeViseme:Kt(de,se),segments:u.map(Ie=>({...Ie,visemes:[...Ie.visemes]})),fullQueueLength:i.length,compactionSkipped:be})},Z=(p,B)=>{h.onLipsyncDebug&&(W={event:p,spokenText:B},x===0&&(x=requestAnimationFrame(()=>{x=0;const se=W;W=null,se&&X(se.event,se.spokenText)})))},ne=()=>{F=!0,re.clear(),I.clearAborted()},ke=()=>{const p=Sa(g);if(p){ie=`bot-${Date.now()}`,p.interruptedTrackIds={[ie]:!0};try{p.interrupt?.()}catch{}}const B=T;try{B?.interrupt?.()}catch{}},J=p=>{if(ae&&I.isSpeaking())return!0;const B=p.context_id?.trim();return B&&re.has(B)?!0:F?!1:!(p.type==="avatar_metadata"||Wr(p))},b=p=>{F=!1,ae=!1;const B=p.context_id?.trim();B&&re.add(B),oe(),Q=!1,te=!1,v.length=0,k=!1,C?.abort(),C=null,G+=1,ke(),I.bargeIn(),U(),e("idle"),Z("interrupt"),ce()},U=()=>{n.length=0,r.length=0,i.length=0,s.length=0,o=0,u.length=0,d="",l="neutral",a.length=0},Y=()=>{oe(),te=!1,Q=!1,I.stop(),U(),Z("reset"),ce()},_=()=>{Y(),e("idle"),ce()},w=(p,B)=>{typeof p.mood=="string"&&p.mood.trim()&&(l=p.mood.trim()),Array.isArray(p.sentence_emotions)&&p.sentence_emotions.length>0&&(B&&(a.length=0),a.push(...Ln(p.sentence_emotions,l)))},S=p=>{if(J({...p,type:"avatar_metadata"}))return;ne(),Q=!0;const B=String(p.spoken_text??p.text??"").trim();B&&(d=B),I.resetForNewStream(c),typeof p.mood=="string"&&p.mood.trim()&&(l=p.mood.trim()),a.length=0,a.push(...Ln(p.sentence_emotions,l)),Array.isArray(p.gestures)&&p.gestures,Z("metadata",B),ce()},P=(p,B,se,de)=>{if(!h.onLipsyncDebug)return;const be=n.slice(se),Ie=de.filter(Pe=>String(Pe.symbol??Pe.viseme??"").trim());u.push({spokenText:B,audioOffsetMs:be[0]?.vtime??0,isNewSegment:!!p.is_new_segment,chunkDurationMs:p.chunk_duration_ms!=null?Number(p.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:be.map((Pe,Ke)=>{const Ve=Ie[Ke];return{rawSymbol:String(Ve?.symbol??Ve?.viseme??Pe.viseme).trim(),viseme:Pe.viseme,startSec:Number(Ve?.start??0),durationSec:Number(Ve?.duration??0),vtimeMs:Pe.vtime,vdurationMs:Pe.vduration}})})},V=(p,B,se,de)=>{if(p.length===0&&B.length===0)return;ji(i,s,p,B,o,c);const be=zi(p,o);let Ie=null;const Pe=se.trim();if(Pe)try{const Ke=atob(Pe.replace(/\s+/g,"")).length,Ve=Number.isFinite(de)&&(de??0)>0?Number(de):16e3;Ie=Ke/2/Ve*1e3}catch{Ie=null}o=Math.max(be,Ie!=null?o+Ie:o)},K=p=>{if(J(p))return;const B=Wr(p);B&&(oe(),ne());const se=String(p.spoken_text??p.text??"").trim(),de=p.visemes??[],be=p.words??[],Ie=String(p.chunk??"").trim(),Pe=Q||B||!te;Q&&(Q=!1),Pe&&(te=!0),se&&(d=se),w(p,B),Pe?(I.resetForNewStream(c),i.length=0,s.length=0,o=0):B&&I.resumeBotStream(),V(de,be,Ie,p.sample_rate);const Ke=n.length;I.playAudioChunk(n,r,Ie,de,be,B,{sampleRate:p.sample_rate,newStream:Pe,audioOffsetMs:Number(p.audio_offset_ms??0),onNewStream:()=>{u.length=0}}).then(()=>{P(p,se,Ke,de),Z("audio_chunk",se),ge()})},ue=p=>{if(J(p))return;(p.is_new_segment||Number(p.audio_offset_ms??-1)===0)&&ne(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const B=String(p.spoken_text??p.text??"").trim();B&&(d=B),w(p,!!p.is_new_segment),V(p.visemes??[],p.words??[],"",void 0);const se=n.length;I.queueTimingsOnly(n,r,p.visemes??[],p.words??[],!!p.is_new_segment,{audioOffsetMs:Number(p.audio_offset_ms??0)}),P(p,B,se,p.visemes??[]),Z("lipsync",B),ce()},me=async p=>{const B=String(p.text??"").trim();if(!B)return;const se=h.authToken?.trim();if(!se){console.error("[realtimeVoice] avatar_speak requires authToken");return}C?.abort();const de=new AbortController;C=de;const be=++G;ne(),I.resetForNewStream(c),d=B;const Pe=`${(h.apiBase??Bt).replace(/\/$/,"")}/avatar_ttsWithPoses`,Ke=lt(c,h.voiceId);Ke.ttsEngineId&&(c=Ke.ttsEngineId,I.setStreamTtsEngineId(c));const Ve=Ke.voiceId?.trim()||(c===dt?wn:fr),qt=h.speakingRate??Gt,xn=Math.max(Sn,Math.min(Tn,qt)),Nt={user_query:B,ttsEngineId:c,speakingRate:xn,tenant:"aiTwin"};jn.has(c)&&(Nt.voice_id=Ve);const St=gn(h.language);St&&(Nt.language=St);try{const Oe=await fetch(Pe,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${se}`},body:JSON.stringify(Nt),signal:de.signal});if(!Oe.ok)throw new Error(`avatar_ttsWithPoses failed (${Oe.status})`);const Je=Oe.body;if(!Je)throw new Error("No response body");const Tt=Je.getReader(),Ae=new TextDecoder;let Ce="",Ze=!0;const We=async je=>{if(be!==G||de.signal.aborted||!F)return;const Me=Ai(je);if(Me){if(Me.event==="audio"){const Be=Me.data.chunk,Ge=Me.data.visemes??[],st=Me.data.words??[],qe=Me.data.is_new_segment??!1,ze=Me.data.sample_rate,kt=Number(Me.data.audio_offset_ms??0);if(Be){const xt=Ze;Ze=!1,await I.playAudioChunk(n,r,Be,Ge,st,qe,{sampleRate:ze,newStream:xt,audioOffsetMs:kt})}else(Ge.length>0||st.length>0)&&I.queueTimingsOnly(n,r,Ge,st,qe,{audioOffsetMs:kt,newStream:Ze})}else if(Me.event==="metadata"){const Be=Me.data.mood;typeof Be=="string"&&Be.trim()&&(l=Be.trim());const Ge=Me.data.sentence_emotions;Array.isArray(Ge)&&(a.length=0,a.push(...Ln(Ge,l))),ce()}else if(Me.event==="error")throw new Error(String(Me.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(be!==G||de.signal.aborted||!F);){const{done:je,value:Me}=await Tt.read();Me&&(Ce+=Ae.decode(Me,{stream:!0}));const Be=Ce.split(`
|
|
4
4
|
|
package/dist/aitwin.js
CHANGED
|
@@ -5,7 +5,7 @@ import { WebSocketTransport as sa, DailyMediaManager as oa, ProtobufFrameSeriali
|
|
|
5
5
|
import { Filter as la, GlProgram as ua, Application as da, RendererType as fa, Sprite as qt, Texture as Ne, VideoSource as ma, Rectangle as ha } from "pixi.js";
|
|
6
6
|
const pa = "https://aitwin.bubu.social", ci = {
|
|
7
7
|
publicBase: pa
|
|
8
|
-
}, wa = "0.7.
|
|
8
|
+
}, wa = "0.7.4", ga = {
|
|
9
9
|
version: wa
|
|
10
10
|
}, ya = {}, Nt = "https://ai.aitwin.me", Yn = `${ci.publicBase}/custom-faces`, va = `${ci.publicBase}/aitwin-workers/v${ga.version}/visemeDiffPreview.worker.js`;
|
|
11
11
|
function _a(e) {
|