@cogitator-ai/voice 0.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 +591 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# @cogitator-ai/voice
|
|
2
|
+
|
|
3
|
+
Voice and Realtime agent capabilities for [Cogitator](https://github.com/cogitator-ai/cogitator).
|
|
4
|
+
|
|
5
|
+
Two modes: **Pipeline** (STT -> Agent -> TTS) for any LLM, and **Realtime** (native speech-to-speech) for OpenAI/Gemini.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @cogitator-ai/voice
|
|
11
|
+
|
|
12
|
+
# Required for OpenAI STT/TTS
|
|
13
|
+
pnpm add openai
|
|
14
|
+
|
|
15
|
+
# Optional dependencies
|
|
16
|
+
pnpm add onnxruntime-node # Silero VAD (neural network-based)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Pipeline Mode** — STT -> Agent -> TTS, works with any Cogitator agent and LLM backend
|
|
22
|
+
- **Realtime Mode** — Native speech-to-speech via OpenAI Realtime API or Gemini Live API
|
|
23
|
+
- **2 STT Providers** — OpenAI (gpt-4o-mini-transcribe) and Deepgram (nova-3, real-time streaming)
|
|
24
|
+
- **2 TTS Providers** — OpenAI (gpt-4o-mini-tts) and ElevenLabs (eleven_flash_v2_5, ~75ms latency)
|
|
25
|
+
- **2 VAD Providers** — Energy-based (zero deps) and Silero (ONNX neural network)
|
|
26
|
+
- **WebSocket Transport** — Built-in server for browser/mobile clients
|
|
27
|
+
- **Agent Tools** — Drop-in `transcribe_audio` and `speak_text` tools for any Cogitator agent
|
|
28
|
+
- **Interruption Handling** — Barge-in support in both pipeline and realtime modes
|
|
29
|
+
- **Audio Utilities** — PCM/WAV conversion, resampling, RMS calculation
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { VoiceAgent, OpenAISTT, OpenAITTS } from '@cogitator-ai/voice';
|
|
37
|
+
import { Agent } from '@cogitator-ai/core';
|
|
38
|
+
|
|
39
|
+
const agent = new Agent({ instructions: 'You are a helpful assistant' });
|
|
40
|
+
|
|
41
|
+
const voiceAgent = new VoiceAgent({
|
|
42
|
+
agent,
|
|
43
|
+
mode: 'pipeline',
|
|
44
|
+
stt: new OpenAISTT({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
45
|
+
tts: new OpenAITTS({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await voiceAgent.listen(8080);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Connect from any WebSocket client at `ws://localhost:8080/voice` — send binary audio frames, receive binary audio + JSON control messages.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## STT Providers
|
|
56
|
+
|
|
57
|
+
| Provider | Default Model | Streaming | Word Timestamps | Notes |
|
|
58
|
+
| ------------- | ------------------------ | ------------------- | --------------- | ---------------------------------------------- |
|
|
59
|
+
| `OpenAISTT` | `gpt-4o-mini-transcribe` | Buffered | Yes | Also supports `gpt-4o-transcribe`, `whisper-1` |
|
|
60
|
+
| `DeepgramSTT` | `nova-3` | Real-time WebSocket | Yes | Interim results, endpointing, auto-punctuation |
|
|
61
|
+
|
|
62
|
+
### OpenAI STT
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { OpenAISTT } from '@cogitator-ai/voice';
|
|
66
|
+
|
|
67
|
+
const stt = new OpenAISTT({
|
|
68
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
69
|
+
model: 'gpt-4o-mini-transcribe',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const result = await stt.transcribe(audioBuffer, { language: 'en' });
|
|
73
|
+
console.log(result.text);
|
|
74
|
+
console.log(result.words);
|
|
75
|
+
console.log(result.duration);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Deepgram STT
|
|
79
|
+
|
|
80
|
+
Real-time streaming with interim results:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { DeepgramSTT } from '@cogitator-ai/voice';
|
|
84
|
+
|
|
85
|
+
const stt = new DeepgramSTT({
|
|
86
|
+
apiKey: process.env.DEEPGRAM_API_KEY!,
|
|
87
|
+
model: 'nova-3',
|
|
88
|
+
language: 'en',
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const stream = stt.createStream({ interimResults: true, endpointing: 500 });
|
|
92
|
+
|
|
93
|
+
stream.on('partial', (text) => {
|
|
94
|
+
console.log('partial:', text);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
stream.on('final', (result) => {
|
|
98
|
+
console.log('final:', result.text);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
stream.write(audioChunk1);
|
|
102
|
+
stream.write(audioChunk2);
|
|
103
|
+
await stream.close();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## TTS Providers
|
|
109
|
+
|
|
110
|
+
| Provider | Default Model | Streaming | Voices | Notes |
|
|
111
|
+
| --------------- | ------------------- | --------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
112
|
+
| `OpenAITTS` | `gpt-4o-mini-tts` | Yes | alloy, ash, ballad, coral, echo, fable, onyx, nova, sage, shimmer, verse, marin, cedar | Also supports `tts-1`, `tts-1-hd`. Supports `instructions` for voice style control |
|
|
113
|
+
| `ElevenLabsTTS` | `eleven_flash_v2_5` | Yes | By voice ID | ~75ms latency. Also supports `eleven_turbo_v2_5`, `eleven_multilingual_v2`, `eleven_v3` |
|
|
114
|
+
|
|
115
|
+
### OpenAI TTS
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { OpenAITTS } from '@cogitator-ai/voice';
|
|
119
|
+
|
|
120
|
+
const tts = new OpenAITTS({
|
|
121
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
122
|
+
model: 'gpt-4o-mini-tts',
|
|
123
|
+
voice: 'coral',
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const audio = await tts.synthesize('Hello, world!', {
|
|
127
|
+
speed: 1.0,
|
|
128
|
+
format: 'mp3',
|
|
129
|
+
instructions: 'Speak in a warm, friendly tone',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
for await (const chunk of tts.streamSynthesize('Streaming response...')) {
|
|
133
|
+
process.stdout.write('.');
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### ElevenLabs TTS
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { ElevenLabsTTS } from '@cogitator-ai/voice';
|
|
141
|
+
|
|
142
|
+
const tts = new ElevenLabsTTS({
|
|
143
|
+
apiKey: process.env.ELEVENLABS_API_KEY!,
|
|
144
|
+
model: 'eleven_flash_v2_5',
|
|
145
|
+
voiceId: '21m00Tcm4TlvDq8ikWAM',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const audio = await tts.synthesize('Hello!', { format: 'mp3' });
|
|
149
|
+
|
|
150
|
+
for await (const chunk of tts.streamSynthesize('Streaming...')) {
|
|
151
|
+
process.stdout.write('.');
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## VAD Providers
|
|
158
|
+
|
|
159
|
+
| Provider | Accuracy | Dependencies | Speed | Notes |
|
|
160
|
+
| ----------- | -------- | ------------------ | ---------- | ------------------------------------------------- |
|
|
161
|
+
| `EnergyVAD` | Basic | None | Fast | RMS energy threshold, good for quiet environments |
|
|
162
|
+
| `SileroVAD` | High | `onnxruntime-node` | ~3ms/frame | Neural network, works in noisy environments |
|
|
163
|
+
|
|
164
|
+
### Energy VAD
|
|
165
|
+
|
|
166
|
+
Zero-dependency voice activity detection based on audio energy levels:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { EnergyVAD } from '@cogitator-ai/voice';
|
|
170
|
+
|
|
171
|
+
const vad = new EnergyVAD({
|
|
172
|
+
threshold: 0.01,
|
|
173
|
+
silenceDuration: 500,
|
|
174
|
+
sampleRate: 16000,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const event = vad.process(float32Samples);
|
|
178
|
+
|
|
179
|
+
switch (event.type) {
|
|
180
|
+
case 'speech_start':
|
|
181
|
+
console.log('User started speaking');
|
|
182
|
+
break;
|
|
183
|
+
case 'speech_end':
|
|
184
|
+
console.log(`Speech ended after ${event.duration}ms`);
|
|
185
|
+
break;
|
|
186
|
+
case 'speech':
|
|
187
|
+
console.log(`Speech probability: ${event.probability}`);
|
|
188
|
+
break;
|
|
189
|
+
case 'silence':
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Silero VAD
|
|
195
|
+
|
|
196
|
+
Neural network-based VAD using the Silero ONNX model:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { SileroVAD } from '@cogitator-ai/voice';
|
|
200
|
+
|
|
201
|
+
const vad = new SileroVAD({
|
|
202
|
+
modelPath: './silero_vad.onnx',
|
|
203
|
+
threshold: 0.5,
|
|
204
|
+
silenceDuration: 500,
|
|
205
|
+
sampleRate: 16000,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
await vad.init();
|
|
209
|
+
|
|
210
|
+
const event = vad.process(float32Samples);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Pipeline Mode
|
|
216
|
+
|
|
217
|
+
The pipeline processes audio through a three-stage loop: STT -> Agent -> TTS. Works with any Cogitator agent regardless of the underlying LLM.
|
|
218
|
+
|
|
219
|
+
### One-shot processing
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { VoicePipeline, OpenAISTT, OpenAITTS } from '@cogitator-ai/voice';
|
|
223
|
+
|
|
224
|
+
const pipeline = new VoicePipeline({
|
|
225
|
+
stt: new OpenAISTT({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
226
|
+
tts: new OpenAITTS({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
227
|
+
agent: myAgent,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const result = await pipeline.process(audioBuffer);
|
|
231
|
+
console.log(result.transcript);
|
|
232
|
+
console.log(result.response);
|
|
233
|
+
// result.audio — synthesized response audio
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Streaming sessions
|
|
237
|
+
|
|
238
|
+
For continuous conversations with VAD-driven turn detection:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { VoicePipeline, OpenAISTT, OpenAITTS, EnergyVAD } from '@cogitator-ai/voice';
|
|
242
|
+
|
|
243
|
+
const pipeline = new VoicePipeline({
|
|
244
|
+
stt: new OpenAISTT({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
245
|
+
tts: new OpenAITTS({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
246
|
+
vad: new EnergyVAD({ threshold: 0.01, silenceDuration: 500 }),
|
|
247
|
+
agent: myAgent,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const session = pipeline.createSession();
|
|
251
|
+
|
|
252
|
+
session.on('speech_start', () => {
|
|
253
|
+
console.log('User started speaking');
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
session.on('transcript', (text, isFinal) => {
|
|
257
|
+
console.log(isFinal ? `Final: ${text}` : `Interim: ${text}`);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
session.on('agent_response', (text) => {
|
|
261
|
+
console.log('Agent:', text);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
session.on('audio', (chunk) => {
|
|
265
|
+
playAudio(chunk);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
session.pushAudio(pcm16Chunk);
|
|
269
|
+
|
|
270
|
+
session.interrupt();
|
|
271
|
+
|
|
272
|
+
await session.close();
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Realtime Mode
|
|
278
|
+
|
|
279
|
+
Native speech-to-speech without the STT/TTS pipeline. The LLM directly processes and generates audio. Lower latency, more natural conversation flow.
|
|
280
|
+
|
|
281
|
+
### OpenAI Realtime
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
import { RealtimeSession } from '@cogitator-ai/voice';
|
|
285
|
+
|
|
286
|
+
const session = new RealtimeSession({
|
|
287
|
+
provider: 'openai',
|
|
288
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
289
|
+
model: 'gpt-4o-mini-realtime-preview',
|
|
290
|
+
voice: 'coral',
|
|
291
|
+
instructions: 'You are a helpful assistant.',
|
|
292
|
+
tools: [
|
|
293
|
+
{
|
|
294
|
+
name: 'get_weather',
|
|
295
|
+
description: 'Get current weather',
|
|
296
|
+
parameters: { type: 'object', properties: { city: { type: 'string' } } },
|
|
297
|
+
execute: async (args) => ({ temp: 72, unit: 'F' }),
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
session.on('connected', () => console.log('Connected'));
|
|
303
|
+
session.on('audio', (chunk) => playAudio(chunk));
|
|
304
|
+
session.on('transcript', (text, role) => console.log(`${role}: ${text}`));
|
|
305
|
+
session.on('speech_start', () => console.log('VAD: speech detected'));
|
|
306
|
+
session.on('tool_call', (name, args) => console.log(`Tool: ${name}`, args));
|
|
307
|
+
|
|
308
|
+
await session.connect();
|
|
309
|
+
|
|
310
|
+
session.pushAudio(pcm16Chunk);
|
|
311
|
+
session.sendText('Hello!');
|
|
312
|
+
|
|
313
|
+
session.interrupt();
|
|
314
|
+
session.close();
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Gemini Live
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { RealtimeSession } from '@cogitator-ai/voice';
|
|
321
|
+
|
|
322
|
+
const session = new RealtimeSession({
|
|
323
|
+
provider: 'gemini',
|
|
324
|
+
apiKey: process.env.GOOGLE_API_KEY!,
|
|
325
|
+
model: 'gemini-live-2.5-flash-native-audio',
|
|
326
|
+
voice: 'Puck',
|
|
327
|
+
instructions: 'You are a helpful assistant.',
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
session.on('audio', (chunk) => playAudio(chunk));
|
|
331
|
+
session.on('transcript', (text, role) => console.log(`${role}: ${text}`));
|
|
332
|
+
|
|
333
|
+
await session.connect();
|
|
334
|
+
session.pushAudio(pcm16Chunk);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## WebSocket Transport
|
|
340
|
+
|
|
341
|
+
Built-in WebSocket server for connecting browser/mobile clients. Binary frames carry audio, text frames carry JSON control messages.
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
import { WebSocketTransport, VoiceClient } from '@cogitator-ai/voice';
|
|
345
|
+
|
|
346
|
+
const transport = new WebSocketTransport({
|
|
347
|
+
path: '/voice',
|
|
348
|
+
maxConnections: 100,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
transport.on('connection', (client: VoiceClient) => {
|
|
352
|
+
console.log(`Client connected: ${client.id}`);
|
|
353
|
+
|
|
354
|
+
client.on('audio', (chunk) => {
|
|
355
|
+
// PCM16 audio from client
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
client.on('message', (msg) => {
|
|
359
|
+
// JSON control messages
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
client.on('close', () => {
|
|
363
|
+
console.log(`Client disconnected: ${client.id}`);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
client.sendAudio(responseChunk);
|
|
367
|
+
client.sendMessage({ type: 'transcript', text: 'Hello' });
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
await transport.listen(8080);
|
|
371
|
+
|
|
372
|
+
// or attach to an existing HTTP server
|
|
373
|
+
transport.attachToServer(httpServer);
|
|
374
|
+
|
|
375
|
+
await transport.close();
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### WebSocket Protocol
|
|
379
|
+
|
|
380
|
+
| Direction | Format | Content |
|
|
381
|
+
| ---------------- | ----------- | ----------------------------------------------------------------------------------- |
|
|
382
|
+
| Client -> Server | Binary | PCM16 audio frames (16kHz, mono, 16-bit LE) |
|
|
383
|
+
| Client -> Server | Text (JSON) | Control messages |
|
|
384
|
+
| Server -> Client | Binary | PCM16 or encoded audio response |
|
|
385
|
+
| Server -> Client | Text (JSON) | `{ type: 'transcript' \| 'agent_response' \| 'speech_start' \| 'speech_end', ... }` |
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## VoiceAgent
|
|
390
|
+
|
|
391
|
+
High-level class that wires together transport, pipeline/realtime, and session management:
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
import { VoiceAgent, OpenAISTT, OpenAITTS, EnergyVAD } from '@cogitator-ai/voice';
|
|
395
|
+
|
|
396
|
+
const voiceAgent = new VoiceAgent({
|
|
397
|
+
agent: myAgent,
|
|
398
|
+
mode: 'pipeline',
|
|
399
|
+
stt: new OpenAISTT({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
400
|
+
tts: new OpenAITTS({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
401
|
+
vad: new EnergyVAD(),
|
|
402
|
+
transport: { path: '/voice', maxConnections: 50 },
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
voiceAgent.on('session_start', (id) => console.log(`Session started: ${id}`));
|
|
406
|
+
voiceAgent.on('session_end', (id) => console.log(`Session ended: ${id}`));
|
|
407
|
+
voiceAgent.on('error', (err) => console.error(err));
|
|
408
|
+
|
|
409
|
+
console.log(`Active sessions: ${voiceAgent.activeSessions}`);
|
|
410
|
+
|
|
411
|
+
await voiceAgent.listen(8080);
|
|
412
|
+
await voiceAgent.close();
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Realtime mode with VoiceAgent
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
const voiceAgent = new VoiceAgent({
|
|
419
|
+
agent: myAgent,
|
|
420
|
+
mode: 'realtime',
|
|
421
|
+
realtimeProvider: 'openai',
|
|
422
|
+
realtimeApiKey: process.env.OPENAI_API_KEY!,
|
|
423
|
+
realtimeModel: 'gpt-4o-mini-realtime-preview',
|
|
424
|
+
voice: 'coral',
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
await voiceAgent.listen(8080);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Agent Integration
|
|
433
|
+
|
|
434
|
+
Give any Cogitator agent the ability to transcribe audio or synthesize speech:
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
import { Agent, tool } from '@cogitator-ai/core';
|
|
438
|
+
import { voiceTools, OpenAISTT, OpenAITTS } from '@cogitator-ai/voice';
|
|
439
|
+
import { z } from 'zod';
|
|
440
|
+
|
|
441
|
+
const [transcribe, speak] = voiceTools({
|
|
442
|
+
stt: new OpenAISTT({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
443
|
+
tts: new OpenAITTS({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
const transcribeTool = tool({
|
|
447
|
+
name: transcribe.name,
|
|
448
|
+
description: transcribe.description,
|
|
449
|
+
parameters: z.object({
|
|
450
|
+
audioBase64: z.string().describe('Base64-encoded audio data'),
|
|
451
|
+
language: z.string().optional().describe('Language code'),
|
|
452
|
+
}),
|
|
453
|
+
execute: async (params) => transcribe.execute(params),
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const speakTool = tool({
|
|
457
|
+
name: speak.name,
|
|
458
|
+
description: speak.description,
|
|
459
|
+
parameters: z.object({
|
|
460
|
+
text: z.string().describe('Text to convert to speech'),
|
|
461
|
+
voice: z.string().optional().describe('Voice to use'),
|
|
462
|
+
}),
|
|
463
|
+
execute: async (params) => speak.execute(params),
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
const agent = new Agent({
|
|
467
|
+
name: 'voice-assistant',
|
|
468
|
+
model: 'gpt-4o',
|
|
469
|
+
instructions: 'You can transcribe audio and generate speech.',
|
|
470
|
+
tools: [transcribeTool, speakTool],
|
|
471
|
+
});
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Audio Utilities
|
|
477
|
+
|
|
478
|
+
Low-level audio conversion functions for working with PCM and WAV data:
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
import {
|
|
482
|
+
float32ToPcm16,
|
|
483
|
+
pcm16ToFloat32,
|
|
484
|
+
pcmToWav,
|
|
485
|
+
wavToPcm,
|
|
486
|
+
resample,
|
|
487
|
+
calculateRMS,
|
|
488
|
+
} from '@cogitator-ai/voice';
|
|
489
|
+
|
|
490
|
+
const pcm = float32ToPcm16(float32Samples);
|
|
491
|
+
const floats = pcm16ToFloat32(pcmBuffer);
|
|
492
|
+
|
|
493
|
+
const wav = pcmToWav(pcmBuffer, 16000);
|
|
494
|
+
const { samples, sampleRate } = wavToPcm(wavBuffer);
|
|
495
|
+
|
|
496
|
+
const resampled = resample(float32Samples, 44100, 16000);
|
|
497
|
+
|
|
498
|
+
const rms = calculateRMS(float32Samples);
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## Configuration Reference
|
|
504
|
+
|
|
505
|
+
### `VoiceAgentConfig`
|
|
506
|
+
|
|
507
|
+
| Field | Type | Required | Description |
|
|
508
|
+
| ------------------ | ---------------------------------------- | ------------- | ------------------------------------ |
|
|
509
|
+
| `agent` | `{ run(input) => Promise<{ content }> }` | Yes | Cogitator agent or compatible object |
|
|
510
|
+
| `mode` | `'pipeline' \| 'realtime'` | Yes | Processing mode |
|
|
511
|
+
| `stt` | `STTProvider` | Pipeline only | Speech-to-text provider |
|
|
512
|
+
| `tts` | `TTSProvider` | Pipeline only | Text-to-speech provider |
|
|
513
|
+
| `vad` | `VADProvider` | No | Voice activity detection |
|
|
514
|
+
| `realtimeProvider` | `'openai' \| 'gemini'` | Realtime only | Realtime API provider |
|
|
515
|
+
| `realtimeApiKey` | `string` | Realtime only | API key for realtime provider |
|
|
516
|
+
| `realtimeModel` | `string` | No | Model override |
|
|
517
|
+
| `voice` | `string` | No | Voice for TTS or realtime |
|
|
518
|
+
| `transport` | `WebSocketTransportConfig` | No | Transport options |
|
|
519
|
+
|
|
520
|
+
### `OpenAISTTConfig`
|
|
521
|
+
|
|
522
|
+
| Field | Type | Default | Description |
|
|
523
|
+
| --------- | -------- | ------------------------ | ------------------- |
|
|
524
|
+
| `apiKey` | `string` | — | OpenAI API key |
|
|
525
|
+
| `model` | `string` | `gpt-4o-mini-transcribe` | Model ID |
|
|
526
|
+
| `baseURL` | `string` | — | Custom API base URL |
|
|
527
|
+
|
|
528
|
+
### `DeepgramSTTConfig`
|
|
529
|
+
|
|
530
|
+
| Field | Type | Default | Description |
|
|
531
|
+
| ---------- | -------- | -------- | --------------------- |
|
|
532
|
+
| `apiKey` | `string` | — | Deepgram API key |
|
|
533
|
+
| `model` | `string` | `nova-3` | Model ID |
|
|
534
|
+
| `language` | `string` | — | Default language code |
|
|
535
|
+
|
|
536
|
+
### `OpenAITTSConfig`
|
|
537
|
+
|
|
538
|
+
| Field | Type | Default | Description |
|
|
539
|
+
| --------- | -------- | ----------------- | ------------------- |
|
|
540
|
+
| `apiKey` | `string` | — | OpenAI API key |
|
|
541
|
+
| `model` | `string` | `gpt-4o-mini-tts` | Model ID |
|
|
542
|
+
| `voice` | `string` | `alloy` | Default voice |
|
|
543
|
+
| `baseURL` | `string` | — | Custom API base URL |
|
|
544
|
+
|
|
545
|
+
### `ElevenLabsTTSConfig`
|
|
546
|
+
|
|
547
|
+
| Field | Type | Default | Description |
|
|
548
|
+
| --------- | -------- | ---------------------- | ------------------ |
|
|
549
|
+
| `apiKey` | `string` | — | ElevenLabs API key |
|
|
550
|
+
| `voiceId` | `string` | `21m00Tcm4TlvDq8ikWAM` | Default voice ID |
|
|
551
|
+
| `model` | `string` | `eleven_flash_v2_5` | Model ID |
|
|
552
|
+
|
|
553
|
+
### `EnergyVADConfig`
|
|
554
|
+
|
|
555
|
+
| Field | Type | Default | Description |
|
|
556
|
+
| ----------------- | -------- | ------- | ----------------------------------------- |
|
|
557
|
+
| `threshold` | `number` | `0.01` | RMS energy threshold for speech detection |
|
|
558
|
+
| `silenceDuration` | `number` | `500` | Silence duration (ms) before `speech_end` |
|
|
559
|
+
| `sampleRate` | `number` | `16000` | Audio sample rate in Hz |
|
|
560
|
+
|
|
561
|
+
### `SileroVADConfig`
|
|
562
|
+
|
|
563
|
+
| Field | Type | Default | Description |
|
|
564
|
+
| ----------------- | -------- | ------- | ----------------------------------------- |
|
|
565
|
+
| `modelPath` | `string` | — | Path to `silero_vad.onnx` model file |
|
|
566
|
+
| `threshold` | `number` | `0.5` | Speech probability threshold (0-1) |
|
|
567
|
+
| `silenceDuration` | `number` | `500` | Silence duration (ms) before `speech_end` |
|
|
568
|
+
| `sampleRate` | `number` | `16000` | Audio sample rate in Hz |
|
|
569
|
+
|
|
570
|
+
### `WebSocketTransportConfig`
|
|
571
|
+
|
|
572
|
+
| Field | Type | Default | Description |
|
|
573
|
+
| ---------------- | -------- | -------- | ------------------------------ |
|
|
574
|
+
| `path` | `string` | `/voice` | WebSocket endpoint path |
|
|
575
|
+
| `maxConnections` | `number` | `100` | Maximum concurrent connections |
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## Examples
|
|
580
|
+
|
|
581
|
+
See [`examples/voice/`](../../examples/voice/) for runnable examples:
|
|
582
|
+
|
|
583
|
+
- **01-pipeline-basic.ts** — Basic pipeline with OpenAI STT + TTS
|
|
584
|
+
- **02-realtime-openai.ts** — OpenAI Realtime API voice agent
|
|
585
|
+
- **03-realtime-gemini.ts** — Gemini Live voice agent
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
## License
|
|
590
|
+
|
|
591
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cogitator-ai/voice",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Voice/Realtime agent capabilities for Cogitator",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"clean": "rm -rf dist",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@cogitator-ai/types": "workspace:*",
|
|
27
|
+
"nanoid": "^5.0.4",
|
|
28
|
+
"ws": "^8.18.0",
|
|
29
|
+
"zod": "^4.3.6"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@cogitator-ai/core": "workspace:*",
|
|
33
|
+
"openai": "^6.0.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependenciesMeta": {
|
|
36
|
+
"@cogitator-ai/core": {
|
|
37
|
+
"optional": true
|
|
38
|
+
},
|
|
39
|
+
"openai": {
|
|
40
|
+
"optional": true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/ws": "^8.5.0",
|
|
45
|
+
"typescript": "^5.7.2",
|
|
46
|
+
"vitest": "^4.0.18"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/cogitator-ai/Cogitator-AI.git",
|
|
51
|
+
"directory": "packages/voice"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public",
|
|
55
|
+
"registry": "https://npm.pkg.github.com"
|
|
56
|
+
},
|
|
57
|
+
"license": "MIT"
|
|
58
|
+
}
|