claude-voice 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 +21 -0
- package/README.md +395 -0
- package/bin/claude-voice +29 -0
- package/config/default.json +109 -0
- package/config/voice-prompt.md +27 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1103 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +140 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +179 -0
- package/dist/config.js.map +1 -0
- package/dist/env.d.ts +40 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +175 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +140 -0
- package/dist/index.js.map +1 -0
- package/dist/platform/index.d.ts +35 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +170 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +185 -0
- package/dist/server.js.map +1 -0
- package/dist/stt/index.d.ts +15 -0
- package/dist/stt/index.d.ts.map +1 -0
- package/dist/stt/index.js +54 -0
- package/dist/stt/index.js.map +1 -0
- package/dist/stt/providers/openai.d.ts +15 -0
- package/dist/stt/providers/openai.d.ts.map +1 -0
- package/dist/stt/providers/openai.js +74 -0
- package/dist/stt/providers/openai.js.map +1 -0
- package/dist/stt/providers/sherpa-onnx.d.ts +50 -0
- package/dist/stt/providers/sherpa-onnx.d.ts.map +1 -0
- package/dist/stt/providers/sherpa-onnx.js +237 -0
- package/dist/stt/providers/sherpa-onnx.js.map +1 -0
- package/dist/stt/providers/whisper-local.d.ts +19 -0
- package/dist/stt/providers/whisper-local.d.ts.map +1 -0
- package/dist/stt/providers/whisper-local.js +141 -0
- package/dist/stt/providers/whisper-local.js.map +1 -0
- package/dist/terminal/input-injector.d.ts +55 -0
- package/dist/terminal/input-injector.d.ts.map +1 -0
- package/dist/terminal/input-injector.js +189 -0
- package/dist/terminal/input-injector.js.map +1 -0
- package/dist/tts/index.d.ts +20 -0
- package/dist/tts/index.d.ts.map +1 -0
- package/dist/tts/index.js +72 -0
- package/dist/tts/index.js.map +1 -0
- package/dist/tts/providers/elevenlabs.d.ts +23 -0
- package/dist/tts/providers/elevenlabs.d.ts.map +1 -0
- package/dist/tts/providers/elevenlabs.js +142 -0
- package/dist/tts/providers/elevenlabs.js.map +1 -0
- package/dist/tts/providers/macos-say.d.ts +17 -0
- package/dist/tts/providers/macos-say.d.ts.map +1 -0
- package/dist/tts/providers/macos-say.js +72 -0
- package/dist/tts/providers/macos-say.js.map +1 -0
- package/dist/tts/providers/openai.d.ts +19 -0
- package/dist/tts/providers/openai.d.ts.map +1 -0
- package/dist/tts/providers/openai.js +118 -0
- package/dist/tts/providers/openai.js.map +1 -0
- package/dist/tts/providers/piper.d.ts +48 -0
- package/dist/tts/providers/piper.d.ts.map +1 -0
- package/dist/tts/providers/piper.js +417 -0
- package/dist/tts/providers/piper.js.map +1 -0
- package/dist/voice-input.d.ts +9 -0
- package/dist/voice-input.d.ts.map +1 -0
- package/dist/voice-input.js +137 -0
- package/dist/voice-input.js.map +1 -0
- package/dist/wake-word/index.d.ts +19 -0
- package/dist/wake-word/index.d.ts.map +1 -0
- package/dist/wake-word/index.js +200 -0
- package/dist/wake-word/index.js.map +1 -0
- package/dist/wake-word/recorder.d.ts +19 -0
- package/dist/wake-word/recorder.d.ts.map +1 -0
- package/dist/wake-word/recorder.js +145 -0
- package/dist/wake-word/recorder.js.map +1 -0
- package/hooks/notification.js +125 -0
- package/hooks/post-tool-use.js +374 -0
- package/hooks/session-start.js +212 -0
- package/hooks/stop.js +254 -0
- package/models/.gitkeep +0 -0
- package/package.json +80 -0
- package/python/stt_service.py +59 -0
- package/python/voice_input.py +154 -0
- package/scripts/install.sh +147 -0
- package/scripts/listen.py +161 -0
- package/scripts/postinstall.js +57 -0
- package/scripts/record.sh +79 -0
- package/scripts/setup-hooks.sh +22 -0
- package/scripts/voice-input.sh +66 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TerminalInputInjector = void 0;
|
|
4
|
+
exports.sendToClaudeCode = sendToClaudeCode;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
8
|
+
/**
|
|
9
|
+
* Injects text into the terminal using AppleScript on macOS.
|
|
10
|
+
* This allows voice-transcribed text to be sent to Claude Code.
|
|
11
|
+
*/
|
|
12
|
+
class TerminalInputInjector {
|
|
13
|
+
terminal;
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
if (options.terminal === 'auto' || !options.terminal) {
|
|
16
|
+
// Auto-detect: prefer iTerm if running, otherwise Terminal
|
|
17
|
+
this.terminal = 'Terminal';
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
this.terminal = options.terminal;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Types text into the active terminal window
|
|
25
|
+
*/
|
|
26
|
+
async type(text, pressEnter = true) {
|
|
27
|
+
if (process.platform !== 'darwin') {
|
|
28
|
+
throw new Error('Terminal input injection is only supported on macOS');
|
|
29
|
+
}
|
|
30
|
+
// Escape special characters for AppleScript
|
|
31
|
+
const escapedText = this.escapeForAppleScript(text);
|
|
32
|
+
const script = this.generateAppleScript(escapedText, pressEnter);
|
|
33
|
+
try {
|
|
34
|
+
await this.runAppleScript(script);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// Try the other terminal app
|
|
38
|
+
const alternateTerminal = this.terminal === 'Terminal' ? 'iTerm' : 'Terminal';
|
|
39
|
+
const alternateScript = this.generateAppleScript(escapedText, pressEnter, alternateTerminal);
|
|
40
|
+
try {
|
|
41
|
+
await this.runAppleScript(alternateScript);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new Error(`Failed to inject text into terminal: ${error}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Runs an AppleScript, handling multi-line scripts properly
|
|
50
|
+
*/
|
|
51
|
+
async runAppleScript(script) {
|
|
52
|
+
// Split script into lines and use multiple -e arguments
|
|
53
|
+
const lines = script.split('\n').filter(line => line.trim());
|
|
54
|
+
const args = lines.map(line => `-e '${line.replace(/'/g, "'\\''")}'`).join(' ');
|
|
55
|
+
await execAsync(`osascript ${args}`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Types text character by character with a delay (for visual effect)
|
|
59
|
+
*/
|
|
60
|
+
async typeSlowly(text, delayMs = 50, pressEnter = true) {
|
|
61
|
+
for (const char of text) {
|
|
62
|
+
await this.type(char, false);
|
|
63
|
+
await this.delay(delayMs);
|
|
64
|
+
}
|
|
65
|
+
if (pressEnter) {
|
|
66
|
+
await this.pressKey('return');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Simulates pressing a key
|
|
71
|
+
*/
|
|
72
|
+
async pressKey(key) {
|
|
73
|
+
if (process.platform !== 'darwin') {
|
|
74
|
+
throw new Error('Key press simulation is only supported on macOS');
|
|
75
|
+
}
|
|
76
|
+
const keyCode = this.getKeyCode(key);
|
|
77
|
+
const script = `
|
|
78
|
+
tell application "System Events"
|
|
79
|
+
key code ${keyCode}
|
|
80
|
+
end tell
|
|
81
|
+
`;
|
|
82
|
+
await execAsync(`osascript -e '${script.replace(/'/g, "'\\''")}'`);
|
|
83
|
+
}
|
|
84
|
+
generateAppleScript(text, pressEnter, terminal) {
|
|
85
|
+
const app = terminal || this.terminal;
|
|
86
|
+
if (app === 'iTerm') {
|
|
87
|
+
return `
|
|
88
|
+
tell application "iTerm"
|
|
89
|
+
tell current session of current window
|
|
90
|
+
write text "${text}"${pressEnter ? '' : ' without newline'}
|
|
91
|
+
end tell
|
|
92
|
+
end tell
|
|
93
|
+
`.replace(/\n/g, ' ');
|
|
94
|
+
}
|
|
95
|
+
// Default: Terminal.app
|
|
96
|
+
// For Terminal, we use System Events to type
|
|
97
|
+
// Note: keystroke and key code must be separate statements
|
|
98
|
+
if (pressEnter) {
|
|
99
|
+
return `tell application "Terminal" to activate
|
|
100
|
+
delay 0.1
|
|
101
|
+
tell application "System Events"
|
|
102
|
+
keystroke "${text}"
|
|
103
|
+
key code 36
|
|
104
|
+
end tell`;
|
|
105
|
+
}
|
|
106
|
+
return `tell application "Terminal" to activate
|
|
107
|
+
delay 0.1
|
|
108
|
+
tell application "System Events"
|
|
109
|
+
keystroke "${text}"
|
|
110
|
+
end tell`;
|
|
111
|
+
}
|
|
112
|
+
escapeForAppleScript(text) {
|
|
113
|
+
return text
|
|
114
|
+
.replace(/\\/g, '\\\\') // Escape backslashes first
|
|
115
|
+
.replace(/"/g, '\\"') // Escape double quotes
|
|
116
|
+
.replace(/\n/g, '\\n') // Escape newlines
|
|
117
|
+
.replace(/\r/g, '\\r') // Escape carriage returns
|
|
118
|
+
.replace(/\t/g, '\\t'); // Escape tabs
|
|
119
|
+
}
|
|
120
|
+
getKeyCode(key) {
|
|
121
|
+
const keyCodes = {
|
|
122
|
+
return: 36,
|
|
123
|
+
enter: 36,
|
|
124
|
+
tab: 48,
|
|
125
|
+
space: 49,
|
|
126
|
+
delete: 51,
|
|
127
|
+
escape: 53,
|
|
128
|
+
command: 55,
|
|
129
|
+
shift: 56,
|
|
130
|
+
capslock: 57,
|
|
131
|
+
option: 58,
|
|
132
|
+
control: 59,
|
|
133
|
+
fn: 63,
|
|
134
|
+
f1: 122,
|
|
135
|
+
f2: 120,
|
|
136
|
+
f3: 99,
|
|
137
|
+
f4: 118,
|
|
138
|
+
f5: 96,
|
|
139
|
+
f6: 97,
|
|
140
|
+
f7: 98,
|
|
141
|
+
f8: 100,
|
|
142
|
+
f9: 101,
|
|
143
|
+
f10: 109,
|
|
144
|
+
f11: 103,
|
|
145
|
+
f12: 111,
|
|
146
|
+
home: 115,
|
|
147
|
+
pageup: 116,
|
|
148
|
+
forwarddelete: 117,
|
|
149
|
+
end: 119,
|
|
150
|
+
pagedown: 121,
|
|
151
|
+
left: 123,
|
|
152
|
+
right: 124,
|
|
153
|
+
down: 125,
|
|
154
|
+
up: 126,
|
|
155
|
+
};
|
|
156
|
+
return keyCodes[key.toLowerCase()] || 0;
|
|
157
|
+
}
|
|
158
|
+
delay(ms) {
|
|
159
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Check if we're running inside a terminal
|
|
163
|
+
*/
|
|
164
|
+
static isInTerminal() {
|
|
165
|
+
return !!(process.stdout.isTTY && (process.env.TERM || process.env.TERM_PROGRAM));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Detect the current terminal application
|
|
169
|
+
*/
|
|
170
|
+
static detectTerminal() {
|
|
171
|
+
const termProgram = process.env.TERM_PROGRAM;
|
|
172
|
+
if (termProgram === 'Apple_Terminal') {
|
|
173
|
+
return 'Terminal';
|
|
174
|
+
}
|
|
175
|
+
if (termProgram === 'iTerm.app') {
|
|
176
|
+
return 'iTerm';
|
|
177
|
+
}
|
|
178
|
+
return 'unknown';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
exports.TerminalInputInjector = TerminalInputInjector;
|
|
182
|
+
/**
|
|
183
|
+
* Convenience function to send voice-transcribed text to Claude Code
|
|
184
|
+
*/
|
|
185
|
+
async function sendToClaudeCode(text) {
|
|
186
|
+
const injector = new TerminalInputInjector({ terminal: 'auto' });
|
|
187
|
+
await injector.type(text, true);
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=input-injector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-injector.js","sourceRoot":"","sources":["../../src/terminal/input-injector.ts"],"names":[],"mappings":";;;AA6NA,4CAGC;AAhOD,iDAAqC;AACrC,+BAAiC;AAEjC,MAAM,SAAS,GAAG,IAAA,gBAAS,EAAC,oBAAI,CAAC,CAAC;AAmBlC;;;GAGG;AACH,MAAa,qBAAqB;IACxB,QAAQ,CAAuB;IAEvC,YAAY,UAAgC,EAAE;QAC5C,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrD,2DAA2D;YAC3D,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACnC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,UAAU,GAAG,IAAI;QACxC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QAED,4CAA4C;QAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAEpD,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QAEjE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,6BAA6B;YAC7B,MAAM,iBAAiB,GAAG,IAAI,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;YAC9E,MAAM,eAAe,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC;YAE7F,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,wCAAwC,KAAK,EAAE,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,cAAc,CAAC,MAAc;QACzC,wDAAwD;QACxD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChF,MAAM,SAAS,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,OAAO,GAAG,EAAE,EAAE,UAAU,GAAG,IAAI;QAC5D,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7B,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG;;mBAEA,OAAO;;KAErB,CAAC;QAEF,MAAM,SAAS,CAAC,iBAAiB,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACrE,CAAC;IAEO,mBAAmB,CAAC,IAAY,EAAE,UAAmB,EAAE,QAAiB;QAC9E,MAAM,GAAG,GAAG,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC;QAEtC,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACpB,OAAO;;;0BAGa,IAAI,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB;;;OAG/D,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACxB,CAAC;QAED,wBAAwB;QACxB,6CAA6C;QAC7C,2DAA2D;QAC3D,IAAI,UAAU,EAAE,CAAC;YACf,OAAO;;;aAGA,IAAI;;SAER,CAAC;QACN,CAAC;QAED,OAAO;;;aAGE,IAAI;SACR,CAAC;IACR,CAAC;IAEO,oBAAoB,CAAC,IAAY;QACvC,OAAO,IAAI;aACR,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,2BAA2B;aAClD,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,uBAAuB;aAC5C,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,kBAAkB;aACxC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,0BAA0B;aAChD,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,cAAc;IAC1C,CAAC;IAEO,UAAU,CAAC,GAAW;QAC5B,MAAM,QAAQ,GAA2B;YACvC,MAAM,EAAE,EAAE;YACV,KAAK,EAAE,EAAE;YACT,GAAG,EAAE,EAAE;YACP,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,EAAE;YACT,QAAQ,EAAE,EAAE;YACZ,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,EAAE;YACX,EAAE,EAAE,EAAE;YACN,EAAE,EAAE,GAAG;YACP,EAAE,EAAE,GAAG;YACP,EAAE,EAAE,EAAE;YACN,EAAE,EAAE,GAAG;YACP,EAAE,EAAE,EAAE;YACN,EAAE,EAAE,EAAE;YACN,EAAE,EAAE,EAAE;YACN,EAAE,EAAE,GAAG;YACP,EAAE,EAAE,GAAG;YACP,GAAG,EAAE,GAAG;YACR,GAAG,EAAE,GAAG;YACR,GAAG,EAAE,GAAG;YACR,IAAI,EAAE,GAAG;YACT,MAAM,EAAE,GAAG;YACX,aAAa,EAAE,GAAG;YAClB,GAAG,EAAE,GAAG;YACR,QAAQ,EAAE,GAAG;YACb,IAAI,EAAE,GAAG;YACT,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,GAAG;YACT,EAAE,EAAE,GAAG;SACR,CAAC;QAEF,OAAO,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAEO,KAAK,CAAC,EAAU;QACtB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,YAAY;QACjB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;IACpF,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,cAAc;QACnB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QAE7C,IAAI,WAAW,KAAK,gBAAgB,EAAE,CAAC;YACrC,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;YAChC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AA9LD,sDA8LC;AAED;;GAEG;AACI,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,MAAM,QAAQ,GAAG,IAAI,qBAAqB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TTSConfig } from '../config';
|
|
2
|
+
export interface TTSProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
speak(text: string): Promise<void>;
|
|
5
|
+
stop(): void;
|
|
6
|
+
isReady(): boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare class TTSManager {
|
|
9
|
+
private provider;
|
|
10
|
+
private queue;
|
|
11
|
+
private isPlaying;
|
|
12
|
+
constructor(config: TTSConfig);
|
|
13
|
+
private createProvider;
|
|
14
|
+
speak(text: string, priority?: boolean): Promise<void>;
|
|
15
|
+
private processQueue;
|
|
16
|
+
stop(): void;
|
|
17
|
+
isReady(): boolean;
|
|
18
|
+
getProviderName(): string;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAMtC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,IAAI,IAAI,CAAC;IACb,OAAO,IAAI,OAAO,CAAC;CACpB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,SAAS;IAI7B,OAAO,CAAC,cAAc;IAgBhB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YAY5C,YAAY;IAqB1B,IAAI,IAAI,IAAI;IAMZ,OAAO,IAAI,OAAO;IAIlB,eAAe,IAAI,MAAM;CAG1B"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TTSManager = void 0;
|
|
4
|
+
const macos_say_1 = require("./providers/macos-say");
|
|
5
|
+
const openai_1 = require("./providers/openai");
|
|
6
|
+
const elevenlabs_1 = require("./providers/elevenlabs");
|
|
7
|
+
const piper_1 = require("./providers/piper");
|
|
8
|
+
class TTSManager {
|
|
9
|
+
provider;
|
|
10
|
+
queue = [];
|
|
11
|
+
isPlaying = false;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.provider = this.createProvider(config);
|
|
14
|
+
}
|
|
15
|
+
createProvider(config) {
|
|
16
|
+
switch (config.provider) {
|
|
17
|
+
case 'macos-say':
|
|
18
|
+
return new macos_say_1.MacOSSayProvider(config.macos);
|
|
19
|
+
case 'openai':
|
|
20
|
+
return new openai_1.OpenAITTSProvider(config.openai);
|
|
21
|
+
case 'elevenlabs':
|
|
22
|
+
return new elevenlabs_1.ElevenLabsProvider(config.elevenlabs);
|
|
23
|
+
case 'piper':
|
|
24
|
+
return new piper_1.PiperProvider(config.piper);
|
|
25
|
+
default:
|
|
26
|
+
console.warn(`Unknown TTS provider: ${config.provider}, falling back to macos-say`);
|
|
27
|
+
return new macos_say_1.MacOSSayProvider(config.macos);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async speak(text, priority = false) {
|
|
31
|
+
if (priority) {
|
|
32
|
+
// High priority: stop current playback and insert at front
|
|
33
|
+
this.stop();
|
|
34
|
+
this.queue.unshift({ text, priority });
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.queue.push({ text, priority });
|
|
38
|
+
}
|
|
39
|
+
await this.processQueue();
|
|
40
|
+
}
|
|
41
|
+
async processQueue() {
|
|
42
|
+
if (this.isPlaying || this.queue.length === 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.isPlaying = true;
|
|
46
|
+
while (this.queue.length > 0) {
|
|
47
|
+
const item = this.queue.shift();
|
|
48
|
+
if (item) {
|
|
49
|
+
try {
|
|
50
|
+
await this.provider.speak(item.text);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error('TTS error:', error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
this.isPlaying = false;
|
|
58
|
+
}
|
|
59
|
+
stop() {
|
|
60
|
+
this.queue = [];
|
|
61
|
+
this.provider.stop();
|
|
62
|
+
this.isPlaying = false;
|
|
63
|
+
}
|
|
64
|
+
isReady() {
|
|
65
|
+
return this.provider.isReady();
|
|
66
|
+
}
|
|
67
|
+
getProviderName() {
|
|
68
|
+
return this.provider.name;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.TTSManager = TTSManager;
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tts/index.ts"],"names":[],"mappings":";;;AACA,qDAAyD;AACzD,+CAAuD;AACvD,uDAA4D;AAC5D,6CAAkD;AASlD,MAAa,UAAU;IACb,QAAQ,CAAc;IACtB,KAAK,GAA0C,EAAE,CAAC;IAClD,SAAS,GAAG,KAAK,CAAC;IAE1B,YAAY,MAAiB;QAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IAEO,cAAc,CAAC,MAAiB;QACtC,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;YACxB,KAAK,WAAW;gBACd,OAAO,IAAI,4BAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5C,KAAK,QAAQ;gBACX,OAAO,IAAI,0BAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9C,KAAK,YAAY;gBACf,OAAO,IAAI,+BAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YACnD,KAAK,OAAO;gBACV,OAAO,IAAI,qBAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACzC;gBACE,OAAO,CAAC,IAAI,CAAC,yBAAyB,MAAM,CAAC,QAAQ,6BAA6B,CAAC,CAAC;gBACpF,OAAO,IAAI,4BAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAY,EAAE,QAAQ,GAAG,KAAK;QACxC,IAAI,QAAQ,EAAE,CAAC;YACb,2DAA2D;YAC3D,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;IAC5B,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAEtB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YAChC,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IACjC,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;CACF;AAvED,gCAuEC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TTSProvider } from '../index';
|
|
2
|
+
interface ElevenLabsConfig {
|
|
3
|
+
voiceId: string;
|
|
4
|
+
modelId: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class ElevenLabsProvider implements TTSProvider {
|
|
7
|
+
name: string;
|
|
8
|
+
private config;
|
|
9
|
+
private apiKey;
|
|
10
|
+
private currentProcess;
|
|
11
|
+
private ready;
|
|
12
|
+
constructor(config: ElevenLabsConfig);
|
|
13
|
+
speak(text: string): Promise<void>;
|
|
14
|
+
private playAudio;
|
|
15
|
+
stop(): void;
|
|
16
|
+
isReady(): boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function listVoices(apiKey: string): Promise<{
|
|
19
|
+
voice_id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
}[]>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=elevenlabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elevenlabs.d.ts","sourceRoot":"","sources":["../../../src/tts/providers/elevenlabs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAMvC,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,qBAAa,kBAAmB,YAAW,WAAW;IACpD,IAAI,SAAgB;IACpB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,gBAAgB;IAiB9B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CxC,OAAO,CAAC,SAAS;IAwBjB,IAAI,IAAI,IAAI;IAOZ,OAAO,IAAI,OAAO;CAGnB;AAGD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAW9F"}
|
|
@@ -0,0 +1,142 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ElevenLabsProvider = void 0;
|
|
40
|
+
exports.listVoices = listVoices;
|
|
41
|
+
const axios_1 = __importDefault(require("axios"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const os = __importStar(require("os"));
|
|
46
|
+
const ELEVENLABS_API_URL = 'https://api.elevenlabs.io/v1';
|
|
47
|
+
class ElevenLabsProvider {
|
|
48
|
+
name = 'elevenlabs';
|
|
49
|
+
config;
|
|
50
|
+
apiKey;
|
|
51
|
+
currentProcess = null;
|
|
52
|
+
ready = false;
|
|
53
|
+
constructor(config) {
|
|
54
|
+
this.config = config;
|
|
55
|
+
this.apiKey = process.env.ELEVENLABS_API_KEY;
|
|
56
|
+
if (!this.apiKey) {
|
|
57
|
+
console.warn('ELEVENLABS_API_KEY not set. ElevenLabs TTS will not work.');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!config.voiceId) {
|
|
61
|
+
console.warn('ElevenLabs voiceId not configured.');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.ready = true;
|
|
65
|
+
}
|
|
66
|
+
async speak(text) {
|
|
67
|
+
if (!this.apiKey || !this.config.voiceId) {
|
|
68
|
+
throw new Error('ElevenLabs not configured. Set ELEVENLABS_API_KEY and voiceId.');
|
|
69
|
+
}
|
|
70
|
+
const url = `${ELEVENLABS_API_URL}/text-to-speech/${this.config.voiceId}`;
|
|
71
|
+
const response = await axios_1.default.post(url, {
|
|
72
|
+
text,
|
|
73
|
+
model_id: this.config.modelId,
|
|
74
|
+
voice_settings: {
|
|
75
|
+
stability: 0.5,
|
|
76
|
+
similarity_boost: 0.75,
|
|
77
|
+
},
|
|
78
|
+
}, {
|
|
79
|
+
headers: {
|
|
80
|
+
Accept: 'audio/mpeg',
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
'xi-api-key': this.apiKey,
|
|
83
|
+
},
|
|
84
|
+
responseType: 'arraybuffer',
|
|
85
|
+
});
|
|
86
|
+
// Save to temporary file
|
|
87
|
+
const tempFile = path.join(os.tmpdir(), `tts-${Date.now()}.mp3`);
|
|
88
|
+
fs.writeFileSync(tempFile, Buffer.from(response.data));
|
|
89
|
+
// Play the audio file
|
|
90
|
+
await this.playAudio(tempFile);
|
|
91
|
+
// Cleanup
|
|
92
|
+
try {
|
|
93
|
+
fs.unlinkSync(tempFile);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Ignore cleanup errors
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
playAudio(filePath) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const player = process.platform === 'darwin' ? 'afplay' : 'ffplay';
|
|
102
|
+
const args = process.platform === 'darwin' ? [filePath] : ['-nodisp', '-autoexit', '-loglevel', 'quiet', filePath];
|
|
103
|
+
this.currentProcess = (0, child_process_1.spawn)(player, args);
|
|
104
|
+
this.currentProcess.on('close', (code) => {
|
|
105
|
+
this.currentProcess = null;
|
|
106
|
+
if (code === 0) {
|
|
107
|
+
resolve();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
reject(new Error(`Audio player exited with code ${code}`));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
this.currentProcess.on('error', (error) => {
|
|
114
|
+
this.currentProcess = null;
|
|
115
|
+
reject(error);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
stop() {
|
|
120
|
+
if (this.currentProcess) {
|
|
121
|
+
this.currentProcess.kill('SIGTERM');
|
|
122
|
+
this.currentProcess = null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
isReady() {
|
|
126
|
+
return this.ready;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.ElevenLabsProvider = ElevenLabsProvider;
|
|
130
|
+
// Get available voices from ElevenLabs
|
|
131
|
+
async function listVoices(apiKey) {
|
|
132
|
+
const response = await axios_1.default.get(`${ELEVENLABS_API_URL}/voices`, {
|
|
133
|
+
headers: {
|
|
134
|
+
'xi-api-key': apiKey,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
return response.data.voices.map((v) => ({
|
|
138
|
+
voice_id: v.voice_id,
|
|
139
|
+
name: v.name,
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=elevenlabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../../src/tts/providers/elevenlabs.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqHA,gCAWC;AAhID,kDAA0B;AAE1B,iDAAoD;AACpD,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AAOzB,MAAM,kBAAkB,GAAG,8BAA8B,CAAC;AAE1D,MAAa,kBAAkB;IAC7B,IAAI,GAAG,YAAY,CAAC;IACZ,MAAM,CAAmB;IACzB,MAAM,CAAqB;IAC3B,cAAc,GAAwB,IAAI,CAAC;IAC3C,KAAK,GAAG,KAAK,CAAC;IAEtB,YAAY,MAAwB;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAE7C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;YAC1E,OAAO;QACT,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,kBAAkB,mBAAmB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAE1E,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAC/B,GAAG,EACH;YACE,IAAI;YACJ,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;YAC7B,cAAc,EAAE;gBACd,SAAS,EAAE,GAAG;gBACd,gBAAgB,EAAE,IAAI;aACvB;SACF,EACD;YACE,OAAO,EAAE;gBACP,MAAM,EAAE,YAAY;gBACpB,cAAc,EAAE,kBAAkB;gBAClC,YAAY,EAAE,IAAI,CAAC,MAAM;aAC1B;YACD,YAAY,EAAE,aAAa;SAC5B,CACF,CAAC;QAEF,yBAAyB;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACjE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAEvD,sBAAsB;QACtB,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAE/B,UAAU;QACV,IAAI,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,QAAgB;QAChC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YACnE,MAAM,IAAI,GACR,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YAExG,IAAI,CAAC,cAAc,GAAG,IAAA,qBAAK,EAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAE1C,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACvC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC3B,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACf,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACxC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC3B,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AApGD,gDAoGC;AAED,uCAAuC;AAChC,KAAK,UAAU,UAAU,CAAC,MAAc;IAC7C,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,GAAG,CAAC,GAAG,kBAAkB,SAAS,EAAE;QAC/D,OAAO,EAAE;YACP,YAAY,EAAE,MAAM;SACrB;KACF,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAqC,EAAE,EAAE,CAAC,CAAC;QAC1E,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,CAAC,CAAC,IAAI;KACb,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TTSProvider } from '../index';
|
|
2
|
+
interface MacOSSayConfig {
|
|
3
|
+
voice: string;
|
|
4
|
+
rate: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class MacOSSayProvider implements TTSProvider {
|
|
7
|
+
name: string;
|
|
8
|
+
private config;
|
|
9
|
+
private currentProcess;
|
|
10
|
+
constructor(config: MacOSSayConfig);
|
|
11
|
+
speak(text: string): Promise<void>;
|
|
12
|
+
stop(): void;
|
|
13
|
+
isReady(): boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function listVoices(): Promise<string[]>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=macos-say.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macos-say.d.ts","sourceRoot":"","sources":["../../../src/tts/providers/macos-say.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAClD,IAAI,SAAe;IACnB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,cAAc,CAA6B;gBAEvC,MAAM,EAAE,cAAc;IAI5B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBxC,IAAI,IAAI,IAAI;IAOZ,OAAO,IAAI,OAAO;CAInB;AAGD,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBpD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MacOSSayProvider = void 0;
|
|
4
|
+
exports.listVoices = listVoices;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
class MacOSSayProvider {
|
|
7
|
+
name = 'macos-say';
|
|
8
|
+
config;
|
|
9
|
+
currentProcess = null;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
async speak(text) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
// Clean text for shell safety
|
|
16
|
+
const cleanText = text.replace(/"/g, '\\"');
|
|
17
|
+
const args = ['-v', this.config.voice, '-r', String(this.config.rate), cleanText];
|
|
18
|
+
this.currentProcess = (0, child_process_1.spawn)('say', args);
|
|
19
|
+
this.currentProcess.on('close', (code) => {
|
|
20
|
+
this.currentProcess = null;
|
|
21
|
+
if (code === 0) {
|
|
22
|
+
resolve();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
reject(new Error(`say command exited with code ${code}`));
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
this.currentProcess.on('error', (error) => {
|
|
29
|
+
this.currentProcess = null;
|
|
30
|
+
reject(error);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
stop() {
|
|
35
|
+
if (this.currentProcess) {
|
|
36
|
+
this.currentProcess.kill('SIGTERM');
|
|
37
|
+
this.currentProcess = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
isReady() {
|
|
41
|
+
// macOS say is always available on macOS
|
|
42
|
+
return process.platform === 'darwin';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.MacOSSayProvider = MacOSSayProvider;
|
|
46
|
+
// List available voices on macOS
|
|
47
|
+
async function listVoices() {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const proc = (0, child_process_1.spawn)('say', ['-v', '?']);
|
|
50
|
+
let output = '';
|
|
51
|
+
proc.stdout.on('data', (data) => {
|
|
52
|
+
output += data.toString();
|
|
53
|
+
});
|
|
54
|
+
proc.on('close', (code) => {
|
|
55
|
+
if (code === 0) {
|
|
56
|
+
const voices = output
|
|
57
|
+
.split('\n')
|
|
58
|
+
.filter((line) => line.trim())
|
|
59
|
+
.map((line) => {
|
|
60
|
+
const match = line.match(/^(\S+)/);
|
|
61
|
+
return match ? match[1] : '';
|
|
62
|
+
})
|
|
63
|
+
.filter((v) => v);
|
|
64
|
+
resolve(voices);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
reject(new Error('Failed to list voices'));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=macos-say.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macos-say.js","sourceRoot":"","sources":["../../../src/tts/providers/macos-say.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TTSProvider } from '../index';
|
|
2
|
+
interface OpenAITTSConfig {
|
|
3
|
+
model: 'tts-1' | 'tts-1-hd';
|
|
4
|
+
voice: 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer';
|
|
5
|
+
}
|
|
6
|
+
export declare class OpenAITTSProvider implements TTSProvider {
|
|
7
|
+
name: string;
|
|
8
|
+
private config;
|
|
9
|
+
private client;
|
|
10
|
+
private currentProcess;
|
|
11
|
+
private ready;
|
|
12
|
+
constructor(config: OpenAITTSConfig);
|
|
13
|
+
speak(text: string): Promise<void>;
|
|
14
|
+
private playAudio;
|
|
15
|
+
stop(): void;
|
|
16
|
+
isReady(): boolean;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/tts/providers/openai.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAMvC,UAAU,eAAe;IACvB,KAAK,EAAE,OAAO,GAAG,UAAU,CAAC;IAC5B,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACjE;AAED,qBAAa,iBAAkB,YAAW,WAAW;IACnD,IAAI,SAAgB;IACpB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,eAAe;IAc7B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BxC,OAAO,CAAC,SAAS;IAyBjB,IAAI,IAAI,IAAI;IAOZ,OAAO,IAAI,OAAO;CAGnB"}
|