aillom-vox-client 1.0.2 → 2.1.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 +102 -195
- package/dist/AillomVox.d.ts +78 -19
- package/dist/AillomVox.js +345 -60
- package/dist/constants.d.ts +19 -0
- package/dist/constants.js +35 -0
- package/dist/gateway-url.d.ts +12 -0
- package/dist/gateway-url.js +74 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/pricing.d.ts +26 -0
- package/dist/pricing.js +20 -0
- package/dist/types.d.ts +168 -11
- package/package.json +18 -7
- package/docs/ASTERISK.md +0 -411
- package/docs/PROTOCOL.md +0 -156
- package/docs/PROVIDERS.md +0 -40
- package/docs/TOOLS.md +0 -314
- package/docs/TROUBLESHOOTING.md +0 -86
- package/docs/VOICES.md +0 -219
- package/docs/providers/AILLOMVOX.md +0 -185
- package/docs/providers/AWS.md +0 -32
- package/docs/providers/GEMINI.md +0 -33
- package/docs/providers/GROK.md +0 -25
- package/docs/providers/OPENAI.md +0 -39
- package/docs/providers/QWEN.md +0 -27
- package/docs/providers/ULTRAVOX.md +0 -29
- package/examples/01-basic/app.js +0 -196
- package/examples/01-basic/index.html +0 -27
- package/examples/02-advanced-dashboard/app.js +0 -465
- package/examples/02-advanced-dashboard/index.html +0 -200
- package/examples/02-advanced-dashboard/style.css +0 -501
- package/examples/03-smart-home/index.html +0 -377
- package/examples/04-customer-support/index.html +0 -474
- package/examples/sdk-usage.ts +0 -44
- package/integrations/n8n-nodes-aillomvox/README.md +0 -56
- package/integrations/n8n-nodes-aillomvox/credentials/AillomVoxApi.credentials.ts +0 -29
- package/integrations/n8n-nodes-aillomvox/dist/credentials/AillomVoxApi.credentials.js +0 -30
- package/integrations/n8n-nodes-aillomvox/dist/nodes/AillomVox/AillomVox.node.js +0 -219
- package/integrations/n8n-nodes-aillomvox/dist/nodes/AillomVox/aillomvox.svg +0 -6
- package/integrations/n8n-nodes-aillomvox/gulpfile.js +0 -10
- package/integrations/n8n-nodes-aillomvox/nodes/AillomVox/AillomVox.node.ts +0 -229
- package/integrations/n8n-nodes-aillomvox/nodes/AillomVox/aillomvox.svg +0 -6
- package/integrations/n8n-nodes-aillomvox/package-lock.json +0 -11741
- package/integrations/n8n-nodes-aillomvox/package.json +0 -56
- package/integrations/n8n-nodes-aillomvox/tsconfig.json +0 -32
- package/src/AillomVox.ts +0 -172
- package/src/index.ts +0 -2
- package/src/types.ts +0 -51
- package/tsconfig.json +0 -23
package/dist/pricing.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VOX_PROVIDER_RATECARD = void 0;
|
|
4
|
+
exports.VOX_PROVIDER_RATECARD = [
|
|
5
|
+
{
|
|
6
|
+
label: 'AillomVox',
|
|
7
|
+
provider: 'aillomvox',
|
|
8
|
+
ttsEngineHint: 'inworld · xai · lmnt · soniox · rime · fish',
|
|
9
|
+
usdPerMinute: 0.04,
|
|
10
|
+
tier: 'Gateway',
|
|
11
|
+
modelSummary: 'Soniox STT · Groq Llama 3.3 70B · selectable TTS',
|
|
12
|
+
badge: 'Best Value',
|
|
13
|
+
},
|
|
14
|
+
{ label: 'AWS Nova', provider: 'aws', usdPerMinute: 0.06, tier: 'S2S', modelSummary: 'nova-2-sonic' },
|
|
15
|
+
{ label: 'Gemini', provider: 'gemini', usdPerMinute: 0.06, tier: 'S2S', modelSummary: 'gemini-3.1-flash-live-preview' },
|
|
16
|
+
{ label: 'Qwen', provider: 'qwen', usdPerMinute: 0.06, tier: 'S2S', modelSummary: 'qwen3.5-omni-flash-realtime' },
|
|
17
|
+
{ label: 'Grok', provider: 'grok', usdPerMinute: 0.1, tier: 'S2S', modelSummary: 'grok-voice-think-fast-1.0' },
|
|
18
|
+
{ label: 'OpenAI', provider: 'openai', usdPerMinute: 0.1, tier: 'S2S', modelSummary: 'gpt-realtime-mini' },
|
|
19
|
+
{ label: 'Ultravox', provider: 'ultravox', usdPerMinute: 0.1, tier: 'Premium', modelSummary: 'ultravox-70B' },
|
|
20
|
+
];
|
package/dist/types.d.ts
CHANGED
|
@@ -1,37 +1,194 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type { AillomVoxTtsEngineId } from './constants';
|
|
2
|
+
/**
|
|
3
|
+
* Known stable provider ids. The gateway may accept additional strings and normalizes aliases
|
|
4
|
+
* (see product docs / `GET /api/providers`).
|
|
5
|
+
*/
|
|
6
|
+
export type VoxProviderId = 'aillomvox' | 'openai' | 'gemini' | 'aws' | 'qwen' | 'grok' | 'ultravox' | (string & {});
|
|
6
7
|
export interface ClientTool {
|
|
7
8
|
name: string;
|
|
8
9
|
description: string;
|
|
9
|
-
parameters
|
|
10
|
+
/** JSON Schema parameters for the function (OpenAI-style). */
|
|
11
|
+
parameters?: Record<string, unknown>;
|
|
12
|
+
/** Backward-compatible location used by some dashboard / n8n tool presets. */
|
|
13
|
+
config?: Record<string, unknown>;
|
|
14
|
+
/** Optional server-side endpoint metadata, including `aillom-connect://...` tools. */
|
|
15
|
+
url?: string;
|
|
16
|
+
endpoint_url?: string;
|
|
17
|
+
endpointUrl?: string;
|
|
18
|
+
[key: string]: unknown;
|
|
10
19
|
}
|
|
20
|
+
export type VoxAuthMode = 'auto' | 'handshake' | 'header' | 'both';
|
|
11
21
|
export interface AillomVoxConfig {
|
|
22
|
+
/**
|
|
23
|
+
* Gateway API key (`av_…`). **Secret** — treat like a password.
|
|
24
|
+
* In public web apps, anyone can extract a key shipped to the browser; prefer a
|
|
25
|
+
* server-issued short-lived token or a backend proxy that holds the real key.
|
|
26
|
+
*/
|
|
12
27
|
apiKey: string;
|
|
13
|
-
|
|
28
|
+
/**
|
|
29
|
+
* WebSocket auth strategy. Default `auto` sends `x-api-key` from Node.js and falls
|
|
30
|
+
* back to the config `apikey` field in browsers, where custom WebSocket headers are unavailable.
|
|
31
|
+
*/
|
|
32
|
+
authMode?: VoxAuthMode;
|
|
33
|
+
/** Lowercase provider id, e.g. `aillomvox`, `openai`. Default: `aillomvox`. */
|
|
34
|
+
provider?: VoxProviderId;
|
|
14
35
|
voice?: string;
|
|
15
36
|
language?: string;
|
|
37
|
+
/** Optional workspace scope; requires an API key authorized for that workspace. */
|
|
38
|
+
workspaceId?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Required for production sessions per gateway docs; defaults are applied only client-side for quick tests.
|
|
41
|
+
*/
|
|
16
42
|
systemPrompt?: string;
|
|
17
43
|
sampleRate?: 8000 | 16000 | 24000;
|
|
44
|
+
/**
|
|
45
|
+
* When true, logs outbound config (with `apikey` redacted) and unknown inbound JSON.
|
|
46
|
+
* Disable in production; logs and the `raw` event may contain user speech text (PII).
|
|
47
|
+
*/
|
|
18
48
|
debug?: boolean;
|
|
19
49
|
tools?: ClientTool[];
|
|
50
|
+
/** HTTPS(S) webhook for server-side session events (if enabled for your key). */
|
|
20
51
|
webhookUrl?: string;
|
|
52
|
+
/** Session cap in seconds (`30`-`7200`; default gateway cap is 300). */
|
|
21
53
|
maxDuration?: number;
|
|
54
|
+
/** Spoken right after the session is ready. */
|
|
55
|
+
firstMessage?: string;
|
|
56
|
+
/** Spoken before forced hangup when `max_duration` is reached (see protocol docs). */
|
|
57
|
+
farewellMessage?: string;
|
|
58
|
+
/**
|
|
59
|
+
* When `provider === "aillomvox"`, selects the TTS stack from `GET /api/providers`.
|
|
60
|
+
* Defaults to **`inworld`** when omitted (the SDK sets `tts_engine` in the handshake).
|
|
61
|
+
*/
|
|
62
|
+
ttsEngine?: AillomVoxTtsEngineId | string;
|
|
63
|
+
/**
|
|
64
|
+
* @deprecated Session model overrides are ignored by the current gateway; model selection
|
|
65
|
+
* is controlled server-side. Use `AillomVox.fetchProviders()` to inspect active defaults.
|
|
66
|
+
*/
|
|
67
|
+
model?: string;
|
|
68
|
+
qualityProfile?: string;
|
|
69
|
+
toolTimeout?: number;
|
|
70
|
+
ttsBufferMs?: number;
|
|
71
|
+
ttsEarlyStartMs?: number;
|
|
72
|
+
ttsMinChunkMs?: number;
|
|
73
|
+
streamLlmTextToTts?: boolean;
|
|
74
|
+
accumulatorMs?: number;
|
|
75
|
+
/** Advanced provider config passed through as `extra_config`. Do not put browser-visible secrets here. */
|
|
76
|
+
extraConfig?: Record<string, unknown>;
|
|
77
|
+
/**
|
|
78
|
+
* WebSocket URL or HTTPS API origin. Examples:
|
|
79
|
+
* - `wss://vox.aillom.com/ws` (default)
|
|
80
|
+
* - `https://vox.aillom.com` (normalized to the same WebSocket URL)
|
|
81
|
+
*/
|
|
22
82
|
gatewayUrl?: string;
|
|
23
83
|
}
|
|
24
84
|
export interface TranscriptEvent {
|
|
85
|
+
type?: 'transcript';
|
|
25
86
|
role: 'user' | 'assistant';
|
|
26
87
|
text: string;
|
|
27
88
|
final: boolean;
|
|
28
89
|
}
|
|
29
90
|
export interface ToolCallEvent {
|
|
91
|
+
type?: 'tool_call';
|
|
30
92
|
call_id: string;
|
|
31
93
|
name: string;
|
|
32
|
-
args:
|
|
94
|
+
args: Record<string, unknown>;
|
|
95
|
+
}
|
|
96
|
+
/** Agent state (Ultravox-oriented pipeline). */
|
|
97
|
+
export type VoxAgentState = 'listening' | 'thinking' | 'speaking';
|
|
98
|
+
export interface StateEvent {
|
|
99
|
+
type: 'state';
|
|
100
|
+
state: VoxAgentState;
|
|
101
|
+
}
|
|
102
|
+
/** Engine connection milestones from the gateway. */
|
|
103
|
+
export interface ControlEvent {
|
|
104
|
+
type: 'control';
|
|
105
|
+
action?: string;
|
|
106
|
+
provider?: string;
|
|
107
|
+
model?: string;
|
|
108
|
+
tts_model?: string;
|
|
109
|
+
[key: string]: unknown;
|
|
110
|
+
}
|
|
111
|
+
export interface ErrorEvent {
|
|
112
|
+
type?: 'error';
|
|
113
|
+
message?: string;
|
|
114
|
+
error?: string;
|
|
115
|
+
code?: string;
|
|
116
|
+
}
|
|
117
|
+
export type EventHandler<T = unknown> = (data: T) => void;
|
|
118
|
+
export interface ProvidersCatalogOptions {
|
|
119
|
+
/** Same base you use for `gatewayUrl` / clone API; defaults to production. */
|
|
120
|
+
baseUrl?: string;
|
|
121
|
+
/** When set, `x-api-key` must belong to that workspace (gateway returns 401/403 otherwise). */
|
|
122
|
+
workspaceId?: string;
|
|
123
|
+
/** Set false to skip nested voices in `/api/providers` for faster catalog loads. */
|
|
124
|
+
includeVoices?: boolean;
|
|
125
|
+
apiKey?: string;
|
|
126
|
+
}
|
|
127
|
+
export interface VoicesCatalogOptions {
|
|
128
|
+
/** Provider or TTS engine id, e.g. `inworld`, `fish`, `aws`, `qwen`. */
|
|
129
|
+
provider: string;
|
|
130
|
+
baseUrl?: string;
|
|
131
|
+
/** When set, `x-api-key` must belong to that workspace. */
|
|
132
|
+
workspaceId?: string;
|
|
133
|
+
apiKey?: string;
|
|
134
|
+
pageSize?: number;
|
|
135
|
+
pageNumber?: number;
|
|
136
|
+
maxPages?: number;
|
|
137
|
+
q?: string;
|
|
138
|
+
title?: string;
|
|
139
|
+
tag?: string;
|
|
140
|
+
language?: string;
|
|
141
|
+
titleLanguage?: string;
|
|
142
|
+
sortBy?: string;
|
|
143
|
+
preferredLanguage?: string;
|
|
144
|
+
type?: string;
|
|
145
|
+
scope?: string;
|
|
146
|
+
visibility?: string;
|
|
147
|
+
}
|
|
148
|
+
export interface VoicePreviewOptions {
|
|
149
|
+
provider: string;
|
|
150
|
+
voice: string;
|
|
151
|
+
baseUrl?: string;
|
|
152
|
+
}
|
|
153
|
+
export interface DeleteVoiceOptions {
|
|
154
|
+
provider?: string;
|
|
155
|
+
workspaceId?: string;
|
|
156
|
+
baseUrl?: string;
|
|
157
|
+
}
|
|
158
|
+
export interface CloneVoiceProviderResult {
|
|
159
|
+
status: 'ok' | 'skipped' | 'error' | string;
|
|
160
|
+
voice_id?: string;
|
|
161
|
+
name?: string;
|
|
162
|
+
error?: string;
|
|
163
|
+
[key: string]: unknown;
|
|
33
164
|
}
|
|
34
|
-
export interface
|
|
35
|
-
|
|
165
|
+
export interface CloneVoiceResult {
|
|
166
|
+
voice_id: string | null;
|
|
167
|
+
name?: string;
|
|
168
|
+
workspace_id?: string | null;
|
|
169
|
+
providers?: Record<string, CloneVoiceProviderResult>;
|
|
170
|
+
message?: string;
|
|
171
|
+
[key: string]: unknown;
|
|
172
|
+
}
|
|
173
|
+
export interface CloneVoiceOptions {
|
|
174
|
+
name?: string;
|
|
175
|
+
description?: string;
|
|
176
|
+
baseUrl?: string;
|
|
177
|
+
gatewayUrl?: string;
|
|
178
|
+
filename?: string;
|
|
179
|
+
workspaceId?: string;
|
|
180
|
+
/** Comma-separated internally by the SDK. Defaults to the server route defaults. */
|
|
181
|
+
providers?: string[];
|
|
182
|
+
/** BCP 47 locale, or `AUTO`. Helps providers that need language hints. */
|
|
183
|
+
language?: string;
|
|
184
|
+
/** Exact transcript of the audio sample; recommended for Inworld and Fish Audio. */
|
|
185
|
+
transcription?: string;
|
|
186
|
+
/** Alias accepted by the gateway. */
|
|
187
|
+
transcript?: string;
|
|
188
|
+
/** Optional xAI clone metadata. */
|
|
189
|
+
gender?: 'male' | 'female' | 'neutral';
|
|
190
|
+
accent?: string;
|
|
191
|
+
age?: 'young' | 'middle-aged' | 'old';
|
|
192
|
+
tone?: 'warm' | 'casual' | 'professional' | 'friendly' | 'authoritative' | 'expressive' | 'calm';
|
|
193
|
+
useCase?: 'conversational' | 'narration' | 'characters' | 'educational' | 'advertisement' | 'social_media' | 'entertainment';
|
|
36
194
|
}
|
|
37
|
-
export type EventHandler<T = any> = (data: T) => void;
|
package/package.json
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aillom-vox-client",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Enterprise-Grade Voice AI SDK for Speech-to-Speech, Audio-to-Audio, and Realtime Multimodal applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"dev": "tsc --watch",
|
|
10
|
-
"
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"prepack": "npm run build",
|
|
12
|
+
"test": "npm run typecheck"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
11
21
|
},
|
|
12
22
|
"dependencies": {
|
|
13
23
|
"isomorphic-ws": "^5.0.0",
|
|
@@ -34,12 +44,13 @@
|
|
|
34
44
|
"low-latency",
|
|
35
45
|
"voice-gateway",
|
|
36
46
|
"sip-trunking",
|
|
37
|
-
"asterisk",
|
|
38
|
-
"inworld-ai",
|
|
39
|
-
"gpt-4o-realtime",
|
|
40
47
|
"telephony",
|
|
41
48
|
"ultravox",
|
|
42
|
-
"nova-sonic"
|
|
49
|
+
"nova-sonic",
|
|
50
|
+
"grok-voice",
|
|
51
|
+
"fish-audio",
|
|
52
|
+
"rime-ai",
|
|
53
|
+
"inworld-tts"
|
|
43
54
|
],
|
|
44
55
|
"author": "Aillom Technologies <contato@aillom.com.br>",
|
|
45
56
|
"license": "ISC",
|
|
@@ -47,4 +58,4 @@
|
|
|
47
58
|
"url": "https://github.com/aillom/aillom-vox-client/issues"
|
|
48
59
|
},
|
|
49
60
|
"homepage": "https://vox.aillom.com"
|
|
50
|
-
}
|
|
61
|
+
}
|
package/docs/ASTERISK.md
DELETED
|
@@ -1,411 +0,0 @@
|
|
|
1
|
-
# 📞 Asterisk 23 Integration Guide - AillomVox
|
|
2
|
-
|
|
3
|
-
Complete guide for integrating **Asterisk 23** with **AillomVox** for real-time Voice AI calls.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🎯 Overview
|
|
8
|
-
|
|
9
|
-
AillomVox provides **two integration architectures** for Asterisk:
|
|
10
|
-
|
|
11
|
-
### 1. **Direct Mode** (Simple)
|
|
12
|
-
```
|
|
13
|
-
Asterisk → AudioSocket → AillomVox Gateway → AI Provider
|
|
14
|
-
```
|
|
15
|
-
✅ Simple voice conversations
|
|
16
|
-
❌ No client tools (transfer, AMI control)
|
|
17
|
-
|
|
18
|
-
### 2. **Middleware Mode** (Advanced)
|
|
19
|
-
```
|
|
20
|
-
Asterisk → AudioSocket → Node.js Middleware → AillomVox Gateway
|
|
21
|
-
↓ AMI/ARI
|
|
22
|
-
```
|
|
23
|
-
✅ Client tools enabled (transfer, hangup, dial)
|
|
24
|
-
✅ Full Asterisk control from AI
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## 📋 Prerequisites
|
|
29
|
-
|
|
30
|
-
### Asterisk Requirements
|
|
31
|
-
- **Asterisk 23** (or 18+)
|
|
32
|
-
- **AudioSocket** module compiled and enabled
|
|
33
|
-
- **API Key** for AillomVox gateway
|
|
34
|
-
|
|
35
|
-
### Verify AudioSocket Module
|
|
36
|
-
```bash
|
|
37
|
-
asterisk -rx "module show like audiosocket"
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Expected output:
|
|
41
|
-
```
|
|
42
|
-
Module Description
|
|
43
|
-
res_audiosocket.so AudioSocket
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
If not loaded:
|
|
47
|
-
```bash
|
|
48
|
-
# Load module
|
|
49
|
-
asterisk -rx "module load res_audiosocket"
|
|
50
|
-
|
|
51
|
-
# Make it persistent
|
|
52
|
-
echo "load = res_audiosocket.so" >> /etc/asterisk/modules.conf
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## 🔐 Authentication
|
|
58
|
-
|
|
59
|
-
AillomVox uses **API Key** authentication for security and usage tracking.
|
|
60
|
-
|
|
61
|
-
### Getting Your API Key
|
|
62
|
-
|
|
63
|
-
Get your API key from the AillomVox dashboard or contact support.
|
|
64
|
-
|
|
65
|
-
### Storing API Key
|
|
66
|
-
|
|
67
|
-
Store in `extensions.conf`:
|
|
68
|
-
|
|
69
|
-
```ini
|
|
70
|
-
[globals]
|
|
71
|
-
AILLOM_API_KEY=your-api-key-here
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## 🏗️ Architecture 1: Direct Mode (Simple)
|
|
77
|
-
|
|
78
|
-
### When to Use
|
|
79
|
-
- Simple AI voice conversations
|
|
80
|
-
- No need to transfer calls or control Asterisk
|
|
81
|
-
- Just want AI to answer and respond
|
|
82
|
-
|
|
83
|
-
### Dialplan Configuration
|
|
84
|
-
|
|
85
|
-
```ini
|
|
86
|
-
[from-internal]
|
|
87
|
-
|
|
88
|
-
; Call extension 6000 to talk to AI
|
|
89
|
-
exten => 6000,1,NoOp(AillomVox Direct Mode)
|
|
90
|
-
same => n,Set(WS_URL=ws://vox.aillom.com/ws?apiKey=${AILLOM_API_KEY})
|
|
91
|
-
same => n,Set(CONFIG={"provider":"aillomvox","voice":"Heitor","language":"pt-BR","system_prompt":"Você é um assistente. Seja conciso.","first_message":"Olá! Como posso ajudar?","sample_rate":8000})
|
|
92
|
-
same => n,Answer()
|
|
93
|
-
same => n,AudioSocket(${WS_URL},${CONFIG})
|
|
94
|
-
same => n,Hangup()
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Configuration JSON
|
|
98
|
-
|
|
99
|
-
```json
|
|
100
|
-
{
|
|
101
|
-
"provider": "aillomvox",
|
|
102
|
-
"voice": "Heitor",
|
|
103
|
-
"language": "pt-BR",
|
|
104
|
-
"system_prompt": "Você é um assistente virtual.",
|
|
105
|
-
"first_message": "Olá! Como posso ajudar?",
|
|
106
|
-
"farewell_message": "Obrigado por ligar. Até logo!",
|
|
107
|
-
"sample_rate": 8000,
|
|
108
|
-
"max_duration": 300
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
**Note**: No `tools` array needed in Direct Mode.
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## 🏗️ Architecture 2: Middleware Mode (Advanced)
|
|
117
|
-
|
|
118
|
-
### When to Use
|
|
119
|
-
- AI needs to **transfer** calls to extensions
|
|
120
|
-
- AI needs to **hangup** via AMI (not just end conversation)
|
|
121
|
-
- AI needs to **dial** external numbers
|
|
122
|
-
- Advanced call control
|
|
123
|
-
|
|
124
|
-
### Architecture
|
|
125
|
-
```
|
|
126
|
-
Asterisk → AudioSocket (port 9000) → Node.js Middleware
|
|
127
|
-
↓
|
|
128
|
-
AMI/ARI Control
|
|
129
|
-
↓
|
|
130
|
-
AillomVox Gateway
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Step 1: Install Dependencies
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
npm install aillom-vox-client asterisk-manager
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Step 2: Create Middleware (`asterisk-bridge.js`)
|
|
140
|
-
|
|
141
|
-
```javascript
|
|
142
|
-
const net = require('net');
|
|
143
|
-
const AillomVoxClient = require('aillom-vox-client');
|
|
144
|
-
const AMI = require('asterisk-manager');
|
|
145
|
-
|
|
146
|
-
// AMI connection for Asterisk control
|
|
147
|
-
const ami = new AMI(5038, 'localhost', 'admin', 'secret', true);
|
|
148
|
-
|
|
149
|
-
ami.keepConnected();
|
|
150
|
-
|
|
151
|
-
// AudioSocket server (receives from Asterisk)
|
|
152
|
-
const server = net.createServer((socket) => {
|
|
153
|
-
console.log('[Bridge] New call from Asterisk');
|
|
154
|
-
|
|
155
|
-
// Connect to AillomVox
|
|
156
|
-
const client = new AillomVoxClient({
|
|
157
|
-
apiKey: process.env.AILLOM_API_KEY,
|
|
158
|
-
url: 'wss://vox.aillom.com/ws'
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Register client tools
|
|
162
|
-
client.connect({
|
|
163
|
-
provider: 'aillomvox',
|
|
164
|
-
voice: 'Heitor',
|
|
165
|
-
language: 'pt-BR',
|
|
166
|
-
system_prompt: 'Você é um assistente. Se o usuário pedir, transfira para ramal 100 ou desligue a ligação.',
|
|
167
|
-
sample_rate: 8000,
|
|
168
|
-
tools: [{
|
|
169
|
-
name: 'hangup',
|
|
170
|
-
description: 'End the call',
|
|
171
|
-
parameters: { type: 'object', properties: {} }
|
|
172
|
-
}, {
|
|
173
|
-
name: 'transfer',
|
|
174
|
-
description: 'Transfer call to extension',
|
|
175
|
-
parameters: {
|
|
176
|
-
type: 'object',
|
|
177
|
-
properties: {
|
|
178
|
-
extension: { type: 'string', description: 'Target extension' }
|
|
179
|
-
},
|
|
180
|
-
required: ['extension']
|
|
181
|
-
}
|
|
182
|
-
}]
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Handle tool calls from AI
|
|
186
|
-
client.on('tool_call', async (tool) => {
|
|
187
|
-
console.log(`[Tool] AI called: ${tool.name}`, tool.args);
|
|
188
|
-
|
|
189
|
-
if (tool.name === 'hangup') {
|
|
190
|
-
console.log('[Tool] Hanging up call');
|
|
191
|
-
socket.end();
|
|
192
|
-
client.disconnect();
|
|
193
|
-
return 'Call ended';
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (tool.name === 'transfer') {
|
|
197
|
-
const ext = tool.args.extension;
|
|
198
|
-
console.log(`[Tool] Transferring to ${ext}`);
|
|
199
|
-
|
|
200
|
-
// Use AMI to transfer (implement based on your channel tracking)
|
|
201
|
-
ami.action({
|
|
202
|
-
action: 'redirect',
|
|
203
|
-
channel: 'PJSIP/1234-00000001', // Track this from call setup
|
|
204
|
-
exten: ext,
|
|
205
|
-
context: 'from-internal',
|
|
206
|
-
priority: 1
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
return `Transferred to extension ${ext}`;
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// Pipe audio: Asterisk ↔ AillomVox
|
|
214
|
-
socket.on('data', (data) => {
|
|
215
|
-
// Parse AudioSocket protocol if needed, then send PCM
|
|
216
|
-
client.sendAudio(data);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
client.on('audio', (pcmData) => {
|
|
220
|
-
socket.write(pcmData);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
socket.on('end', () => {
|
|
224
|
-
console.log('[Bridge] Asterisk closed connection');
|
|
225
|
-
client.disconnect();
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
server.listen(9000, '127.0.0.1', () => {
|
|
230
|
-
console.log('[Bridge] Listening on 127.0.0.1:9000');
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### Step 3: Configure Asterisk
|
|
235
|
-
|
|
236
|
-
```ini
|
|
237
|
-
[from-internal]
|
|
238
|
-
|
|
239
|
-
; Call extension 7000 using middleware (with client tools)
|
|
240
|
-
exten => 7000,1,NoOp(AillomVox Middleware Mode)
|
|
241
|
-
same => n,Set(CONFIG={"provider":"aillomvox"})
|
|
242
|
-
same => n,Answer()
|
|
243
|
-
same => n,AudioSocket(127.0.0.1:9000,${CONFIG})
|
|
244
|
-
same => n,Hangup()
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Step 4: Run Middleware
|
|
248
|
-
|
|
249
|
-
```bash
|
|
250
|
-
AILLOM_API_KEY=your-api-key node asterisk-bridge.js
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Step 5: Test
|
|
254
|
-
|
|
255
|
-
Call extension 7000 and say:
|
|
256
|
-
- "Transfer me to extension 100" → AI calls `transfer` tool
|
|
257
|
-
- "Goodbye" → AI calls `hangup` tool
|
|
258
|
-
|
|
259
|
-
---
|
|
260
|
-
|
|
261
|
-
## 🎙️ Audio Format
|
|
262
|
-
|
|
263
|
-
### AudioSocket Protocol
|
|
264
|
-
- **Format**: PCM 16-bit signed little-endian (`slin`)
|
|
265
|
-
- **Sample Rate**: 8000 Hz (telephony standard)
|
|
266
|
-
- **Channels**: 1 (mono)
|
|
267
|
-
- **Encoding**: `pcm_s16le`
|
|
268
|
-
|
|
269
|
-
### Codec Conversion (ulaw/alaw → slin)
|
|
270
|
-
|
|
271
|
-
**No Brasil e na maioria dos países**, trunks SIP usam:
|
|
272
|
-
- **ulaw** (G.711μ) - Padrão nos EUA/Brasil
|
|
273
|
-
- **alaw** (G.711a) - Padrão na Europa
|
|
274
|
-
|
|
275
|
-
**Asterisk converte automaticamente**:
|
|
276
|
-
```
|
|
277
|
-
Trunk SIP (ulaw/alaw) → Asterisk → slin → AudioSocket → AillomVox
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
Não precisa configurar nada! Asterisk faz a conversão transparente.
|
|
281
|
-
|
|
282
|
-
### Forcing Codec (Optional)
|
|
283
|
-
|
|
284
|
-
Se tiver problemas de áudio, force o codec:
|
|
285
|
-
|
|
286
|
-
```ini
|
|
287
|
-
exten => 6000,1,Set(CHANNEL(audioreadformat)=slin)
|
|
288
|
-
same => n,Set(CHANNEL(audiowriteformat)=slin)
|
|
289
|
-
same => n,Answer()
|
|
290
|
-
same => n,AudioSocket(...)
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Isso garante que Asterisk sempre entrega PCM 16-bit para o AudioSocket.
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
## 🌍 Multi-Provider Examples (Direct Mode)
|
|
298
|
-
|
|
299
|
-
### AillomVox (Best for Telephony)
|
|
300
|
-
|
|
301
|
-
```ini
|
|
302
|
-
exten => 7001,1,Set(CONFIG={"provider":"aillomvox","voice":"Heitor","sample_rate":8000})
|
|
303
|
-
same => n,AudioSocket(ws://vox.aillom.com/ws?apiKey=${AILLOM_API_KEY},${CONFIG})
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
**Why?** Lowest latency, optimized for 8kHz, $0.03/min.
|
|
307
|
-
|
|
308
|
-
### Gemini 2.5 Flash
|
|
309
|
-
|
|
310
|
-
```ini
|
|
311
|
-
exten => 7002,1,Set(CONFIG={"provider":"gemini","voice":"Puck","sample_rate":8000})
|
|
312
|
-
same => n,AudioSocket(ws://vox.aillom.com/ws?apiKey=${AILLOM_API_KEY},${CONFIG})
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
**Why?** Multimodal, fast, $0.06/min.
|
|
316
|
-
|
|
317
|
-
### OpenAI Realtime
|
|
318
|
-
|
|
319
|
-
```ini
|
|
320
|
-
exten => 7003,1,Set(CONFIG={"provider":"openai","voice":"shimmer","sample_rate":8000})
|
|
321
|
-
same => n,AudioSocket(ws://vox.aillom.com/ws?apiKey=${AILLOM_API_KEY},${CONFIG})
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
**Why?** Best for complex reasoning, $0.10/min.
|
|
325
|
-
|
|
326
|
-
---
|
|
327
|
-
|
|
328
|
-
## ⚠️ Troubleshooting
|
|
329
|
-
|
|
330
|
-
### Problem: "Module audiosocket not loaded"
|
|
331
|
-
|
|
332
|
-
```bash
|
|
333
|
-
asterisk -rx "module load res_audiosocket"
|
|
334
|
-
echo "load = res_audiosocket.so" >> /etc/asterisk/modules.conf
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Problem: "Connection refused"
|
|
338
|
-
|
|
339
|
-
**Direct Mode**: Check firewall, verify server is running
|
|
340
|
-
**Middleware Mode**: Ensure middleware is running on `127.0.0.1:9000`
|
|
341
|
-
|
|
342
|
-
```bash
|
|
343
|
-
# Test direct connection
|
|
344
|
-
curl -I https://vox.aillom.com/health
|
|
345
|
-
|
|
346
|
-
# Test middleware
|
|
347
|
-
netstat -tuln | grep 9000
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
### Problem: "No audio"
|
|
351
|
-
|
|
352
|
-
Force codec:
|
|
353
|
-
```ini
|
|
354
|
-
exten => 6000,1,Set(CHANNEL(audioreadformat)=slin)
|
|
355
|
-
same => n,Set(CHANNEL(audiowriteformat)=slin)
|
|
356
|
-
same => n,AudioSocket(...)
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
---
|
|
360
|
-
|
|
361
|
-
## 📊 Configuration Options
|
|
362
|
-
|
|
363
|
-
| Field | Type | Description | Default |
|
|
364
|
-
|-------|------|-------------|---------|
|
|
365
|
-
| `provider` | string | `aillomvox`, `gemini`, `openai`, `qwen`, `grok`, `aws`, `ultravox` | **Required** |
|
|
366
|
-
| `voice` | string | Voice ID (provider-specific) | **Required** |
|
|
367
|
-
| `language` | string | `pt-BR`, `en-US`, `es-ES`, etc | `en-US` |
|
|
368
|
-
| `system_prompt` | string | Instructions for AI | **Required** |
|
|
369
|
-
| `first_message` | string | Initial greeting | `null` |
|
|
370
|
-
| `farewell_message` | string | Goodbye message | `null` |
|
|
371
|
-
| `sample_rate` | number | `8000` (tel), `16000` (hd) | **Required** |
|
|
372
|
-
| `max_duration` | number | Max seconds (120-3600) | `300` |
|
|
373
|
-
| `tools` | array | Client tools (Middleware only) | `[]` |
|
|
374
|
-
|
|
375
|
-
---
|
|
376
|
-
|
|
377
|
-
## 🌐 Production Checklist
|
|
378
|
-
|
|
379
|
-
- [ ] AudioSocket module loaded and persistent
|
|
380
|
-
- [ ] API key stored securely in `[globals]`
|
|
381
|
-
- [ ] Sample rate set to 8000 Hz
|
|
382
|
-
- [ ] Max duration configured
|
|
383
|
-
- [ ] If using Middleware: process manager (PM2, systemd)
|
|
384
|
-
- [ ] If using Middleware: AMI credentials configured
|
|
385
|
-
- [ ] Tested with real calls
|
|
386
|
-
- [ ] Monitoring enabled
|
|
387
|
-
|
|
388
|
-
---
|
|
389
|
-
|
|
390
|
-
## 💡 Which Architecture Should I Use?
|
|
391
|
-
|
|
392
|
-
| Feature | Direct Mode | Middleware Mode |
|
|
393
|
-
|---------|-------------|-----------------|
|
|
394
|
-
| Simple conversations | ✅ Yes | ✅ Yes |
|
|
395
|
-
| Transfer calls | ❌ No | ✅ Yes |
|
|
396
|
-
| Hangup via AMI | ❌ No | ✅ Yes |
|
|
397
|
-
| Dial external numbers | ❌ No | ✅ Yes |
|
|
398
|
-
| Complexity | Low | Medium |
|
|
399
|
-
| Setup | 2 minutes | 10 minutes |
|
|
400
|
-
|
|
401
|
-
**Recommendation**: Start with **Direct Mode**. Upgrade to **Middleware** when you need client tools.
|
|
402
|
-
|
|
403
|
-
---
|
|
404
|
-
|
|
405
|
-
## 📚 Additional Resources
|
|
406
|
-
|
|
407
|
-
- [Client Tools Guide](TOOLS.md)
|
|
408
|
-
- [AillomVox Protocol](PROTOCOL.md)
|
|
409
|
-
- [Provider Comparison](PROVIDERS.md)
|
|
410
|
-
|
|
411
|
-
Happy building! 🎉
|