@drakulavich/kesha-voice-kit 1.4.3 → 1.4.4

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 CHANGED
@@ -14,7 +14,7 @@
14
14
  <p align="center"><b>Open-source voice toolkit.</b> Optimized for Apple Silicon (CoreML), works on any platform (ONNX fallback).<br>A collection of small, fast, open-source audio models — packaged as CLI tools and an <a href="https://github.com/openclaw/openclaw">OpenClaw</a> skill for LLM agents.</p>
15
15
 
16
16
  - **Speech-to-text** — 25 languages, ~15x faster than Whisper on Apple Silicon, ~2.5x on CPU
17
- - **Text-to-speech** — Kokoro (EN) + Piper (RU) + macOS system voices, SSML preview
17
+ - **Text-to-speech** — Kokoro (EN) + Vosk-TTS (RU) + macOS system voices, SSML preview
18
18
  - **Rust engine** — single 20MB binary, no ffmpeg, no Python, no native Node addons
19
19
  - **OpenClaw-ready** — plug into your LLM agent as a voice processing skill
20
20
 
@@ -61,12 +61,12 @@ For long / silence-heavy audio, use `--vad` (auto-on past 120 s). Details: [docs
61
61
 
62
62
  ## Text-to-speech
63
63
 
64
- Kesha speaks back via Kokoro-82M (English) and Piper (Russian) — voice auto-picks from the text's language:
64
+ Kesha speaks back via Kokoro-82M (English) and Vosk-TTS (Russian) — voice auto-picks from the text's language:
65
65
 
66
66
  ```bash
67
- kesha install --tts # ~490MB (Kokoro + Piper RU + ONNX G2P, opt-in)
67
+ kesha install --tts # ~990MB (Kokoro + Vosk-TTS RU, opt-in)
68
68
  kesha say "Hello, world" > hello.wav
69
- kesha say "Привет, мир" > privet.wav # auto-routes to ru-denis
69
+ kesha say "Привет, мир" > privet.wav # auto-routes (Milena on darwin, ru-vosk-m02 elsewhere)
70
70
  ```
71
71
 
72
72
  macOS system voices, SSML, voice listing, and the full voice catalogue: [docs/tts.md](docs/tts.md).
@@ -89,7 +89,7 @@ See [BENCHMARK.md](BENCHMARK.md) for the full per-file breakdown (Russian + Engl
89
89
  | SpeechBrain ECAPA-TDNN | Audio language detection | ~86MB | [HuggingFace](https://huggingface.co/speechbrain/lang-id-voxlingua107-ecapa) |
90
90
  | Apple NLLanguageRecognizer | Text language detection | built-in | macOS system framework |
91
91
  | Silero VAD v5 (opt-in) | Voice activity detection | ~2.3MB | [snakers4/silero-vad](https://github.com/snakers4/silero-vad) |
92
- | Kokoro-82M / Piper (opt-in) | Text-to-speech | ~490MB | [Kokoro](https://huggingface.co/hexgrad/Kokoro-82M) · [Piper](https://github.com/rhasspy/piper) |
92
+ | Kokoro-82M / Vosk-TTS (opt-in) | Text-to-speech | ~990MB | [Kokoro](https://huggingface.co/hexgrad/Kokoro-82M) · [Vosk-TTS](https://github.com/alphacep/vosk-tts) |
93
93
 
94
94
  All models run through `kesha-engine` — a Rust binary using [FluidAudio](https://github.com/FluidInference/FluidAudio) (CoreML) on Apple Silicon and [ort](https://github.com/pykeio/ort) (ONNX Runtime) on other platforms.
95
95
 
@@ -117,7 +117,8 @@ const text = await transcribe("audio.ogg"); // transcribe
117
117
  ## Requirements
118
118
 
119
119
  - [Bun](https://bun.sh) >= 1.3
120
- - macOS arm64, Linux x64, or Windows x64
120
+ - macOS arm64 or Linux x64
121
+ - Windows x64 temporarily unsupported in v1.5.0 — Vosk-TTS native deps trigger MSVC link conflicts. Tracked in [#216](https://github.com/drakulavich/kesha-voice-kit/issues/216).
121
122
 
122
123
  ## Contributing
123
124
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@drakulavich/kesha-voice-kit",
3
- "version": "1.4.3",
4
- "description": "Open-source voice toolkit. Speech-to-text (25 langs, ~19x faster than Whisper on Apple Silicon, ONNX fallback on CPU), text-to-speech (Kokoro + Piper + ~180 macOS system voices, SSML), voice-activity detection, language detection (107 langs). Rust engine, OpenClaw skill.",
3
+ "version": "1.4.4",
4
+ "description": "Open-source voice toolkit. Speech-to-text (25 langs, ~19x faster than Whisper on Apple Silicon, ONNX fallback on CPU), text-to-speech (Kokoro + Vosk-TTS + ~180 macOS system voices, SSML), voice-activity detection, language detection (107 langs). Rust engine, OpenClaw skill.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "kesha": "bin/kesha.js",
@@ -92,7 +92,7 @@ export const installCommand = defineCommand({
92
92
  },
93
93
  tts: {
94
94
  type: "boolean",
95
- description: "Also install TTS models (Kokoro EN + Piper RU + ONNX G2P, ~490MB)",
95
+ description: "Also install TTS models (Kokoro EN + Vosk-TTS RU, ~990MB)",
96
96
  default: false,
97
97
  },
98
98
  vad: {
package/src/cli/say.ts CHANGED
@@ -3,17 +3,25 @@ import { detectTextLanguageEngine, getEngineBinPath } from "../engine";
3
3
  import { log } from "../log";
4
4
  import { say, SayError } from "../say";
5
5
 
6
+ /**
7
+ * Darwin defaults to AVSpeech Milena — zero install, no model download required.
8
+ * Linux/Windows fall through to Vosk-TTS `ru-vosk-m02` (male, per CLAUDE.md
9
+ * "DEFAULT TTS VOICES MUST BE MALE"; replaces Piper-ruslan as of #213).
10
+ */
11
+ const RU_DARWIN_FALLBACK_VOICE = "macos-com.apple.voice.compact.ru-RU.Milena";
12
+
6
13
  /** Map a detected language code to a default voice id. Unknown / low-confidence → undefined. */
7
14
  export function pickVoiceForLang(
8
15
  code: string | undefined,
9
16
  confidence: number,
17
+ platform: NodeJS.Platform = process.platform,
10
18
  ): string | undefined {
11
19
  if (!code || confidence < 0.5) return undefined;
12
20
  switch (code) {
13
21
  case "en":
14
- return "en-af_heart";
22
+ return "en-am_michael";
15
23
  case "ru":
16
- return "ru-denis";
24
+ return platform === "darwin" ? RU_DARWIN_FALLBACK_VOICE : "ru-vosk-m02";
17
25
  default:
18
26
  return undefined;
19
27
  }
@@ -50,7 +58,7 @@ export const sayCommand = defineCommand({
50
58
  },
51
59
  args: {
52
60
  text: { type: "positional", required: false, description: "Text to speak (stdin if omitted)" },
53
- voice: { type: "string", description: "Voice id, e.g. en-af_heart" },
61
+ voice: { type: "string", description: "Voice id, e.g. en-am_michael" },
54
62
  lang: { type: "string", description: "BCP 47 language code (default en-us)" },
55
63
  out: { type: "string", description: "Write WAV to file instead of stdout" },
56
64
  rate: { type: "string", description: "Speaking rate 0.5–2.0", default: "1.0" },
@@ -36,7 +36,14 @@ function getEngineBinaryName(): string {
36
36
 
37
37
  if (platform === "darwin" && arch === "arm64") return "kesha-engine-darwin-arm64";
38
38
  if (platform === "linux" && arch === "x64") return "kesha-engine-linux-x64";
39
- if (platform === "win32" && arch === "x64") return "kesha-engine-windows-x64.exe";
39
+ if (platform === "win32" && arch === "x64") {
40
+ throw new Error(
41
+ "Windows x64 is temporarily unsupported in v1.5.0 — the Vosk-TTS engine has " +
42
+ "native deps that trip MSVC at link time. Tracked at " +
43
+ "https://github.com/drakulavich/kesha-voice-kit/issues/216. " +
44
+ "Use v1.4.x as a workaround until the fix lands.",
45
+ );
46
+ }
40
47
 
41
48
  throw new Error(`Unsupported platform: ${platform} ${arch}`);
42
49
  }
@@ -51,7 +58,7 @@ function getEngineBinaryName(): string {
51
58
  * Best-effort: 404s (older engine versions predate the sidecar) and
52
59
  * network errors log a warning and return — macos-* voices simply won't
53
60
  * be available, which is a graceful degradation. The user keeps Kokoro +
54
- * Piper.
61
+ * Vosk-TTS.
55
62
  */
56
63
  async function downloadAVSpeechSidecar(binPath: string, engineVersion: string): Promise<void> {
57
64
  if (process.platform !== "darwin" || process.arch !== "arm64") return;
@@ -95,7 +102,7 @@ async function downloadAVSpeechSidecar(binPath: string, engineVersion: string):
95
102
  }
96
103
 
97
104
  export interface InstallOptions {
98
- /** Also install Kokoro + Piper + ONNX G2P TTS models. */
105
+ /** Also install Kokoro + Vosk-TTS models. */
99
106
  tts?: boolean;
100
107
  /** Also install Silero VAD model for long-audio preprocessing. */
101
108
  vad?: boolean;
package/src/say.ts CHANGED
@@ -8,7 +8,7 @@ export interface SayOptions {
8
8
  * arg) handles stdin separately before invoking `say()`.
9
9
  */
10
10
  text?: string;
11
- /** Voice id, e.g. `en-af_heart`. Defaults to engine default. */
11
+ /** Voice id, e.g. `en-am_michael`. Defaults to engine default. */
12
12
  voice?: string;
13
13
  /** Override the voice's default BCP 47 language code (e.g. `en-us`, `ru`). */
14
14
  lang?: string;
package/src/status.ts CHANGED
@@ -104,8 +104,7 @@ function showDiskUsage(binPath: string): void {
104
104
  { label: "Language ID", path: join(cache, "models/lang-id-ecapa") },
105
105
  { label: "VAD (Silero)", path: join(cache, "models/silero-vad") },
106
106
  { label: "TTS (Kokoro)", path: join(cache, "models/kokoro-82m") },
107
- { label: "TTS (Piper)", path: join(cache, "models/piper-ru") },
108
- { label: "TTS (G2P)", path: join(cache, "models/g2p") },
107
+ { label: "TTS (Vosk)", path: join(cache, "models/vosk-ru") },
109
108
  ];
110
109
 
111
110
  const rows: Array<{ label: string; size: number }> = [];
@@ -173,16 +172,16 @@ function listInstalledVoices(): string[] {
173
172
  /* Kokoro not installed */
174
173
  }
175
174
  try {
176
- // Piper RU files follow `ru_RU-<name>-<quality>.onnx` — report just `<name>`.
177
- const piper = readdirSync(join(cache, "models", "piper-ru"));
178
- for (const f of piper) {
179
- if (!f.endsWith(".onnx")) continue;
180
- const stem = f.replace(/\.onnx$/, "");
181
- const name = stem.replace(/^ru_RU-/, "").split("-")[0];
182
- if (name) voices.push(`ru-${name}`);
175
+ // Vosk-TTS Russian is a single multi-speaker model. Mirror the Rust-side
176
+ // gate (models::is_vosk_ru_cached) — checking model.onnx + bert/model.onnx
177
+ // avoids advertising voices that would fail to load on a partial install.
178
+ statSync(join(cache, "models", "vosk-ru", "model.onnx"));
179
+ statSync(join(cache, "models", "vosk-ru", "bert", "model.onnx"));
180
+ for (const id of ["f01", "f02", "f03", "m01", "m02"]) {
181
+ voices.push(`ru-vosk-${id}`);
183
182
  }
184
183
  } catch {
185
- /* Piper not installed */
184
+ /* Vosk not installed */
186
185
  }
187
186
  return voices.sort();
188
187
  }