@streamoji/avatar-widget 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avatar-widget.js +2264 -560
- package/dist/avatar-widget.js.map +1 -1
- package/dist/avatar-widget.umd.cjs +9 -0
- package/dist/avatar-widget.umd.cjs.map +1 -0
- package/dist/avatar-widget.umd.js +1 -1
- package/dist/avatar-widget.umd.js.map +1 -1
- package/package.json +1 -1
- package/dist/avatar-widget.cjs +0 -8
- package/dist/avatar-widget.cjs.map +0 -1
- /package/dist/{avatar-widget.css → style.css} +0 -0
|
@@ -4150,7 +4150,7 @@ void main() {
|
|
|
4150
4150
|
`);){const pt=Bt.current.indexOf(`
|
|
4151
4151
|
`),O=Bt.current.slice(0,pt).trim();Bt.current=Bt.current.slice(pt+1);const Y=Oe(O);Y&&pe(Y)}};Ce.useEffect(()=>{(async()=>{if(!sessionStorage.getItem("STREAMOJI_LEADS_SESSION_LEAD_ID")){const O="secret",Y=Math.floor(Date.now()/1e3).toString();try{const ee=new TextEncoder,ge=await crypto.subtle.importKey("raw",ee.encode(O),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),Me=await crypto.subtle.sign("HMAC",ge,ee.encode(Y)),Ze=Array.from(new Uint8Array(Me)).map(He=>He.toString(16).padStart(2,"0")).join("");sessionStorage.setItem("STREAMOJI_LEADS_SESSION_LEAD_ID",Ze),$a("[SESSION] New HMAC UID generated and saved:",Ze)}catch(ee){console.error("[SESSION] HMAC generation failed:",ee);const ge=Math.random().toString(36)+Date.now().toString();sessionStorage.setItem("STREAMOJI_LEADS_SESSION_LEAD_ID",ge)}}sessionStorage.getItem("STREAMOJI_LEADS_SESSION_MESSAGES")||sessionStorage.setItem("STREAMOJI_LEADS_SESSION_MESSAGES",JSON.stringify([]))})()},[]);const Lt=()=>{try{return JSON.parse(sessionStorage.getItem("STREAMOJI_LEADS_SESSION_MESSAGES")||"[]")}catch{return[]}},xt=rt=>{sessionStorage.setItem("STREAMOJI_LEADS_SESSION_MESSAGES",JSON.stringify(rt))},[Ot,kt]=Ce.useState(!1),[Je,qe]=Ce.useState(0),_t=Ce.useRef(null),At=Ce.useRef([]),ot=Ce.useRef(0),[Ht,me]=Ce.useState(null),[Ue,st]=Ce.useState(null),St=Ce.useRef(null),je=Ce.useRef(null),ke=Ce.useCallback(()=>{D.current=[],w.current=!1,b(!1),z.current=0,k.current=0,N.current=0,H.current.forEach(rt=>{try{rt.stop()}catch{}}),fn.current&&(clearTimeout(fn.current),fn.current=null),en(null),ce(""),H.current=[]},[]),mt=async()=>{try{const rt=await navigator.mediaDevices.getUserMedia({audio:!0}),pt=window.AudioContext||window.webkitAudioContext,O=new pt,Y=O.createMediaStreamSource(rt),ee=O.createAnalyser();ee.fftSize=64,Y.connect(ee),St.current=O,je.current=Y,st(ee);const ge=new MediaRecorder(rt);_t.current=ge,At.current=[],ge.ondataavailable=Me=>{Me.data.size>0&&At.current.push(Me.data)},ge.onstop=async()=>{const Me=Date.now()-ot.current;if(st(null),je.current&&(je.current.disconnect(),je.current=null),St.current&&St.current.state!=="closed"&&(St.current.close(),St.current=null),Me<1e3){_("Recording too short. Hold or click longer."),y(!1);return}const be=new Blob(At.current,{type:"audio/wav"});await Ca(be)},ot.current=Date.now(),ge.start(100),kt(!0),_("Listening...")}catch(rt){console.error("Error accessing microphone:",rt),_("Mic Access Error")}},tn=()=>{_t.current&&_t.current.state!=="inactive"&&(_t.current.stop(),_t.current.stream.getTracks().forEach(rt=>rt.stop()),kt(!1))},Tn=()=>{_t.current&&_t.current.state!=="inactive"&&(_t.current.onstop=null,_t.current.stop(),_t.current.stream.getTracks().forEach(rt=>rt.stop()),st(null),je.current&&(je.current.disconnect(),je.current=null),St.current&&St.current.state!=="closed"&&(St.current.close(),St.current=null),kt(!1),At.current=[],_("Ready"))};Ce.useEffect(()=>{if(!x)return;const rt=()=>{const pt=N.current;if(pt<=0)return;const O=U.current,Y=z.current;if(!O)return;const ee=O.currentTime-Y,ge=Math.min(Math.max(0,ee),pt),Me=h.trim().length;if(Me<=0)return;const be=Math.min(Math.round(ge/pt*Me),Me);ae(be)};return clearInterval(ie.current??void 0),ie.current=setInterval(rt,90),()=>clearInterval(ie.current??void 0)},[x,h,N.current]),Ce.useEffect(()=>{let rt;return Ot?(qe(0),rt=window.setInterval(()=>{qe(pt=>pt+1)},1e3)):qe(0),()=>clearInterval(rt)},[Ot]);const yn=rt=>{const pt=rt.numberOfChannels,O=rt.length*pt*2+44,Y=new ArrayBuffer(O),ee=new DataView(Y);let ge=0;const Me=Ve=>{ee.setUint16(ge,Ve,!0),ge+=2},be=Ve=>{ee.setUint32(ge,Ve,!0),ge+=4};be(1179011410),be(O-8),be(1163280727),be(544501094),be(16),Me(1),Me(pt),be(rt.sampleRate),be(rt.sampleRate*2*pt),Me(pt*2),Me(16),be(1635017060),be(O-ge-4);const Ze=[];for(let Ve=0;Ve<pt;Ve++)Ze.push(rt.getChannelData(Ve));let He=0;for(;ge<O;){for(let Ve=0;Ve<pt;Ve++){let Ge=Math.max(-1,Math.min(1,Ze[Ve][He]));Ge=Ge<0?Ge*32768:Ge*32767,ee.setInt16(ge,Ge,!0),ge+=2}He++}return new Blob([Y],{type:"audio/wav"})},vi=async(rt,pt,O=!1)=>{if(R.current){T.current.push({audio:rt,visemes:pt,isNewSegment:O});return}R.current=!0;try{const Y=window.AudioContext||window.webkitAudioContext,ee=U.current??new Y;ee.state==="suspended"&&await ee.resume(),U.current=ee;const ge=window.atob(rt),Me=new Uint8Array(ge.length);for(let V=0;V<ge.length;V++)Me[V]=ge.charCodeAt(V);const be=await ee.decodeAudioData(Me.buffer.slice(0));N.current+=be.duration;const Ze=ee.currentTime;let He=k.current;const Ve=!w.current;He<Ze&&(He=Ze+.1),k.current=He+be.duration;const Ge=ee.createBufferSource();Ge.buffer=be;let tt=Ht;if((!tt||tt.context!==ee)&&(tt=ee.createAnalyser(),tt.fftSize=64,tt.connect(ee.destination),me(tt)),Ge.connect(tt),H.current.push(Ge),Ve){w.current=!0,b(!0),$a(`[AUDIO] setIsSpeaking(true) - First chunk starting at ${He.toFixed(3)}`),z.current=He;const V=(He-Ze)*1e3;M.current=performance.now()+V,$a(`[AUDIO] Response started. Initial startTime: ${He.toFixed(3)}, CT: ${Ze.toFixed(3)}`)}Ge.start(He);const nt=(He-z.current)*1e3;O&&(F.current=nt,$a(`[AUDIO] New segment detected at +${nt.toFixed(0)}ms. Resetting segment offset.`)),pt.forEach((V,te)=>{const ue=V.symbol??"";if(ue){const he=GF(ue),fe=Math.round(V.start*1e3),We=Math.round((V.duration??0)*1e3),lt=F.current+fe;te<3&&$a(`[AUDIO] Viseme "${ue}": segment_relative=${fe}ms, segment_offset=${F.current.toFixed(0)}ms => vtime=${lt}ms`),he.forEach(ct=>{D.current.push({viseme:ct.v,weight:ct.w,vtime:lt,vduration:We})})}}),_("Speaking...")}finally{if(R.current=!1,T.current.length>0){const Y=T.current.shift();Y&&vi(Y.audio,Y.visemes,Y.isNewSegment)}}},Ca=async rt=>{try{y(!0),Dt.current="",d(""),_("Processing Voice...");const pt=await rt.arrayBuffer(),Y=await new(window.AudioContext||window.webkitAudioContext)().decodeAudioData(pt),ee=yn(Y),ge=new FileReader;ge.readAsDataURL(ee),ge.onloadend=async()=>{const Me=ge.result.split(",")[1];ke(),l(""),Bt.current="",ft.current=!1;const be=`${fC}/stt?token=${encodeURIComponent(n)}`,Ze=await fetch(be,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({audio_base64:Me,audio_format:"wav"})});if(!Ze.ok){const te=await Ze.text();let ue="STT Failed";try{ue=JSON.parse(te).error||ue}catch{te&&(ue=te.slice(0,200))}throw new Error(ue)}const He=Ze.body;if($a("this is body"+He),!He){_("STT Failed"),y(!1);return}const Ve=He.getReader(),Ge=new TextDecoder;let tt="",nt=!1;const V=async(te,ue)=>{switch(te){case"transcript":ue.transcript!=null&&l(String(ue.transcript));break;case"text":{const he=ue.delta??ue.text??"";he&&Le(he);break}case"audio":{const he=ue.chunk,fe=ue.visemes??[],We=!!ue.is_new_segment;he&&await vi(he,fe,We);break}case"done":{nt=!0,_("Ready"),y(!1);break}case"error":{nt=!0,_("STT Failed"),y(!1);break}default:break}};for(;;){const{done:te,value:ue}=await Ve.read();ue&&(tt+=Ge.decode(ue,{stream:!0}));const he=tt.split(`
|
|
4152
4152
|
|
|
4153
|
-
`);tt=he.pop()??"";for(const fe of he){const We=es(fe);We&&await V(We.event,We.data)}if(te){if(tt.trim()){const fe=es(tt.trim());fe&&await V(fe.event,fe.data)}nt||(_("Ready"),y(!1));break}}}}catch(pt){console.error("Audio Submission Error:",pt),_("STT Failed"),y(!1)}},eo=async rt=>{rt&&rt.preventDefault(),Dt.current="",d(""),!(!o||v)&&await wa(o)},es=rt=>{const pt=rt.split(/\r?\n/);let O="",Y="";for(const ge of pt)ge.startsWith("event:")?O=ge.slice(6).trim():ge.startsWith("data:")&&(Y=ge.slice(5).trim());if(!O)return null;let ee={};if(Y)try{ee=JSON.parse(Y)}catch{ee={raw:Y}}return{event:O,data:ee}},Ra=(rt,pt)=>{switch(rt){case"connected":Bt.current="",ft.current=!1;break;case"text":{const O=pt.delta??"";O&&Le(O);break}case"audio":{const O=pt.chunk,Y=pt.visemes??[];O&&vi(O,Y);break}case"done":{const O=Lt(),Y=Dt.current.trim(),ee=[...O,{role:"user",content:o||"..."},{role:"assistant",content:Y}];xt(ee),I.current=[...D.current],_("Ready"),y(!1),l("");break}case"error":{const O=pt.message??"Unknown error";Dt.current=O,d(O),_("Agent Failed"),y(!1);break}}},wa=async rt=>{y(!0),_("Thinking..."),Dt.current="",Bt.current="",ft.current=!1,ke(),N.current=0,ae(0);const pt=`${fC}/agent/chat?token=${encodeURIComponent(n)}`;try{const O=Lt();let Y=sessionStorage.getItem("STREAMOJI_LEADS_SESSION_LEAD_ID");Y||(CF("[CHAT] Session UID missing at send time! Generating emergency backup."),Y="emergency-"+Math.random().toString(36).substring(7),sessionStorage.setItem("STREAMOJI_LEADS_SESSION_LEAD_ID",Y));const ee={history:O,question:rt,lead_id:Y};$a("[CHAT] Sending payload:",ee);const ge=await fetch(pt,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(ee)});if(!ge.ok)throw new Error("Agent request failed");const Me=ge.body;if(!Me){_("Agent Failed"),y(!1);return}const be=Me.getReader(),Ze=new TextDecoder;let He="";for(;;){const{done:Ve,value:Ge}=await be.read();$a(`[SSE] Chunk received. done=${Ve}, length=${Ge?.length||0}`),Ge&&(He+=Ze.decode(Ge,{stream:!0}));const tt=He.split(`
|
|
4153
|
+
`);tt=he.pop()??"";for(const fe of he){const We=es(fe);We&&await V(We.event,We.data)}if(te){if(tt.trim()){const fe=es(tt.trim());fe&&await V(fe.event,fe.data)}nt||(_("Ready"),y(!1));break}}}}catch(pt){console.error("Audio Submission Error:",pt),_("STT Failed"),y(!1)}},eo=async rt=>{rt&&rt.preventDefault(),Dt.current="",d(""),!(!o||v)&&await wa(o)},es=rt=>{const pt=rt.split(/\r?\n/);let O="",Y="";for(const ge of pt)ge.startsWith("event:")?O=ge.slice(6).trim():ge.startsWith("data:")&&(Y=ge.slice(5).trim());if(!O)return null;let ee={};if(Y)try{ee=JSON.parse(Y)}catch{ee={raw:Y}}return{event:O,data:ee}},Ra=(rt,pt)=>{switch(rt){case"connected":Bt.current="",ft.current=!1;break;case"text":{const O=pt.delta??"";O&&Le(O);break}case"audio":{const O=pt.chunk,Y=pt.visemes??[];O&&vi(O,Y);break}case"done":{const O=Lt(),Y=Dt.current.trim(),ee=[...O,{role:"user",content:o||"..."},{role:"assistant",content:Y}];xt(ee),I.current=[...D.current],_("Ready"),y(!1),l("");break}case"error":{const O=pt.message??"Unknown error";Dt.current=O,d(O),_("Agent Failed"),y(!1);break}}},wa=async rt=>{y(!0),_("Thinking..."),Dt.current="",Bt.current="",ft.current=!1,ke(),N.current=0,ae(0);const pt=`${fC}/agent/chat?token=${encodeURIComponent(n)}`;try{const O=Lt();let Y=sessionStorage.getItem("STREAMOJI_LEADS_SESSION_LEAD_ID");Y||(CF("[CHAT] Session UID missing at send time! Generating emergency backup."),Y="emergency-"+Math.random().toString(36).substring(7),sessionStorage.setItem("STREAMOJI_LEADS_SESSION_LEAD_ID",Y));const ee={history:O,question:rt,lead_id:Y};$a("[CHAT] Sending payload:",ee);const ge=await fetch(pt,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(ee),cache:"default"});if(!ge.ok)throw new Error("Agent request failed");const Me=ge.body;if(!Me){_("Agent Failed"),y(!1);return}const be=Me.getReader(),Ze=new TextDecoder;let He="";for(;;){const{done:Ve,value:Ge}=await be.read();$a(`[SSE] Chunk received. done=${Ve}, length=${Ge?.length||0}`),Ge&&(He+=Ze.decode(Ge,{stream:!0}));const tt=He.split(`
|
|
4154
4154
|
|
|
4155
4155
|
`);He=tt.pop()??"";for(const nt of tt){$a(`[SSE] Processing block: ${nt.slice(0,50)}...`);const V=es(nt);V&&($a(`[SSE] Event: ${V.event}`),Ra(V.event,V.data))}if(Ve){if($a("[SSE] Stream finished"),He.trim()){const nt=es(He.trim());nt&&Ra(nt.event,nt.data)}_("Ready"),y(!1),l("");break}}}catch(O){console.error("Chat Error:",O),_("Agent Failed"),y(!1)}},Ba=h.trim(),bi=Ba&&x?Ba.slice(0,W!=null&&W>0?W:0):"";Ce.useEffect(()=>{const rt=$.current;rt!=="exiting"&&(bi?(ht(bi),rt==="hidden"&&$e("entering")):(rt==="visible"||rt==="entering")&&$e("exiting"))},[bi,Fe]);const jt=Ce.useCallback(()=>{const rt=$.current;rt==="entering"?$e("visible"):rt==="exiting"&&$e("hidden")},[]);return Ce.useLayoutEffect(()=>{const rt=Xt.current;rt&&(rt.scrollTop=rt.scrollHeight)},[Pe]),Vt.jsxs("div",{className:"avatar-widget-container",children:[Vt.jsxs("div",{className:"avatar-input-area",children:[Ee!=="hidden"?Vt.jsx("div",{className:`avatar-thinking-tab${Ee==="exiting"?" avatar-thinking-tab--exiting":Ee==="entering"?" avatar-thinking-tab--entering":""}`,onAnimationEnd:G,children:ve}):null,Vt.jsx("div",{className:"avatar-input-container",children:Vt.jsx("div",{style:{display:"flex",alignItems:"center",width:"100%",height:"100%"},children:Ot?Vt.jsxs("div",{className:"avatar-input-recording",children:[Vt.jsx("button",{type:"button",className:"avatar-recording-cancel",onClick:Tn,title:"Cancel",children:Vt.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",style:{display:"block"},children:[Vt.jsx("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),Vt.jsx("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]})}),Vt.jsxs("div",{style:{flex:1,height:"100%",position:"relative",display:"flex",alignItems:"center",minWidth:0},children:[Vt.jsx("div",{style:{flex:1,height:"100%"},children:Vt.jsx(uC,{analyser:Ue})}),Vt.jsxs("span",{style:{fontSize:"0.75rem",color:"#64748b",fontWeight:500,marginLeft:"4px",minWidth:"32px",textAlign:"right",fontVariantNumeric:"tabular-nums"},children:[Math.floor(Je/60),":",String(Je%60).padStart(2,"0")]})]}),Vt.jsx("button",{type:"button",className:"avatar-recording-confirm",onClick:tn,title:"Send",children:Vt.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",style:{display:"block"},children:Vt.jsx("polyline",{points:"20 6 9 17 4 12"})})})]}):x?Vt.jsx("div",{style:{flex:1,height:"100%",display:"flex",alignItems:"center",paddingRight:"8px"},children:Vt.jsx(uC,{analyser:Ht})}):v?Vt.jsx("div",{style:{flex:1,height:"100%",display:"flex",alignItems:"center",justifyContent:"center"},children:Vt.jsx("div",{className:"avatar-input-loader"})}):Vt.jsxs("form",{onSubmit:eo,style:{flex:1,display:"flex",height:"100%",alignItems:"center"},children:[Vt.jsx("input",{id:"avatar-text-input",type:"text",value:o,onChange:rt=>l(rt.target.value),placeholder:"Ask me anything",disabled:v,autoComplete:"off",style:{width:"100%",height:"100%"}}),o.trim()===""?Vt.jsx("button",{type:"button",className:"mic-button",onClick:mt,disabled:v,style:{backgroundColor:"#1e4a5e"},children:Vt.jsxs("svg",{width:"28",height:"28",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[Vt.jsx("path",{d:"M12 14C13.66 14 15 12.66 15 11V5C15 3.34 13.66 2 12 2C10.34 2 9 3.34 9 5V11C9 12.66 10.34 14 12 14Z",fill:"white"}),Vt.jsx("path",{d:"M17 11C17 13.76 14.76 16 12 16C9.24 16 7 13.76 7 11H5C5 14.53 7.61 17.43 11 17.93V21H13V17.93C16.39 17.43 19 14.53 19 11H17Z",fill:"white"})]})}):Vt.jsx("button",{type:"submit",className:"mic-button",disabled:v,style:{backgroundColor:"#1e4a5e"},title:"Send",children:Vt.jsxs("svg",{width:"22",height:"22",viewBox:"0 0 24 24",fill:"none","aria-hidden":"true",children:[Vt.jsx("path",{d:"M22 2L11 13",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),Vt.jsx("path",{d:"M22 2L15 22L11 13L2 9L22 2Z",stroke:"white",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})})]})})})]}),Vt.jsx("div",{className:"avatar-wrapper",children:Vt.jsxs("div",{className:"avatar-scene-wrapper",children:[Fe!=="hidden"&&Vt.jsx("div",{className:`avatar-bubble${Fe==="entering"?" avatar-bubble--entering":Fe==="exiting"?" avatar-bubble--exiting":""}`,onAnimationEnd:jt,children:Vt.jsx("div",{ref:Xt,className:"avatar-bubble__content",children:Pe})}),Vt.jsx("div",{className:"avatar-canvas-layer",style:{width:600,height:600},children:Vt.jsxs(RO,{shadows:!0,camera:{position:[.2,1.4,3],fov:42},gl:{alpha:!0},dpr:1.8,style:{pointerEvents:"none",width:"100%",height:"100%"},children:[Vt.jsx(zF,{target:OF}),Vt.jsx("ambientLight",{intensity:.7}),Vt.jsx("directionalLight",{position:[0,2,2],intensity:1}),Vt.jsx(YI,{preset:"city"}),Vt.jsx(Ce.Suspense,{fallback:null,children:i!==null&&Vt.jsx(VF,{avatarUrl:i,isPlayingRef:w,visemeQueueRef:D,audioContextRef:U,responseAudioStartTimeRef:z,adjustments:LF,mood:re,expression:P,agentResponse:h,isSpeaking:x,nextStartTimeRef:k,stopPlayback:ke,setIsSpeaking:b,expressionUrl:Q,onExpressionFinished:Ye})})]})})]})})]})},YF=({token:s,onNavigationRequested:e})=>Vt.jsx(XF,{token:s,onNavigationRequested:e}),dC="streamoji-leads-avatar-widget-root";function pC(s){const{token:e}=s;let t=document.getElementById(dC);if(!t){t=document.createElement("div"),t.id=dC,t.style.cssText="position:fixed;bottom:0;right:0;z-index:9999;pointer-events:none;";const i=document.createElement("div");i.style.cssText="pointer-events:auto;",t.appendChild(i),document.body.appendChild(t),t=i}pR.createRoot(t).render(MM.createElement(YF,{token:e||""}))}return window.StreamojiLeadsAvatarWidget={init:pC},Oy.init=pC,Object.defineProperty(Oy,Symbol.toStringTag,{value:"Module"}),Oy})({});
|
|
4156
4156
|
//# sourceMappingURL=avatar-widget.umd.js.map
|