@drakulavich/kesha-voice-kit 1.4.3 → 1.5.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/NOTICES.md CHANGED
@@ -27,19 +27,13 @@ Pinned to the `v6.2.1` tag.
27
27
 
28
28
  Text-to-speech (English). Apache 2.0. ONNX export by [onnx-community/Kokoro-82M-v1.0-ONNX](https://huggingface.co/onnx-community/Kokoro-82M-v1.0-ONNX).
29
29
 
30
- ### Piper voices (Russian: `ru-denis`)
30
+ ### Vosk-TTS (Russian, multi-speaker)
31
31
 
32
- Text-to-speech (multilingual, Piper VITS). MIT. Voice packs from [rhasspy/piper-voices](https://huggingface.co/rhasspy/piper-voices).
32
+ Text-to-speech (Russian, 5 baked-in speakers). Apache 2.0. Model: [alphacep/vosk-tts](https://huggingface.co/alphacep/vosk-tts) (`vosk-model-tts-ru-0.9-multi`). Integrated via [`vosk-tts-rs`](https://github.com/alphacep/vosk-tts-rs).
33
33
 
34
- ### CharsiuG2P ByT5-tiny (ONNX export)
34
+ ### misaki-rs (English G2P)
35
35
 
36
- Grapheme-to-phoneme conversion for Kokoro and Piper pipelines (#123).
37
-
38
- **License: CC-BY 4.0** (declared on the ONNX-export repo). Attribution required.
39
-
40
- - ONNX export: [klebster/g2p_multilingual_byT5_tiny_onnx](https://huggingface.co/klebster/g2p_multilingual_byT5_tiny_onnx) by Kleber Noel — CC-BY 4.0.
41
- - Base checkpoint: [charsiu/g2p_multilingual_byT5_tiny_16_layers_100](https://huggingface.co/charsiu/g2p_multilingual_byT5_tiny_16_layers_100) — **no explicit license declared on HuggingFace**; usage here follows the CC-BY 4.0 declared by the downstream export and the paper's terms.
42
- - Paper: Zhu, J., Zhang, C., & Jurgens, D. (2022). "ByT5 model for massively multilingual grapheme-to-phoneme conversion." [arXiv:2204.03067](https://arxiv.org/abs/2204.03067) · Interspeech 2022.
36
+ Embedded grapheme-to-phoneme for English (Kokoro pipeline, #207). MIT. Source: [`misaki-rs`](https://github.com/MicheleYin/misaki-rs).
43
37
 
44
38
  ## System libraries linked by the engine binary
45
39
 
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/SKILL.md CHANGED
@@ -1,15 +1,14 @@
1
1
  ---
2
2
  name: kesha-voice-kit
3
- description: Local multilingual voice toolkit — speech-to-text (STT), text-to-speech (TTS), and language detection. Runs entirely offline on Apple Silicon, Linux, and Windows. No API keys, no cloud. NVIDIA Parakeet TDT for STT across 25 European languages, Kokoro-82M + Piper VITS for TTS, plus macOS AVSpeechSynthesizer for ~180 system voices with zero install.
3
+ description: Local multilingual voice toolkit — speech-to-text (STT), text-to-speech (TTS), and language detection. Runs entirely offline on Apple Silicon, Linux, and Windows. No API keys, no cloud. NVIDIA Parakeet TDT for STT across 25 European languages, Kokoro-82M + Vosk-TTS for TTS, plus macOS AVSpeechSynthesizer for ~180 system voices with zero install.
4
4
  emoji: 🎙️
5
5
 
6
6
  requires:
7
7
  bins: [kesha]
8
8
 
9
9
  install:
10
- - kind: npm
11
- packages: [@drakulavich/kesha-voice-kit]
12
- flags: [--global]
10
+ - kind: bash
11
+ cmd: bun add -g "@drakulavich/kesha-voice-kit"
13
12
  - kind: bash
14
13
  cmd: kesha install
15
14
  ---
@@ -23,7 +22,7 @@ Local voice toolkit: transcribe voice messages to text, synthesize speech, detec
23
22
  ## When to use
24
23
 
25
24
  - **Voice memo arrived** (Telegram, WhatsApp, Slack, Signal .ogg/.opus/.m4a): transcribe with `kesha --json <path>` and branch on the detected language.
26
- - **Need to reply with audio**: synthesize with `kesha say "<text>" > reply.wav`. Auto-routes by detected language (Kokoro-82M for English, Piper for Russian). For other languages and ~180 more voices use `--voice macos-*` on macOS (zero model download).
25
+ - **Need to reply with audio**: synthesize with `kesha say "<text>" > reply.wav`. Auto-routes by detected language (Kokoro-82M for English, Vosk-TTS for Russian). For other languages and ~180 more voices use `--voice macos-*` on macOS (zero model download).
27
26
  - **Need to detect what language a file is in** before choosing a pipeline: `kesha --json audio.ogg` returns both audio-based and text-based language detection with confidence scores.
28
27
 
29
28
  ## STT: transcribe audio
@@ -57,9 +56,9 @@ Use `lang` (or the more detailed `audioLanguage`/`textLanguage`) to decide how t
57
56
 
58
57
  ```bash
59
58
  kesha say "Hello, world" > hello.wav # auto-routes en → Kokoro-82M
60
- kesha say "Привет, мир" > privet.wav # auto-routes ru → Piper
59
+ kesha say "Привет, мир" > privet.wav # auto-routes ru → Vosk-TTS
61
60
  kesha say --voice macos-de-DE "Guten Tag" > de.wav # any macOS system voice — German, French, Italian, ...
62
- kesha say --list-voices # Kokoro + Piper + ~180 macos-* voices
61
+ kesha say --list-voices # Kokoro + Vosk-TTS + ~180 macos-* voices
63
62
  ```
64
63
 
65
64
  Output: WAV mono float32. `--out <path>` writes to a file instead of stdout.
@@ -71,18 +70,18 @@ Output: WAV mono float32. `--out <path>` writes to a file instead of stdout.
71
70
  ## Install
72
71
 
73
72
  ```bash
74
- bun add --global @drakulavich/kesha-voice-kit # or: npm i -g @drakulavich/kesha-voice-kit
73
+ bun add -g @drakulavich/kesha-voice-kit # global CLI install
75
74
  kesha install # downloads engine (~350 MB)
76
- kesha install --tts # adds Kokoro + Piper RU + ONNX G2P (~490 MB more, for TTS)
75
+ kesha install --tts # adds Kokoro + Vosk-TTS RU (~990 MB more, for TTS)
77
76
  ```
78
77
 
79
- No system deps — G2P runs as ONNX alongside Kokoro/Piper. `macos-*` voices need no install either — they use voices already on the Mac.
78
+ No system deps — English G2P is embedded (`misaki-rs`); Russian G2P is bundled inside Vosk-TTS. `macos-*` voices need no install either — they use voices already on the Mac.
80
79
 
81
80
  ## Supported languages
82
81
 
83
82
  **Speech-to-text (25):** Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Italian, Latvian, Lithuanian, Maltese, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish, Ukrainian.
84
83
 
85
- **Text-to-speech:** English (Kokoro-82M, ~70 voices), Russian (Piper `ru-denis`), plus any macOS system voice via `--voice macos-*`.
84
+ **Text-to-speech:** English (Kokoro-82M, ~70 voices), Russian (Vosk-TTS, 5 baked-in speakers — default `ru-vosk-m02`), plus any macOS system voice via `--voice macos-*`.
86
85
 
87
86
  ## Performance
88
87
 
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.5.0",
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",
@@ -30,7 +30,7 @@
30
30
  ]
31
31
  },
32
32
  "keshaEngine": {
33
- "version": "1.4.1"
33
+ "version": "1.5.0"
34
34
  },
35
35
  "scripts": {
36
36
  "test": "bun test",
@@ -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
  }