@glydeunity/voice-sdk 1.3.6 → 1.4.1

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.
@@ -0,0 +1,271 @@
1
+ (function(c,l){typeof exports=="object"&&typeof module<"u"?l(exports,require("react"),require("react/jsx-runtime"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react","react/jsx-runtime","react-dom/client"],l):(c=typeof globalThis<"u"?globalThis:c||self,l(c.GlydeChat={},c.React,c.jsxRuntime,c.ReactDOM))})(this,(function(c,l,t,V){"use strict";const oe=`
2
+ class AudioCaptureProcessor extends AudioWorkletProcessor {
3
+ constructor() {
4
+ super();
5
+ this.bufferSize = 4096;
6
+ this.buffer = new Float32Array(this.bufferSize);
7
+ this.bufferIndex = 0;
8
+ }
9
+
10
+ process(inputs) {
11
+ const input = inputs[0];
12
+ if (!input || !input[0]) return true;
13
+
14
+ const samples = input[0];
15
+
16
+ for (let i = 0; i < samples.length; i++) {
17
+ this.buffer[this.bufferIndex++] = samples[i];
18
+
19
+ if (this.bufferIndex >= this.bufferSize) {
20
+ const pcm16 = new Int16Array(this.bufferSize);
21
+ for (let j = 0; j < this.bufferSize; j++) {
22
+ const s = Math.max(-1, Math.min(1, this.buffer[j]));
23
+ pcm16[j] = s < 0 ? s * 0x8000 : s * 0x7FFF;
24
+ }
25
+
26
+ this.port.postMessage(pcm16.buffer, [pcm16.buffer]);
27
+ this.bufferIndex = 0;
28
+ }
29
+ }
30
+
31
+ return true;
32
+ }
33
+ }
34
+
35
+ registerProcessor('audio-capture-processor', AudioCaptureProcessor);
36
+ `,ie=`
37
+ class AudioPlaybackProcessor extends AudioWorkletProcessor {
38
+ constructor() {
39
+ super();
40
+
41
+ this.bufferSize = 48000 * 15;
42
+ this.buffer = new Float32Array(this.bufferSize);
43
+ this.writeIndex = 0;
44
+ this.readIndex = 0;
45
+ this.samplesAvailable = 0;
46
+ this.isPlaying = false;
47
+
48
+ this.port.onmessage = (event) => {
49
+ const { type, data } = event.data;
50
+
51
+ switch (type) {
52
+ case 'audio':
53
+ const audioData = data instanceof Float32Array ? data : new Float32Array(data);
54
+ this.writeAudio(audioData);
55
+ break;
56
+ case 'clear':
57
+ this.clearBuffer();
58
+ break;
59
+ }
60
+ };
61
+ }
62
+
63
+ writeAudio(samples) {
64
+ if (!samples || samples.length === 0) return;
65
+
66
+ const samplesToWrite = samples.length;
67
+
68
+ if (this.samplesAvailable + samplesToWrite > this.bufferSize) {
69
+ const overflow = (this.samplesAvailable + samplesToWrite) - this.bufferSize;
70
+ this.readIndex = (this.readIndex + overflow) % this.bufferSize;
71
+ this.samplesAvailable -= overflow;
72
+ }
73
+
74
+ for (let i = 0; i < samplesToWrite; i++) {
75
+ this.buffer[this.writeIndex] = samples[i];
76
+ this.writeIndex = (this.writeIndex + 1) % this.bufferSize;
77
+ }
78
+
79
+ this.samplesAvailable += samplesToWrite;
80
+ this.isPlaying = true;
81
+ }
82
+
83
+ clearBuffer() {
84
+ this.readIndex = 0;
85
+ this.writeIndex = 0;
86
+ this.samplesAvailable = 0;
87
+ this.isPlaying = false;
88
+ this.port.postMessage({ type: 'cleared' });
89
+ }
90
+
91
+ process(inputs, outputs) {
92
+ const output = outputs[0];
93
+ if (!output || !output[0]) return true;
94
+
95
+ const outputChannel = output[0];
96
+ const samplesToRead = outputChannel.length;
97
+
98
+ if (this.samplesAvailable >= samplesToRead) {
99
+ for (let i = 0; i < samplesToRead; i++) {
100
+ outputChannel[i] = this.buffer[this.readIndex];
101
+ this.readIndex = (this.readIndex + 1) % this.bufferSize;
102
+ }
103
+ this.samplesAvailable -= samplesToRead;
104
+ } else if (this.samplesAvailable > 0) {
105
+ let i = 0;
106
+ while (this.samplesAvailable > 0 && i < samplesToRead) {
107
+ outputChannel[i] = this.buffer[this.readIndex];
108
+ this.readIndex = (this.readIndex + 1) % this.bufferSize;
109
+ this.samplesAvailable--;
110
+ i++;
111
+ }
112
+ while (i < samplesToRead) {
113
+ outputChannel[i] = 0;
114
+ i++;
115
+ }
116
+
117
+ if (this.isPlaying) {
118
+ this.isPlaying = false;
119
+ this.port.postMessage({ type: 'bufferEmpty' });
120
+ }
121
+ } else {
122
+ for (let i = 0; i < samplesToRead; i++) {
123
+ outputChannel[i] = 0;
124
+ }
125
+ this.isPlaying = false;
126
+ }
127
+
128
+ return true;
129
+ }
130
+ }
131
+
132
+ registerProcessor('audio-playback-processor', AudioPlaybackProcessor);
133
+ `;class D{config;unityUrl;active=!1;serverConfig=null;ws=null;audioContext=null;mediaStream=null;captureWorkletNode=null;playbackWorkletNode=null;isMuted=!1;outputSampleRate=24e3;inputSampleRate=48e3;isAgentSpeaking=!1;agentAudioDoneReceived=!1;conversationHistory=[];sessionContext={};constructor(e){this.config=e,this.unityUrl=e.unityBaseUrl||"https://api.glydeunity.com",e.conversationHistory&&(this.conversationHistory=e.conversationHistory),!e.publishableKey&&!e.apiKey&&!e.authToken&&console.warn("[GlydeVoice] No authentication method provided. One of publishableKey, apiKey, or authToken is required.")}getAuthHeaders(){const e={"Content-Type":"application/json"};return this.config.publishableKey&&(e["x-publishable-key"]=this.config.publishableKey),this.config.apiKey&&(e["x-api-key"]=this.config.apiKey),this.config.authToken&&(e.Authorization=`Bearer ${this.config.authToken}`),e}async fetchConfig(){const e=`${this.unityUrl}/api/unity/voice/config/${this.config.contextType}`,r=this.config.contextId?`${e}/${this.config.contextId}`:e,i=await fetch(r,{method:"GET",headers:this.getAuthHeaders()});if(!i.ok){const n=await i.json();throw new Error(n.error?.message||n.message||"Failed to fetch voice config")}const{data:s}=await i.json();return s}async start(){if(!this.active){this.active=!0;try{this.config.systemPrompt||(this.serverConfig=await this.fetchConfig(),console.log("[GlydeVoice] Fetched config:",this.serverConfig));const e={context_id:this.config.contextId,domain:typeof window<"u"?window.location.hostname:"localhost"};this.config.systemPrompt&&(e.system_prompt=this.config.systemPrompt),this.config.deepgramConfig&&(e.deepgram_config=this.config.deepgramConfig);const r=await fetch(`${this.unityUrl}/api/unity/voice/auth`,{method:"POST",headers:this.getAuthHeaders(),body:JSON.stringify(e)});if(!r.ok){const a=await r.json();throw new Error(a.error?.message||a.message||"Failed to authenticate voice session")}const{data:i}=await r.json(),{token:s,agent_config:n,deepgram_config:h}=i;this.setSessionContext({clientUuid:n?.client_uuid,contextId:this.config.contextId,contextType:this.config.contextType,currentJobUuid:n?.job_uuid});let f=this.config.systemPrompt||n.instructions||this.serverConfig?.system_prompt||"You are a helpful AI assistant.";this.conversationHistory&&this.conversationHistory.length>0&&(f=`Previous conversation context:
134
+ ${this.conversationHistory.map(g=>`${g.role==="agent"?"Assistant":"User"}: ${g.content}`).join(`
135
+ `)}
136
+
137
+ IMPORTANT: This is a continuation of a previous conversation. When the user starts speaking, you must first greet them warmly and acknowledge that you're continuing the conversation. Say something like "Welcome back! I'm glad you're continuing our conversation. How can I help you today?" or similar, then continue naturally based on the previous context.
138
+
139
+ ${f}`),await this.initializeAudio();let p="wss://agent.deepgram.com/v1/agent/converse";const u=this.config.deepgramConfig||h||this.serverConfig?.deepgram_config;if(u?.tags&&u.tags.length>0){const a=new URLSearchParams;u.tags.forEach(g=>a.append("tag",g)),p+=`?${a.toString()}`}this.ws=new WebSocket(p,["bearer",s]),this.ws.onopen=()=>{const a=u||{think:{provider:{type:"open_ai",model:"gpt-4.1-nano"}},speak:{provider:{type:"deepgram",model:"aura-2-thalia-en"}},listen:{provider:{type:"deepgram",version:"v2",model:"flux-general-en"}}},g={type:"Settings",audio:{input:{encoding:"linear16",sample_rate:this.inputSampleRate},output:{encoding:"linear16",sample_rate:this.outputSampleRate,container:"none"}},agent:{language:"en",speak:a.speak||{provider:{type:"deepgram",model:"aura-2-thalia-en"}},listen:a.listen||{provider:{type:"deepgram",version:"v2",model:"flux-general-en"}},think:{provider:a.think?.provider||{type:"open_ai",model:"gpt-4.1-nano"},...a.think?.functions&&{functions:a.think.functions}},...!this.conversationHistory||this.conversationHistory.length===0?{greeting:"Hi! I'm excited you chose to speak with me. Are you ready to start?"}:{}}};a.tags&&a.tags.length>0&&(g.tags=a.tags),this.ws.send(JSON.stringify(g)),this.emit({type:"open",payload:{config:n,serverConfig:this.serverConfig}})};const m=f;this.ws.onmessage=a=>{if(typeof a.data=="string"){try{const g=JSON.parse(a.data);if(g.type==="SettingsApplied"){const b={type:"UpdatePrompt",prompt:m};this.ws.send(JSON.stringify(b)),setTimeout(()=>{this.mediaStream||this.startMicrophone().catch(k=>{console.error("[GlydeVoice] Failed to start microphone:",k)})},500)}g.type==="PromptUpdated"&&(this.mediaStream||this.startMicrophone().catch(b=>{console.error("[GlydeVoice] Failed to start microphone:",b)}))}catch{}this.handleTextMessage(a.data)}else a.data instanceof Blob?this.handleAudioData(a.data):a.data instanceof ArrayBuffer&&this.handleAudioBuffer(a.data)},this.ws.onerror=a=>{console.error("[GlydeVoice] WebSocket error:",a),this.emit({type:"error",payload:a})},this.ws.onclose=()=>{this.cleanup(),this.emit({type:"close"})},this.renderUI()}catch(e){throw console.error("[GlydeVoice] Error starting session:",e),this.active=!1,this.emit({type:"error",payload:e}),e}}}createWorkletBlobUrl(e){const r=new Blob([e],{type:"application/javascript"});return URL.createObjectURL(r)}async initializeAudio(){this.audioContext=new AudioContext({sampleRate:this.inputSampleRate});const e=this.createWorkletBlobUrl(oe),r=this.createWorkletBlobUrl(ie);try{await Promise.all([this.audioContext.audioWorklet.addModule(e),this.audioContext.audioWorklet.addModule(r)])}finally{URL.revokeObjectURL(e),URL.revokeObjectURL(r)}this.playbackWorkletNode=new AudioWorkletNode(this.audioContext,"audio-playback-processor"),this.playbackWorkletNode.connect(this.audioContext.destination),this.playbackWorkletNode.port.onmessage=i=>{const{type:s}=i.data;(s==="cleared"||s==="bufferEmpty")&&(this.isAgentSpeaking=!1,this.agentAudioDoneReceived=!1,this.emit({type:"agent_speaking",payload:!1}))}}handleTextMessage(e){try{const r=JSON.parse(e);switch(r.type){case"Welcome":this.emit({type:"ready"});break;case"SettingsApplied":break;case"PromptUpdated":break;case"UserStartedSpeaking":this.emit({type:"user_speaking",payload:!0}),this.clearPlaybackBuffer(),this.isAgentSpeaking=!1,this.agentAudioDoneReceived=!1;break;case"UserStoppedSpeaking":this.emit({type:"user_speaking",payload:!1});break;case"ConversationText":if(r.content&&r.content.trim()){const i=r.role==="assistant"?"agent":"user";this.config.onTranscript&&this.config.onTranscript(r.content,i),this.emit({type:"transcript",payload:{text:r.content,role:i}}),this.saveTranscript(r.content,r.role)}break;case"AgentStartedSpeaking":this.isAgentSpeaking=!0,this.agentAudioDoneReceived=!1,this.emit({type:"agent_speaking",payload:!0});break;case"AgentAudioDone":this.agentAudioDoneReceived=!0;break;case"Error":console.error("[GlydeVoice] Agent error:",r),this.emit({type:"error",payload:r});break;case"FunctionCallRequest":this.handleFunctionCallRequest(r);break}}catch(r){console.error("[GlydeVoice] Failed to parse message:",r)}}async handleAudioData(e){const r=await e.arrayBuffer();this.handleAudioBuffer(r)}handleAudioBuffer(e){if(!this.playbackWorkletNode||!this.audioContext)return;this.audioContext.state==="suspended"&&this.audioContext.resume();const r=e.byteLength;if(r===0)return;const i=r-r%2;if(i===0)return;const s=i===r?e:e.slice(0,i),n=new Int16Array(s),h=new Float32Array(n.length);for(let u=0;u<n.length;u++)h[u]=n[u]/32768;const f=this.resample24kTo48k(h);!this.isAgentSpeaking&&!this.agentAudioDoneReceived&&(this.isAgentSpeaking=!0,this.emit({type:"agent_speaking",payload:!0}));const p=new Float32Array(f);this.playbackWorkletNode.port.postMessage({type:"audio",data:p},[p.buffer])}resample24kTo48k(e){const r=e.length*2,i=new Float32Array(r);for(let n=0;n<e.length-1;n++){const h=e[n],f=e[n+1];i[n*2]=h,i[n*2+1]=(h+f)/2}const s=e.length-1;return i[s*2]=e[s],i[s*2+1]=e[s],i}clearPlaybackBuffer(){this.playbackWorkletNode&&this.playbackWorkletNode.port.postMessage({type:"clear"})}async startMicrophone(){if(!this.audioContext)throw new Error("Audio context not initialized");try{this.mediaStream=await navigator.mediaDevices.getUserMedia({audio:{channelCount:1,sampleRate:this.inputSampleRate,echoCancellation:!0,noiseSuppression:!0}});const e=this.audioContext.createMediaStreamSource(this.mediaStream);this.captureWorkletNode=new AudioWorkletNode(this.audioContext,"audio-capture-processor"),this.captureWorkletNode.port.onmessage=r=>{!this.active||!this.ws||this.ws.readyState!==WebSocket.OPEN||this.isMuted||this.ws.send(r.data)},e.connect(this.captureWorkletNode),this.emit({type:"microphone_ready"})}catch(e){throw console.error("[GlydeVoice] Microphone error:",e),e}}async saveTranscript(e,r){if(!(!this.config.contextId||!e))try{await fetch(`${this.unityUrl}/api/unity/voice/transcript`,{method:"POST",headers:this.getAuthHeaders(),body:JSON.stringify({context_id:this.config.contextId,content:e,role:r==="assistant"?"assistant":"user"})})}catch{}}setMuted(e){this.isMuted=e}getMuted(){return this.isMuted}isActive(){return this.active}getServerConfig(){return this.serverConfig}stop(){this.active=!1,this.cleanup()}cleanup(){this.captureWorkletNode&&(this.captureWorkletNode.disconnect(),this.captureWorkletNode.port.close(),this.captureWorkletNode=null),this.playbackWorkletNode&&(this.playbackWorkletNode.disconnect(),this.playbackWorkletNode.port.close(),this.playbackWorkletNode=null),this.mediaStream&&(this.mediaStream.getTracks().forEach(e=>e.stop()),this.mediaStream=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.ws&&(this.ws.readyState===WebSocket.OPEN&&this.ws.close(),this.ws=null)}emit(e){this.config.onEvent&&this.config.onEvent(e)}renderUI(){if(!this.config.container)return;const e=typeof this.config.container=="string"?document.querySelector(this.config.container):this.config.container;e&&(e.innerHTML=`
140
+ <div style="padding: 20px; border: 1px solid #ccc; border-radius: 8px; background: #fff;">
141
+ <h3>Glyde Voice Agent</h3>
142
+ <p>Status: Active</p>
143
+ <p>Context: ${this.config.contextType}</p>
144
+ <button onclick="this.closest('div').remove()">Close</button>
145
+ </div>
146
+ `)}async handleFunctionCallRequest(e){for(const r of e.functions){console.log("[GlydeVoice] Function call request:",r.name,r.arguments);let i={};try{i=r.arguments?JSON.parse(r.arguments):{}}catch(h){console.warn("[GlydeVoice] Failed to parse function arguments:",h)}let s;try{r.name==="end_conversation"?s=await this.handleEndConversation(i):s=await this.executeVoiceFunction(r.name,r.id,i)}catch(h){console.error("[GlydeVoice] Function call error:",h),s=JSON.stringify({error:"Function execution failed",details:h instanceof Error?h.message:String(h)})}const n={type:"FunctionCallResponse",id:r.id,name:r.name,content:s};this.ws&&this.ws.readyState===WebSocket.OPEN?(this.ws.send(JSON.stringify(n)),console.log("[GlydeVoice] Function response sent:",r.name)):console.error("[GlydeVoice] Cannot send function response - WebSocket not open")}}async executeVoiceFunction(e,r,i){console.log("[GlydeVoice] Executing voice function via Unity API:",e);try{const s=await fetch(`${this.unityUrl}/api/unity/voice/function`,{method:"POST",headers:this.getAuthHeaders(),body:JSON.stringify({function_name:e,function_call_id:r,input:i,context:{context_id:this.sessionContext.contextId,context_type:this.sessionContext.contextType,current_job_uuid:this.sessionContext.currentJobUuid}})});if(!s.ok){const h=await s.json().catch(()=>({}));throw new Error(h.error?.message||`Function call failed: ${s.status}`)}const n=await s.json();if(n.success&&n.data?.output)return typeof n.data.output=="string"?n.data.output:JSON.stringify(n.data.output);throw new Error("Invalid response from voice function endpoint")}catch(s){return console.error("[GlydeVoice] Voice function error:",s),JSON.stringify({success:!1,error:s instanceof Error?s.message:"Function execution failed",fallback_message:"I apologize, but I'm having trouble with that request right now. Is there something else I can help you with?"})}}async handleEndConversation(e){const r=e.item||"user request";return console.log(`[GlydeVoice] End conversation triggered by: ${r}`),setTimeout(()=>{this.stop()},2e3),JSON.stringify({success:!0,message:"Conversation ending. Say goodbye to the user.",trigger_phrase:r})}setSessionContext(e){this.sessionContext={...this.sessionContext,...e},console.log("[GlydeVoice] Session context updated:",{hasContextId:!!e.contextId,contextType:e.contextType,hasJobUuid:!!e.currentJobUuid})}}class G{config;unityUrl;history=[];isTyping=!1;initialized=!1;constructor(e){this.config=e,this.unityUrl=e.unityBaseUrl||"https://api.glydeunity.com",!e.publishableKey&&!e.apiKey&&!e.authToken&&console.warn("[GlydeText] No authentication method provided. One of publishableKey, apiKey, or authToken is required.")}getAuthHeaders(){const e={"Content-Type":"application/json"};return this.config.publishableKey&&(e["x-publishable-key"]=this.config.publishableKey),this.config.apiKey&&(e["x-api-key"]=this.config.apiKey),this.config.authToken&&(e.Authorization=`Bearer ${this.config.authToken}`),e}emit(e){this.config.onEvent&&this.config.onEvent(e)}setTyping(e){this.isTyping=e,this.config.onTyping&&this.config.onTyping(e)}async initialize(){if(!this.config.contextId)throw new Error("contextId is required for text chat initialization");this.setTyping(!0);try{const e=await fetch(`${this.unityUrl}/api/unity/screening/start`,{method:"POST",headers:this.getAuthHeaders(),body:JSON.stringify({application_uuid:this.config.contextId})});if(!e.ok){const i=await e.json().catch(()=>({}));throw new Error(i.error?.message||i.message||"Failed to initialize chat")}const r=await e.json();return r.messages&&(this.history=r.messages),this.initialized=!0,this.emit({type:"ready"}),this.emit({type:"history_loaded",payload:this.history}),this.history}catch(e){throw console.error("[GlydeText] Initialization error:",e),this.emit({type:"error",payload:e}),e}finally{this.setTyping(!1)}}async sendMessage(e){if(!this.config.contextId)throw new Error("contextId is required for sending messages");if(!e.trim())throw new Error("Message cannot be empty");this.initialized||await this.initialize();const r={role:"user",content:e.trim(),created:new Date().toISOString()};this.history.push(r),this.config.onMessage&&this.config.onMessage(r),this.emit({type:"message",payload:r}),this.setTyping(!0);try{const i=await fetch(`${this.unityUrl}/api/unity/screening/chat`,{method:"POST",headers:this.getAuthHeaders(),body:JSON.stringify({application_uuid:this.config.contextId,message:e.trim()})});if(!i.ok){const f=await i.json().catch(()=>({}));throw new Error(f.error?.message||f.message||"Failed to send message")}const s=await i.json();s.history?.messages&&(this.history=s.history.messages);const n=[...this.history].reverse().find(f=>f.role==="assistant");return n?(this.config.onMessage&&this.config.onMessage(n),this.emit({type:"message",payload:n}),n):{role:"assistant",content:s.response||"I received your message.",created:new Date().toISOString()}}catch(i){throw console.error("[GlydeText] Send message error:",i),this.emit({type:"error",payload:i}),i}finally{this.setTyping(!1)}}getHistory(){return[...this.history]}clearHistory(){this.history=[],this.initialized=!1}getIsTyping(){return this.isTyping}getIsInitialized(){return this.initialized}}function H(o){const[e,r]=l.useState("idle"),[i,s]=l.useState([]),[n,h]=l.useState(!1),[f,p]=l.useState(!1),[u,m]=l.useState(!1),[a,g]=l.useState(null),b=l.useRef(null),k=l.useCallback(d=>{switch(d.type){case"ready":r("active");break;case"close":r("idle"),h(!1),p(!1);break;case"error":r("error"),g(typeof d.payload=="object"&&d.payload!==null&&"message"in d.payload?String(d.payload.message):"Connection error");break;case"user_speaking":h(!!d.payload);break;case"agent_speaking":p(!!d.payload);break}},[]),v=l.useCallback((d,M)=>{s(E=>[...E,{role:M,content:d,timestamp:new Date}])},[]),y=l.useCallback(async()=>{r("connecting"),g(null);try{const d=new D({...o,onEvent:k,onTranscript:v});b.current=d,await d.start()}catch(d){console.error("[useVoiceAgent] Failed to start:",d),r("error"),g(d instanceof Error?d.message:"Failed to connect")}},[o,k,v]),w=l.useCallback(()=>{b.current?.stop(),b.current=null,r("idle"),h(!1),p(!1)},[]),C=l.useCallback(()=>{const d=!u;m(d),b.current?.setMuted(d)},[u]),I=l.useCallback(d=>{m(d),b.current?.setMuted(d)},[]),T=l.useCallback(()=>{s([])},[]);return l.useEffect(()=>()=>{b.current?.stop()},[]),l.useEffect(()=>{o.autoStart&&e==="idle"&&y()},[o.autoStart,e,y]),{status:e,transcripts:i,isUserSpeaking:n,isAgentSpeaking:f,isMuted:u,errorMessage:a,start:y,stop:w,toggleMute:C,setMuted:I,clearTranscripts:T,voiceAgent:b.current}}function F(o){const[e,r]=l.useState("idle"),[i,s]=l.useState([]),[n,h]=l.useState(!1),[f,p]=l.useState(null),u=l.useRef(null),m=l.useRef(!1),a=l.useCallback(()=>(u.current||(u.current=new G({...o,onTyping:h})),u.current),[o]),g=l.useCallback(async()=>{if(!m.current){r("loading"),p(null);try{const y=await a().initialize();s(y),r("ready"),m.current=!0}catch(v){console.error("[useTextChat] Initialization error:",v),r("error"),p(v instanceof Error?v.message:"Failed to initialize chat")}}},[a]),b=l.useCallback(async v=>{if(v.trim()){p(null);try{const y=a(),w={role:"user",content:v.trim(),created:new Date().toISOString()};s(I=>[...I,w]),await y.sendMessage(v);const C=y.getHistory();s(C),e!=="ready"&&(r("ready"),m.current=!0)}catch(y){console.error("[useTextChat] Send message error:",y),p(y instanceof Error?y.message:"Failed to send message")}}},[a,e]),k=l.useCallback(()=>{u.current?.clearHistory(),s([]),m.current=!1,r("idle")},[]);return l.useEffect(()=>{o.autoInit&&!m.current&&o.contextId&&g()},[o.autoInit,o.contextId,g]),l.useEffect(()=>()=>{u.current=null},[]),{status:e,messages:i,isLoading:n,errorMessage:f,initialize:g,sendMessage:b,clearHistory:k,textChat:u.current}}const W=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("path",{d:"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"}),t.jsx("path",{d:"M19 10v2a7 7 0 0 1-14 0v-2"}),t.jsx("line",{x1:"12",x2:"12",y1:"19",y2:"22"})]}),se=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("line",{x1:"2",x2:"22",y1:"2",y2:"22"}),t.jsx("path",{d:"M18.89 13.23A7.12 7.12 0 0 0 19 12v-2"}),t.jsx("path",{d:"M5 10v2a7 7 0 0 0 12 5"}),t.jsx("path",{d:"M15 9.34V5a3 3 0 0 0-5.68-1.33"}),t.jsx("path",{d:"M9 9v3a3 3 0 0 0 5.12 2.12"}),t.jsx("line",{x1:"12",x2:"12",y1:"19",y2:"22"})]}),ne=({size:o=24,color:e="currentColor",className:r})=>t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:t.jsx("path",{d:"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"})}),K=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("path",{d:"M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7 2 2 0 0 1 1.72 2v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67m-2.67-3.34a19.79 19.79 0 0 1-3.07-8.63A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91"}),t.jsx("line",{x1:"22",x2:"2",y1:"2",y2:"22"})]}),j=({size:o=24,color:e="currentColor",className:r})=>t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:t.jsx("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})}),J=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("line",{x1:"22",x2:"11",y1:"2",y2:"13"}),t.jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]}),q=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"}),t.jsx("circle",{cx:"12",cy:"7",r:"4"})]}),Y=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("path",{d:"M12 8V4H8"}),t.jsx("rect",{width:"16",height:"12",x:"4",y:"8",rx:"2"}),t.jsx("path",{d:"M2 14h2"}),t.jsx("path",{d:"M20 14h2"}),t.jsx("path",{d:"M15 13v2"}),t.jsx("path",{d:"M9 13v2"})]}),X=({size:o=24,color:e="currentColor",className:r})=>t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:t.jsx("polyline",{points:"22 12 18 12 15 21 9 3 6 12 2 12"})}),Z=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("polygon",{points:"11 5 6 9 2 9 2 15 6 15 11 19 11 5"}),t.jsx("line",{x1:"22",x2:"16",y1:"9",y2:"15"}),t.jsx("line",{x1:"16",x2:"22",y1:"9",y2:"15"})]}),Q=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("line",{x1:"18",x2:"6",y1:"6",y2:"18"}),t.jsx("line",{x1:"6",x2:"18",y1:"6",y2:"18"})]}),R=({size:o=24,color:e="currentColor",className:r})=>t.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,children:[t.jsx("path",{d:"M8 3v3a2 2 0 0 1-2 2H3"}),t.jsx("path",{d:"M21 8h-3a2 2 0 0 1-2-2V3"}),t.jsx("path",{d:"M3 16h3a2 2 0 0 1 2 2v3"}),t.jsx("path",{d:"M16 21v-3a2 2 0 0 1 2-2h3"})]}),ae=({size:o=24,color:e="currentColor",className:r})=>t.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:o,height:o,viewBox:"0 0 24 24",fill:"none",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:r,style:{animation:"spin 1s linear infinite"},children:t.jsx("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})}),ee={light:{primary:"#c026d3",primaryHover:"#a21caf",primaryLight:"#fdf4ff",primaryText:"#ffffff",secondary:"#0284c7",secondaryHover:"#0369a1",secondaryLight:"#f0f9ff",secondaryText:"#ffffff",success:"#059669",successLight:"#dcfce7",successText:"#166534",error:"#ef4444",errorHover:"#dc2626",errorLight:"#fef2f2",errorText:"#b91c1c",background:"#ffffff",surface:"#f9fafb",border:"#e5e7eb",borderLight:"#f3f4f6",text:"#1f2937",textSecondary:"#6b7280",textMuted:"#9ca3af"},dark:{primary:"#d946ef",primaryHover:"#c026d3",primaryLight:"#3b0764",primaryText:"#ffffff",secondary:"#38bdf8",secondaryHover:"#0ea5e9",secondaryLight:"#0c4a6e",secondaryText:"#ffffff",success:"#34d399",successLight:"#064e3b",successText:"#a7f3d0",error:"#f87171",errorHover:"#ef4444",errorLight:"#450a0a",errorText:"#fecaca",background:"#111827",surface:"#1f2937",border:"#374151",borderLight:"#4b5563",text:"#f9fafb",textSecondary:"#d1d5db",textMuted:"#9ca3af"}};function U(o){const e=ee[o];return`
147
+ --glyde-primary: ${e.primary};
148
+ --glyde-primary-hover: ${e.primaryHover};
149
+ --glyde-primary-light: ${e.primaryLight};
150
+ --glyde-primary-text: ${e.primaryText};
151
+ --glyde-secondary: ${e.secondary};
152
+ --glyde-secondary-hover: ${e.secondaryHover};
153
+ --glyde-secondary-light: ${e.secondaryLight};
154
+ --glyde-secondary-text: ${e.secondaryText};
155
+ --glyde-success: ${e.success};
156
+ --glyde-success-light: ${e.successLight};
157
+ --glyde-success-text: ${e.successText};
158
+ --glyde-error: ${e.error};
159
+ --glyde-error-hover: ${e.errorHover};
160
+ --glyde-error-light: ${e.errorLight};
161
+ --glyde-error-text: ${e.errorText};
162
+ --glyde-background: ${e.background};
163
+ --glyde-surface: ${e.surface};
164
+ --glyde-border: ${e.border};
165
+ --glyde-border-light: ${e.borderLight};
166
+ --glyde-text: ${e.text};
167
+ --glyde-text-secondary: ${e.textSecondary};
168
+ --glyde-text-muted: ${e.textMuted};
169
+ `}const N=`
170
+ @keyframes glyde-pulse {
171
+ 0%, 100% { opacity: 1; transform: scale(1); }
172
+ 50% { opacity: 0.5; transform: scale(1.2); }
173
+ }
174
+
175
+ @keyframes glyde-spin {
176
+ to { transform: rotate(360deg); }
177
+ }
178
+
179
+ @keyframes glyde-fade-in {
180
+ from { opacity: 0; transform: translateY(10px); }
181
+ to { opacity: 1; transform: translateY(0); }
182
+ }
183
+
184
+ @keyframes glyde-slide-up {
185
+ from { opacity: 0; transform: translateY(20px); }
186
+ to { opacity: 1; transform: translateY(0); }
187
+ }
188
+
189
+ @keyframes glyde-bounce {
190
+ 0%, 100% { transform: translateY(0); }
191
+ 50% { transform: translateY(-5px); }
192
+ }
193
+
194
+ .glyde-widget-root {
195
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
196
+ font-size: 14px;
197
+ line-height: 1.5;
198
+ color: var(--glyde-text);
199
+ box-sizing: border-box;
200
+ }
201
+
202
+ .glyde-widget-root *, .glyde-widget-root *::before, .glyde-widget-root *::after {
203
+ box-sizing: border-box;
204
+ }
205
+
206
+ .glyde-spinner {
207
+ width: 32px;
208
+ height: 32px;
209
+ border: 3px solid var(--glyde-border);
210
+ border-top-color: var(--glyde-primary);
211
+ border-radius: 50%;
212
+ animation: glyde-spin 1s linear infinite;
213
+ }
214
+
215
+ .glyde-pulse-dot {
216
+ animation: glyde-pulse 1.5s infinite;
217
+ }
218
+
219
+ .glyde-fade-in {
220
+ animation: glyde-fade-in 0.3s ease-out;
221
+ }
222
+
223
+ .glyde-slide-up {
224
+ animation: glyde-slide-up 0.3s ease-out;
225
+ }
226
+ `,x={floatingButton:{position:"fixed",width:"60px",height:"60px",borderRadius:"50%",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15)",transition:"transform 0.2s, box-shadow 0.2s",zIndex:9999},widgetPanel:{position:"fixed",width:"380px",height:"600px",borderRadius:"16px",boxShadow:"0 10px 40px rgba(0, 0, 0, 0.2)",display:"flex",flexDirection:"column",overflow:"hidden",zIndex:9998},card:{background:"var(--glyde-background)",borderRadius:"12px",boxShadow:"0 4px 6px rgba(0, 0, 0, 0.1)",overflow:"hidden"},header:{padding:"16px 20px",borderBottom:"1px solid var(--glyde-border)",display:"flex",justifyContent:"space-between",alignItems:"center"},modeSelector:{display:"flex",gap:"8px",padding:"4px",background:"var(--glyde-surface)",borderRadius:"8px"},modeSelectorButton:{padding:"8px 16px",border:"none",borderRadius:"6px",cursor:"pointer",display:"flex",alignItems:"center",gap:"6px",fontSize:"14px",fontWeight:500,transition:"all 0.2s"},transcriptArea:{flex:1,overflowY:"auto",padding:"16px",background:"var(--glyde-surface)"},messageBubble:{maxWidth:"80%",padding:"10px 14px",borderRadius:"12px",boxShadow:"0 1px 3px rgba(0, 0, 0, 0.1)"},messageBubbleUser:{background:"var(--glyde-primary)",color:"var(--glyde-primary-text)",borderTopRightRadius:"4px"},messageBubbleAgent:{background:"var(--glyde-background)",color:"var(--glyde-text)",borderTopLeftRadius:"4px"},controlsArea:{padding:"16px",borderTop:"1px solid var(--glyde-border)",background:"var(--glyde-background)"},speakingIndicator:{display:"flex",alignItems:"center",gap:"6px",fontSize:"13px"},speakingDot:{width:"8px",height:"8px",borderRadius:"50%",transition:"background-color 0.2s"},primaryButton:{padding:"12px 24px",background:"var(--glyde-primary)",color:"var(--glyde-primary-text)",border:"none",borderRadius:"8px",fontSize:"15px",fontWeight:600,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",gap:"8px",transition:"background-color 0.2s, transform 0.1s"},secondaryButton:{padding:"10px 20px",background:"var(--glyde-surface)",color:"var(--glyde-text)",border:"1px solid var(--glyde-border)",borderRadius:"8px",fontSize:"14px",fontWeight:500,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",gap:"6px",transition:"background-color 0.2s"},dangerButton:{padding:"12px 24px",background:"var(--glyde-error)",color:"white",border:"none",borderRadius:"24px",fontSize:"15px",fontWeight:600,cursor:"pointer",display:"flex",alignItems:"center",gap:"8px",transition:"background-color 0.2s"},iconButton:{width:"44px",height:"44px",padding:"0",border:"none",borderRadius:"50%",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",transition:"background-color 0.2s"},inputField:{flex:1,padding:"12px 16px",borderRadius:"8px",border:"1px solid var(--glyde-border)",background:"var(--glyde-background)",color:"var(--glyde-text)",fontSize:"14px",outline:"none",transition:"border-color 0.2s"},statusBadge:{padding:"4px 10px",borderRadius:"20px",fontSize:"12px",fontWeight:500,display:"flex",alignItems:"center",gap:"4px"},statusBadgeLive:{background:"var(--glyde-success-light)",color:"var(--glyde-success-text)"},statusBadgeConnecting:{background:"var(--glyde-primary-light)",color:"var(--glyde-primary)"}};function te(o,e=20){return{"bottom-right":{button:{bottom:e,right:e},panel:{bottom:e+70,right:e}},"bottom-left":{button:{bottom:e,left:e},panel:{bottom:e+70,left:e}},"top-right":{button:{top:e,right:e},panel:{top:e+70,right:e}},"top-left":{button:{top:e,left:e},panel:{top:e+70,left:e}}}[o]}function L(o="light"){const e="glyde-widget-styles";if(document.getElementById(e))return;const r=document.createElement("style");r.id=e,r.textContent=`
227
+ :root {
228
+ ${U(o)}
229
+ }
230
+
231
+ ${N}
232
+ `,document.head.appendChild(r)}function le(o){const r=document.getElementById("glyde-widget-styles");r?r.textContent=`
233
+ :root {
234
+ ${U(o)}
235
+ }
236
+
237
+ ${N}
238
+ `:L(o)}const O=({contextId:o,publishableKey:e,apiKey:r,authToken:i,unityApiUrl:s="https://api.glydeunity.com",contextType:n="screening",height:h="600px",onTranscript:f,onCallEnd:p,onError:u})=>{const m=l.useRef(null),{status:a,transcripts:g,isUserSpeaking:b,isAgentSpeaking:k,isMuted:v,errorMessage:y,start:w,stop:C,toggleMute:I,clearTranscripts:T}=H({publishableKey:e,apiKey:r,authToken:i,contextType:n,contextId:o,unityBaseUrl:s});l.useEffect(()=>{m.current?.scrollIntoView({behavior:"smooth"})},[g]),l.useEffect(()=>{if(f&&g.length>0){const S=g[g.length-1];f(S.content,S.role)}},[g,f]),l.useEffect(()=>{a==="error"&&y&&u&&u(new Error(y))},[a,y,u]);const d=()=>{switch(n){case"screening":return"Screening Interview";case"recruiter":return"Recruiter Copilot";case"custom":return"Custom Agent";case"phone":return"Phone Agent";default:return"Voice Interview"}},M=async()=>{T(),await w()},E=()=>{C(),p?.()};return t.jsxs("div",{style:{background:"var(--glyde-background, white)",borderRadius:"12px",boxShadow:"0 4px 6px rgba(0,0,0,0.1)",height:typeof h=="number"?`${h}px`:h,display:"flex",flexDirection:"column",overflow:"hidden"},children:[t.jsxs("div",{style:{padding:"16px 20px",borderBottom:"1px solid var(--glyde-border, #e5e7eb)",display:"flex",justifyContent:"space-between",alignItems:"center"},children:[t.jsxs("div",{children:[t.jsx("h2",{style:{margin:0,fontSize:"1.1rem",fontWeight:600,color:"var(--glyde-text, #1f2937)"},children:d()}),t.jsx("small",{style:{color:"var(--glyde-text-secondary, #6b7280)",fontSize:"0.8rem"},children:i?"JWT Auth":e?"Publishable Key":"API Key"})]}),a==="active"&&t.jsxs("div",{style:{...x.statusBadge,...x.statusBadgeLive},children:[t.jsx(X,{size:14})," Live"]})]}),t.jsx("div",{style:{flex:1,display:"flex",flexDirection:"column",overflow:"hidden"},children:a==="idle"||a==="error"?t.jsxs("div",{style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"40px"},children:[t.jsx("div",{style:{width:"100px",height:"100px",borderRadius:"50%",background:"var(--glyde-primary-light, #fdf4ff)",display:"flex",alignItems:"center",justifyContent:"center",marginBottom:"24px"},children:t.jsx(W,{size:48,color:"var(--glyde-primary, #c026d3)"})}),t.jsxs("h3",{style:{marginBottom:"8px",color:"var(--glyde-text, #1f2937)"},children:["Ready for ",d(),"?"]}),t.jsx("p",{style:{color:"var(--glyde-text-secondary, #666)",marginBottom:"24px",textAlign:"center",maxWidth:"280px"},children:n==="screening"?"The AI recruiter will speak with you. Make sure your microphone is ready.":n==="recruiter"?"The AI copilot will assist you with recruiting tasks.":"The AI agent will speak with you. Make sure your microphone is ready."}),t.jsxs("button",{onClick:M,style:{...x.primaryButton,padding:"14px 36px",borderRadius:"30px",boxShadow:"0 4px 12px rgba(192, 38, 211, 0.3)"},children:["Start ",n==="screening"?"Interview":"Call"]}),y&&t.jsx("p",{style:{color:"var(--glyde-error, #ef4444)",marginTop:"16px",fontSize:"0.9rem"},children:y})]}):t.jsxs(t.Fragment,{children:[t.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"16px",background:"var(--glyde-surface, #f9fafb)"},children:[a==="connecting"&&t.jsxs("div",{style:{textAlign:"center",color:"var(--glyde-text-secondary, #6b7280)",padding:"40px"},children:[t.jsx("div",{className:"glyde-spinner",style:{margin:"0 auto 12px"}}),"Connecting to AI Agent..."]}),g.length===0&&a==="active"&&t.jsxs("div",{style:{textAlign:"center",color:"var(--glyde-text-muted, #9ca3af)",padding:"40px"},children:[t.jsx(j,{size:32,color:"var(--glyde-text-muted, #9ca3af)"}),t.jsx("p",{style:{marginTop:"8px"},children:"Start speaking - the AI will respond"})]}),g.map((S,$)=>t.jsx(de,{transcript:S,contextType:n},$)),t.jsx("div",{ref:m})]}),t.jsxs("div",{style:{padding:"16px",borderTop:"1px solid var(--glyde-border, #e5e7eb)",background:"var(--glyde-background, white)"},children:[t.jsx(ce,{isUserSpeaking:b,isAgentSpeaking:k}),t.jsxs("div",{style:{display:"flex",justifyContent:"center",gap:"12px",marginTop:"16px"},children:[t.jsx("button",{onClick:I,style:{...x.iconButton,background:v?"var(--glyde-error-light, #fecaca)":"var(--glyde-secondary-light, #e0f2fe)"},title:v?"Unmute":"Mute",children:v?t.jsx(Z,{size:20,color:"var(--glyde-error, #dc2626)"}):t.jsx(W,{size:20,color:"var(--glyde-secondary, #0ea5e9)"})}),t.jsxs("button",{onClick:E,style:x.dangerButton,children:[t.jsx(K,{size:18,color:"white"})," End Call"]})]})]})]})}),t.jsx("style",{children:`
239
+ @keyframes glyde-pulse {
240
+ 0%, 100% { opacity: 1; transform: scale(1); }
241
+ 50% { opacity: 0.5; transform: scale(1.2); }
242
+ }
243
+ .glyde-spinner {
244
+ width: 32px;
245
+ height: 32px;
246
+ border: 3px solid var(--glyde-border, #e5e7eb);
247
+ border-top-color: var(--glyde-primary, #c026d3);
248
+ border-radius: 50%;
249
+ animation: spin 1s linear infinite;
250
+ }
251
+ @keyframes spin {
252
+ to { transform: rotate(360deg); }
253
+ }
254
+ `})]})},de=({transcript:o,contextType:e})=>{const r=o.role==="user";return t.jsx("div",{style:{marginBottom:"12px",display:"flex",justifyContent:r?"flex-end":"flex-start"},children:t.jsxs("div",{style:{...x.messageBubble,...r?x.messageBubbleUser:x.messageBubbleAgent},children:[t.jsx("div",{style:{fontSize:"0.75rem",opacity:.7,marginBottom:"4px"},children:r?"You":e==="recruiter"?"AI Copilot":"AI Recruiter"}),o.content]})})},ce=({isUserSpeaking:o,isAgentSpeaking:e})=>t.jsxs("div",{style:{display:"flex",justifyContent:"center",gap:"20px"},children:[t.jsxs("div",{style:{...x.speakingIndicator,color:o?"var(--glyde-primary, #c026d3)":"var(--glyde-text-muted, #9ca3af)"},children:[t.jsx("div",{style:{...x.speakingDot,background:o?"var(--glyde-primary, #c026d3)":"var(--glyde-border, #d1d5db)",animation:o?"glyde-pulse 1s infinite":"none"}}),"You"]}),t.jsxs("div",{style:{...x.speakingIndicator,color:e?"var(--glyde-success, #059669)":"var(--glyde-text-muted, #9ca3af)"},children:[t.jsx("div",{style:{...x.speakingDot,background:e?"var(--glyde-success, #059669)":"var(--glyde-border, #d1d5db)",animation:e?"glyde-pulse 1s infinite":"none"}}),"AI Agent"]})]}),_=({contextId:o,publishableKey:e,apiKey:r,authToken:i,unityApiUrl:s="https://api.glydeunity.com",height:n="600px",title:h="AI Chat",placeholder:f="Type your message...",autoInit:p=!0,onMessage:u,onError:m})=>{const[a,g]=l.useState(""),b=l.useRef(null),{status:k,messages:v,isLoading:y,errorMessage:w,sendMessage:C}=F({publishableKey:e,apiKey:r,authToken:i,contextId:o,unityBaseUrl:s,autoInit:p});l.useEffect(()=>{b.current?.scrollIntoView({behavior:"smooth"})},[v]),l.useEffect(()=>{k==="error"&&w&&m&&m(new Error(w))},[k,w,m]);const I=async()=>{if(!a.trim()||y)return;const d=a.trim();g(""),await C(d),u&&u({role:"user",content:d})},T=d=>{d.key==="Enter"&&!d.shiftKey&&(d.preventDefault(),I())};return t.jsxs("div",{style:{background:"var(--glyde-background, white)",borderRadius:"12px",boxShadow:"0 4px 6px rgba(0,0,0,0.1)",height:typeof n=="number"?`${n}px`:n,display:"flex",flexDirection:"column",overflow:"hidden"},children:[t.jsx("div",{style:{padding:"16px 20px",borderBottom:"1px solid var(--glyde-border, #eee)",background:"var(--glyde-secondary, #0284c7)",color:"white",borderTopLeftRadius:"12px",borderTopRightRadius:"12px"},children:t.jsx("h2",{style:{margin:0,fontSize:"1.1rem",fontWeight:600},children:h})}),t.jsxs("div",{style:{flex:1,overflowY:"auto",padding:"20px",display:"flex",flexDirection:"column",gap:"15px",background:"var(--glyde-background, white)"},children:[k==="loading"&&v.length===0&&t.jsxs("div",{style:{textAlign:"center",color:"var(--glyde-text-muted, #94a3b8)",padding:"20px"},children:[t.jsx("div",{className:"glyde-spinner",style:{margin:"0 auto 12px"}}),"Loading conversation..."]}),v.map((d,M)=>t.jsx(he,{message:d},M)),y&&t.jsx("div",{style:{color:"var(--glyde-text-muted, #94a3b8)",fontSize:"0.9rem",marginLeft:"42px"},children:t.jsx(pe,{})}),t.jsx("div",{ref:b})]}),t.jsxs("div",{style:{padding:"16px 20px",borderTop:"1px solid var(--glyde-border, #eee)"},children:[w&&t.jsx("p",{style:{color:"var(--glyde-error, #ef4444)",fontSize:"0.85rem",marginBottom:"10px"},children:w}),t.jsxs("div",{style:{display:"flex",gap:"10px"},children:[t.jsx("input",{type:"text",value:a,onChange:d=>g(d.target.value),onKeyDown:T,placeholder:f,style:{...x.inputField,flex:1},disabled:y}),t.jsx("button",{onClick:I,disabled:y||!a.trim(),style:{...x.iconButton,background:"var(--glyde-secondary, #0284c7)",width:"48px",height:"48px",opacity:y||!a.trim()?.5:1,cursor:y||!a.trim()?"not-allowed":"pointer"},children:t.jsx(J,{size:20,color:"white"})})]})]}),t.jsx("style",{children:`
255
+ .glyde-spinner {
256
+ width: 24px;
257
+ height: 24px;
258
+ border: 2px solid var(--glyde-border, #e5e7eb);
259
+ border-top-color: var(--glyde-secondary, #0284c7);
260
+ border-radius: 50%;
261
+ animation: spin 1s linear infinite;
262
+ }
263
+ @keyframes spin {
264
+ to { transform: rotate(360deg); }
265
+ }
266
+ @keyframes typing-dot {
267
+ 0%, 60%, 100% { opacity: 0.3; }
268
+ 30% { opacity: 1; }
269
+ }
270
+ `})]})},he=({message:o})=>{const e=o.role==="user";return t.jsxs("div",{style:{display:"flex",gap:"10px",flexDirection:e?"row-reverse":"row",alignItems:"flex-start"},children:[t.jsx("div",{style:{width:"32px",height:"32px",borderRadius:"50%",background:e?"var(--glyde-primary-light, #e0e7ff)":"var(--glyde-secondary-light, #f0f9ff)",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0},children:e?t.jsx(q,{size:18,color:"var(--glyde-primary, #4338ca)"}):t.jsx(Y,{size:18,color:"var(--glyde-secondary, #0284c7)"})}),t.jsx("div",{style:{padding:"12px 16px",borderRadius:"12px",background:e?"var(--glyde-primary, #4338ca)":"var(--glyde-surface, #f1f5f9)",color:e?"white":"var(--glyde-text, #1e293b)",maxWidth:"70%",borderTopRightRadius:e?"4px":"12px",borderTopLeftRadius:e?"12px":"4px",lineHeight:1.5},children:o.content})]})},pe=()=>t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"4px"},children:[t.jsx("span",{children:"Typing"}),t.jsx("span",{style:{display:"flex",gap:"2px"},children:[0,1,2].map(o=>t.jsx("span",{style:{width:"4px",height:"4px",borderRadius:"50%",background:"var(--glyde-text-muted, #94a3b8)",animation:"typing-dot 1.4s infinite",animationDelay:`${o*.2}s`}},o))})]}),z=({publishableKey:o,apiKey:e,authToken:r,contextId:i,unityBaseUrl:s="https://api.glydeunity.com",contextType:n="screening",defaultMode:h="voice",position:f="bottom-right",theme:p="light",allowModeSwitch:u=!0,container:m,onReady:a,onModeChange:g,onTranscript:b,onError:k,initialExpanded:v=!1})=>{const[y,w]=l.useState(v),[C,I]=l.useState(h);l.useEffect(()=>{const S=p==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":p;L(S)},[p]),l.useEffect(()=>{a?.()},[a]);const T=te(f),d=S=>{I(S),g?.(S)},M=(S,$)=>{b?.(S,$)},E=S=>{k?.(S)};return m?t.jsx(ge,{publishableKey:o,apiKey:e,authToken:r,contextId:i,unityBaseUrl:s,contextType:n,mode:C,allowModeSwitch:u,onModeChange:d,onTranscript:M,onError:E}):t.jsxs("div",{className:"glyde-widget-root",children:[!y&&t.jsx("button",{onClick:()=>w(!0),style:{...x.floatingButton,...T.button,background:"linear-gradient(135deg, var(--glyde-primary, #c026d3) 0%, var(--glyde-secondary, #7c3aed) 100%)"},"aria-label":"Open chat",children:t.jsx(W,{size:28,color:"white"})}),y&&t.jsxs("div",{style:{...x.widgetPanel,...T.panel,background:"var(--glyde-background, white)"},className:"glyde-slide-up",children:[t.jsxs("div",{style:{...x.header,background:"linear-gradient(135deg, var(--glyde-primary, #c026d3) 0%, var(--glyde-secondary, #7c3aed) 100%)",color:"white",borderTopLeftRadius:"16px",borderTopRightRadius:"16px"},children:[t.jsxs("div",{children:[t.jsx("h3",{style:{margin:0,fontSize:"1rem",fontWeight:600},children:"GLYDE Assistant"}),t.jsx("small",{style:{opacity:.8,fontSize:"0.75rem"},children:n==="screening"?"Candidate Screening":"AI Assistant"})]}),t.jsxs("div",{style:{display:"flex",gap:"8px"},children:[t.jsx("button",{onClick:()=>w(!1),style:{...x.iconButton,background:"rgba(255,255,255,0.2)",width:"32px",height:"32px"},"aria-label":"Minimize",children:t.jsx(R,{size:16,color:"white"})}),t.jsx("button",{onClick:()=>w(!1),style:{...x.iconButton,background:"rgba(255,255,255,0.2)",width:"32px",height:"32px"},"aria-label":"Close",children:t.jsx(Q,{size:16,color:"white"})})]})]}),u&&t.jsx("div",{style:{padding:"12px 16px",borderBottom:"1px solid var(--glyde-border, #e5e7eb)"},children:t.jsx(re,{mode:C,onModeChange:d})}),t.jsx("div",{style:{flex:1,display:"flex",flexDirection:"column",overflow:"hidden"},children:C==="voice"?t.jsx(O,{publishableKey:o,apiKey:e,authToken:r,contextId:i||"",unityApiUrl:s,contextType:n,height:"100%",onTranscript:M,onError:E}):t.jsx(_,{publishableKey:o,apiKey:e,authToken:r,contextId:i||"",unityApiUrl:s,height:"100%",title:"Text Chat",onError:E})})]})]})},re=({mode:o,onModeChange:e})=>t.jsxs("div",{style:x.modeSelector,children:[t.jsxs("button",{onClick:()=>e("voice"),style:{...x.modeSelectorButton,background:o==="voice"?"var(--glyde-primary, #c026d3)":"transparent",color:o==="voice"?"white":"var(--glyde-text, #1f2937)"},children:[t.jsx(W,{size:16})," Voice"]}),t.jsxs("button",{onClick:()=>e("text"),style:{...x.modeSelectorButton,background:o==="text"?"var(--glyde-secondary, #0284c7)":"transparent",color:o==="text"?"white":"var(--glyde-text, #1f2937)"},children:[t.jsx(j,{size:16})," Text"]})]}),ge=({publishableKey:o,apiKey:e,authToken:r,contextId:i,unityBaseUrl:s,contextType:n,mode:h,allowModeSwitch:f,onModeChange:p,onTranscript:u,onError:m})=>{const[a,g]=l.useState(h),b=k=>{g(k),p(k)};return t.jsxs("div",{className:"glyde-widget-root",style:{height:"100%",display:"flex",flexDirection:"column"},children:[f&&t.jsx("div",{style:{padding:"12px 16px",borderBottom:"1px solid var(--glyde-border, #e5e7eb)",background:"var(--glyde-background, white)"},children:t.jsx(re,{mode:a,onModeChange:b})}),t.jsx("div",{style:{flex:1,overflow:"hidden"},children:a==="voice"?t.jsx(O,{publishableKey:o,apiKey:e,authToken:r,contextId:i||"",unityApiUrl:s,contextType:n,height:"100%",onTranscript:u,onError:m}):t.jsx(_,{publishableKey:o,apiKey:e,authToken:r,contextId:i||"",unityApiUrl:s,height:"100%",title:"Text Chat",onError:m})})]})};let A=null,B=null;const P={init(o){if(!o.publishableKey&&!o.apiKey&&!o.authToken)return console.error("[GlydeChat] Authentication required: provide publishableKey, apiKey, or authToken"),null;const e=o.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":o.theme||"light";L(e),A&&B&&(A.unmount(),B.remove(),A=null,B=null);const r=document.createElement("div");r.id="glyde-chat-widget",r.className="glyde-widget-root",document.body.appendChild(r),B=r;const i=V.createRoot(r);return A=i,i.render(l.createElement(z,{...o,initialExpanded:!1})),console.log("[GlydeChat] Widget initialized"),{destroy(){A&&B&&(A.unmount(),B.remove(),A=null,B=null,console.log("[GlydeChat] Widget destroyed"))},update(s){A&&A.render(l.createElement(z,{...o,...s}))}}},render(o,e){const r=typeof o=="string"?document.querySelector(o):o;if(!r)return console.error("[GlydeChat] Container not found:",o),null;const i=e.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e.theme||"light";L(i);const s=V.createRoot(r);return s.render(l.createElement(z,{...e,container:r})),{destroy(){s.unmount()},update(n){s.render(l.createElement(z,{...e,...n,container:r}))}}},isReady(){return!0},get version(){return"__SDK_VERSION__"}};function ue(){const o=document.querySelectorAll('script[src*="glyde-chat"]'),e=o[o.length-1];if(!e){console.log("[GlydeChat] No script tag found for auto-init");return}const r=e.getAttribute("data-auto-init");if(r==="false"){console.log('[GlydeChat] Auto-init disabled via data-auto-init="false"');return}const i=e.getAttribute("data-publishable-key")||void 0,s=e.getAttribute("data-api-key")||void 0,n=e.getAttribute("data-auth-token")||void 0,h=i||s||n;if(!h&&!(r==="true")){console.log("[GlydeChat] Auto-init skipped: no authentication data attributes found. Call GlydeChat.init() manually.");return}if(!h){console.warn("[GlydeChat] Auto-init skipped: no authentication provided (publishableKey, apiKey, or authToken required)");return}const p={publishableKey:i,apiKey:s,authToken:n,contextId:e.getAttribute("data-context-id")||void 0,unityBaseUrl:e.getAttribute("data-unity-url")||"https://api.glydeunity.com",contextType:e.getAttribute("data-context-type")||"screening",defaultMode:e.getAttribute("data-default-mode")||"voice",position:e.getAttribute("data-position")||"bottom-right",theme:e.getAttribute("data-theme")||"light",allowModeSwitch:e.getAttribute("data-allow-mode-switch")!=="false"};console.log("[GlydeChat] Auto-initializing with config:",{hasPublishableKey:!!p.publishableKey,hasApiKey:!!p.apiKey,hasAuthToken:!!p.authToken,contextId:p.contextId,defaultMode:p.defaultMode,position:p.position,theme:p.theme}),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>P.init(p)):P.init(p)}typeof window<"u"&&(window.GlydeChat=P,ue()),c.ActivityIcon=X,c.BotIcon=Y,c.ChatWidget=z,c.GlydeChat=P,c.GlydeText=G,c.GlydeVoice=D,c.LoaderIcon=ae,c.MessageIcon=j,c.MicIcon=W,c.MicOffIcon=se,c.MinimizeIcon=R,c.PhoneIcon=ne,c.PhoneOffIcon=K,c.SendIcon=J,c.TextChat=_,c.UserIcon=q,c.VoiceChat=O,c.VolumeXIcon=Z,c.XIcon=Q,c.componentStyles=x,c.getPositionStyles=te,c.getThemeCSSVariables=U,c.globalStyles=N,c.injectGlobalStyles=L,c.themeColors=ee,c.updateTheme=le,c.useTextChat=F,c.useVoiceAgent=H,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
271
+ //# sourceMappingURL=glyde-chat.umd.js.map