claude-voice 1.3.6 → 1.3.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-voice",
3
- "version": "1.3.6",
3
+ "version": "1.3.7",
4
4
  "description": "Voice interface extension for Claude Code - TTS, STT, and wake word detection",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,6 +23,8 @@ const CONFIG_DIR = path.join(os.homedir(), '.claude-voice');
23
23
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
24
24
  const DEFAULT_CONFIG = path.join(__dirname, '..', 'config', 'default.json');
25
25
  const HOOKS_DIR = path.join(__dirname, '..', 'hooks');
26
+ const MODELS_DIR = path.join(CONFIG_DIR, 'models');
27
+ const VOICES_DIR = path.join(CONFIG_DIR, 'voices');
26
28
 
27
29
  console.log('\n╔════════════════════════════════════════════════════════════╗');
28
30
  console.log('║ Claude Voice Extension - Auto Setup ║');
@@ -89,16 +91,94 @@ try {
89
91
  }
90
92
 
91
93
  // 6. Install Piper TTS and download default voice
92
- const binPath = path.join(__dirname, '..', 'bin', 'claude-voice');
93
94
  console.log('\nStep 4/7: Installing Piper TTS engine...');
94
95
  console.log(' (First-time install may take 1-2 minutes)\n');
95
96
  try {
96
- execSync(`"${binPath}" voice download en_US-joe-medium`, {
97
- stdio: 'inherit',
98
- timeout: 300000 // 5 min timeout
99
- });
97
+ // Direct download without going through CLI
98
+ const voiceId = 'en_US-joe-medium';
99
+ const onnxPath = path.join(VOICES_DIR, `${voiceId}.onnx`);
100
+ const jsonPath = path.join(VOICES_DIR, `${voiceId}.onnx.json`);
101
+
102
+ if (fs.existsSync(onnxPath) && fs.existsSync(jsonPath)) {
103
+ console.log(` [✓] Voice already installed: ${voiceId}`);
104
+ } else {
105
+ // Create voices directory
106
+ if (!fs.existsSync(VOICES_DIR)) {
107
+ fs.mkdirSync(VOICES_DIR, { recursive: true });
108
+ }
109
+
110
+ // Get voice URLs from HuggingFace
111
+ const parts = voiceId.split('-');
112
+ const langCode = parts[0];
113
+ const lang = langCode.split('_')[0];
114
+ const voiceName = parts[1];
115
+ const quality = parts[2];
116
+ const baseUrl = 'https://huggingface.co/rhasspy/piper-voices/resolve/main';
117
+ const voicePath = `${lang}/${langCode}/${voiceName}/${quality}`;
118
+ const onnxUrl = `${baseUrl}/${voicePath}/${voiceId}.onnx`;
119
+ const jsonUrl = `${baseUrl}/${voicePath}/${voiceId}.onnx.json`;
120
+
121
+ console.log(` Voice: Joe (US English)`);
122
+ console.log(` [1/2] Downloading voice model (~50MB)...`);
123
+ execSync(`curl -L --progress-bar -o "${onnxPath}" "${onnxUrl}"`, { stdio: 'inherit' });
124
+
125
+ console.log(` [2/2] Downloading voice config...`);
126
+ execSync(`curl -sL -o "${jsonPath}" "${jsonUrl}"`, { stdio: 'inherit' });
127
+
128
+ console.log(` [✓] Voice installed: ${voiceId}`);
129
+ }
130
+
131
+ // Install Piper TTS via pip if needed
132
+ const PIPER_DIR = path.join(CONFIG_DIR, 'piper');
133
+ const PIPER_VENV = path.join(PIPER_DIR, 'venv');
134
+ const PIPER_BIN = path.join(PIPER_VENV, 'bin', 'piper');
135
+
136
+ if (!fs.existsSync(PIPER_BIN)) {
137
+ // Find Python 3.9-3.13
138
+ const pythonCandidates = [
139
+ '/opt/homebrew/bin/python3.12', '/opt/homebrew/bin/python3.11', '/opt/homebrew/bin/python3',
140
+ '/usr/local/bin/python3.12', '/usr/local/bin/python3.11', '/usr/local/bin/python3',
141
+ '/usr/bin/python3.12', '/usr/bin/python3.11', '/usr/bin/python3.10', '/usr/bin/python3.9', '/usr/bin/python3',
142
+ 'python3.12', 'python3.11', 'python3.10', 'python3'
143
+ ];
144
+
145
+ let python = null;
146
+ for (const py of pythonCandidates) {
147
+ try {
148
+ const version = execSync(`${py} --version 2>&1`, { encoding: 'utf-8' });
149
+ const match = version.match(/Python 3\.(\d+)/);
150
+ if (match) {
151
+ const minor = parseInt(match[1], 10);
152
+ if (minor >= 9 && minor <= 13) {
153
+ python = py;
154
+ break;
155
+ }
156
+ }
157
+ } catch {}
158
+ }
159
+
160
+ if (python) {
161
+ console.log(` [1/3] Found Python: ${python}`);
162
+ if (!fs.existsSync(PIPER_DIR)) {
163
+ fs.mkdirSync(PIPER_DIR, { recursive: true });
164
+ }
165
+ console.log(' [2/3] Creating Python virtual environment...');
166
+ execSync(`${python} -m venv "${PIPER_VENV}"`, { stdio: 'pipe' });
167
+ console.log(' [3/3] Installing piper-tts package...');
168
+ const pip = path.join(PIPER_VENV, 'bin', 'pip');
169
+ execSync(`"${pip}" install --quiet piper-tts`, { stdio: 'pipe' });
170
+ console.log(' [✓] Piper TTS installed successfully');
171
+ } else {
172
+ const installCmd = os.platform() === 'darwin'
173
+ ? 'brew install python@3.12'
174
+ : 'sudo apt install python3.12 python3.12-venv';
175
+ console.log(` [!] Python 3.9-3.13 not found. Install with: ${installCmd}`);
176
+ }
177
+ } else {
178
+ console.log(' [✓] Piper TTS already installed');
179
+ }
100
180
  } catch (err) {
101
- console.log(' [!] Could not install Piper voice.');
181
+ console.log(' [!] Could not install Piper voice:', err.message);
102
182
  console.log(' Run manually: claude-voice voice download en_US-joe-medium');
103
183
  }
104
184
 
@@ -106,12 +186,41 @@ try {
106
186
  console.log('\nStep 5/7: Downloading Whisper STT model...');
107
187
  console.log(' (This may take 2-3 minutes depending on connection)\n');
108
188
  try {
109
- execSync(`"${binPath}" model download whisper-tiny`, {
110
- stdio: 'inherit',
111
- timeout: 300000 // 5 min timeout
112
- });
189
+ // Direct download without going through CLI
190
+ const modelId = 'whisper-tiny';
191
+ const modelFolder = 'sherpa-onnx-whisper-tiny';
192
+ const modelUrl = 'https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-whisper-tiny.tar.bz2';
193
+ const modelPath = path.join(MODELS_DIR, modelFolder);
194
+
195
+ if (fs.existsSync(modelPath)) {
196
+ console.log(` [✓] Model already installed: ${modelId}`);
197
+ } else {
198
+ // Create models directory
199
+ if (!fs.existsSync(MODELS_DIR)) {
200
+ fs.mkdirSync(MODELS_DIR, { recursive: true });
201
+ }
202
+
203
+ const archivePath = path.join(MODELS_DIR, `${modelId}.tar.bz2`);
204
+
205
+ console.log(` Model: Whisper Tiny (75MB)`);
206
+ console.log(` [1/2] Downloading model...`);
207
+ execSync(`curl -L --progress-bar -o "${archivePath}" "${modelUrl}"`, {
208
+ stdio: 'inherit',
209
+ cwd: MODELS_DIR
210
+ });
211
+
212
+ console.log(' [2/2] Extracting model files...');
213
+ execSync(`tar -xjf "${archivePath}"`, {
214
+ stdio: 'pipe',
215
+ cwd: MODELS_DIR
216
+ });
217
+
218
+ // Cleanup archive
219
+ fs.unlinkSync(archivePath);
220
+ console.log(` [✓] Model installed: ${modelId}`);
221
+ }
113
222
  } catch (err) {
114
- console.log(' [!] Could not download STT model.');
223
+ console.log(' [!] Could not download STT model:', err.message);
115
224
  console.log(' Run manually: claude-voice model download whisper-tiny');
116
225
  }
117
226
 
@@ -119,12 +228,41 @@ try {
119
228
  console.log('\nStep 6/7: Downloading Sherpa-ONNX Wake Word model...');
120
229
  console.log(' (Sherpa-ONNX keyword spotting - ~19MB)\n');
121
230
  try {
122
- execSync(`"${binPath}" model download kws-zipformer-gigaspeech`, {
123
- stdio: 'inherit',
124
- timeout: 300000 // 5 min timeout
125
- });
231
+ // Direct download without going through CLI
232
+ const kwsModelId = 'kws-zipformer-gigaspeech';
233
+ const kwsModelFolder = 'sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01';
234
+ const kwsModelUrl = 'https://github.com/k2-fsa/sherpa-onnx/releases/download/kws-models/sherpa-onnx-kws-zipformer-gigaspeech-3.3M-2024-01-01.tar.bz2';
235
+ const kwsModelPath = path.join(MODELS_DIR, kwsModelFolder);
236
+
237
+ if (fs.existsSync(kwsModelPath)) {
238
+ console.log(` [✓] Model already installed: ${kwsModelId}`);
239
+ } else {
240
+ // Create models directory
241
+ if (!fs.existsSync(MODELS_DIR)) {
242
+ fs.mkdirSync(MODELS_DIR, { recursive: true });
243
+ }
244
+
245
+ const archivePath = path.join(MODELS_DIR, `${kwsModelId}.tar.bz2`);
246
+
247
+ console.log(` Model: Keyword Spotter English (19MB)`);
248
+ console.log(` [1/2] Downloading model...`);
249
+ execSync(`curl -L --progress-bar -o "${archivePath}" "${kwsModelUrl}"`, {
250
+ stdio: 'inherit',
251
+ cwd: MODELS_DIR
252
+ });
253
+
254
+ console.log(' [2/2] Extracting model files...');
255
+ execSync(`tar -xjf "${archivePath}"`, {
256
+ stdio: 'pipe',
257
+ cwd: MODELS_DIR
258
+ });
259
+
260
+ // Cleanup archive
261
+ fs.unlinkSync(archivePath);
262
+ console.log(` [✓] Model installed: ${kwsModelId}`);
263
+ }
126
264
  } catch (err) {
127
- console.log(' [!] Could not download wake word model.');
265
+ console.log(' [!] Could not download wake word model:', err.message);
128
266
  console.log(' Run manually: claude-voice model download kws-zipformer-gigaspeech');
129
267
  }
130
268