@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 +7 -6
- package/package.json +2 -2
- package/src/cli/install.ts +1 -1
- package/src/cli/say.ts +11 -3
- package/src/engine-install.ts +10 -3
- package/src/say.ts +1 -1
- package/src/status.ts +9 -10
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) +
|
|
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
|
|
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 # ~
|
|
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
|
|
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 /
|
|
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
|
|
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.
|
|
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 +
|
|
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",
|
package/src/cli/install.ts
CHANGED
|
@@ -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 +
|
|
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-
|
|
22
|
+
return "en-am_michael";
|
|
15
23
|
case "ru":
|
|
16
|
-
return "ru-
|
|
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-
|
|
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" },
|
package/src/engine-install.ts
CHANGED
|
@@ -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")
|
|
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
|
-
*
|
|
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 +
|
|
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-
|
|
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 (
|
|
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
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
/*
|
|
184
|
+
/* Vosk not installed */
|
|
186
185
|
}
|
|
187
186
|
return voices.sort();
|
|
188
187
|
}
|