vox-ai-react 1.3.4 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -41,16 +41,18 @@ async function decodeAudioData(arrayBuffer, ctx, sampleRate, numChannels) {
41
41
  }
42
42
  return audioBuffer;
43
43
  }
44
- // Icons - matching exact website icons
45
- const MessageCircleIcon = () => (jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) }));
46
- const MicIcon = ({ size = 14 }) => (jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }), jsxRuntime.jsx("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }), jsxRuntime.jsx("line", { x1: "12", x2: "12", y1: "19", y2: "22" })] }));
47
- const MicOffIcon = ({ size = 40 }) => (jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "2", x2: "22", y1: "2", y2: "22" }), jsxRuntime.jsx("path", { d: "M18.89 13.23A7.12 7.12 0 0 0 19 12v-2" }), jsxRuntime.jsx("path", { d: "M5 10v2a7 7 0 0 0 12 5" }), jsxRuntime.jsx("path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33" }), jsxRuntime.jsx("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12" }), jsxRuntime.jsx("line", { x1: "12", x2: "12", y1: "19", y2: "22" })] }));
48
- const XIcon = () => (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M18 6 6 18" }), jsxRuntime.jsx("path", { d: "m6 6 12 12" })] }));
49
- const PhoneOffIcon = () => (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.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" }), jsxRuntime.jsx("line", { x1: "22", x2: "2", y1: "2", y2: "22" })] }));
50
- const VoxLogoIcon = () => (jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 48 48", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M28.764 25.966c0-4.489-1.936-5.99-4.764-5.99s-4.764 1.501-4.764 5.99m-.55 0h.55v5.324h0h-.55a1.826 1.826 0 0 1-1.826-1.826v-1.672a1.826 1.826 0 0 1 1.826-1.826m10.628 5.324h-.55h0v-5.324h.55a1.826 1.826 0 0 1 1.826 1.826v1.672a1.826 1.826 0 0 1-1.826 1.826" }), jsxRuntime.jsx("path", { d: "M24 42.476L12.938 33.58V5.524L24 16.351" }), jsxRuntime.jsx("path", { d: "M24 42.476L9.125 35.557V7.501L24 16.351" }), jsxRuntime.jsx("path", { d: "M24 42.476L5.5 38.004V9.948L24 16.351m0 26.125l11.062-8.896V5.524L24 16.351" }), jsxRuntime.jsx("path", { d: "m24 42.476l14.875-6.919V7.501L24 16.351" }), jsxRuntime.jsx("path", { d: "m24 42.476l18.5-4.472V9.948L24 16.351" })] }));
51
- const UserIcon = () => (jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }), jsxRuntime.jsx("circle", { cx: "12", cy: "7", r: "4" })] }));
52
- const Loader2Icon = () => (jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { animation: 'vox-spin 1s linear infinite' }, children: jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }));
53
- const AlertCircleIcon = () => (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }), jsxRuntime.jsx("line", { x1: "12", x2: "12", y1: "8", y2: "12" }), jsxRuntime.jsx("line", { x1: "12", x2: "12.01", y1: "16", y2: "16" })] }));
44
+ // Icons
45
+ const MessageCircleIcon = () => (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) }));
46
+ const MicIcon = ({ size = 20 }) => (jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }), jsxRuntime.jsx("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }), jsxRuntime.jsx("line", { x1: "12", x2: "12", y1: "19", y2: "22" })] }));
47
+ const MicOffIcon = ({ size = 20 }) => (jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("line", { x1: "2", x2: "22", y1: "2", y2: "22" }), jsxRuntime.jsx("path", { d: "M18.89 13.23A7.12 7.12 0 0 0 19 12v-2" }), jsxRuntime.jsx("path", { d: "M5 10v2a7 7 0 0 0 12 5" }), jsxRuntime.jsx("path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33" }), jsxRuntime.jsx("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12" }), jsxRuntime.jsx("line", { x1: "12", x2: "12", y1: "19", y2: "22" })] }));
48
+ const XIcon = () => (jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M18 6 6 18" }), jsxRuntime.jsx("path", { d: "m6 6 12 12" })] }));
49
+ const PhoneOffIcon = () => (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.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" }), jsxRuntime.jsx("line", { x1: "22", x2: "2", y1: "2", y2: "22" })] }));
50
+ const UserIcon = () => (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }), jsxRuntime.jsx("circle", { cx: "12", cy: "7", r: "4" })] }));
51
+ const BotIcon = () => (jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M12 8V4H8" }), jsxRuntime.jsx("rect", { width: "16", height: "12", x: "4", y: "8", rx: "2" }), jsxRuntime.jsx("path", { d: "M2 14h2" }), jsxRuntime.jsx("path", { d: "M20 14h2" }), jsxRuntime.jsx("path", { d: "M15 13v2" }), jsxRuntime.jsx("path", { d: "M9 13v2" })] }));
52
+ const SendIcon = () => (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "m22 2-7 20-4-9-9-4Z" }), jsxRuntime.jsx("path", { d: "M22 2 11 13" })] }));
53
+ const PlusIcon = () => (jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M5 12h14" }), jsxRuntime.jsx("path", { d: "M12 5v14" })] }));
54
+ const Loader2Icon = () => (jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { animation: 'vox-spin 1s linear infinite' }, children: jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }));
55
+ const AlertCircleIcon = () => (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }), jsxRuntime.jsx("line", { x1: "12", x2: "12", y1: "8", y2: "12" }), jsxRuntime.jsx("line", { x1: "12", x2: "12.01", y1: "16", y2: "16" })] }));
54
56
  // Visualizer Component
55
57
  const Visualizer = ({ analyser, isActive }) => {
56
58
  const canvasRef = react.useRef(null);
@@ -104,9 +106,9 @@ const Visualizer = ({ analyser, isActive }) => {
104
106
  return jsxRuntime.jsx("canvas", { ref: canvasRef, width: 300, height: 50, style: { width: '100%', height: '50px', background: 'transparent' } });
105
107
  };
106
108
  // Text Interface Component
107
- const TextInterface = ({ apiKey, apiUrl, agentName, systemInstruction }) => {
109
+ const TextInterface = ({ apiKey, apiUrl, agentName, systemInstruction, logoUrl }) => {
108
110
  const [messages, setMessages] = react.useState([
109
- { id: 'welcome', role: 'assistant', text: `VOX INITIALIZED. GREETINGS. I AM ${agentName}. HOW MAY I ASSIST YOUR INQUIRY?` }
111
+ { id: 'welcome', role: 'assistant', text: `Hello! I'm ${agentName}. How can I help you today?` }
110
112
  ]);
111
113
  const [input, setInput] = react.useState('');
112
114
  const [isLoading, setIsLoading] = react.useState(false);
@@ -116,7 +118,6 @@ const TextInterface = ({ apiKey, apiUrl, agentName, systemInstruction }) => {
116
118
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
117
119
  }, [messages]);
118
120
  const handleSend = async (e) => {
119
- var _a;
120
121
  e === null || e === void 0 ? void 0 : e.preventDefault();
121
122
  if (!input.trim() || isLoading)
122
123
  return;
@@ -137,35 +138,36 @@ const TextInterface = ({ apiKey, apiUrl, agentName, systemInstruction }) => {
137
138
  throw new Error(errorData.error || 'API request failed');
138
139
  }
139
140
  const data = await response.json();
140
- const botMsg = { id: (Date.now() + 1).toString(), role: 'assistant', text: ((_a = data.response) === null || _a === void 0 ? void 0 : _a.toUpperCase()) || 'ERROR: NO RESPONSE' };
141
+ const botMsg = { id: (Date.now() + 1).toString(), role: 'assistant', text: data.response || 'Error: No response' };
141
142
  setMessages(prev => [...prev, botMsg]);
142
143
  }
143
144
  catch (err) {
144
145
  console.error('VOX Chat Error:', err);
145
- const errorMsg = { id: (Date.now() + 1).toString(), role: 'assistant', text: `ERROR: ${err.message || 'SIGNAL LOST. RETRY.'}` };
146
+ const errorMsg = { id: (Date.now() + 1).toString(), role: 'assistant', text: `Error: ${err.message || 'Connection lost. Please try again.'}` };
146
147
  setMessages(prev => [...prev, errorMsg]);
147
148
  }
148
149
  finally {
149
150
  setIsLoading(false);
150
151
  }
151
152
  };
152
- return (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', background: '#000000' }, children: [jsxRuntime.jsxs("div", { ref: scrollRef, style: { flex: 1, overflowY: 'auto', padding: '16px', display: 'flex', flexDirection: 'column', gap: '16px' }, children: [messages.map((msg) => (jsxRuntime.jsx("div", { style: { display: 'flex', justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start' }, children: jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: msg.role === 'user' ? 'row-reverse' : 'row', alignItems: 'flex-start', gap: '8px', maxWidth: '85%' }, children: [jsxRuntime.jsx("div", { style: {
153
+ return (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', background: '#000000', fontFamily: 'Outfit, sans-serif' }, children: [jsxRuntime.jsxs("div", { ref: scrollRef, style: { flex: 1, overflowY: 'auto', padding: '16px', display: 'flex', flexDirection: 'column', gap: '16px' }, children: [messages.map((msg) => (jsxRuntime.jsx("div", { style: { display: 'flex', justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start' }, children: jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: msg.role === 'user' ? 'row-reverse' : 'row', alignItems: 'flex-start', gap: '8px', maxWidth: '85%' }, children: [jsxRuntime.jsx("div", { style: {
153
154
  flexShrink: 0, width: '24px', height: '24px', display: 'flex', alignItems: 'center', justifyContent: 'center',
154
- border: msg.role === 'user' ? '1px solid #ffffff' : '1px solid #52525b',
155
+ border: msg.role === 'user' ? '1px solid #ffffff' : 'none',
155
156
  background: msg.role === 'user' ? '#ffffff' : 'transparent',
156
157
  color: msg.role === 'user' ? '#000000' : '#ffffff'
157
- }, children: msg.role === 'user' ? jsxRuntime.jsx(UserIcon, {}) : jsxRuntime.jsx(VoxLogoIcon, {}) }), jsxRuntime.jsx("div", { style: {
158
- padding: '8px 12px', fontSize: '10px', fontWeight: 700, letterSpacing: '0.05em', lineHeight: 1.6,
159
- border: '1px solid #3f3f46', background: msg.role === 'user' ? '#27272a' : '#000000',
158
+ }, children: msg.role === 'user' ? jsxRuntime.jsx(UserIcon, {}) : (logoUrl ? jsxRuntime.jsx("img", { src: logoUrl, alt: agentName, style: { width: '24px', height: '24px', objectFit: 'contain' } }) : jsxRuntime.jsx(BotIcon, {})) }), jsxRuntime.jsx("div", { style: {
159
+ padding: '8px 12px', fontSize: '14px', fontWeight: 500, lineHeight: 1.6,
160
+ border: '1px solid', borderRadius: '8px',
161
+ borderColor: msg.role === 'user' ? '#52525b' : '#3f3f46',
162
+ background: msg.role === 'user' ? '#27272a' : '#000000',
160
163
  color: msg.role === 'user' ? '#ffffff' : '#d4d4d8'
161
- }, children: msg.text })] }) }, msg.id))), isLoading && (jsxRuntime.jsx("div", { style: { display: 'flex', justifyContent: 'flex-start' }, children: jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', gap: '8px' }, children: [jsxRuntime.jsx("div", { style: { flexShrink: 0, width: '24px', height: '24px', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid #3f3f46', color: '#ffffff', opacity: 0.2 }, children: jsxRuntime.jsx(VoxLogoIcon, {}) }), jsxRuntime.jsx("div", { style: { padding: '12px 16px', border: '1px solid #3f3f46', background: '#000000', color: '#71717a' }, children: jsxRuntime.jsx(Loader2Icon, {}) })] }) }))] }), jsxRuntime.jsx("div", { style: { padding: '16px' }, children: jsxRuntime.jsxs("form", { onSubmit: handleSend, style: { display: 'flex', gap: '8px' }, children: [jsxRuntime.jsx("input", { type: "text", value: input, onChange: (e) => setInput(e.target.value), placeholder: "INPUT COMMAND...", disabled: isLoading, style: {
162
- flex: 1, padding: '12px 16px', border: '1px solid #52525b', background: '#000000', color: '#ffffff',
163
- outline: 'none', fontSize: '9px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.1em'
164
- } }), jsxRuntime.jsx("button", { type: "submit", disabled: !input.trim() || isLoading, style: {
165
- padding: '12px 16px', background: '#ffffff', color: '#000000', border: 'none', cursor: 'pointer',
166
- fontSize: '9px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.1em',
167
- opacity: !input.trim() || isLoading ? 0.2 : 1
168
- }, children: "EXECUTE" })] }) })] }));
164
+ }, children: msg.text })] }) }, msg.id))), isLoading && (jsxRuntime.jsx("div", { style: { display: 'flex', justifyContent: 'flex-start' }, children: jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', gap: '8px' }, children: [jsxRuntime.jsx("div", { style: { flexShrink: 0, width: '24px', height: '24px', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#ffffff', opacity: 0.2 }, children: logoUrl ? jsxRuntime.jsx("img", { src: logoUrl, alt: agentName, style: { width: '24px', height: '24px', objectFit: 'contain' } }) : jsxRuntime.jsx(BotIcon, {}) }), jsxRuntime.jsx("div", { style: { padding: '12px 16px', border: '1px solid #3f3f46', background: '#000000', borderRadius: '8px' }, children: jsxRuntime.jsx(Loader2Icon, {}) })] }) }))] }), jsxRuntime.jsx("div", { style: { padding: '16px' }, children: jsxRuntime.jsx("form", { onSubmit: handleSend, children: jsxRuntime.jsxs("div", { style: {
165
+ width: '100%', cursor: 'text', overflow: 'clip', padding: '6px', boxShadow: '0 4px 6px -1px rgba(0,0,0,0.1)', border: '1px solid #3f3f46', borderRadius: '9999px',
166
+ display: 'grid', gridTemplateColumns: 'auto 1fr auto', gridTemplateRows: 'auto', gap: '4px', alignItems: 'center', background: 'rgba(0,0,0,0.5)'
167
+ }, children: [jsxRuntime.jsx("button", { type: "button", style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '32px', height: '32px', borderRadius: '9999px', outline: 'none', border: 'none', background: 'transparent', cursor: 'pointer', color: '#71717a' }, children: jsxRuntime.jsx(PlusIcon, {}) }), jsxRuntime.jsx("input", { type: "text", value: input, onChange: (e) => setInput(e.target.value), onKeyDown: (e) => { if (e.key === 'Enter' && !e.shiftKey) {
168
+ e.preventDefault();
169
+ handleSend();
170
+ } }, placeholder: "Type your message...", disabled: isLoading, style: { width: '100%', minHeight: '32px', resize: 'none', border: 0, padding: 0, fontSize: '14px', outline: 'none', background: 'transparent', color: '#ffffff' } }), jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '4px' }, children: [jsxRuntime.jsx("button", { type: "button", style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '32px', height: '32px', borderRadius: '9999px', outline: 'none', border: 'none', background: 'transparent', cursor: 'pointer', color: '#71717a' }, children: jsxRuntime.jsx(MicIcon, { size: 16 }) }), input.trim() && (jsxRuntime.jsx("button", { type: "submit", disabled: isLoading, style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '32px', height: '32px', borderRadius: '9999px', border: 'none', background: '#ffffff', color: '#000000', cursor: 'pointer' }, children: jsxRuntime.jsx(SendIcon, {}) }))] })] }) }) })] }));
169
171
  };
170
172
  // Voice Interface Component
171
173
  const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall }) => {
@@ -173,30 +175,20 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
173
175
  const [errorMsg, setErrorMsg] = react.useState('');
174
176
  const [isMuted, setIsMuted] = react.useState(false);
175
177
  const [callDuration, setCallDuration] = react.useState(0);
176
- const [isSpeaking, setIsSpeaking] = react.useState(false);
177
- const [speakingIntensity, setSpeakingIntensity] = react.useState(0);
178
178
  const callStartTimeRef = react.useRef(null);
179
179
  const durationIntervalRef = react.useRef(null);
180
180
  const inputAudioContextRef = react.useRef(null);
181
181
  const outputAudioContextRef = react.useRef(null);
182
182
  const inputAnalyserRef = react.useRef(null);
183
- const outputAnalyserRef = react.useRef(null);
184
183
  const outputGainRef = react.useRef(null);
185
184
  const nextStartTimeRef = react.useRef(0);
186
185
  const sourcesRef = react.useRef(new Set());
187
- const speakingAnimationRef = react.useRef(null);
188
186
  const sessionRef = react.useRef(null);
189
187
  const streamRef = react.useRef(null);
190
188
  const scriptProcessorRef = react.useRef(null);
191
189
  const sourceNodeRef = react.useRef(null);
192
190
  const cleanupAudio = react.useCallback(() => {
193
191
  var _a, _b, _c, _d;
194
- if (speakingAnimationRef.current) {
195
- cancelAnimationFrame(speakingAnimationRef.current);
196
- speakingAnimationRef.current = null;
197
- }
198
- setIsSpeaking(false);
199
- setSpeakingIntensity(0);
200
192
  sourcesRef.current.forEach(source => { try {
201
193
  source.stop();
202
194
  }
@@ -227,13 +219,6 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
227
219
  catch (e) { }
228
220
  outputGainRef.current = null;
229
221
  }
230
- if (outputAnalyserRef.current) {
231
- try {
232
- outputAnalyserRef.current.disconnect();
233
- }
234
- catch (e) { }
235
- outputAnalyserRef.current = null;
236
- }
237
222
  if (((_a = inputAudioContextRef.current) === null || _a === void 0 ? void 0 : _a.state) !== 'closed') {
238
223
  try {
239
224
  (_b = inputAudioContextRef.current) === null || _b === void 0 ? void 0 : _b.close();
@@ -268,34 +253,16 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
268
253
  const analyser = inputCtx.createAnalyser();
269
254
  analyser.fftSize = 256;
270
255
  inputAnalyserRef.current = analyser;
271
- const outputAnalyser = outputCtx.createAnalyser();
272
- outputAnalyser.fftSize = 256;
273
- outputAnalyserRef.current = outputAnalyser;
274
256
  const outputGain = outputCtx.createGain();
275
257
  outputGain.gain.value = 1;
276
258
  outputGainRef.current = outputGain;
277
- outputGain.connect(outputAnalyser);
278
- outputAnalyser.connect(outputCtx.destination);
279
- const monitorSpeaking = () => {
280
- if (!outputAnalyserRef.current)
281
- return;
282
- const dataArray = new Uint8Array(outputAnalyserRef.current.frequencyBinCount);
283
- outputAnalyserRef.current.getByteFrequencyData(dataArray);
284
- const average = dataArray.reduce((a, b) => a + b, 0) / dataArray.length;
285
- const intensity = Math.min(average / 128, 1);
286
- setIsSpeaking(intensity > 0.05);
287
- setSpeakingIntensity(intensity);
288
- speakingAnimationRef.current = requestAnimationFrame(monitorSpeaking);
289
- };
290
- monitorSpeaking();
259
+ outputGain.connect(outputCtx.destination);
291
260
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
292
261
  streamRef.current = stream;
293
262
  const wsUrl = `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent?key=${geminiApiKey}`;
294
- console.log('[VOX] Connecting to Gemini Live API...');
295
263
  const ws = new WebSocket(wsUrl);
296
264
  sessionRef.current = ws;
297
265
  ws.onopen = () => {
298
- console.log('[VOX] WebSocket connected, sending setup...');
299
266
  const setupMsg = {
300
267
  setup: {
301
268
  model: 'models/gemini-2.5-flash-native-audio-preview-09-2025',
@@ -325,9 +292,7 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
325
292
  return;
326
293
  }
327
294
  }
328
- console.log('[VOX] Received:', data);
329
295
  if (data.setupComplete) {
330
- console.log('[VOX] Setup complete, voice ready!');
331
296
  setConnectionState(ConnectionState.CONNECTED);
332
297
  const source = inputCtx.createMediaStreamSource(stream);
333
298
  sourceNodeRef.current = source;
@@ -368,19 +333,14 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
368
333
  nextStartTimeRef.current = 0;
369
334
  }
370
335
  };
371
- ws.onclose = (event) => {
372
- console.log('[VOX] WebSocket closed:', event.code, event.reason);
373
- setConnectionState(ConnectionState.DISCONNECTED);
374
- };
375
- ws.onerror = (error) => {
376
- console.error('[VOX] WebSocket error:', error);
336
+ ws.onclose = () => setConnectionState(ConnectionState.DISCONNECTED);
337
+ ws.onerror = () => {
377
338
  setConnectionState(ConnectionState.ERROR);
378
339
  setErrorMsg('Connection failed. Check your Gemini API key.');
379
340
  cleanupAudio();
380
341
  };
381
342
  }
382
343
  catch (err) {
383
- console.error('[VOX] Connection error:', err);
384
344
  setConnectionState(ConnectionState.ERROR);
385
345
  setErrorMsg(err.message || 'Failed to access microphone or connect.');
386
346
  cleanupAudio();
@@ -406,15 +366,24 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
406
366
  connect();
407
367
  return () => disconnect();
408
368
  }, []);
409
- return (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: '32px', height: '100%', padding: '24px' }, children: [jsxRuntime.jsxs("div", { style: { position: 'relative' }, children: [connectionState === ConnectionState.CONNECTED && isSpeaking && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { style: { position: 'absolute', inset: 0, borderRadius: '50%', border: '1px solid rgba(255,255,255,0.2)', transform: `scale(${1 + speakingIntensity * 0.3})`, animation: 'vox-ping 1s infinite' } }), jsxRuntime.jsx("div", { style: { position: 'absolute', inset: 0, borderRadius: '50%', border: '1px solid rgba(255,255,255,0.1)', transform: `scale(${1 + speakingIntensity * 0.5})`, transition: 'transform 0.1s ease-out' } })] })), jsxRuntime.jsx("div", { style: {
369
+ const toggleMute = () => {
370
+ setIsMuted(!isMuted);
371
+ if (streamRef.current)
372
+ streamRef.current.getAudioTracks().forEach(track => { track.enabled = isMuted; });
373
+ };
374
+ return (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: '32px', height: '100%', padding: '24px', fontFamily: 'Outfit, sans-serif' }, children: [jsxRuntime.jsxs("div", { style: { position: 'relative' }, children: [jsxRuntime.jsx("div", { style: {
410
375
  width: '112px', height: '112px', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center',
411
376
  border: `1px solid ${connectionState === ConnectionState.CONNECTED ? '#ffffff' : '#52525b'}`,
412
- boxShadow: connectionState === ConnectionState.CONNECTED ? `0 0 ${30 + speakingIntensity * 40}px rgba(255,255,255,${0.15 + speakingIntensity * 0.25})` : 'none',
413
- transform: isSpeaking ? `scale(${1 + speakingIntensity * 0.08})` : 'scale(1)', transition: 'all 0.3s'
414
- }, children: connectionState === ConnectionState.CONNECTING ? (jsxRuntime.jsx("div", { style: { width: '40px', height: '40px', border: '2px solid #ffffff', borderTopColor: 'transparent', borderRadius: '50%', animation: 'vox-spin 1s linear infinite' } })) : (jsxRuntime.jsx("div", { style: { padding: '20px', color: isMuted ? '#52525b' : '#ffffff' }, children: isMuted ? jsxRuntime.jsx(MicOffIcon, {}) : jsxRuntime.jsx(MicIcon, { size: 40 }) })) }), connectionState === ConnectionState.CONNECTED && (jsxRuntime.jsxs("span", { style: { position: 'absolute', bottom: '-4px', right: '-4px', display: 'flex', width: '12px', height: '12px' }, children: [jsxRuntime.jsx("span", { style: { position: 'absolute', display: 'inline-flex', width: '100%', height: '100%', borderRadius: '50%', background: '#ffffff', opacity: isSpeaking ? 1 : 0.75, animation: isSpeaking ? 'vox-ping 1s infinite' : 'none' } }), jsxRuntime.jsx("span", { style: { position: 'relative', display: 'inline-flex', borderRadius: '50%', width: '12px', height: '12px', background: '#ffffff' } })] }))] }), jsxRuntime.jsxs("div", { style: { width: '100%', maxWidth: '280px', display: 'flex', flexDirection: 'column', gap: '16px' }, children: [jsxRuntime.jsxs("p", { style: { textAlign: 'center', fontSize: '10px', fontWeight: 900, color: '#71717a', textTransform: 'uppercase', letterSpacing: '0.2em', height: '20px' }, children: [connectionState === ConnectionState.CONNECTING && 'Initializing...', connectionState === ConnectionState.CONNECTED && (isSpeaking ? 'Agent Speaking...' : isMuted ? 'Signal Muted' : 'Listening...'), connectionState === ConnectionState.ERROR && 'Connection Error', connectionState === ConnectionState.DISCONNECTED && 'Disconnected'] }), connectionState === ConnectionState.CONNECTED && callDuration > 0 && (jsxRuntime.jsxs("p", { style: { textAlign: 'center', fontSize: '11px', fontFamily: 'monospace', color: '#ffffff' }, children: [Math.floor(callDuration / 60).toString().padStart(2, '0'), ":", (callDuration % 60).toString().padStart(2, '0')] })), jsxRuntime.jsx(Visualizer, { analyser: inputAnalyserRef.current, isActive: connectionState === ConnectionState.CONNECTED && !isMuted })] }), connectionState === ConnectionState.ERROR && (jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', fontSize: '10px', textTransform: 'uppercase', letterSpacing: '0.1em', padding: '12px 16px', maxWidth: '280px', textAlign: 'center', color: '#71717a', background: '#18181b', border: '1px solid #3f3f46' }, children: [jsxRuntime.jsx(AlertCircleIcon, {}), jsxRuntime.jsx("span", { style: { marginLeft: '12px' }, children: errorMsg })] })), connectionState === ConnectionState.CONNECTED && (jsxRuntime.jsxs("button", { onClick: () => { disconnect(); onEndCall === null || onEndCall === void 0 ? void 0 : onEndCall(); }, style: {
415
- padding: '12px 24px', border: '1px solid #3f3f46', background: '#000000', color: '#71717a', cursor: 'pointer',
416
- fontSize: '10px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.1em', display: 'flex', alignItems: 'center', gap: '8px'
417
- }, children: [jsxRuntime.jsx(PhoneOffIcon, {}), "End Call"] }))] }));
377
+ boxShadow: connectionState === ConnectionState.CONNECTED ? '0 0 30px rgba(255,255,255,0.15)' : 'none',
378
+ transition: 'all 0.3s'
379
+ }, children: connectionState === ConnectionState.CONNECTING ? (jsxRuntime.jsx("div", { style: { width: '40px', height: '40px', border: '2px solid #ffffff', borderTopColor: 'transparent', borderRadius: '50%', animation: 'vox-spin 1s linear infinite' } })) : (jsxRuntime.jsx("div", { style: { padding: '20px', color: isMuted ? '#52525b' : '#ffffff' }, children: isMuted ? jsxRuntime.jsx(MicOffIcon, {}) : jsxRuntime.jsx(MicIcon, {}) })) }), connectionState === ConnectionState.CONNECTED && (jsxRuntime.jsxs("span", { style: { position: 'absolute', bottom: '-4px', right: '-4px', display: 'flex', width: '12px', height: '12px' }, children: [jsxRuntime.jsx("span", { style: { position: 'absolute', display: 'inline-flex', width: '100%', height: '100%', borderRadius: '50%', background: '#ffffff', opacity: 0.75 } }), jsxRuntime.jsx("span", { style: { position: 'relative', display: 'inline-flex', borderRadius: '50%', width: '12px', height: '12px', background: '#ffffff' } })] }))] }), jsxRuntime.jsxs("div", { style: { width: '100%', maxWidth: '280px', display: 'flex', flexDirection: 'column', gap: '16px' }, children: [jsxRuntime.jsxs("p", { style: { textAlign: 'center', fontSize: '14px', fontWeight: 600, color: '#71717a', height: '20px' }, children: [connectionState === ConnectionState.CONNECTING && 'Initializing...', connectionState === ConnectionState.CONNECTED && (isMuted ? 'Muted' : 'Listening...'), connectionState === ConnectionState.ERROR && 'Connection error', connectionState === ConnectionState.DISCONNECTED && 'Disconnected'] }), connectionState === ConnectionState.CONNECTED && callDuration > 0 && (jsxRuntime.jsxs("p", { style: { textAlign: 'center', fontSize: '11px', fontFamily: 'monospace', color: '#ffffff' }, children: [Math.floor(callDuration / 60).toString().padStart(2, '0'), ":", (callDuration % 60).toString().padStart(2, '0')] })), jsxRuntime.jsx(Visualizer, { analyser: inputAnalyserRef.current, isActive: connectionState === ConnectionState.CONNECTED && !isMuted })] }), connectionState === ConnectionState.ERROR && (jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', fontSize: '14px', fontWeight: 600, padding: '12px 16px', maxWidth: '280px', textAlign: 'center', color: '#71717a', background: '#18181b', border: '1px solid #3f3f46', borderRadius: '8px', gap: '12px' }, children: [jsxRuntime.jsx(AlertCircleIcon, {}), jsxRuntime.jsx("span", { children: errorMsg })] })), connectionState === ConnectionState.CONNECTED && (jsxRuntime.jsxs("div", { style: { display: 'flex', gap: '16px' }, children: [jsxRuntime.jsx("button", { onClick: toggleMute, style: {
380
+ padding: '16px', borderRadius: '50%', border: 'none', cursor: 'pointer', transition: 'all 0.2s',
381
+ background: isMuted ? '#27272a' : '#ffffff',
382
+ color: isMuted ? '#71717a' : '#000000'
383
+ }, children: isMuted ? jsxRuntime.jsx(MicOffIcon, {}) : jsxRuntime.jsx(MicIcon, {}) }), jsxRuntime.jsx("button", { onClick: () => { disconnect(); onEndCall === null || onEndCall === void 0 ? void 0 : onEndCall(); }, style: {
384
+ padding: '16px', borderRadius: '50%', border: 'none', cursor: 'pointer', transition: 'all 0.2s',
385
+ background: '#dc2626', color: '#ffffff'
386
+ }, children: jsxRuntime.jsx(PhoneOffIcon, {}) })] }))] }));
418
387
  };
419
388
  // Main VoxChat Component
420
389
  const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', agentName: propAgentName = 'VOX-01', voiceName: propVoiceName = 'Kore', systemInstruction: propSystemInstruction = 'You are a helpful AI assistant.', position = 'bottom-right', theme = 'dark', buttonColor, buttonSize = 56, borderRadius = 0, iconColor, onOpen, onClose, useServerConfig = false, configPollInterval = 10000 }) => {
@@ -422,11 +391,9 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
422
391
  const [isOpen, setIsOpen] = react.useState(false);
423
392
  const [activeTab, setActiveTab] = react.useState('text');
424
393
  const [isVoiceActive, setIsVoiceActive] = react.useState(false);
425
- // Server config state
426
394
  const [serverConfig, setServerConfig] = react.useState(null);
427
395
  const [configLoaded, setConfigLoaded] = react.useState(!useServerConfig);
428
396
  const [isInitialLoad, setIsInitialLoad] = react.useState(true);
429
- // Fetch config from server
430
397
  const fetchConfig = react.useCallback(() => {
431
398
  if (useServerConfig && apiKey && apiUrl) {
432
399
  fetch(`${apiUrl}/api/v1/config`, {
@@ -447,22 +414,16 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
447
414
  });
448
415
  }
449
416
  }, [useServerConfig, apiKey, apiUrl]);
450
- // Initial fetch and real-time polling (every 10 seconds)
451
417
  react.useEffect(() => {
452
418
  if (useServerConfig && apiKey && apiUrl) {
453
- // Fetch immediately
454
419
  fetchConfig();
455
- // Poll at specified interval for real-time updates
456
420
  const intervalId = setInterval(fetchConfig, configPollInterval);
457
- // Cleanup interval on unmount
458
421
  return () => clearInterval(intervalId);
459
422
  }
460
423
  }, [useServerConfig, apiKey, apiUrl, fetchConfig, configPollInterval]);
461
- // Use server config if available, otherwise use props
462
424
  const agentName = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.name) || propAgentName;
463
425
  const voiceName = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.voiceName) || propVoiceName;
464
426
  const systemInstruction = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.systemInstruction) || propSystemInstruction;
465
- // Widget style from server or props
466
427
  const finalButtonColor = ((_a = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _a === void 0 ? void 0 : _a.buttonColor) || buttonColor || (theme === 'light' ? '#000000' : '#ffffff');
467
428
  const finalButtonSize = ((_b = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _b === void 0 ? void 0 : _b.buttonSize) || buttonSize || 56;
468
429
  const finalBorderRadius = ((_c = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _c === void 0 ? void 0 : _c.borderRadius) !== undefined ? serverConfig.widgetStyle.borderRadius : (borderRadius !== undefined ? borderRadius : 50);
@@ -488,7 +449,7 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
488
449
  const positionStyles = finalPosition === 'bottom-left'
489
450
  ? { bottom: '16px', left: '16px' }
490
451
  : { bottom: '16px', right: '16px' };
491
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("style", { children: `
452
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("link", { href: "https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;900&display=swap", rel: "stylesheet" }), jsxRuntime.jsx("style", { children: `
492
453
  @keyframes vox-fade-in { from { opacity: 0; transform: translateY(40px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
493
454
  @keyframes vox-spin { to { transform: rotate(360deg); } }
494
455
  @keyframes vox-ping { 0% { transform: scale(1); opacity: 0.5; } 50% { transform: scale(1.15); opacity: 0; } 100% { transform: scale(1); opacity: 0; } }
@@ -496,14 +457,17 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
496
457
  ` }), jsxRuntime.jsxs("div", { style: { position: 'fixed', zIndex: 10000, display: 'flex', flexDirection: 'column', alignItems: finalPosition === 'bottom-left' ? 'flex-start' : 'flex-end', gap: '24px', ...positionStyles }, children: [isOpen && (jsxRuntime.jsxs("div", { className: "vox-widget", style: {
497
458
  width: 'min(calc(100vw - 32px), 360px)', height: '550px', maxHeight: '550px',
498
459
  background: '#000000', overflow: 'hidden', display: 'flex', flexDirection: 'column',
499
- border: '1px solid #3f3f46', boxShadow: '0 20px 40px -10px rgba(0,0,0,0.5)', borderRadius: '12px'
500
- }, children: [jsxRuntime.jsxs("div", { style: { height: '48px', background: '#000000', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', flexShrink: 0, borderBottom: '1px solid #3f3f46' }, children: [jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [jsxRuntime.jsx("div", { style: { width: '28px', height: '28px', border: '1px solid #52525b', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#ffffff', transition: 'all 0.3s ease' }, children: finalLogoUrl ? (jsxRuntime.jsx("img", { src: finalLogoUrl, alt: agentName, style: { width: '16px', height: '16px', objectFit: 'contain', transition: 'opacity 0.3s ease' } }, finalLogoUrl)) : (jsxRuntime.jsx(MessageCircleIcon, {})) }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h2", { style: { color: '#ffffff', fontWeight: 900, fontSize: '9px', textTransform: 'uppercase', letterSpacing: '0.15em', margin: 0, transition: 'all 0.3s ease' }, children: agentName }), jsxRuntime.jsxs("p", { style: { color: '#a1a1aa', fontSize: '8px', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', margin: 0, display: 'flex', alignItems: 'center' }, children: [jsxRuntime.jsx("span", { style: { width: '4px', height: '4px', background: '#ffffff', borderRadius: '50%', marginRight: '6px' } }), "Active"] })] })] }), jsxRuntime.jsx("button", { onClick: handleClose, style: { background: 'none', border: 'none', color: '#a1a1aa', cursor: 'pointer', padding: '4px', transition: 'color 0.2s' }, children: jsxRuntime.jsx(XIcon, {}) })] }), jsxRuntime.jsxs("div", { style: { display: 'flex', padding: '2px', background: '#18181b', borderBottom: '1px solid #3f3f46', flexShrink: 0 }, children: [jsxRuntime.jsx("button", { onClick: () => handleTabChange('text'), style: {
501
- flex: 1, padding: '8px', fontSize: '9px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.15em',
502
- background: 'none', border: 'none', cursor: 'pointer', color: activeTab === 'text' ? '#ffffff' : '#71717a', transition: 'color 0.2s'
503
- }, children: "Text Interface" }), jsxRuntime.jsx("div", { style: { width: '1px', background: '#3f3f46' } }), jsxRuntime.jsx("button", { onClick: () => handleTabChange('voice'), style: {
504
- flex: 1, padding: '8px', fontSize: '9px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.15em',
505
- background: 'none', border: 'none', cursor: 'pointer', color: activeTab === 'voice' ? '#ffffff' : '#71717a', transition: 'color 0.2s'
506
- }, children: "Voice Protocol" })] }), jsxRuntime.jsx("div", { style: { flex: 1, overflow: 'hidden', position: 'relative', background: '#000000' }, children: activeTab === 'text' ? (jsxRuntime.jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction })) : (isVoiceActive ? (jsxRuntime.jsx(VoiceInterface, { geminiApiKey: geminiApiKey, voiceName: voiceName, systemInstruction: systemInstruction, onEndCall: handleEndCall })) : (jsxRuntime.jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction }))) })] })), !isOpen && (!useServerConfig || configLoaded) && (jsxRuntime.jsx("button", { onClick: handleOpen, style: {
460
+ border: '1px solid #3f3f46', boxShadow: '0 20px 40px -10px rgba(0,0,0,0.5)', borderRadius: '12px',
461
+ transition: 'all 0.3s ease'
462
+ }, children: [jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 16px', flexShrink: 0, borderBottom: '1px solid #3f3f46', background: '#000000', fontFamily: 'Outfit, sans-serif' }, children: [jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [jsxRuntime.jsx("div", { style: { width: '28px', height: '28px', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.3s ease' }, children: finalLogoUrl ? (jsxRuntime.jsx("img", { src: finalLogoUrl, alt: agentName, style: { width: '28px', height: '28px', objectFit: 'contain', transition: 'opacity 0.3s ease' } }, finalLogoUrl)) : (activeTab === 'voice' ? jsxRuntime.jsx(MicIcon, {}) : jsxRuntime.jsx(MessageCircleIcon, {})) }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h2", { style: { color: '#ffffff', fontWeight: 700, fontSize: '14px', margin: 0, transition: 'all 0.3s ease' }, children: agentName }), jsxRuntime.jsxs("p", { style: { color: '#a1a1aa', fontSize: '12px', fontWeight: 500, margin: 0, display: 'flex', alignItems: 'center' }, children: [jsxRuntime.jsx("span", { style: { width: '6px', height: '6px', background: '#ffffff', borderRadius: '50%', marginRight: '6px' } }), "Active"] })] })] }), jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '2px', padding: '2px', borderRadius: '8px', background: '#18181b' }, children: [jsxRuntime.jsx("button", { onClick: () => handleTabChange('text'), style: {
463
+ padding: '6px 12px', fontSize: '12px', fontWeight: 600, borderRadius: '6px',
464
+ background: activeTab === 'text' ? '#27272a' : 'transparent', border: 'none', cursor: 'pointer', color: activeTab === 'text' ? '#ffffff' : '#71717a', transition: 'all 0.2s',
465
+ boxShadow: activeTab === 'text' ? '0 1px 2px rgba(0,0,0,0.1)' : 'none'
466
+ }, children: "Text" }), jsxRuntime.jsx("button", { onClick: () => handleTabChange('voice'), style: {
467
+ padding: '6px 12px', fontSize: '12px', fontWeight: 600, borderRadius: '6px',
468
+ background: activeTab === 'voice' ? '#27272a' : 'transparent', border: 'none', cursor: 'pointer', color: activeTab === 'voice' ? '#ffffff' : '#71717a', transition: 'all 0.2s',
469
+ boxShadow: activeTab === 'voice' ? '0 1px 2px rgba(0,0,0,0.1)' : 'none'
470
+ }, children: "Voice" })] }), jsxRuntime.jsx("button", { onClick: handleClose, style: { background: 'none', border: 'none', color: '#a1a1aa', cursor: 'pointer', padding: '4px', transition: 'color 0.2s' }, children: jsxRuntime.jsx(XIcon, {}) })] }), jsxRuntime.jsx("div", { style: { flex: 1, overflow: 'hidden', position: 'relative', background: '#000000' }, children: activeTab === 'text' ? (jsxRuntime.jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction, logoUrl: finalLogoUrl })) : (isVoiceActive ? (jsxRuntime.jsx(VoiceInterface, { geminiApiKey: geminiApiKey, voiceName: voiceName, systemInstruction: systemInstruction, onEndCall: handleEndCall })) : (jsxRuntime.jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction, logoUrl: finalLogoUrl }))) })] })), !isOpen && (!useServerConfig || configLoaded) && (jsxRuntime.jsx("button", { onClick: handleOpen, style: {
507
471
  width: `${finalButtonSize}px`, height: `${finalButtonSize}px`,
508
472
  borderRadius: `${finalBorderRadius}px`,
509
473
  background: finalButtonColor, color: finalIconColor, border: 'none', cursor: 'pointer',