@actrun_ai/tastekit-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.
Files changed (53) hide show
  1. package/dist/__tests__/elevenlabs-smoke.d.ts +7 -0
  2. package/dist/__tests__/elevenlabs-smoke.d.ts.map +1 -0
  3. package/dist/__tests__/elevenlabs-smoke.js +157 -0
  4. package/dist/__tests__/elevenlabs-smoke.js.map +1 -0
  5. package/dist/audio/player.d.ts +27 -0
  6. package/dist/audio/player.d.ts.map +1 -0
  7. package/dist/audio/player.js +69 -0
  8. package/dist/audio/player.js.map +1 -0
  9. package/dist/audio/recorder.d.ts +22 -0
  10. package/dist/audio/recorder.d.ts.map +1 -0
  11. package/dist/audio/recorder.js +45 -0
  12. package/dist/audio/recorder.js.map +1 -0
  13. package/dist/config.d.ts +99 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +36 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/index.d.ts +16 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +14 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/resolve.d.ts +16 -0
  22. package/dist/resolve.d.ts.map +1 -0
  23. package/dist/resolve.js +77 -0
  24. package/dist/resolve.js.map +1 -0
  25. package/dist/stt/elevenlabs-stt.d.ts +25 -0
  26. package/dist/stt/elevenlabs-stt.d.ts.map +1 -0
  27. package/dist/stt/elevenlabs-stt.js +140 -0
  28. package/dist/stt/elevenlabs-stt.js.map +1 -0
  29. package/dist/stt/provider.d.ts +25 -0
  30. package/dist/stt/provider.d.ts.map +1 -0
  31. package/dist/stt/provider.js +8 -0
  32. package/dist/stt/provider.js.map +1 -0
  33. package/dist/stt/whisper-stt.d.ts +27 -0
  34. package/dist/stt/whisper-stt.d.ts.map +1 -0
  35. package/dist/stt/whisper-stt.js +95 -0
  36. package/dist/stt/whisper-stt.js.map +1 -0
  37. package/dist/tts/elevenlabs-tts.d.ts +24 -0
  38. package/dist/tts/elevenlabs-tts.d.ts.map +1 -0
  39. package/dist/tts/elevenlabs-tts.js +67 -0
  40. package/dist/tts/elevenlabs-tts.js.map +1 -0
  41. package/dist/tts/piper-tts.d.ts +23 -0
  42. package/dist/tts/piper-tts.d.ts.map +1 -0
  43. package/dist/tts/piper-tts.js +59 -0
  44. package/dist/tts/piper-tts.js.map +1 -0
  45. package/dist/tts/provider.d.ts +17 -0
  46. package/dist/tts/provider.d.ts.map +1 -0
  47. package/dist/tts/provider.js +8 -0
  48. package/dist/tts/provider.js.map +1 -0
  49. package/dist/voice-io.d.ts +48 -0
  50. package/dist/voice-io.d.ts.map +1 -0
  51. package/dist/voice-io.js +110 -0
  52. package/dist/voice-io.js.map +1 -0
  53. package/package.json +47 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { STTProvider, TranscriptEvent } from './provider.js';
2
+ export interface ElevenLabsSTTOptions {
3
+ apiKey: string;
4
+ language?: string;
5
+ /** VAD silence threshold in seconds (default 1.5) */
6
+ vadSilenceThreshold?: number;
7
+ /** Base WebSocket URL (default: wss://api.elevenlabs.io) */
8
+ baseUrl?: string;
9
+ sampleRate?: number;
10
+ }
11
+ /**
12
+ * ElevenLabs Scribe v2 realtime speech-to-text provider.
13
+ *
14
+ * Opens a WebSocket to the ElevenLabs realtime STT endpoint.
15
+ * Sends base64-encoded PCM audio chunks and yields transcript events.
16
+ * Built-in VAD commits transcription when the user stops speaking.
17
+ */
18
+ export declare class ElevenLabsSTT implements STTProvider {
19
+ readonly name = "elevenlabs-stt";
20
+ private options;
21
+ constructor(options: ElevenLabsSTTOptions);
22
+ transcribe(audio: AsyncIterable<Buffer>): AsyncIterable<TranscriptEvent>;
23
+ dispose(): Promise<void>;
24
+ }
25
+ //# sourceMappingURL=elevenlabs-stt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevenlabs-stt.d.ts","sourceRoot":"","sources":["../../src/stt/elevenlabs-stt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,qBAAa,aAAc,YAAW,WAAW;IAC/C,QAAQ,CAAC,IAAI,oBAAoB;IACjC,OAAO,CAAC,OAAO,CAAiH;gBAEpH,OAAO,EAAE,oBAAoB;IAUlC,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,eAAe,CAAC;IA6HzE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
@@ -0,0 +1,140 @@
1
+ import WebSocket from 'ws';
2
+ /**
3
+ * ElevenLabs Scribe v2 realtime speech-to-text provider.
4
+ *
5
+ * Opens a WebSocket to the ElevenLabs realtime STT endpoint.
6
+ * Sends base64-encoded PCM audio chunks and yields transcript events.
7
+ * Built-in VAD commits transcription when the user stops speaking.
8
+ */
9
+ export class ElevenLabsSTT {
10
+ name = 'elevenlabs-stt';
11
+ options;
12
+ constructor(options) {
13
+ this.options = {
14
+ apiKey: options.apiKey,
15
+ language: options.language ?? 'en',
16
+ vadSilenceThreshold: options.vadSilenceThreshold ?? 1.5,
17
+ baseUrl: options.baseUrl ?? 'wss://api.elevenlabs.io',
18
+ sampleRate: options.sampleRate ?? 16000,
19
+ };
20
+ }
21
+ async *transcribe(audio) {
22
+ const { apiKey, language, vadSilenceThreshold, baseUrl, sampleRate } = this.options;
23
+ const url = `${baseUrl}/v1/speech-to-text/realtime?model_id=scribe_v2_realtime&language_code=${language}&audio_format=pcm_${sampleRate}`;
24
+ const ws = new WebSocket(url, {
25
+ headers: { 'xi-api-key': apiKey },
26
+ });
27
+ // Queue for transcript events received from the server
28
+ const eventQueue = [];
29
+ let resolveWaiting = null;
30
+ let done = false;
31
+ let error = null;
32
+ ws.on('message', (data) => {
33
+ try {
34
+ const msg = JSON.parse(data.toString());
35
+ if (msg.message_type === 'partial_transcript' && msg.text) {
36
+ eventQueue.push({ type: 'partial', text: msg.text });
37
+ }
38
+ else if (msg.message_type === 'committed_transcript' && msg.text) {
39
+ eventQueue.push({ type: 'final', text: msg.text });
40
+ }
41
+ else if (msg.message_type === 'error' || msg.message_type === 'auth_error') {
42
+ error = new Error(`ElevenLabs STT error: ${msg.message ?? msg.error ?? 'unknown'}`);
43
+ }
44
+ if (resolveWaiting) {
45
+ resolveWaiting();
46
+ resolveWaiting = null;
47
+ }
48
+ }
49
+ catch {
50
+ // Ignore malformed messages
51
+ }
52
+ });
53
+ ws.on('error', (err) => {
54
+ error = err instanceof Error ? err : new Error(String(err));
55
+ if (resolveWaiting) {
56
+ resolveWaiting();
57
+ resolveWaiting = null;
58
+ }
59
+ });
60
+ ws.on('close', () => {
61
+ done = true;
62
+ if (resolveWaiting) {
63
+ resolveWaiting();
64
+ resolveWaiting = null;
65
+ }
66
+ });
67
+ // Wait for connection to open
68
+ await new Promise((resolve, reject) => {
69
+ ws.on('open', resolve);
70
+ ws.on('error', reject);
71
+ });
72
+ // Start sending audio in the background
73
+ const sendAudio = (async () => {
74
+ try {
75
+ let isFirst = true;
76
+ for await (const chunk of audio) {
77
+ if (ws.readyState !== WebSocket.OPEN)
78
+ break;
79
+ const message = {
80
+ message_type: 'input_audio_chunk',
81
+ audio_base_64: chunk.toString('base64'),
82
+ sample_rate: sampleRate,
83
+ commit: false,
84
+ };
85
+ // Only send previous_text on the first chunk
86
+ if (isFirst) {
87
+ message.previous_text = '';
88
+ isFirst = false;
89
+ }
90
+ ws.send(JSON.stringify(message));
91
+ }
92
+ // Send a final commit to flush any remaining audio
93
+ if (ws.readyState === WebSocket.OPEN) {
94
+ ws.send(JSON.stringify({
95
+ message_type: 'input_audio_chunk',
96
+ audio_base_64: '',
97
+ sample_rate: sampleRate,
98
+ commit: true,
99
+ }));
100
+ }
101
+ }
102
+ catch {
103
+ // Audio stream ended or WebSocket closed
104
+ }
105
+ })();
106
+ // Yield transcript events as they arrive
107
+ try {
108
+ while (!done || eventQueue.length > 0) {
109
+ if (error)
110
+ throw error;
111
+ if (eventQueue.length > 0) {
112
+ yield eventQueue.shift();
113
+ // If we got a final transcript, we're done with this utterance
114
+ if (eventQueue.length === 0) {
115
+ const lastEvent = eventQueue[eventQueue.length];
116
+ // Check if the last yielded event was final
117
+ // Actually, let's check: we already yielded it above, so we need
118
+ // to track differently. Let's just continue and let the caller
119
+ // decide when to stop.
120
+ }
121
+ }
122
+ else if (!done) {
123
+ await new Promise((resolve) => {
124
+ resolveWaiting = resolve;
125
+ });
126
+ }
127
+ }
128
+ }
129
+ finally {
130
+ await sendAudio;
131
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
132
+ ws.close();
133
+ }
134
+ }
135
+ }
136
+ async dispose() {
137
+ // No persistent state to clean up — each transcribe() call manages its own WebSocket
138
+ }
139
+ }
140
+ //# sourceMappingURL=elevenlabs-stt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevenlabs-stt.js","sourceRoot":"","sources":["../../src/stt/elevenlabs-stt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Speech-to-Text Provider Interface
3
+ *
4
+ * Consumes an audio stream and yields transcription events.
5
+ * Implementations: ElevenLabs Scribe v2, Whisper.cpp
6
+ */
7
+ export interface TranscriptEvent {
8
+ /** 'partial' = interim result, 'final' = committed transcription */
9
+ type: 'partial' | 'final';
10
+ /** Transcribed text */
11
+ text: string;
12
+ /** Confidence score 0-1, if available */
13
+ confidence?: number;
14
+ }
15
+ export interface STTProvider {
16
+ readonly name: string;
17
+ /**
18
+ * Transcribe an audio stream into text events.
19
+ * @param audio PCM audio chunks (16-bit, 16kHz mono)
20
+ */
21
+ transcribe(audio: AsyncIterable<Buffer>): AsyncIterable<TranscriptEvent>;
22
+ /** Clean up resources (close WebSocket, etc.) */
23
+ dispose?(): Promise<void>;
24
+ }
25
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/stt/provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;IACzE,iDAAiD;IACjD,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Speech-to-Text Provider Interface
3
+ *
4
+ * Consumes an audio stream and yields transcription events.
5
+ * Implementations: ElevenLabs Scribe v2, Whisper.cpp
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/stt/provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,27 @@
1
+ import type { STTProvider, TranscriptEvent } from './provider.js';
2
+ export interface WhisperSTTOptions {
3
+ /** Path to whisper.cpp main binary (default: 'whisper-cpp') */
4
+ binaryPath?: string;
5
+ /** Whisper model name/path (default: 'base.en') */
6
+ model?: string;
7
+ /** Language for transcription */
8
+ language?: string;
9
+ }
10
+ /**
11
+ * Local Whisper.cpp speech-to-text provider.
12
+ *
13
+ * Records the full utterance, writes to a temp WAV file,
14
+ * then runs whisper.cpp for batch transcription.
15
+ * No partial transcripts — yields a single final event.
16
+ */
17
+ export declare class WhisperSTT implements STTProvider {
18
+ readonly name = "whisper-stt";
19
+ private binaryPath;
20
+ private model;
21
+ private language;
22
+ constructor(options?: WhisperSTTOptions);
23
+ transcribe(audio: AsyncIterable<Buffer>): AsyncIterable<TranscriptEvent>;
24
+ private runWhisper;
25
+ dispose(): Promise<void>;
26
+ }
27
+ //# sourceMappingURL=whisper-stt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-stt.d.ts","sourceRoot":"","sources":["../../src/stt/whisper-stt.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,UAAW,YAAW,WAAW;IAC5C,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,CAAC,EAAE,iBAAiB;IAMhC,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,eAAe,CAAC;IA0B/E,OAAO,CAAC,UAAU;IAoBZ,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
@@ -0,0 +1,95 @@
1
+ import { execFile } from 'child_process';
2
+ import { writeFileSync, unlinkSync } from 'fs';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ /**
6
+ * Local Whisper.cpp speech-to-text provider.
7
+ *
8
+ * Records the full utterance, writes to a temp WAV file,
9
+ * then runs whisper.cpp for batch transcription.
10
+ * No partial transcripts — yields a single final event.
11
+ */
12
+ export class WhisperSTT {
13
+ name = 'whisper-stt';
14
+ binaryPath;
15
+ model;
16
+ language;
17
+ constructor(options) {
18
+ this.binaryPath = options?.binaryPath ?? 'whisper-cpp';
19
+ this.model = options?.model ?? 'base.en';
20
+ this.language = options?.language ?? 'en';
21
+ }
22
+ async *transcribe(audio) {
23
+ // Collect all audio chunks into a single buffer
24
+ const chunks = [];
25
+ for await (const chunk of audio) {
26
+ chunks.push(chunk);
27
+ }
28
+ const rawPcm = Buffer.concat(chunks);
29
+ if (rawPcm.length === 0) {
30
+ return;
31
+ }
32
+ // Write raw PCM as a WAV file (16-bit, 16kHz, mono)
33
+ const tempPath = join(tmpdir(), `tastekit-voice-${Date.now()}.wav`);
34
+ writeWav(tempPath, rawPcm, 16000);
35
+ try {
36
+ const text = await this.runWhisper(tempPath);
37
+ if (text.trim()) {
38
+ yield { type: 'final', text: text.trim() };
39
+ }
40
+ }
41
+ finally {
42
+ try {
43
+ unlinkSync(tempPath);
44
+ }
45
+ catch { /* ignore */ }
46
+ }
47
+ }
48
+ runWhisper(wavPath) {
49
+ return new Promise((resolve, reject) => {
50
+ const args = [
51
+ '-m', this.model,
52
+ '-l', this.language,
53
+ '-f', wavPath,
54
+ '--no-timestamps',
55
+ '--print-progress', 'false',
56
+ ];
57
+ execFile(this.binaryPath, args, { timeout: 30000 }, (err, stdout, stderr) => {
58
+ if (err) {
59
+ reject(new Error(`Whisper failed: ${stderr || err.message}`));
60
+ }
61
+ else {
62
+ resolve(stdout);
63
+ }
64
+ });
65
+ });
66
+ }
67
+ async dispose() {
68
+ // Stateless
69
+ }
70
+ }
71
+ /** Write raw 16-bit PCM data as a WAV file. */
72
+ function writeWav(path, pcm, sampleRate) {
73
+ const numChannels = 1;
74
+ const bitsPerSample = 16;
75
+ const byteRate = sampleRate * numChannels * (bitsPerSample / 8);
76
+ const blockAlign = numChannels * (bitsPerSample / 8);
77
+ const dataSize = pcm.length;
78
+ const headerSize = 44;
79
+ const header = Buffer.alloc(headerSize);
80
+ header.write('RIFF', 0);
81
+ header.writeUInt32LE(dataSize + headerSize - 8, 4);
82
+ header.write('WAVE', 8);
83
+ header.write('fmt ', 12);
84
+ header.writeUInt32LE(16, 16); // fmt chunk size
85
+ header.writeUInt16LE(1, 20); // PCM format
86
+ header.writeUInt16LE(numChannels, 22);
87
+ header.writeUInt32LE(sampleRate, 24);
88
+ header.writeUInt32LE(byteRate, 28);
89
+ header.writeUInt16LE(blockAlign, 32);
90
+ header.writeUInt16LE(bitsPerSample, 34);
91
+ header.write('data', 36);
92
+ header.writeUInt32LE(dataSize, 40);
93
+ writeFileSync(path, Buffer.concat([header, pcm]));
94
+ }
95
+ //# sourceMappingURL=whisper-stt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-stt.js","sourceRoot":"","sources":["../../src/stt/whisper-stt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { TTSProvider } from './provider.js';
2
+ export interface ElevenLabsTTSOptions {
3
+ apiKey: string;
4
+ /** ElevenLabs voice ID (default: Rachel - 21m00Tcm4TlvDq8ikWAM) */
5
+ voiceId?: string;
6
+ /** Model ID (default: eleven_multilingual_v2) */
7
+ modelId?: string;
8
+ /** Base URL (default: https://api.elevenlabs.io) */
9
+ baseUrl?: string;
10
+ }
11
+ /**
12
+ * ElevenLabs streaming text-to-speech provider.
13
+ *
14
+ * Uses the REST streaming endpoint to convert text to audio.
15
+ * Returns raw PCM audio chunks for streaming playback.
16
+ */
17
+ export declare class ElevenLabsTTS implements TTSProvider {
18
+ readonly name = "elevenlabs-tts";
19
+ private options;
20
+ constructor(options: ElevenLabsTTSOptions);
21
+ synthesize(text: string): Promise<AsyncIterable<Buffer>>;
22
+ dispose(): Promise<void>;
23
+ }
24
+ //# sourceMappingURL=elevenlabs-tts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevenlabs-tts.d.ts","sourceRoot":"","sources":["../../src/tts/elevenlabs-tts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,WAAW;IAC/C,QAAQ,CAAC,IAAI,oBAAoB;IACjC,OAAO,CAAC,OAAO,CAAqF;gBAExF,OAAO,EAAE,oBAAoB;IASnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAmDxD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * ElevenLabs streaming text-to-speech provider.
3
+ *
4
+ * Uses the REST streaming endpoint to convert text to audio.
5
+ * Returns raw PCM audio chunks for streaming playback.
6
+ */
7
+ export class ElevenLabsTTS {
8
+ name = 'elevenlabs-tts';
9
+ options;
10
+ constructor(options) {
11
+ this.options = {
12
+ apiKey: options.apiKey,
13
+ voiceId: options.voiceId ?? '21m00Tcm4TlvDq8ikWAM',
14
+ modelId: options.modelId ?? 'eleven_multilingual_v2',
15
+ baseUrl: options.baseUrl ?? 'https://api.elevenlabs.io',
16
+ };
17
+ }
18
+ async synthesize(text) {
19
+ const { apiKey, voiceId, modelId, baseUrl } = this.options;
20
+ // output_format is a query parameter, not a body field
21
+ const url = `${baseUrl}/v1/text-to-speech/${voiceId}/stream?output_format=pcm_22050`;
22
+ const response = await fetch(url, {
23
+ method: 'POST',
24
+ headers: {
25
+ 'Content-Type': 'application/json',
26
+ 'xi-api-key': apiKey,
27
+ },
28
+ body: JSON.stringify({
29
+ text,
30
+ model_id: modelId,
31
+ voice_settings: {
32
+ stability: 0.5,
33
+ similarity_boost: 0.75,
34
+ style: 0.0,
35
+ use_speaker_boost: true,
36
+ },
37
+ }),
38
+ });
39
+ if (!response.ok) {
40
+ const errorText = await response.text();
41
+ throw new Error(`ElevenLabs TTS error (${response.status}): ${errorText}`);
42
+ }
43
+ if (!response.body) {
44
+ throw new Error('ElevenLabs TTS returned no body');
45
+ }
46
+ // Convert the ReadableStream to AsyncIterable<Buffer>
47
+ const reader = response.body.getReader();
48
+ async function* streamToAsyncIterable() {
49
+ try {
50
+ while (true) {
51
+ const { done, value } = await reader.read();
52
+ if (done)
53
+ break;
54
+ yield Buffer.from(value);
55
+ }
56
+ }
57
+ finally {
58
+ reader.releaseLock();
59
+ }
60
+ }
61
+ return streamToAsyncIterable();
62
+ }
63
+ async dispose() {
64
+ // Stateless — nothing to clean up
65
+ }
66
+ }
67
+ //# sourceMappingURL=elevenlabs-tts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevenlabs-tts.js","sourceRoot":"","sources":["../../src/tts/elevenlabs-tts.ts"],"names":[],"mappings":"AAYA;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,gBAAgB,CAAC;IACzB,OAAO,CAAqF;IAEpG,YAAY,OAA6B;QACvC,IAAI,CAAC,OAAO,GAAG;YACb,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,sBAAsB;YAClD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,wBAAwB;YACpD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,2BAA2B;SACxD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAE3D,uDAAuD;QACvD,MAAM,GAAG,GAAG,GAAG,OAAO,sBAAsB,OAAO,iCAAiC,CAAC;QAErF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,YAAY,EAAE,MAAM;aACrB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI;gBACJ,QAAQ,EAAE,OAAO;gBACjB,cAAc,EAAE;oBACd,SAAS,EAAE,GAAG;oBACd,gBAAgB,EAAE,IAAI;oBACtB,KAAK,EAAE,GAAG;oBACV,iBAAiB,EAAE,IAAI;iBACxB;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,sDAAsD;QACtD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAEzC,KAAK,SAAS,CAAC,CAAC,qBAAqB;YACnC,IAAI,CAAC;gBACH,OAAO,IAAI,EAAE,CAAC;oBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;oBAC5C,IAAI,IAAI;wBAAE,MAAM;oBAChB,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;QAED,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,kCAAkC;IACpC,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ import type { TTSProvider } from './provider.js';
2
+ export interface PiperTTSOptions {
3
+ /** Path to piper binary (default: 'piper') */
4
+ binaryPath?: string;
5
+ /** Path to voice model ONNX file */
6
+ model?: string;
7
+ }
8
+ /**
9
+ * Local Piper text-to-speech provider.
10
+ *
11
+ * Runs piper via child process to generate WAV audio.
12
+ * Returns the audio as a single-chunk AsyncIterable for playback.
13
+ */
14
+ export declare class PiperTTS implements TTSProvider {
15
+ readonly name = "piper-tts";
16
+ private binaryPath;
17
+ private model;
18
+ constructor(options?: PiperTTSOptions);
19
+ synthesize(text: string): Promise<AsyncIterable<Buffer>>;
20
+ private runPiper;
21
+ dispose(): Promise<void>;
22
+ }
23
+ //# sourceMappingURL=piper-tts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piper-tts.d.ts","sourceRoot":"","sources":["../../src/tts/piper-tts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,qBAAa,QAAS,YAAW,WAAW;IAC1C,QAAQ,CAAC,IAAI,eAAe;IAC5B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAqB;gBAEtB,OAAO,CAAC,EAAE,eAAe;IAK/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAkB9D,OAAO,CAAC,QAAQ;IAuBV,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
@@ -0,0 +1,59 @@
1
+ import { execFile } from 'child_process';
2
+ import { readFileSync, unlinkSync } from 'fs';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ /**
6
+ * Local Piper text-to-speech provider.
7
+ *
8
+ * Runs piper via child process to generate WAV audio.
9
+ * Returns the audio as a single-chunk AsyncIterable for playback.
10
+ */
11
+ export class PiperTTS {
12
+ name = 'piper-tts';
13
+ binaryPath;
14
+ model;
15
+ constructor(options) {
16
+ this.binaryPath = options?.binaryPath ?? 'piper';
17
+ this.model = options?.model;
18
+ }
19
+ async synthesize(text) {
20
+ const tempPath = join(tmpdir(), `tastekit-tts-${Date.now()}.wav`);
21
+ await this.runPiper(text, tempPath);
22
+ const audioData = readFileSync(tempPath);
23
+ try {
24
+ unlinkSync(tempPath);
25
+ }
26
+ catch { /* ignore */ }
27
+ // Strip the WAV header (44 bytes) to get raw PCM
28
+ const pcm = audioData.subarray(44);
29
+ async function* singleChunk() {
30
+ yield pcm;
31
+ }
32
+ return singleChunk();
33
+ }
34
+ runPiper(text, outputPath) {
35
+ return new Promise((resolve, reject) => {
36
+ const args = ['--output_file', outputPath];
37
+ if (this.model) {
38
+ args.push('--model', this.model);
39
+ }
40
+ const child = execFile(this.binaryPath, args, { timeout: 30000 }, (err) => {
41
+ if (err) {
42
+ reject(new Error(`Piper failed: ${err.message}`));
43
+ }
44
+ else {
45
+ resolve();
46
+ }
47
+ });
48
+ // Pipe text to piper's stdin
49
+ if (child.stdin) {
50
+ child.stdin.write(text);
51
+ child.stdin.end();
52
+ }
53
+ });
54
+ }
55
+ async dispose() {
56
+ // Stateless
57
+ }
58
+ }
59
+ //# sourceMappingURL=piper-tts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"piper-tts.js","sourceRoot":"","sources":["../../src/tts/piper-tts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAU5B;;;;;GAKG;AACH,MAAM,OAAO,QAAQ;IACV,IAAI,GAAG,WAAW,CAAC;IACpB,UAAU,CAAS;IACnB,KAAK,CAAqB;IAElC,YAAY,OAAyB;QACnC,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,OAAO,CAAC;QACjD,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAElE,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAEpC,MAAM,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC;YAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAEpD,iDAAiD;QACjD,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEnC,KAAK,SAAS,CAAC,CAAC,WAAW;YACzB,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;IAEO,QAAQ,CAAC,IAAY,EAAE,UAAkB;QAC/C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;YAC3C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;YAED,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;gBACxE,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACpD,CAAC;qBAAM,CAAC;oBACN,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,6BAA6B;YAC7B,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACxB,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO;QACX,YAAY;IACd,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Text-to-Speech Provider Interface
3
+ *
4
+ * Converts text into an audio stream for playback.
5
+ * Implementations: ElevenLabs, Piper
6
+ */
7
+ export interface TTSProvider {
8
+ readonly name: string;
9
+ /**
10
+ * Synthesize text into an audio stream.
11
+ * @returns AsyncIterable of PCM or MP3 audio chunks
12
+ */
13
+ synthesize(text: string): Promise<AsyncIterable<Buffer>>;
14
+ /** Clean up resources */
15
+ dispose?(): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/tts/provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,yBAAyB;IACzB,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Text-to-Speech Provider Interface
3
+ *
4
+ * Converts text into an audio stream for playback.
5
+ * Implementations: ElevenLabs, Piper
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/tts/provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,48 @@
1
+ import type { STTProvider } from './stt/provider.js';
2
+ import type { TTSProvider } from './tts/provider.js';
3
+ import { MicRecorder } from './audio/recorder.js';
4
+ import { AudioPlayer } from './audio/player.js';
5
+ export interface VoiceIOOptions {
6
+ /** Show live transcription while user speaks */
7
+ showTranscription?: boolean;
8
+ /** Called with partial transcription updates */
9
+ onPartial?: (text: string) => void;
10
+ /** Called when the user's final transcription is ready */
11
+ onFinalTranscript?: (text: string) => void;
12
+ /** Print interviewer text to console alongside audio */
13
+ printText?: boolean;
14
+ }
15
+ /**
16
+ * Voice I/O orchestrator for TasteKit onboarding.
17
+ *
18
+ * Composes STT + TTS + mic recorder + audio player into the two
19
+ * callbacks the Interviewer expects: getUserInput() and onInterviewerMessage().
20
+ *
21
+ * Drop-in replacement for the text-based inquirer callbacks.
22
+ */
23
+ export declare class VoiceIO {
24
+ private stt;
25
+ private tts;
26
+ private recorder;
27
+ private player;
28
+ private options;
29
+ constructor(stt: STTProvider, tts: TTSProvider, recorder?: MicRecorder, player?: AudioPlayer, options?: VoiceIOOptions);
30
+ /**
31
+ * Drop-in replacement for Interviewer's getUserInput callback.
32
+ * Records from mic → runs STT → returns transcribed text.
33
+ */
34
+ getUserInput(): Promise<string>;
35
+ /**
36
+ * Drop-in replacement for Interviewer's onInterviewerMessage callback.
37
+ * Prints text AND plays it as audio via TTS.
38
+ */
39
+ onInterviewerMessage(message: string): Promise<void>;
40
+ /** Clean up all resources. */
41
+ dispose(): Promise<void>;
42
+ /**
43
+ * Wrap an async iterable so it stops yielding when a condition is met.
44
+ * This lets us stop the mic recording when STT returns a final transcript.
45
+ */
46
+ private createControlledStream;
47
+ }
48
+ //# sourceMappingURL=voice-io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-io.d.ts","sourceRoot":"","sources":["../src/voice-io.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gDAAgD;IAChD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAA2B;gBAGxC,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,WAAW,EAChB,QAAQ,CAAC,EAAE,WAAW,EACtB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,cAAc;IAc1B;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IA8CrC;;;OAGG;IACG,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB1D,8BAA8B;IACxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B;;;OAGG;YACY,sBAAsB;CAStC"}