vox-ai-react 1.2.0 → 1.3.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/README.md +136 -94
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +40 -22
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +39 -21
- package/dist/index.js.map +1 -1
- package/package.json +45 -43
package/README.md
CHANGED
|
@@ -1,94 +1,136 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
Official React component for VOX AI Chat Widget.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install
|
|
9
|
-
# or
|
|
10
|
-
yarn add
|
|
11
|
-
# or
|
|
12
|
-
pnpm add
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Quick Start
|
|
16
|
-
|
|
17
|
-
```jsx
|
|
18
|
-
import { VoxChat } from '
|
|
19
|
-
|
|
20
|
-
function App() {
|
|
21
|
-
return (
|
|
22
|
-
<div>
|
|
23
|
-
<h1>My Website</h1>
|
|
24
|
-
<VoxChat
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
##
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
# vox-ai-react
|
|
2
|
+
|
|
3
|
+
Official React component for VOX AI Chat Widget.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install vox-ai-react
|
|
9
|
+
# or
|
|
10
|
+
yarn add vox-ai-react
|
|
11
|
+
# or
|
|
12
|
+
pnpm add vox-ai-react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```jsx
|
|
18
|
+
import { VoxChat } from 'vox-ai-react';
|
|
19
|
+
|
|
20
|
+
function App() {
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
<h1>My Website</h1>
|
|
24
|
+
<VoxChat
|
|
25
|
+
apiKey="vox_live_xxxxxxxx"
|
|
26
|
+
geminiApiKey="your-gemini-api-key"
|
|
27
|
+
apiUrl="https://voxai.zeabur.app"
|
|
28
|
+
/>
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Using Server-Stored Configuration (Real-Time)
|
|
35
|
+
|
|
36
|
+
You can configure your agent (name, system instruction, voice, logo, colors, etc.) in the VOX Dashboard, and the widget will automatically use those settings. The widget polls for updates every 10 seconds, so changes you make in the dashboard appear in real-time on your website!
|
|
37
|
+
|
|
38
|
+
```jsx
|
|
39
|
+
<VoxChat
|
|
40
|
+
apiKey="vox_live_xxxxxxxx"
|
|
41
|
+
geminiApiKey="your-gemini-api-key"
|
|
42
|
+
apiUrl="https://voxai.zeabur.app"
|
|
43
|
+
useServerConfig={true} // Fetches config from your VOX account
|
|
44
|
+
/>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Custom Polling Interval
|
|
48
|
+
|
|
49
|
+
By default, the widget checks for configuration updates every 10 seconds. You can customize this:
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
<VoxChat
|
|
53
|
+
apiKey="vox_live_xxxxxxxx"
|
|
54
|
+
geminiApiKey="your-gemini-api-key"
|
|
55
|
+
apiUrl="https://voxai.zeabur.app"
|
|
56
|
+
useServerConfig={true}
|
|
57
|
+
configPollInterval={5000} // Check every 5 seconds
|
|
58
|
+
/>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**What gets synced in real-time:**
|
|
62
|
+
- Agent name
|
|
63
|
+
- System instructions
|
|
64
|
+
- Voice settings
|
|
65
|
+
- Custom logo
|
|
66
|
+
- Button colors
|
|
67
|
+
- Button size
|
|
68
|
+
- Border radius
|
|
69
|
+
- Widget position
|
|
70
|
+
|
|
71
|
+
## Props
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Default | Description |
|
|
74
|
+
|------|------|---------|-------------|
|
|
75
|
+
| `apiKey` | `string` | Required | Your VOX API key |
|
|
76
|
+
| `geminiApiKey` | `string` | Required | Your Gemini API key (for voice) |
|
|
77
|
+
| `apiUrl` | `string` | Required | VOX API server URL |
|
|
78
|
+
| `agentName` | `string` | `'VOX-01'` | Display name for the agent |
|
|
79
|
+
| `voiceName` | `string` | `'Kore'` | Voice name for voice chat |
|
|
80
|
+
| `systemInstruction` | `string` | `'You are a helpful AI assistant.'` | System instruction for the AI |
|
|
81
|
+
| `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Widget position |
|
|
82
|
+
| `theme` | `'dark' \| 'light'` | `'dark'` | Color theme |
|
|
83
|
+
| `buttonColor` | `string` | Theme default | Custom button background color |
|
|
84
|
+
| `buttonSize` | `number` | `56` | Button size in pixels |
|
|
85
|
+
| `borderRadius` | `number` | `0` | Button border radius in pixels |
|
|
86
|
+
| `iconColor` | `string` | Theme default | Custom icon color |
|
|
87
|
+
| `useServerConfig` | `boolean` | `false` | Fetch agent config from server |
|
|
88
|
+
| `configPollInterval` | `number` | `10000` | Config polling interval in ms (when useServerConfig is true) |
|
|
89
|
+
| `onOpen` | `() => void` | - | Callback when chat opens |
|
|
90
|
+
| `onClose` | `() => void` | - | Callback when chat closes |
|
|
91
|
+
|
|
92
|
+
## Customization Examples
|
|
93
|
+
|
|
94
|
+
### Custom Colors
|
|
95
|
+
|
|
96
|
+
```jsx
|
|
97
|
+
<VoxChat
|
|
98
|
+
apiKey="vox_live_xxxxxxxx"
|
|
99
|
+
geminiApiKey="your-gemini-api-key"
|
|
100
|
+
apiUrl="https://voxai.zeabur.app"
|
|
101
|
+
buttonColor="#6366f1"
|
|
102
|
+
iconColor="#ffffff"
|
|
103
|
+
borderRadius={24}
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Light Theme
|
|
108
|
+
|
|
109
|
+
```jsx
|
|
110
|
+
<VoxChat
|
|
111
|
+
apiKey="vox_live_xxxxxxxx"
|
|
112
|
+
geminiApiKey="your-gemini-api-key"
|
|
113
|
+
apiUrl="https://voxai.zeabur.app"
|
|
114
|
+
theme="light"
|
|
115
|
+
/>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### With Callbacks
|
|
119
|
+
|
|
120
|
+
```jsx
|
|
121
|
+
<VoxChat
|
|
122
|
+
apiKey="vox_live_xxxxxxxx"
|
|
123
|
+
geminiApiKey="your-gemini-api-key"
|
|
124
|
+
apiUrl="https://voxai.zeabur.app"
|
|
125
|
+
onOpen={() => console.log('Chat opened')}
|
|
126
|
+
onClose={() => console.log('Chat closed')}
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Get Your API Key
|
|
131
|
+
|
|
132
|
+
Visit the VOX Dashboard to get your API key and configure your agent.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
package/dist/index.d.ts
CHANGED
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useEffect, useRef
|
|
2
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
3
3
|
|
|
4
4
|
var ConnectionState;
|
|
5
5
|
(function (ConnectionState) {
|
|
@@ -43,14 +43,14 @@ const MicIcon = ({ size = 14 }) => (jsxs("svg", { width: size, height: size, vie
|
|
|
43
43
|
const MicOffIcon = ({ size = 40 }) => (jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "2", x2: "22", y1: "2", y2: "22" }), jsx("path", { d: "M18.89 13.23A7.12 7.12 0 0 0 19 12v-2" }), jsx("path", { d: "M5 10v2a7 7 0 0 0 12 5" }), jsx("path", { d: "M15 9.34V5a3 3 0 0 0-5.68-1.33" }), jsx("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12" }), jsx("line", { x1: "12", x2: "12", y1: "19", y2: "22" })] }));
|
|
44
44
|
const XIcon = () => (jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 6 6 18" }), jsx("path", { d: "m6 6 12 12" })] }));
|
|
45
45
|
const PhoneOffIcon = () => (jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [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" }), jsx("line", { x1: "22", x2: "2", y1: "2", y2: "22" })] }));
|
|
46
|
-
const
|
|
46
|
+
const VoxLogoIcon = () => (jsxs("svg", { width: "12", height: "12", viewBox: "0 0 48 48", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [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" }), jsx("path", { d: "M24 42.476L12.938 33.58V5.524L24 16.351" }), jsx("path", { d: "M24 42.476L9.125 35.557V7.501L24 16.351" }), jsx("path", { d: "M24 42.476L5.5 38.004V9.948L24 16.351m0 26.125l11.062-8.896V5.524L24 16.351" }), jsx("path", { d: "m24 42.476l14.875-6.919V7.501L24 16.351" }), jsx("path", { d: "m24 42.476l18.5-4.472V9.948L24 16.351" })] }));
|
|
47
47
|
const UserIcon = () => (jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }), jsx("circle", { cx: "12", cy: "7", r: "4" })] }));
|
|
48
48
|
const Loader2Icon = () => (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: jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }));
|
|
49
49
|
const AlertCircleIcon = () => (jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("circle", { cx: "12", cy: "12", r: "10" }), jsx("line", { x1: "12", x2: "12", y1: "8", y2: "12" }), jsx("line", { x1: "12", x2: "12.01", y1: "16", y2: "16" })] }));
|
|
50
50
|
// Visualizer Component
|
|
51
51
|
const Visualizer = ({ analyser, isActive }) => {
|
|
52
52
|
const canvasRef = useRef(null);
|
|
53
|
-
const animationRef = useRef();
|
|
53
|
+
const animationRef = useRef(undefined);
|
|
54
54
|
useEffect(() => {
|
|
55
55
|
const canvas = canvasRef.current;
|
|
56
56
|
if (!canvas)
|
|
@@ -150,11 +150,11 @@ const TextInterface = ({ apiKey, apiUrl, agentName, systemInstruction }) => {
|
|
|
150
150
|
border: msg.role === 'user' ? '1px solid #ffffff' : '1px solid #52525b',
|
|
151
151
|
background: msg.role === 'user' ? '#ffffff' : 'transparent',
|
|
152
152
|
color: msg.role === 'user' ? '#000000' : '#ffffff'
|
|
153
|
-
}, children: msg.role === 'user' ? jsx(UserIcon, {}) : jsx(
|
|
153
|
+
}, children: msg.role === 'user' ? jsx(UserIcon, {}) : jsx(VoxLogoIcon, {}) }), jsx("div", { style: {
|
|
154
154
|
padding: '12px 16px', fontSize: '11px', fontWeight: 700, letterSpacing: '0.05em', lineHeight: 1.6,
|
|
155
155
|
border: '1px solid #3f3f46', background: msg.role === 'user' ? '#27272a' : '#000000',
|
|
156
156
|
color: msg.role === 'user' ? '#ffffff' : '#d4d4d8'
|
|
157
|
-
}, children: msg.text })] }) }, msg.id))), isLoading && (jsx("div", { style: { display: 'flex', justifyContent: 'flex-start' }, children: jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', gap: '12px' }, children: [jsx("div", { style: { flexShrink: 0, width: '28px', height: '28px', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid #3f3f46', color: '#ffffff', opacity: 0.2 }, children: jsx(
|
|
157
|
+
}, children: msg.text })] }) }, msg.id))), isLoading && (jsx("div", { style: { display: 'flex', justifyContent: 'flex-start' }, children: jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', gap: '12px' }, children: [jsx("div", { style: { flexShrink: 0, width: '28px', height: '28px', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid #3f3f46', color: '#ffffff', opacity: 0.2 }, children: jsx(VoxLogoIcon, {}) }), jsx("div", { style: { padding: '16px 24px', border: '1px solid #3f3f46', background: '#000000', color: '#71717a' }, children: jsx(Loader2Icon, {}) })] }) }))] }), jsx("div", { style: { padding: '24px' }, children: jsxs("form", { onSubmit: handleSend, style: { display: 'flex', gap: '16px' }, children: [jsx("input", { type: "text", value: input, onChange: (e) => setInput(e.target.value), placeholder: "INPUT COMMAND...", disabled: isLoading, style: {
|
|
158
158
|
flex: 1, padding: '16px 24px', border: '1px solid #52525b', background: '#000000', color: '#ffffff',
|
|
159
159
|
outline: 'none', fontSize: '10px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.1em'
|
|
160
160
|
} }), jsx("button", { type: "submit", disabled: !input.trim() || isLoading, style: {
|
|
@@ -413,15 +413,16 @@ const VoiceInterface = ({ geminiApiKey, voiceName, systemInstruction, onEndCall
|
|
|
413
413
|
}, children: [jsx(PhoneOffIcon, {}), "End Call"] }))] }));
|
|
414
414
|
};
|
|
415
415
|
// Main VoxChat Component
|
|
416
|
-
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 }) => {
|
|
416
|
+
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 }) => {
|
|
417
|
+
var _a, _b, _c, _d, _e, _f;
|
|
417
418
|
const [isOpen, setIsOpen] = useState(false);
|
|
418
419
|
const [activeTab, setActiveTab] = useState('text');
|
|
419
420
|
const [isVoiceActive, setIsVoiceActive] = useState(false);
|
|
420
421
|
// Server config state
|
|
421
422
|
const [serverConfig, setServerConfig] = useState(null);
|
|
422
423
|
const [configLoaded, setConfigLoaded] = useState(!useServerConfig);
|
|
423
|
-
// Fetch config from server
|
|
424
|
-
|
|
424
|
+
// Fetch config from server
|
|
425
|
+
const fetchConfig = useCallback(() => {
|
|
425
426
|
if (useServerConfig && apiKey && apiUrl) {
|
|
426
427
|
fetch(`${apiUrl}/api/v1/config`, {
|
|
427
428
|
headers: { 'x-api-key': apiKey }
|
|
@@ -439,10 +440,28 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
|
|
|
439
440
|
});
|
|
440
441
|
}
|
|
441
442
|
}, [useServerConfig, apiKey, apiUrl]);
|
|
443
|
+
// Initial fetch and real-time polling (every 10 seconds)
|
|
444
|
+
useEffect(() => {
|
|
445
|
+
if (useServerConfig && apiKey && apiUrl) {
|
|
446
|
+
// Fetch immediately
|
|
447
|
+
fetchConfig();
|
|
448
|
+
// Poll at specified interval for real-time updates
|
|
449
|
+
const intervalId = setInterval(fetchConfig, configPollInterval);
|
|
450
|
+
// Cleanup interval on unmount
|
|
451
|
+
return () => clearInterval(intervalId);
|
|
452
|
+
}
|
|
453
|
+
}, [useServerConfig, apiKey, apiUrl, fetchConfig, configPollInterval]);
|
|
442
454
|
// Use server config if available, otherwise use props
|
|
443
455
|
const agentName = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.name) || propAgentName;
|
|
444
456
|
const voiceName = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.voiceName) || propVoiceName;
|
|
445
457
|
const systemInstruction = (serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.systemInstruction) || propSystemInstruction;
|
|
458
|
+
// Widget style from server or props
|
|
459
|
+
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');
|
|
460
|
+
const finalButtonSize = ((_b = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _b === void 0 ? void 0 : _b.buttonSize) || buttonSize || 56;
|
|
461
|
+
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);
|
|
462
|
+
const finalPosition = ((_d = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _d === void 0 ? void 0 : _d.position) || position || 'bottom-right';
|
|
463
|
+
const finalIconColor = ((_e = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _e === void 0 ? void 0 : _e.iconColor) || iconColor || (theme === 'light' ? '#ffffff' : '#000000');
|
|
464
|
+
const finalLogoUrl = (_f = serverConfig === null || serverConfig === void 0 ? void 0 : serverConfig.widgetStyle) === null || _f === void 0 ? void 0 : _f.logoUrl;
|
|
446
465
|
const handleOpen = () => { setIsOpen(true); onOpen === null || onOpen === void 0 ? void 0 : onOpen(); };
|
|
447
466
|
const handleClose = () => { setIsOpen(false); setIsVoiceActive(false); setActiveTab('text'); onClose === null || onClose === void 0 ? void 0 : onClose(); };
|
|
448
467
|
const handleTabChange = (tab) => {
|
|
@@ -459,33 +478,32 @@ const VoxChat = ({ apiKey, geminiApiKey, apiUrl = 'https://your-server.com', age
|
|
|
459
478
|
setIsVoiceActive(false);
|
|
460
479
|
setActiveTab('text');
|
|
461
480
|
};
|
|
462
|
-
const positionStyles =
|
|
481
|
+
const positionStyles = finalPosition === 'bottom-left'
|
|
463
482
|
? { bottom: '16px', left: '16px' }
|
|
464
483
|
: { bottom: '16px', right: '16px' };
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
@keyframes vox-spin { to { transform: rotate(360deg); } }
|
|
471
|
-
@keyframes vox-ping { 0% { transform: scale(1); opacity: 0.5; } 50% { transform: scale(1.15); opacity: 0; } 100% { transform: scale(1); opacity: 0; } }
|
|
472
|
-
.vox-widget { animation: vox-fade-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
|
|
484
|
+
return (jsxs(Fragment, { children: [jsx("style", { children: `
|
|
485
|
+
@keyframes vox-fade-in { from { opacity: 0; transform: translateY(40px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
|
|
486
|
+
@keyframes vox-spin { to { transform: rotate(360deg); } }
|
|
487
|
+
@keyframes vox-ping { 0% { transform: scale(1); opacity: 0.5; } 50% { transform: scale(1.15); opacity: 0; } 100% { transform: scale(1); opacity: 0; } }
|
|
488
|
+
.vox-widget { animation: vox-fade-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
|
|
473
489
|
` }), jsxs("div", { style: { position: 'fixed', zIndex: 10000, display: 'flex', flexDirection: 'column', alignItems: position === 'bottom-left' ? 'flex-start' : 'flex-end', gap: '24px', ...positionStyles }, children: [isOpen && (jsxs("div", { className: "vox-widget", style: {
|
|
474
490
|
width: 'min(calc(100vw - 32px), 400px)', height: 'min(calc(100vh - 100px), 640px)', maxHeight: '640px',
|
|
475
491
|
background: '#000000', overflow: 'hidden', display: 'flex', flexDirection: 'column',
|
|
476
492
|
border: '1px solid #3f3f46', boxShadow: '0 30px 60px -15px rgba(0,0,0,0.5)'
|
|
477
|
-
}, children: [jsxs("div", { style: { height: '56px', background: '#000000', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', flexShrink: 0, borderBottom: '1px solid #3f3f46' }, children: [jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '12px' }, children: [jsx("div", { style: { width: '32px', height: '32px', border: '1px solid #52525b', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#ffffff' }, children: jsx(MessageCircleIcon, {}) }), jsxs("div", { children: [jsx("h2", { style: { color: '#ffffff', fontWeight: 900, fontSize: '10px', textTransform: 'uppercase', letterSpacing: '0.2em', margin: 0 }, children: agentName }), jsxs("p", { style: { color: '#a1a1aa', fontSize: '9px', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', margin: 0, display: 'flex', alignItems: 'center' }, children: [jsx("span", { style: { width: '4px', height: '4px', background: '#ffffff', borderRadius: '50%', marginRight: '8px' } }), "Active"] })] })] }), jsx("button", { onClick: handleClose, style: { background: 'none', border: 'none', color: '#a1a1aa', cursor: 'pointer', padding: '4px', transition: 'color 0.2s' }, children: jsx(XIcon, {}) })] }), jsxs("div", { style: { display: 'flex', padding: '4px', background: '#18181b', borderBottom: '1px solid #3f3f46', flexShrink: 0 }, children: [jsx("button", { onClick: () => handleTabChange('text'), style: {
|
|
493
|
+
}, children: [jsxs("div", { style: { height: '56px', background: '#000000', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', flexShrink: 0, borderBottom: '1px solid #3f3f46' }, children: [jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '12px' }, children: [jsx("div", { style: { width: '32px', height: '32px', border: '1px solid #52525b', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#ffffff' }, children: finalLogoUrl ? (jsx("img", { src: finalLogoUrl, alt: agentName, style: { width: '18px', height: '18px', objectFit: 'contain' } })) : (jsx(MessageCircleIcon, {})) }), jsxs("div", { children: [jsx("h2", { style: { color: '#ffffff', fontWeight: 900, fontSize: '10px', textTransform: 'uppercase', letterSpacing: '0.2em', margin: 0 }, children: agentName }), jsxs("p", { style: { color: '#a1a1aa', fontSize: '9px', fontWeight: 700, textTransform: 'uppercase', letterSpacing: '0.1em', margin: 0, display: 'flex', alignItems: 'center' }, children: [jsx("span", { style: { width: '4px', height: '4px', background: '#ffffff', borderRadius: '50%', marginRight: '8px' } }), "Active"] })] })] }), jsx("button", { onClick: handleClose, style: { background: 'none', border: 'none', color: '#a1a1aa', cursor: 'pointer', padding: '4px', transition: 'color 0.2s' }, children: jsx(XIcon, {}) })] }), jsxs("div", { style: { display: 'flex', padding: '4px', background: '#18181b', borderBottom: '1px solid #3f3f46', flexShrink: 0 }, children: [jsx("button", { onClick: () => handleTabChange('text'), style: {
|
|
478
494
|
flex: 1, padding: '12px', fontSize: '10px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.2em',
|
|
479
495
|
background: 'none', border: 'none', cursor: 'pointer', color: activeTab === 'text' ? '#ffffff' : '#71717a', transition: 'color 0.2s'
|
|
480
496
|
}, children: "Text Interface" }), jsx("div", { style: { width: '1px', background: '#3f3f46' } }), jsx("button", { onClick: () => handleTabChange('voice'), style: {
|
|
481
497
|
flex: 1, padding: '12px', fontSize: '10px', fontWeight: 900, textTransform: 'uppercase', letterSpacing: '0.2em',
|
|
482
498
|
background: 'none', border: 'none', cursor: 'pointer', color: activeTab === 'voice' ? '#ffffff' : '#71717a', transition: 'color 0.2s'
|
|
483
499
|
}, children: "Voice Protocol" })] }), jsx("div", { style: { flex: 1, overflow: 'hidden', position: 'relative', background: '#000000' }, children: activeTab === 'text' ? (jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction })) : (isVoiceActive ? (jsx(VoiceInterface, { geminiApiKey: geminiApiKey, voiceName: voiceName, systemInstruction: systemInstruction, onEndCall: handleEndCall })) : (jsx(TextInterface, { apiKey: apiKey, apiUrl: apiUrl, agentName: agentName, systemInstruction: systemInstruction }))) })] })), !isOpen && (jsx("button", { onClick: handleOpen, style: {
|
|
484
|
-
width: `${
|
|
485
|
-
|
|
500
|
+
width: `${finalButtonSize}px`, height: `${finalButtonSize}px`,
|
|
501
|
+
borderRadius: `${finalBorderRadius}px`,
|
|
502
|
+
background: finalButtonColor, color: finalIconColor, border: 'none', cursor: 'pointer',
|
|
486
503
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
487
|
-
boxShadow: '0 4px 20px rgba(0,0,0,0.3)',
|
|
488
|
-
|
|
504
|
+
boxShadow: '0 4px 20px rgba(0,0,0,0.3)',
|
|
505
|
+
transition: 'all 0.3s ease, transform 0.2s'
|
|
506
|
+
}, children: finalLogoUrl ? (jsx("img", { src: finalLogoUrl, alt: "Chat", style: { width: '60%', height: '60%', objectFit: 'contain', transition: 'opacity 0.3s ease' } })) : (jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: jsx("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }) })) }))] })] }));
|
|
489
507
|
};
|
|
490
508
|
|
|
491
509
|
export { VoxChat, VoxChat as default };
|