aillom-vox-client 1.0.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/LICENSE +15 -0
- package/README.md +272 -0
- package/dist/AillomVox.d.ts +36 -0
- package/dist/AillomVox.js +152 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.js +2 -0
- package/docs/ASTERISK.md +411 -0
- package/docs/PROTOCOL.md +156 -0
- package/docs/PROVIDERS.md +40 -0
- package/docs/TOOLS.md +314 -0
- package/docs/TROUBLESHOOTING.md +86 -0
- package/docs/VOICES.md +219 -0
- package/docs/providers/AILLOMVOX.md +185 -0
- package/docs/providers/AWS.md +32 -0
- package/docs/providers/GEMINI.md +33 -0
- package/docs/providers/GROK.md +25 -0
- package/docs/providers/OPENAI.md +39 -0
- package/docs/providers/QWEN.md +27 -0
- package/docs/providers/ULTRAVOX.md +29 -0
- package/examples/01-basic/app.js +196 -0
- package/examples/01-basic/index.html +27 -0
- package/examples/02-advanced-dashboard/app.js +465 -0
- package/examples/02-advanced-dashboard/index.html +200 -0
- package/examples/02-advanced-dashboard/style.css +501 -0
- package/examples/03-smart-home/index.html +377 -0
- package/examples/04-customer-support/index.html +474 -0
- package/examples/sdk-usage.ts +44 -0
- package/integrations/n8n-nodes-aillomvox/README.md +56 -0
- package/integrations/n8n-nodes-aillomvox/credentials/AillomVoxApi.credentials.ts +29 -0
- package/integrations/n8n-nodes-aillomvox/dist/credentials/AillomVoxApi.credentials.js +30 -0
- package/integrations/n8n-nodes-aillomvox/dist/nodes/AillomVox/AillomVox.node.js +219 -0
- package/integrations/n8n-nodes-aillomvox/dist/nodes/AillomVox/aillomvox.svg +6 -0
- package/integrations/n8n-nodes-aillomvox/gulpfile.js +10 -0
- package/integrations/n8n-nodes-aillomvox/nodes/AillomVox/AillomVox.node.ts +229 -0
- package/integrations/n8n-nodes-aillomvox/nodes/AillomVox/aillomvox.svg +6 -0
- package/integrations/n8n-nodes-aillomvox/package-lock.json +11741 -0
- package/integrations/n8n-nodes-aillomvox/package.json +56 -0
- package/integrations/n8n-nodes-aillomvox/tsconfig.json +32 -0
- package/package.json +55 -0
- package/src/AillomVox.ts +169 -0
- package/src/index.ts +2 -0
- package/src/types.ts +50 -0
- package/tsconfig.json +23 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Aillom Technologies
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# 🎙️ AillomVox Public Client
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/aillom-vox-client)
|
|
4
|
+
[](https://opensource.org/licenses/ISC)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
**The Enterprise-Grade Voice AI SDK.**
|
|
8
|
+
|
|
9
|
+
Build **Speech-to-Speech**, **Audio-to-Audio**, and **Realtime Multimodal** applications with a single, unified protocol.
|
|
10
|
+
Connect effortlessly to **OpenAI Realtime**, **Gemini Multimodal**, **AWS Nova**, **Qwen**, **Grok**, **UltraVox**, and **AillomVox** native models.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 📦 Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install aillom-vox-client
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 📚 Documentation
|
|
21
|
+
- [**Quick Start (SDK)**](#-quick-start-sdk) - The modern way
|
|
22
|
+
- [**Quick Start (WebSocket)**](#-quick-start-websocket) - The low-level way
|
|
23
|
+
- [**Examples**](#-examples) - Ready-to-use client implementations
|
|
24
|
+
- [**N8N Integration**](#-n8n-node) - Official AillomVox node for n8n
|
|
25
|
+
- [**Client Tools**](#-client-tools) - Add custom UI controls to your AI
|
|
26
|
+
- [**Voice Catalog**](docs/VOICES.md) - All voices across all providers
|
|
27
|
+
- [**Asterisk Integration**](docs/ASTERISK.md) - Complete guide for Asterisk 23/SIP
|
|
28
|
+
- [**Protocol Specification**](docs/PROTOCOL.md) - WebSocket messages and binary formats
|
|
29
|
+
- [**Supported Providers**](docs/PROVIDERS.md) - AI models and configuration options
|
|
30
|
+
- [**Troubleshooting**](docs/TROUBLESHOOTING.md) - Common errors and solutions
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 🚀 Key Features
|
|
35
|
+
- **Unified API**: Switch between OpenAI, Gemini, and others by changing one string
|
|
36
|
+
- **Real-Time Streaming**: Full-duplex WebSocket for sub-500ms latency
|
|
37
|
+
- **65 Voices**: Full Inworld TTS 1.5 catalog across 15 languages
|
|
38
|
+
- **Robust Audio**: Native PCM 16-bit at **8kHz**, **16kHz**, or **24kHz**
|
|
39
|
+
- **Client Tools**: Add custom UI controls (hangup, alerts, navigation) to your AI
|
|
40
|
+
- **15 Languages**: en, pt, es, fr, de, it, ja, zh, ko, hi, ar, ru, pl, nl, he
|
|
41
|
+
- **Event Driven**: Simple event emitter (`audio`, `transcript`, `interrupt`)
|
|
42
|
+
- **Enterprise Security**: Automatic key redaction and sanitized error messages
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 💰 Pricing & Performance
|
|
47
|
+
|
|
48
|
+
Choose the tier that fits your budget. **AillomVox** is optimized for telephony and high-volume use cases.
|
|
49
|
+
|
|
50
|
+
| Provider | Cost/Min | Tier | Recommended For |
|
|
51
|
+
| :--- | :--- | :--- | :--- |
|
|
52
|
+
| **AillomVox** | **$0.03** | 🚀 **Best Value** | High volume, Telephony, Support |
|
|
53
|
+
| **Gemini** | $0.06 | Standard | Google Gemini 2.5 Flash. Multimodal |
|
|
54
|
+
| **AWS** | $0.06 | Standard | AWS Nova Sonic 2. Enterprise |
|
|
55
|
+
| **Qwen** | $0.06 | Standard | Alibaba Qwen Omni 3. Cost-effective |
|
|
56
|
+
| **OpenAI** | $0.10 | Premium | GPT Realtime Mini. Logic-heavy |
|
|
57
|
+
| **Grok** | $0.10 | Premium | Grok Beta. Witty personality |
|
|
58
|
+
| **UltraVox** | $0.10 | Premium | High emotional intelligence |
|
|
59
|
+
|
|
60
|
+
> **Why AillomVox?**
|
|
61
|
+
> Native optimized pipeline delivers **sub-500ms latency** and **8kHz support** at less than half the cost. Choose from **65 voices** with dynamic mid-conversation switching.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 📱 Examples
|
|
66
|
+
|
|
67
|
+
This repository contains multiple examples ranging from a minimal connection script to full-featured dashboards and creative use cases.
|
|
68
|
+
|
|
69
|
+
| Folder | Level | Description |
|
|
70
|
+
| :--- | :--- | :--- |
|
|
71
|
+
| [`examples/01-basic`](./examples/01-basic) | ⭐ Beginner | Minimal HTML/JS implementation. Connects, sends defaults, streams audio. Perfect for understanding the core protocol. |
|
|
72
|
+
| [`examples/02-advanced-dashboard`](./examples/02-advanced-dashboard) | ⭐⭐⭐ Expert | Full-featured UI with Dark Mode. Configures Voice, LLM Provider, Tools, and Visualizations. |
|
|
73
|
+
| [`examples/03-smart-home`](./examples/03-smart-home) | ⭐⭐ Creative | A Smart Home Controller simulation. Use voice to "turn on lights" or "adjust temperature" via Tool Calling. |
|
|
74
|
+
| [`examples/04-customer-support`](./examples/04-customer-support) | ⭐⭐ Industry | A CRM / Support Agent interface. Demonstrates integration with business data. |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## ⚡ Quick Start (SDK)
|
|
79
|
+
|
|
80
|
+
The easiest way to connect to AillomVox.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { AillomVox } from 'aillom-vox-client';
|
|
84
|
+
|
|
85
|
+
const client = new AillomVox({
|
|
86
|
+
apiKey: 'av_YOUR_KEY',
|
|
87
|
+
voice: 'Edward',
|
|
88
|
+
debug: true
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
client.on('transcript', (msg) => {
|
|
92
|
+
console.log(`[${msg.role}] ${msg.text}`);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
client.on('audio', (chunk) => {
|
|
96
|
+
// Play chunk (ArrayBuffer)
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await client.connect();
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 🔌 Quick Start (WebSocket)
|
|
105
|
+
|
|
106
|
+
If you prefer raw WebSockets (e.g. for Python, Go, or minimal JS):
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
const ws = new WebSocket("wss://vox.aillom.com/ws");
|
|
110
|
+
|
|
111
|
+
ws.onopen = () => {
|
|
112
|
+
ws.send(JSON.stringify({
|
|
113
|
+
type: "config",
|
|
114
|
+
apikey: "YOUR_API_KEY",
|
|
115
|
+
provider: "aillomvox",
|
|
116
|
+
voice: "Edward"
|
|
117
|
+
}));
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
ws.onmessage = (event) => {
|
|
121
|
+
if (event.data instanceof ArrayBuffer) {
|
|
122
|
+
playAudio(event.data);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 🎤 Voices
|
|
130
|
+
|
|
131
|
+
AillomVox uses **Inworld TTS 1.5** with 65 voices across 15 languages. See the full [Voice Catalog](docs/VOICES.md).
|
|
132
|
+
|
|
133
|
+
### Top Picks
|
|
134
|
+
|
|
135
|
+
| Voice | Gender | Style | Best For |
|
|
136
|
+
| :--- | :--- | :--- | :--- |
|
|
137
|
+
| **Edward** | Male | Fast-talking, emphatic | General purpose (default EN) |
|
|
138
|
+
| **Julia** | Female | Quirky, playful | Customer support |
|
|
139
|
+
| **Heitor** | Male | Composed, neutral | Portuguese (default PT) |
|
|
140
|
+
| **Maitê** | Female | Professional | Portuguese |
|
|
141
|
+
| **Ashley** | Female | Warm, natural | Sales, onboarding |
|
|
142
|
+
| **Craig** | Male | Refined, articulate | Enterprise, authority |
|
|
143
|
+
| **Diego** | Male | Soothing, gentle | Spanish (default ES) |
|
|
144
|
+
| **Luna** | Female | Calm, relaxing | Wellness, concierge |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 🛠️ Client Tools
|
|
149
|
+
|
|
150
|
+
**Client Tools** allow the AI to control your application's UI directly. When the AI decides to execute a tool, your app receives a callback and can respond.
|
|
151
|
+
|
|
152
|
+
### Registering Tools
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
{
|
|
156
|
+
"provider": "aillomvox",
|
|
157
|
+
"voice": "Edward",
|
|
158
|
+
"tools": [
|
|
159
|
+
{
|
|
160
|
+
"name": "hangup",
|
|
161
|
+
"description": "End the call when user says goodbye.",
|
|
162
|
+
"parameters": { "type": "object", "properties": {} }
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"name": "show_alert",
|
|
166
|
+
"description": "Show alert to user",
|
|
167
|
+
"parameters": {
|
|
168
|
+
"type": "object",
|
|
169
|
+
"properties": {
|
|
170
|
+
"message": { "type": "string", "description": "Alert message" }
|
|
171
|
+
},
|
|
172
|
+
"required": ["message"]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Handling Tool Calls (Client-Side)
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
socket.onmessage = (event) => {
|
|
183
|
+
if (typeof event.data !== 'string') return;
|
|
184
|
+
const msg = JSON.parse(event.data);
|
|
185
|
+
|
|
186
|
+
if (msg.type === 'tool_call') {
|
|
187
|
+
console.log(`Tool requested: ${msg.name}`, msg.args);
|
|
188
|
+
|
|
189
|
+
let result = 'OK';
|
|
190
|
+
if (msg.name === 'hangup') {
|
|
191
|
+
disconnect();
|
|
192
|
+
result = 'Call ended';
|
|
193
|
+
} else if (msg.name === 'show_alert') {
|
|
194
|
+
alert(msg.args.message);
|
|
195
|
+
result = 'Alert displayed';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Always respond — AI waits for this (15s timeout)
|
|
199
|
+
socket.send(JSON.stringify({
|
|
200
|
+
type: 'tool_result',
|
|
201
|
+
call_id: msg.call_id,
|
|
202
|
+
result: result
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 🔧 Advanced Configuration
|
|
211
|
+
|
|
212
|
+
### Audio Formats
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
{
|
|
216
|
+
sample_rate: 16000, // 8000 (telephony), 16000 (standard), 24000 (high-quality)
|
|
217
|
+
// Audio is PCM 16-bit little-endian Mono
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Session Limits
|
|
222
|
+
|
|
223
|
+
```javascript
|
|
224
|
+
{
|
|
225
|
+
max_duration: 300, // 1-3600 seconds (default: 300 = 5 minutes)
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
At 15 seconds remaining, the AI will say the `farewell_message`. At 0 seconds, the connection closes.
|
|
230
|
+
|
|
231
|
+
### Multi-Language Support
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
{
|
|
235
|
+
language: 'pt-BR',
|
|
236
|
+
voice: 'Heitor', // or 'Maitê' for female
|
|
237
|
+
system_prompt: 'Você é um assistente da Aillom. Seja conciso.',
|
|
238
|
+
first_message: 'Olá! Como posso ajudar?',
|
|
239
|
+
farewell_message: 'Obrigado por ligar. Até logo!'
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Supported: `en-US`, `pt-BR`, `es-ES`, `fr-FR`, `de-DE`, `it-IT`, `ja-JP`, `ko-KR`, `zh-CN`, `hi-IN`, `ar-SA`, `ru-RU`, `pl-PL`, `nl-NL`, `he-IL`
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🛡️ Security & Limits
|
|
248
|
+
|
|
249
|
+
### Automatic Sanitization
|
|
250
|
+
- All error messages are stripped of sensitive data
|
|
251
|
+
- API keys are never exposed in logs
|
|
252
|
+
- Client cannot access server-side resources
|
|
253
|
+
|
|
254
|
+
### Rate Limits
|
|
255
|
+
- **Concurrent**: 3 connections per user, 2 per API key
|
|
256
|
+
- **Max Duration**: 1-60 minutes per call
|
|
257
|
+
- **Default**: 5 minutes per session
|
|
258
|
+
- **Behavior**: Warning at 15s remaining, force disconnect at 0s
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## 🤝 Support
|
|
263
|
+
|
|
264
|
+
- **Documentation**: [https://vox.aillom.com/docs](https://vox.aillom.com/docs)
|
|
265
|
+
- **Issues**: [GitHub Issues](https://github.com/aillom/aillom-vox-client/issues)
|
|
266
|
+
- **Email**: contato@aillom.com.br
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 📄 License
|
|
271
|
+
|
|
272
|
+
ISC © Aillom Technologies
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AillomVoxConfig, TranscriptEvent, ToolCallEvent } from './types';
|
|
2
|
+
export declare class AillomVox {
|
|
3
|
+
private ws;
|
|
4
|
+
private config;
|
|
5
|
+
private eventListeners;
|
|
6
|
+
private isConnected;
|
|
7
|
+
private url;
|
|
8
|
+
constructor(config: AillomVoxConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Connects to the AillomVox Gateway
|
|
11
|
+
*/
|
|
12
|
+
connect(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Sends audio chunk (PCM 16-bit) to the AI
|
|
15
|
+
*/
|
|
16
|
+
sendAudio(chunk: ArrayBuffer | Int16Array | Buffer): void;
|
|
17
|
+
/**
|
|
18
|
+
* Sends a tool result back to the AI
|
|
19
|
+
*/
|
|
20
|
+
sendToolResult(callId: string, result: any): void;
|
|
21
|
+
/**
|
|
22
|
+
* Disconnects the session
|
|
23
|
+
*/
|
|
24
|
+
disconnect(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Subscribes to an event
|
|
27
|
+
*/
|
|
28
|
+
on(event: 'audio', handler: (data: ArrayBuffer) => void): void;
|
|
29
|
+
on(event: 'transcript', handler: (data: TranscriptEvent) => void): void;
|
|
30
|
+
on(event: 'tool_call', handler: (data: ToolCallEvent) => void): void;
|
|
31
|
+
on(event: 'error', handler: (error: any) => void): void;
|
|
32
|
+
on(event: 'connected' | 'disconnected' | 'interruption', handler: (data: any) => void): void;
|
|
33
|
+
private sendConfig;
|
|
34
|
+
private handleMessage;
|
|
35
|
+
private emit;
|
|
36
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AillomVox = void 0;
|
|
7
|
+
const isomorphic_ws_1 = __importDefault(require("isomorphic-ws"));
|
|
8
|
+
class AillomVox {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.ws = null;
|
|
11
|
+
this.eventListeners = new Map();
|
|
12
|
+
this.isConnected = false;
|
|
13
|
+
this.url = 'wss://vox.aillom.com/ws';
|
|
14
|
+
this.config = config;
|
|
15
|
+
if (!this.config.apiKey) {
|
|
16
|
+
throw new Error('AillomVox: apiKey is required');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Connects to the AillomVox Gateway
|
|
21
|
+
*/
|
|
22
|
+
connect() {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
try {
|
|
25
|
+
this.ws = new isomorphic_ws_1.default(this.url);
|
|
26
|
+
this.ws.binaryType = 'arraybuffer';
|
|
27
|
+
this.ws.onopen = () => {
|
|
28
|
+
this.isConnected = true;
|
|
29
|
+
this.sendConfig();
|
|
30
|
+
this.emit('connected', {});
|
|
31
|
+
resolve();
|
|
32
|
+
};
|
|
33
|
+
this.ws.onmessage = (event) => {
|
|
34
|
+
this.handleMessage(event);
|
|
35
|
+
};
|
|
36
|
+
this.ws.onerror = (error) => {
|
|
37
|
+
this.emit('error', error);
|
|
38
|
+
if (!this.isConnected)
|
|
39
|
+
reject(error);
|
|
40
|
+
};
|
|
41
|
+
this.ws.onclose = (event) => {
|
|
42
|
+
this.isConnected = false;
|
|
43
|
+
this.emit('disconnected', { code: event.code, reason: event.reason });
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
reject(err);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Sends audio chunk (PCM 16-bit) to the AI
|
|
53
|
+
*/
|
|
54
|
+
sendAudio(chunk) {
|
|
55
|
+
if (!this.ws || this.ws.readyState !== isomorphic_ws_1.default.OPEN)
|
|
56
|
+
return;
|
|
57
|
+
this.ws.send(chunk);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Sends a tool result back to the AI
|
|
61
|
+
*/
|
|
62
|
+
sendToolResult(callId, result) {
|
|
63
|
+
if (!this.ws || this.ws.readyState !== isomorphic_ws_1.default.OPEN)
|
|
64
|
+
return;
|
|
65
|
+
this.ws.send(JSON.stringify({
|
|
66
|
+
type: 'tool_result',
|
|
67
|
+
call_id: callId,
|
|
68
|
+
result: result
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Disconnects the session
|
|
73
|
+
*/
|
|
74
|
+
disconnect() {
|
|
75
|
+
if (this.ws) {
|
|
76
|
+
this.ws.close();
|
|
77
|
+
this.ws = null;
|
|
78
|
+
this.isConnected = false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
on(event, handler) {
|
|
82
|
+
if (!this.eventListeners.has(event)) {
|
|
83
|
+
this.eventListeners.set(event, []);
|
|
84
|
+
}
|
|
85
|
+
this.eventListeners.get(event)?.push(handler);
|
|
86
|
+
}
|
|
87
|
+
sendConfig() {
|
|
88
|
+
if (!this.ws)
|
|
89
|
+
return;
|
|
90
|
+
const payload = {
|
|
91
|
+
type: 'config',
|
|
92
|
+
apikey: this.config.apiKey,
|
|
93
|
+
provider: this.config.provider || 'aillomvox',
|
|
94
|
+
voice: this.config.voice || 'Edward',
|
|
95
|
+
language: this.config.language || 'en-US',
|
|
96
|
+
sample_rate: this.config.sampleRate || 16000,
|
|
97
|
+
system_prompt: this.config.systemPrompt,
|
|
98
|
+
tools: this.config.tools,
|
|
99
|
+
webhook_url: this.config.webhookUrl,
|
|
100
|
+
max_duration: this.config.maxDuration
|
|
101
|
+
};
|
|
102
|
+
if (this.config.debug) {
|
|
103
|
+
console.log('[AillomVox] Sending config:', JSON.stringify(payload, null, 2));
|
|
104
|
+
}
|
|
105
|
+
this.ws.send(JSON.stringify(payload));
|
|
106
|
+
}
|
|
107
|
+
handleMessage(event) {
|
|
108
|
+
const data = event.data;
|
|
109
|
+
// Handle Binary Audio
|
|
110
|
+
if (data instanceof ArrayBuffer || (typeof Buffer !== 'undefined' && Buffer.isBuffer(data))) {
|
|
111
|
+
this.emit('audio', data);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Handle JSON Control Messages
|
|
115
|
+
if (typeof data === 'string') {
|
|
116
|
+
try {
|
|
117
|
+
const msg = JSON.parse(data);
|
|
118
|
+
switch (msg.type) {
|
|
119
|
+
case 'transcript':
|
|
120
|
+
this.emit('transcript', msg);
|
|
121
|
+
break;
|
|
122
|
+
case 'tool_call':
|
|
123
|
+
this.emit('tool_call', msg);
|
|
124
|
+
break;
|
|
125
|
+
case 'error':
|
|
126
|
+
this.emit('error', msg);
|
|
127
|
+
break;
|
|
128
|
+
case 'interruption':
|
|
129
|
+
this.emit('interruption', {});
|
|
130
|
+
break;
|
|
131
|
+
case 'hangup':
|
|
132
|
+
this.disconnect();
|
|
133
|
+
this.emit('disconnected', { reason: 'agent_hangup' });
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
if (this.config.debug)
|
|
137
|
+
console.log('[AillomVox] Data:', msg);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
console.error('[AillomVox] Failed to parse message:', e);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
emit(event, data) {
|
|
146
|
+
const listeners = this.eventListeners.get(event);
|
|
147
|
+
if (listeners) {
|
|
148
|
+
listeners.forEach(handler => handler(data));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.AillomVox = AillomVox;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./AillomVox"), exports);
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type ProviderType = 'aillomvox' | 'gemini' | 'openai' | 'aws' | 'qwen' | 'grok' | 'ultravox';
|
|
2
|
+
export interface MicrophoneConfig {
|
|
3
|
+
sampleRate?: 8000 | 16000 | 24000;
|
|
4
|
+
inputSampleRate?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ClientTool {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
parameters: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
export interface AillomVoxConfig {
|
|
12
|
+
apiKey: string;
|
|
13
|
+
provider?: ProviderType;
|
|
14
|
+
voice?: string;
|
|
15
|
+
language?: string;
|
|
16
|
+
systemPrompt?: string;
|
|
17
|
+
sampleRate?: 8000 | 16000 | 24000;
|
|
18
|
+
debug?: boolean;
|
|
19
|
+
tools?: ClientTool[];
|
|
20
|
+
webhookUrl?: string;
|
|
21
|
+
maxDuration?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface TranscriptEvent {
|
|
24
|
+
role: 'user' | 'assistant';
|
|
25
|
+
text: string;
|
|
26
|
+
final: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface ToolCallEvent {
|
|
29
|
+
call_id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
args: any;
|
|
32
|
+
}
|
|
33
|
+
export interface AudioEvent {
|
|
34
|
+
buffer: ArrayBuffer;
|
|
35
|
+
}
|
|
36
|
+
export type EventHandler<T = any> = (data: T) => void;
|
package/dist/types.js
ADDED