@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.
- package/dist/glyde-chat.umd.js +271 -0
- package/dist/glyde-chat.umd.js.map +1 -0
- package/dist/index.d.ts +857 -16
- package/dist/voice-sdk.es.js +1784 -75
- package/dist/voice-sdk.es.js.map +1 -0
- package/package.json +28 -7
- package/dist/voice-sdk.umd.js +0 -140
|
@@ -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
|