@makemore/agent-frontend 1.3.0 → 1.4.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 +135 -2
- package/dist/chat-widget.css +13 -0
- package/dist/chat-widget.js +175 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,14 +23,17 @@ Most chat widgets are tightly coupled to specific frameworks or require complex
|
|
|
23
23
|
| Feature | Description |
|
|
24
24
|
|---------|-------------|
|
|
25
25
|
| 💬 **Real-time Streaming** | SSE-based message streaming for instant, token-by-token responses |
|
|
26
|
+
| 🔊 **Text-to-Speech** | ElevenLabs integration with secure Django proxy support |
|
|
26
27
|
| 🎨 **Theming** | Customize colors, titles, messages, and position |
|
|
27
28
|
| 🌙 **Dark Mode** | Automatic dark mode based on system preferences |
|
|
28
29
|
| 📱 **Responsive** | Works seamlessly on desktop and mobile |
|
|
29
30
|
| 🔧 **Debug Mode** | Toggle visibility of tool calls and results |
|
|
30
|
-
| 🤖 **Demo Flows** | Built-in auto-run mode
|
|
31
|
+
| 🤖 **Demo Flows** | Built-in auto-run mode with automatic, confirm, and manual modes |
|
|
31
32
|
| 🔒 **Sessions** | Automatic anonymous session creation and management |
|
|
32
33
|
| 💾 **Persistence** | Conversations persist across page reloads via localStorage |
|
|
33
34
|
| 🛡️ **Isolated CSS** | Scoped styles that won't leak into or from your page |
|
|
35
|
+
| 🎯 **Configurable APIs** | Customize backend endpoints to match your server structure |
|
|
36
|
+
| 📝 **Enhanced Markdown** | Optional rich markdown with tables, code blocks, and syntax highlighting |
|
|
34
37
|
|
|
35
38
|
## Installation
|
|
36
39
|
|
|
@@ -85,7 +88,7 @@ The widget automatically detects and uses the enhanced markdown parser if availa
|
|
|
85
88
|
|
|
86
89
|
## Quick Start
|
|
87
90
|
|
|
88
|
-
###
|
|
91
|
+
### Basic Setup
|
|
89
92
|
|
|
90
93
|
```html
|
|
91
94
|
<script>
|
|
@@ -98,6 +101,23 @@ The widget automatically detects and uses the enhanced markdown parser if availa
|
|
|
98
101
|
</script>
|
|
99
102
|
```
|
|
100
103
|
|
|
104
|
+
### With Text-to-Speech (Recommended: Django Proxy)
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<script>
|
|
108
|
+
ChatWidget.init({
|
|
109
|
+
backendUrl: 'https://your-api.com',
|
|
110
|
+
agentKey: 'your-agent',
|
|
111
|
+
title: 'Voice-Enabled Chat',
|
|
112
|
+
primaryColor: '#0066cc',
|
|
113
|
+
enableTTS: true,
|
|
114
|
+
ttsProxyUrl: 'https://your-api.com/api/tts/speak/',
|
|
115
|
+
});
|
|
116
|
+
</script>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
See `django-tts-example.py` for the complete Django backend implementation.
|
|
120
|
+
|
|
101
121
|
### With custom API paths
|
|
102
122
|
|
|
103
123
|
```html
|
|
@@ -139,6 +159,85 @@ The widget automatically detects and uses the enhanced markdown parser if availa
|
|
|
139
159
|
| `apiPaths` | object | See below | API endpoint paths (customizable for different backends) |
|
|
140
160
|
| `autoRunMode` | string | `'automatic'` | Demo flow mode: `'automatic'`, `'confirm'`, or `'manual'` |
|
|
141
161
|
| `autoRunDelay` | number | `1000` | Delay in milliseconds before auto-generating next message (automatic mode) |
|
|
162
|
+
| `enableTTS` | boolean | `false` | Enable text-to-speech for messages |
|
|
163
|
+
| `ttsProxyUrl` | string | `null` | Django proxy URL for TTS (recommended for security) |
|
|
164
|
+
| `elevenLabsApiKey` | string | `null` | ElevenLabs API key (only if not using proxy) |
|
|
165
|
+
| `ttsVoices` | object | `{ assistant: null, user: null }` | Voice IDs (only if not using proxy) |
|
|
166
|
+
| `ttsModel` | string | `'eleven_turbo_v2_5'` | ElevenLabs model (only if not using proxy) |
|
|
167
|
+
| `ttsSettings` | object | See below | ElevenLabs voice settings (only if not using proxy) |
|
|
168
|
+
|
|
169
|
+
### Text-to-Speech (ElevenLabs)
|
|
170
|
+
|
|
171
|
+
Add realistic voice narration to your chat widget using ElevenLabs. Two integration options:
|
|
172
|
+
|
|
173
|
+
#### Option 1: Secure Django Proxy (Recommended)
|
|
174
|
+
|
|
175
|
+
Keep your API key secure on the server:
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
ChatWidget.init({
|
|
179
|
+
enableTTS: true,
|
|
180
|
+
ttsProxyUrl: 'https://your-backend.com/api/tts/speak/',
|
|
181
|
+
// No API key or voice IDs needed - configured on server
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Django Setup:**
|
|
186
|
+
|
|
187
|
+
See `django-tts-example.py` for a complete Django REST Framework implementation. Quick setup:
|
|
188
|
+
|
|
189
|
+
1. Install: `pip install requests`
|
|
190
|
+
2. Add to `settings.py`:
|
|
191
|
+
```python
|
|
192
|
+
ELEVENLABS_API_KEY = 'your_api_key_here'
|
|
193
|
+
ELEVENLABS_VOICES = {
|
|
194
|
+
'assistant': 'EXAVITQu4vr4xnSDxMaL', # Bella
|
|
195
|
+
'user': 'pNInz6obpgDQGcFmaJgB', # Adam
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
3. Add view from `django-tts-example.py` to your Django app
|
|
199
|
+
4. Add URL route: `path('api/tts/speak/', views.text_to_speech)`
|
|
200
|
+
|
|
201
|
+
#### Option 2: Direct API (Client-Side)
|
|
202
|
+
|
|
203
|
+
For testing or simple deployments:
|
|
204
|
+
|
|
205
|
+
```javascript
|
|
206
|
+
ChatWidget.init({
|
|
207
|
+
enableTTS: true,
|
|
208
|
+
elevenLabsApiKey: 'your_elevenlabs_api_key', // ⚠️ Exposed to client
|
|
209
|
+
ttsVoices: {
|
|
210
|
+
assistant: 'EXAVITQu4vr4xnSDxMaL', // Bella
|
|
211
|
+
user: 'pNInz6obpgDQGcFmaJgB', // Adam
|
|
212
|
+
},
|
|
213
|
+
ttsModel: 'eleven_turbo_v2_5',
|
|
214
|
+
ttsSettings: {
|
|
215
|
+
stability: 0.5,
|
|
216
|
+
similarity_boost: 0.75,
|
|
217
|
+
style: 0.0,
|
|
218
|
+
use_speaker_boost: true,
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Features:**
|
|
224
|
+
- Speaks assistant responses automatically
|
|
225
|
+
- Speaks simulated user messages in demo mode
|
|
226
|
+
- Queues messages to prevent overlap
|
|
227
|
+
- Waits for speech to finish before continuing demo (automatic mode)
|
|
228
|
+
- Toggle TTS on/off with button in header
|
|
229
|
+
- Visual indicator when speaking (pulsing icon)
|
|
230
|
+
|
|
231
|
+
**Get Voice IDs:**
|
|
232
|
+
1. Go to https://elevenlabs.io/app/voice-library
|
|
233
|
+
2. Choose voices and copy their IDs
|
|
234
|
+
3. Or use the API: https://api.elevenlabs.io/v1/voices
|
|
235
|
+
|
|
236
|
+
**Control TTS:**
|
|
237
|
+
```javascript
|
|
238
|
+
ChatWidget.toggleTTS(); // Toggle on/off
|
|
239
|
+
ChatWidget.stopSpeech(); // Stop current speech and clear queue
|
|
240
|
+
```
|
|
142
241
|
|
|
143
242
|
### Demo Flow Control
|
|
144
243
|
|
|
@@ -233,6 +332,10 @@ ChatWidget.send('Hello, I need help!');
|
|
|
233
332
|
// Clear the conversation
|
|
234
333
|
ChatWidget.clearMessages();
|
|
235
334
|
|
|
335
|
+
// Text-to-speech controls
|
|
336
|
+
ChatWidget.toggleTTS(); // Toggle TTS on/off
|
|
337
|
+
ChatWidget.stopSpeech(); // Stop current speech and clear queue
|
|
338
|
+
|
|
236
339
|
// Start a demo flow
|
|
237
340
|
ChatWidget.startDemoFlow('quote');
|
|
238
341
|
|
|
@@ -377,6 +480,36 @@ agent-frontend/
|
|
|
377
480
|
|
|
378
481
|
Requires: `EventSource` (SSE), `fetch`, `localStorage`
|
|
379
482
|
|
|
483
|
+
## Version History
|
|
484
|
+
|
|
485
|
+
### v1.4.0 (Latest)
|
|
486
|
+
- ✨ **Text-to-Speech**: ElevenLabs integration with secure Django proxy support
|
|
487
|
+
- 🔊 Automatic speech for assistant and simulated user messages
|
|
488
|
+
- 🎛️ Smart speech queuing to prevent overlap
|
|
489
|
+
- 🔐 Secure proxy approach keeps API keys on server
|
|
490
|
+
|
|
491
|
+
### v1.3.0
|
|
492
|
+
- 🎮 **Demo Flow Control**: Three modes (automatic, confirm-next, manual)
|
|
493
|
+
- ⏱️ Configurable delay for automatic mode (0-5000ms)
|
|
494
|
+
- 🎯 Real-time mode switching via dropdown menu
|
|
495
|
+
- ▶️ Continue button for confirm mode
|
|
496
|
+
|
|
497
|
+
### v1.2.0
|
|
498
|
+
- 📝 **Enhanced Markdown**: Optional rich markdown with tables and code blocks
|
|
499
|
+
- 🎨 Syntax highlighting support via highlight.js
|
|
500
|
+
- 🔧 Automatic detection of markdown addon
|
|
501
|
+
|
|
502
|
+
### v1.1.0
|
|
503
|
+
- 🔌 **Configurable API Paths**: Customize backend endpoints
|
|
504
|
+
- 🛠️ Support for different backend URL structures
|
|
505
|
+
|
|
506
|
+
### v1.0.0
|
|
507
|
+
- 🎉 Initial release
|
|
508
|
+
- 💬 Real-time SSE streaming
|
|
509
|
+
- 🎨 Theming and customization
|
|
510
|
+
- 🤖 Demo flows
|
|
511
|
+
- 🔒 Session management
|
|
512
|
+
|
|
380
513
|
## License
|
|
381
514
|
|
|
382
515
|
MIT © 2024
|
package/dist/chat-widget.css
CHANGED
|
@@ -159,6 +159,19 @@
|
|
|
159
159
|
color: #ffd700;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
.cw-btn-speaking {
|
|
163
|
+
animation: pulse-speaking 1.5s ease-in-out infinite;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@keyframes pulse-speaking {
|
|
167
|
+
0%, 100% {
|
|
168
|
+
background: rgba(255, 255, 255, 0.3);
|
|
169
|
+
}
|
|
170
|
+
50% {
|
|
171
|
+
background: rgba(255, 255, 255, 0.5);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
162
175
|
/* Status bar */
|
|
163
176
|
.cw-status-bar {
|
|
164
177
|
display: flex;
|
package/dist/chat-widget.js
CHANGED
|
@@ -46,6 +46,21 @@
|
|
|
46
46
|
// Demo flow control
|
|
47
47
|
autoRunDelay: 1000, // Delay in ms before auto-generating next message
|
|
48
48
|
autoRunMode: 'automatic', // 'automatic', 'confirm', or 'manual'
|
|
49
|
+
// Text-to-speech (ElevenLabs)
|
|
50
|
+
enableTTS: false,
|
|
51
|
+
ttsProxyUrl: null, // If set, uses Django proxy instead of direct API calls
|
|
52
|
+
elevenLabsApiKey: null, // Only needed if not using proxy
|
|
53
|
+
ttsVoices: {
|
|
54
|
+
assistant: null, // ElevenLabs voice ID for assistant (not needed if using proxy)
|
|
55
|
+
user: null, // ElevenLabs voice ID for simulated user (not needed if using proxy)
|
|
56
|
+
},
|
|
57
|
+
ttsModel: 'eleven_turbo_v2_5', // ElevenLabs model (not needed if using proxy)
|
|
58
|
+
ttsSettings: {
|
|
59
|
+
stability: 0.5,
|
|
60
|
+
similarity_boost: 0.75,
|
|
61
|
+
style: 0.0,
|
|
62
|
+
use_speaker_boost: true,
|
|
63
|
+
},
|
|
49
64
|
};
|
|
50
65
|
|
|
51
66
|
// State
|
|
@@ -64,6 +79,9 @@
|
|
|
64
79
|
sessionToken: null,
|
|
65
80
|
error: null,
|
|
66
81
|
eventSource: null,
|
|
82
|
+
currentAudio: null,
|
|
83
|
+
isSpeaking: false,
|
|
84
|
+
speechQueue: [],
|
|
67
85
|
};
|
|
68
86
|
|
|
69
87
|
// DOM elements
|
|
@@ -138,6 +156,135 @@
|
|
|
138
156
|
}
|
|
139
157
|
}
|
|
140
158
|
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// Text-to-Speech (ElevenLabs)
|
|
161
|
+
// ============================================================================
|
|
162
|
+
|
|
163
|
+
async function speakText(text, role) {
|
|
164
|
+
if (!config.enableTTS) return;
|
|
165
|
+
|
|
166
|
+
// Check if we have either proxy or direct API access
|
|
167
|
+
if (!config.ttsProxyUrl && !config.elevenLabsApiKey) return;
|
|
168
|
+
|
|
169
|
+
// If using direct API, check for voice ID
|
|
170
|
+
if (!config.ttsProxyUrl) {
|
|
171
|
+
const voiceId = role === 'assistant' ? config.ttsVoices.assistant : config.ttsVoices.user;
|
|
172
|
+
if (!voiceId) return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Add to queue
|
|
176
|
+
state.speechQueue.push({ text, role });
|
|
177
|
+
|
|
178
|
+
// Process queue if not already speaking
|
|
179
|
+
if (!state.isSpeaking) {
|
|
180
|
+
processSpeechQueue();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function processSpeechQueue() {
|
|
185
|
+
if (state.speechQueue.length === 0) {
|
|
186
|
+
state.isSpeaking = false;
|
|
187
|
+
render();
|
|
188
|
+
|
|
189
|
+
// If auto-run is waiting for speech to finish, continue
|
|
190
|
+
if (state.autoRunActive && state.autoRunPaused && config.autoRunMode === 'automatic') {
|
|
191
|
+
setTimeout(() => {
|
|
192
|
+
if (state.autoRunActive && !state.isSpeaking) {
|
|
193
|
+
continueAutoRun();
|
|
194
|
+
}
|
|
195
|
+
}, config.autoRunDelay);
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
state.isSpeaking = true;
|
|
201
|
+
render();
|
|
202
|
+
|
|
203
|
+
const { text, role } = state.speechQueue.shift();
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
let response;
|
|
207
|
+
|
|
208
|
+
if (config.ttsProxyUrl) {
|
|
209
|
+
// Use Django proxy
|
|
210
|
+
response = await fetch(config.ttsProxyUrl, {
|
|
211
|
+
method: 'POST',
|
|
212
|
+
headers: {
|
|
213
|
+
'Content-Type': 'application/json',
|
|
214
|
+
...(state.sessionToken ? { [config.anonymousTokenHeader]: state.sessionToken } : {}),
|
|
215
|
+
},
|
|
216
|
+
body: JSON.stringify({
|
|
217
|
+
text: text,
|
|
218
|
+
role: role,
|
|
219
|
+
}),
|
|
220
|
+
});
|
|
221
|
+
} else {
|
|
222
|
+
// Direct ElevenLabs API call
|
|
223
|
+
const voiceId = role === 'assistant' ? config.ttsVoices.assistant : config.ttsVoices.user;
|
|
224
|
+
response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, {
|
|
225
|
+
method: 'POST',
|
|
226
|
+
headers: {
|
|
227
|
+
'Accept': 'audio/mpeg',
|
|
228
|
+
'Content-Type': 'application/json',
|
|
229
|
+
'xi-api-key': config.elevenLabsApiKey,
|
|
230
|
+
},
|
|
231
|
+
body: JSON.stringify({
|
|
232
|
+
text: text,
|
|
233
|
+
model_id: config.ttsModel,
|
|
234
|
+
voice_settings: config.ttsSettings,
|
|
235
|
+
}),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
throw new Error(`TTS API error: ${response.status}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const audioBlob = await response.blob();
|
|
244
|
+
const audioUrl = URL.createObjectURL(audioBlob);
|
|
245
|
+
const audio = new Audio(audioUrl);
|
|
246
|
+
|
|
247
|
+
state.currentAudio = audio;
|
|
248
|
+
|
|
249
|
+
audio.onended = () => {
|
|
250
|
+
URL.revokeObjectURL(audioUrl);
|
|
251
|
+
state.currentAudio = null;
|
|
252
|
+
processSpeechQueue();
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
audio.onerror = () => {
|
|
256
|
+
console.error('[ChatWidget] Audio playback error');
|
|
257
|
+
URL.revokeObjectURL(audioUrl);
|
|
258
|
+
state.currentAudio = null;
|
|
259
|
+
processSpeechQueue();
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
await audio.play();
|
|
263
|
+
} catch (err) {
|
|
264
|
+
console.error('[ChatWidget] TTS error:', err);
|
|
265
|
+
state.currentAudio = null;
|
|
266
|
+
processSpeechQueue();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function stopSpeech() {
|
|
271
|
+
if (state.currentAudio) {
|
|
272
|
+
state.currentAudio.pause();
|
|
273
|
+
state.currentAudio = null;
|
|
274
|
+
}
|
|
275
|
+
state.speechQueue = [];
|
|
276
|
+
state.isSpeaking = false;
|
|
277
|
+
render();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function toggleTTS() {
|
|
281
|
+
config.enableTTS = !config.enableTTS;
|
|
282
|
+
if (!config.enableTTS) {
|
|
283
|
+
stopSpeech();
|
|
284
|
+
}
|
|
285
|
+
render();
|
|
286
|
+
}
|
|
287
|
+
|
|
141
288
|
// ============================================================================
|
|
142
289
|
// Session Management
|
|
143
290
|
// ============================================================================
|
|
@@ -347,10 +494,21 @@
|
|
|
347
494
|
state.eventSource = null;
|
|
348
495
|
render();
|
|
349
496
|
|
|
497
|
+
// Speak assistant message if TTS enabled
|
|
498
|
+
if (assistantContent && !state.error) {
|
|
499
|
+
speakText(assistantContent, 'assistant');
|
|
500
|
+
}
|
|
501
|
+
|
|
350
502
|
// Trigger auto-run if enabled
|
|
351
503
|
if (state.autoRunActive && !state.error) {
|
|
352
504
|
if (config.autoRunMode === 'automatic') {
|
|
353
|
-
|
|
505
|
+
// Wait for speech to finish before continuing
|
|
506
|
+
if (config.enableTTS && assistantContent) {
|
|
507
|
+
state.autoRunPaused = true;
|
|
508
|
+
// processSpeechQueue will continue when done
|
|
509
|
+
} else {
|
|
510
|
+
setTimeout(() => triggerAutoRun(), config.autoRunDelay);
|
|
511
|
+
}
|
|
354
512
|
} else if (config.autoRunMode === 'confirm') {
|
|
355
513
|
state.autoRunPaused = true;
|
|
356
514
|
render();
|
|
@@ -402,6 +560,12 @@
|
|
|
402
560
|
const data = await response.json();
|
|
403
561
|
if (data.response) {
|
|
404
562
|
state.isSimulating = false;
|
|
563
|
+
|
|
564
|
+
// Speak simulated user message if TTS enabled
|
|
565
|
+
if (config.enableTTS && config.ttsVoices.user) {
|
|
566
|
+
await speakText(data.response, 'user');
|
|
567
|
+
}
|
|
568
|
+
|
|
405
569
|
await sendMessage(data.response);
|
|
406
570
|
return;
|
|
407
571
|
}
|
|
@@ -674,6 +838,13 @@
|
|
|
674
838
|
</svg>
|
|
675
839
|
</button>
|
|
676
840
|
` : ''}
|
|
841
|
+
${config.elevenLabsApiKey ? `
|
|
842
|
+
<button class="cw-header-btn ${config.enableTTS ? 'cw-btn-active' : ''} ${state.isSpeaking ? 'cw-btn-speaking' : ''}"
|
|
843
|
+
data-action="toggle-tts"
|
|
844
|
+
title="${config.enableTTS ? (state.isSpeaking ? 'Speaking...' : 'TTS Enabled') : 'TTS Disabled'}">
|
|
845
|
+
${state.isSpeaking ? '🔊' : (config.enableTTS ? '🔉' : '🔇')}
|
|
846
|
+
</button>
|
|
847
|
+
` : ''}
|
|
677
848
|
${renderJourneyDropdown()}
|
|
678
849
|
<button class="cw-header-btn" data-action="toggle-expand" title="${state.isExpanded ? 'Minimize' : 'Expand'}">
|
|
679
850
|
${state.isExpanded ? '⊖' : '⊕'}
|
|
@@ -721,6 +892,7 @@
|
|
|
721
892
|
case 'close': closeWidget(); break;
|
|
722
893
|
case 'toggle-expand': toggleExpand(); break;
|
|
723
894
|
case 'toggle-debug': toggleDebugMode(); break;
|
|
895
|
+
case 'toggle-tts': toggleTTS(); break;
|
|
724
896
|
case 'clear': clearMessages(); break;
|
|
725
897
|
case 'stop-autorun': stopAutoRun(); break;
|
|
726
898
|
case 'continue-autorun': continueAutoRun(); break;
|
|
@@ -838,6 +1010,8 @@
|
|
|
838
1010
|
continueAutoRun,
|
|
839
1011
|
setAutoRunMode,
|
|
840
1012
|
setAutoRunDelay,
|
|
1013
|
+
toggleTTS,
|
|
1014
|
+
stopSpeech,
|
|
841
1015
|
getState: () => ({ ...state }),
|
|
842
1016
|
getConfig: () => ({ ...config }),
|
|
843
1017
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makemore/agent-frontend",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A standalone, zero-dependency chat widget for AI agents. Embed conversational AI into any website with a single script tag.",
|
|
5
5
|
"main": "dist/chat-widget.js",
|
|
6
6
|
"files": [
|