@drakulavich/kesha-voice-kit 1.27.0 → 1.28.0-alpha.1
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 +48 -26
- package/SKILL.md +1 -1
- package/completions/kesha.bash +3 -3
- package/completions/kesha.fish +5 -3
- package/completions/kesha.zsh +7 -4
- package/man/kesha.1 +9 -3
- package/model-plan.json +6 -6
- package/openclaw-plugin.cjs +20 -59
- package/package.json +8 -4
- package/src/asset-modules.d.ts +20 -0
- package/src/cache-layout.ts +44 -0
- package/src/cli/completions.ts +10 -7
- package/src/cli/dispatch.ts +21 -1
- package/src/cli/init.ts +2 -11
- package/src/cli/install.ts +1 -2
- package/src/cli/main.ts +23 -20
- package/src/cli/manpage.ts +4 -3
- package/src/cli/record.ts +38 -11
- package/src/cli/say.ts +16 -29
- package/src/diagnostic-log.ts +2 -1
- package/src/doctor.ts +95 -85
- package/src/engine-health.ts +50 -0
- package/src/engine-install.ts +110 -76
- package/src/engine-targets.ts +19 -3
- package/src/engine.ts +190 -17
- package/src/error-codes.ts +2 -2
- package/src/fluid-asr-cache.ts +24 -30
- package/src/fluid-roots.ts +159 -0
- package/src/format.ts +3 -2
- package/src/install-plan.ts +23 -25
- package/src/kokoro-ane.ts +92 -0
- package/src/lib.ts +1 -1
- package/src/log.ts +3 -1
- package/src/mcp/tools.ts +9 -2
- package/src/mcp/voices.ts +19 -10
- package/src/progress.ts +15 -11
- package/src/star.ts +64 -36
- package/src/stats.ts +1 -1
- package/src/status.ts +66 -72
- package/src/suggest-command.ts +2 -2
- package/src/synth.ts +54 -3
- package/src/toon.ts +9 -5
- package/src/transcribe.ts +16 -1
- package/src/voice-routing.ts +32 -3
- package/tsconfig.json +7 -0
- package/src/fluid-kokoro-cache.ts +0 -47
package/README.md
CHANGED
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
<a href="https://bun.sh"><img src="https://img.shields.io/badge/runtime-Bun-f9f1e1?logo=bun" alt="Bun"></a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
|
-
<p align="center"><b>Give your local tools and LLM agents a voice.</b><br>Fast speech-to-text, text-to-speech, voice-activity detection, and language detection in one local-first CLI
|
|
14
|
+
<p align="center"><b>Give your local tools and LLM agents a voice.</b><br>Fast speech-to-text, text-to-speech, voice-activity detection, and language detection in one local-first CLI — CoreML on Apple Silicon, ONNX on Linux and Windows.</p>
|
|
15
15
|
|
|
16
16
|
- **Transcribe locally** — [25 languages](docs/languages.md#speech-to-text-25), up to ~19x faster than Whisper on Apple Silicon, ~2.5x on CPU
|
|
17
17
|
- **Speak back** — text-to-speech in [9 languages](docs/languages.md#text-to-speech)
|
|
18
18
|
- **Plug into agents** — ship voice workflows as CLI commands, an MCP server, an <a href="docs/openclaw.md">OpenClaw</a> skill, or a <a href="docs/hermes.md">Hermes</a> agent
|
|
19
|
-
- **Small Rust engine** — single ~
|
|
19
|
+
- **Small Rust engine** — single ~65MB binary, no ffmpeg, no Python, no native Node addons
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
22
22
|
<img src="https://github.com/drakulavich/kesha-voice-kit/raw/main/demo.gif" alt="kesha demo — English + Russian transcription with automatic language detection" width="800">
|
|
@@ -24,30 +24,46 @@
|
|
|
24
24
|
|
|
25
25
|
## Quick Start
|
|
26
26
|
|
|
27
|
-
Runtime: **[Bun](https://bun.sh)** >= 1.3.0
|
|
27
|
+
Runtime: **[Bun](https://bun.sh)** >= 1.3.0.
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
# 1. Install Bun (skip if you have it)
|
|
31
|
-
curl -fsSL https://bun.sh/install | bash # or: brew install oven-sh/bun/bun
|
|
32
|
-
|
|
33
|
-
# if `bun --version` fails, reload PATH: exec $SHELL -l
|
|
30
|
+
# 1. Install Bun (skip if you have it)
|
|
31
|
+
curl -fsSL https://bun.sh/install | bash # macOS/Linux — or: brew install oven-sh/bun/bun
|
|
32
|
+
powershell -c "irm bun.sh/install.ps1 | iex" # Windows
|
|
34
33
|
|
|
35
|
-
# 2. Install Kesha
|
|
34
|
+
# 2. Install Kesha
|
|
36
35
|
bun add -g @drakulavich/kesha-voice-kit
|
|
37
36
|
kesha --version # confirms `kesha` resolved on PATH
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
kesha audio.ogg # transcript to stdout
|
|
37
|
+
|
|
38
|
+
# 3. Download the engine and models — pick one path
|
|
39
|
+
kesha init # guided: backend, languages, TTS voices
|
|
40
|
+
kesha install --plan && kesha install # manual: preview the sizes, then download
|
|
41
|
+
|
|
42
|
+
# 4. Transcribe
|
|
43
|
+
kesha audio.ogg # transcript to stdout
|
|
46
44
|
```
|
|
47
45
|
|
|
48
|
-
|
|
46
|
+
`kesha install` pulls ~2.5 GB on Linux/Windows and ~0.6 GB on Apple Silicon, whose CoreML engine reads a smaller model set. It is always explicit — nothing downloads behind your back — and the model step has no progress bar, so expect a few quiet minutes. If `bun --version` fails right after step 1, reload your PATH: `exec $SHELL -l`.
|
|
47
|
+
|
|
48
|
+
Prefer Homebrew or Docker? See [Other install methods](#other-install-methods).
|
|
49
49
|
Air-gapped or behind a corporate mirror? See [docs/model-mirror.md](docs/model-mirror.md).
|
|
50
50
|
|
|
51
|
+
### Platform support
|
|
52
|
+
|
|
53
|
+
All three targets transcribe, detect the spoken language, run VAD, and speak. The macOS-only rows need Apple frameworks — they are not a missing port. Windows is a tested path rather than a published binary nobody ran: CI does a cold `kesha install` on `windows-latest`, transcribes a fixture, and round-trips a synthesis ([#216](https://github.com/drakulavich/kesha-voice-kit/issues/216), [#667](https://github.com/drakulavich/kesha-voice-kit/pull/667)).
|
|
54
|
+
|
|
55
|
+
| | macOS arm64 | Linux x64 | Windows x64 |
|
|
56
|
+
|---|:---:|:---:|:---:|
|
|
57
|
+
| Transcribe · audio language ID · [VAD](docs/vad.md) | CoreML / ANE | ONNX CPU | ONNX CPU |
|
|
58
|
+
| TTS — `en` `ru` `es` `fr` `it` `pt` | ✅ | ✅ | ✅ |
|
|
59
|
+
| TTS — `hi` `ja` `zh` and macOS system voices | ✅ | — | — |
|
|
60
|
+
| Mic capture and live dictation (`kesha record`) | ✅ | — | — |
|
|
61
|
+
| Speaker diarization (`--speakers`) | ✅ | — | — |
|
|
62
|
+
| Word-level timestamps (`words` in `--json`) | ✅ | ✅ | ✅ |
|
|
63
|
+
| Voice auto-routing from the text's language | ✅ | pass `--lang` | pass `--lang` |
|
|
64
|
+
|
|
65
|
+
Intel Macs get no published engine binary. Full matrix with maturity labels: [docs/product-positioning.md](docs/product-positioning.md#platform-matrix).
|
|
66
|
+
|
|
51
67
|
## Speech-to-text
|
|
52
68
|
|
|
53
69
|
```bash
|
|
@@ -55,6 +71,7 @@ kesha audio.ogg # transcribe (plain text)
|
|
|
55
71
|
kesha --format transcript audio.ogg # text + language/confidence
|
|
56
72
|
kesha --format json audio.ogg # full JSON with lang fields
|
|
57
73
|
kesha --json --timestamps audio.ogg # JSON with timestamped segments
|
|
74
|
+
kesha --itn audio.ogg # spelled-out numbers -> digits
|
|
58
75
|
kesha --toon audio.ogg # compact LLM-friendly TOON
|
|
59
76
|
kesha status # show installed backend info
|
|
60
77
|
kesha status --disk # + recursive cache disk usage
|
|
@@ -73,18 +90,22 @@ $ kesha freedom.ogg tahiti.ogg
|
|
|
73
90
|
```
|
|
74
91
|
|
|
75
92
|
- **Record from the mic (macOS):** `kesha record --out hello.wav` writes microphone audio to a WAV file (`kesha hello.wav` transcribes it). macOS prompts for microphone access on first use — grant it under System Settings → Privacy & Security → Microphone if it was denied. On Linux/Windows or headless boxes, pass any existing audio file straight to `kesha` instead.
|
|
93
|
+
- **Dictate straight to text (darwin-arm64):** `kesha record --live` transcribes the mic as it captures and prints the transcript to stdout — no WAV in between, so it pipes (`kesha record --live | pbcopy`). Progress goes to stderr. Other platforms keep the two-step `record --out` + transcribe flow. An interruption is recoverable: Ctrl-C (or SIGTERM) stops the session, still prints what you dictated, and exits 130/143, and the audio is spilled to a recovery WAV under `~/.cache/kesha/recordings/` — named on stderr when the session starts, deleted once the transcript has actually been delivered, kept if anything — a signal, a crash, a closed terminal, a dead pipe — got in the way first ([#962](https://github.com/drakulavich/kesha-voice-kit/issues/962)).
|
|
76
94
|
- **Long / silence-heavy audio:** install VAD (`kesha install --vad`); Kesha auto-uses it past 120 s. Without VAD, long audio falls back to fixed ASR chunks. See [docs/vad.md](docs/vad.md).
|
|
77
95
|
- **Speaker diarization** (darwin-arm64): `kesha install --diarize` (which installs VAD too), then `kesha --json --speakers meeting.m4a` stamps each segment with a `speaker` id. `--speakers` engages VAD windowing itself at any duration, so it cannot be combined with `--no-vad`. Linux/Windows return a clear "darwin-arm64 only" error ([#199](https://github.com/drakulavich/kesha-voice-kit/issues/199)).
|
|
96
|
+
- **Word-level timestamps** (every platform): `kesha --json --timestamps audio.ogg` adds a `words` array to each segment — `{ "word": "email", "start": 0.72, "end": 1.12 }` — on the same file-relative clock as the segment, so a word always lies inside the segment carrying it. Read them off the decoder's own frame grid, so: times are quantised to 0.08 s, consecutive spans may overlap (each `end` is a per-word duration prediction, not the next word's `start`), `end >= start` rather than strictly greater, and punctuation stays attached to its word. The key is simply absent where a segment has none — any segment `--itn` rewrote, for one — so check the `transcribe.words` capability rather than expecting an empty array ([#720](https://github.com/drakulavich/kesha-voice-kit/issues/720)).
|
|
97
|
+
- **Written-form numbers:** `--itn` rewrites what the model spells out — `"two hundred thirty two"` → `"232"`, `"five dollars and fifty cents"` → `"$5.50"`. Opt-in, every platform, timestamps untouched. English-only in practice; Russian and the rest pass through unchanged. Spoken punctuation names stay words (`"dot"`, `"comma"`, `"the period of growth"`) because Kesha transcribes speech rather than dictation — so `"example dot com"` keeps its words too ([#822](https://github.com/drakulavich/kesha-voice-kit/issues/822)).
|
|
78
98
|
|
|
79
99
|
## Text-to-speech
|
|
80
100
|
|
|
81
|
-
Kesha speaks back in [9 languages](docs/languages.md#text-to-speech)
|
|
101
|
+
Kesha speaks back in [9 languages](docs/languages.md#text-to-speech). On macOS it picks the voice from the text's own language; on Linux and Windows text detection needs Apple frameworks, so state the language with `--lang <code>` (or the voice with `--voice <id>`) — otherwise the engine default speaks.
|
|
82
102
|
|
|
83
103
|
```bash
|
|
84
104
|
kesha install --tts # English voices; sizes differ per platform — preview: kesha install --plan
|
|
85
105
|
kesha install --tts en ru # + Russian (+~890 MB, Vosk)
|
|
86
106
|
kesha say "Hello, world" > hello.wav
|
|
87
|
-
kesha say "Привет, мир" > privet.wav # auto-routes by language
|
|
107
|
+
kesha say "Привет, мир" > privet.wav # auto-routes by language (macOS)
|
|
108
|
+
kesha say --lang ru "Привет, мир" > privet.wav # explicit — the Linux/Windows path
|
|
88
109
|
kesha say --voice ru-vosk-m02 "Голос в текст." > ru.wav
|
|
89
110
|
```
|
|
90
111
|
|
|
@@ -100,7 +121,7 @@ kesha say "Hello" --format flac --out hi.flac # FLAC — lossless, plays in
|
|
|
100
121
|
|
|
101
122
|
## Languages
|
|
102
123
|
|
|
103
|
-
**Speech-to-text** spans 25 languages and **text-to-speech**
|
|
124
|
+
**Speech-to-text** spans 25 languages and **text-to-speech** 9 — full tables with codes, flags, and per-platform availability in **[docs/languages.md](docs/languages.md)**. Audio language detection identifies [107 languages](https://huggingface.co/speechbrain/lang-id-voxlingua107-ecapa).
|
|
104
125
|
|
|
105
126
|
## Performance
|
|
106
127
|
|
|
@@ -110,16 +131,16 @@ Compared against Whisper `large-v3-turbo`, all engines auto-detecting language:
|
|
|
110
131
|
|
|
111
132
|

|
|
112
133
|
|
|
113
|
-
Full per-file breakdown (Russian + English): [BENCHMARK.md](BENCHMARK.md).
|
|
134
|
+
Full per-file breakdown (Russian + English): [BENCHMARK.md](BENCHMARK.md). The CPU figure is the ONNX engine on an M2's CPU cores; no x86 numbers are published yet.
|
|
114
135
|
|
|
115
136
|
## Other install methods
|
|
116
137
|
|
|
117
|
-
All of these install the Bun CLI wrapper; engine + models still download explicitly via `kesha install`.
|
|
138
|
+
All of these install the Bun CLI wrapper; engine + models still download explicitly via `kesha install`. (Nix is the exception — it currently builds only the engine from source; see below.)
|
|
118
139
|
|
|
119
140
|
- **Homebrew** — `brew install drakulavich/tap/kesha-voice-kit` · [docs/homebrew.md](docs/homebrew.md)
|
|
120
|
-
- **Linux packages** (`.deb`/`.rpm`, x64) —
|
|
141
|
+
- **Linux packages** (`.deb`/`.rpm`, x64) — published on CLI releases, see [docs/linux-packages.md](docs/linux-packages.md)
|
|
121
142
|
- **Docker** (GHCR image) — [docs/docker.md](docs/docker.md)
|
|
122
|
-
- **Nix** (`aarch64-darwin` / `x86_64-linux`) — `nix
|
|
143
|
+
- **Nix** (`aarch64-darwin` / `x86_64-linux`) — builds the engine from source (`nix build github:drakulavich/kesha-voice-kit#kesha-engine`). The full `kesha` CLI via `nix run` / `nix profile install` is **not yet available** — it needs a maintainer with Nix to populate a build hash ([#946](https://github.com/drakulavich/kesha-voice-kit/issues/946)). · [docs/nix-install.md](docs/nix-install.md)
|
|
123
144
|
- **Shell completions + manpage** — `kesha completions bash|zsh|fish` and `kesha manpage` print the packaged files to install wherever your shell expects them.
|
|
124
145
|
|
|
125
146
|
## Integrations
|
|
@@ -135,13 +156,14 @@ All of these install the Bun CLI wrapper; engine + models still download explici
|
|
|
135
156
|
- [Architecture](docs/architecture.md) — runtime data flow, the models that ship, the CLI ↔ Rust engine boundary, model pinning, and where tests live.
|
|
136
157
|
- [Use cases](docs/use-cases.md) — copy-paste recipes (transcribe a meeting, speak from OpenClaw, run offline, move the cache).
|
|
137
158
|
- [Product positioning](docs/product-positioning.md) — supported workflows, non-goals, maturity labels, platform matrix.
|
|
159
|
+
- [Changelog](CHANGELOG.md) — every release, with the behaviour changes spelled out.
|
|
138
160
|
- **Diagnostics:** `kesha doctor`, `kesha support-bundle` (redacted `.tar.gz` for issues), and `kesha logs` produce local, content-free diagnostics — see [docs/diagnostic-logs.md](docs/diagnostic-logs.md). Every failure prints a stable `error [CODE]: …` line and a documented [process exit code](docs/errors.md#process-exit-codes).
|
|
139
|
-
- **Scripting & CI:** `--json` (or `--toon`) for machine-readable output, `--quiet`/`-q` to silence progress, and `--no-color` (or `NO_COLOR=1`) for plain logs. Colors switch off automatically when `CI=true`.
|
|
161
|
+
- **Scripting & CI:** `--json` (or `--toon`) for machine-readable output, `--include-errors` (with either) to get per-file failures on stdout alongside the results, `--quiet`/`-q` to silence progress, and `--no-color` (or `NO_COLOR=1`) for plain logs. Colors switch off automatically when `CI=true`.
|
|
140
162
|
- **Privacy / Local Stats:** Stats are **off by default** and fully local. Opt in with `kesha stats enable` to record content-free operational metrics in a local SQLite database — never networked, never storing audio, transcripts, text, or paths. Full commands & lifecycle: [docs/local-stats.md](docs/local-stats.md).
|
|
141
163
|
|
|
142
164
|
## Contributing
|
|
143
165
|
|
|
144
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md), the [Roadmap](ROADMAP.md) (Now / Next / Later), and the [Decision log](docs/decision-log.md) (why platform/model choices were made — and reversed). Dev setup: `
|
|
166
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md), the [Roadmap](ROADMAP.md) (Now / Next / Later), and the [Decision log](docs/decision-log.md) (why platform/model choices were made — and reversed). Dev setup: `just dev-setup` (Bun, Rust, nextest, platform libs).
|
|
145
167
|
|
|
146
168
|
## License
|
|
147
169
|
|
package/SKILL.md
CHANGED
|
@@ -196,7 +196,7 @@ Format is also inferred from `--out` extension (`.ogg` / `.opus` / `.oga` → OG
|
|
|
196
196
|
|
|
197
197
|
**Russian abbreviations** (`ru-vosk-*`): all-uppercase Cyrillic 2-5-char tokens auto-expand letter-by-letter when not pronounceable as a Russian syllable (ФСБ → "эф-эс-бэ", ВОЗ → "воз"). Disable with `--no-expand-abbrev`. See [docs/tts.md#russian-abbreviation-auto-expansion](docs/tts.md#russian-abbreviation-auto-expansion).
|
|
198
198
|
|
|
199
|
-
**English acronyms** (`en-*`, Kokoro): three-table mechanism (letter-spell rule + STOP_LIST + IPA_LEXICON) auto-expands FBI → "ef bee eye" and gives EPAM/JSON/Anthropic the right IPA. Disable letter-spell with `--no-expand-abbrev
|
|
199
|
+
**English acronyms** (`en-*`, Kokoro): three-table mechanism (letter-spell rule + STOP_LIST + IPA_LEXICON) auto-expands FBI → "ef bee eye" and gives EPAM/JSON/Anthropic the right IPA. Disable letter-spell with `--no-expand-abbrev` — honored on ONNX builds only; the released darwin-arm64 binary spells initialisms inside FluidAudio's own G2P and warns that the flag is a no-op ([#842](https://github.com/drakulavich/kesha-voice-kit/issues/842)). See [docs/tts.md#english-acronym-auto-expansion](docs/tts.md#english-acronym-auto-expansion).
|
|
200
200
|
|
|
201
201
|
**Russian word stress** (`ru-vosk-*` only): `<emphasis>сл+ово</emphasis>` shifts stress to the vowel marked with `+`. `<emphasis level="none">сл+ово</emphasis>` strips the `+` (cancel inherited emphasis). Other voices (`en-*`, `macos-*`) silently strip the `+` and warn once per process. Auto-stress dictionary not provided — caller writes the `+` manually. Closes [#233](https://github.com/drakulavich/kesha-voice-kit/issues/233).
|
|
202
202
|
|
package/completions/kesha.bash
CHANGED
|
@@ -10,7 +10,7 @@ _kesha_completion() {
|
|
|
10
10
|
|
|
11
11
|
if [[ "$COMP_CWORD" -eq 1 ]]; then
|
|
12
12
|
if [[ "$cur" == -* ]]; then
|
|
13
|
-
COMPREPLY=( $(compgen -W "--help -h --version -v --json --toon --timestamps --speakers --include-errors --verbose --format --lang --debug --vad --no-vad --quiet --no-color" -- "$cur") )
|
|
13
|
+
COMPREPLY=( $(compgen -W "--help -h --version -v --json --toon --timestamps --speakers --itn --include-errors --verbose --format --lang --debug --vad --no-vad --quiet --no-color" -- "$cur") )
|
|
14
14
|
else
|
|
15
15
|
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
|
|
16
16
|
fi
|
|
@@ -25,12 +25,12 @@ _kesha_completion() {
|
|
|
25
25
|
logs) opts="--help -h --json" ;;
|
|
26
26
|
manpage) opts="--help -h" ;;
|
|
27
27
|
mcp) opts="--help -h" ;;
|
|
28
|
-
record) opts="--help -h --out --max-seconds --debug" ;;
|
|
28
|
+
record) opts="--help -h --out --live --max-seconds --debug" ;;
|
|
29
29
|
say) opts="--help -h --voice --lang --out --rate --list-voices --ssml --format --bitrate --sample-rate --no-expand-abbrev --verbose --debug" ;;
|
|
30
30
|
stats) opts="--help -h --format" ;;
|
|
31
31
|
status) opts="--help -h --disk --json" ;;
|
|
32
32
|
support-bundle) opts="--help -h --output --include-logs" ;;
|
|
33
|
-
*) opts="--help -h --version -v --json --toon --timestamps --speakers --include-errors --verbose --format --lang --debug --vad --no-vad --quiet --no-color" ;;
|
|
33
|
+
*) opts="--help -h --version -v --json --toon --timestamps --speakers --itn --include-errors --verbose --format --lang --debug --vad --no-vad --quiet --no-color" ;;
|
|
34
34
|
esac
|
|
35
35
|
|
|
36
36
|
if [[ "$cur" == -* ]]; then
|
package/completions/kesha.fish
CHANGED
|
@@ -7,7 +7,7 @@ complete -c kesha -n '__fish_use_subcommand' -a 'install' -d 'Download inference
|
|
|
7
7
|
complete -c kesha -n '__fish_use_subcommand' -a 'logs' -d 'Manage local privacy-safe diagnostic logs'
|
|
8
8
|
complete -c kesha -n '__fish_use_subcommand' -a 'manpage' -d 'Print the kesha(1) manpage'
|
|
9
9
|
complete -c kesha -n '__fish_use_subcommand' -a 'mcp' -d 'Run a Model Context Protocol server over stdio (transcribe_audio, synthesize_speech, list_voices, list_languages). Configure an MCP client with: { command: \'kesha\', args: [\'mcp\'] }.'
|
|
10
|
-
complete -c kesha -n '__fish_use_subcommand' -a 'record' -d 'Record microphone audio to a WAV file'
|
|
10
|
+
complete -c kesha -n '__fish_use_subcommand' -a 'record' -d 'Record microphone audio to a WAV file, or transcribe it live'
|
|
11
11
|
complete -c kesha -n '__fish_use_subcommand' -a 'say' -d 'Synthesize speech from text (TTS). Writes audio to stdout (or --out file). Defaults to WAV; use --format ogg-opus for messenger-ready voice notes.'
|
|
12
12
|
complete -c kesha -n '__fish_use_subcommand' -a 'stats' -d 'Manage local anonymous Kesha Stats'
|
|
13
13
|
complete -c kesha -n '__fish_use_subcommand' -a 'status' -d 'Show backend installation status'
|
|
@@ -20,7 +20,8 @@ complete -c kesha -n '__fish_use_subcommand' -l json -d 'Output results as JSON'
|
|
|
20
20
|
complete -c kesha -n '__fish_use_subcommand' -l toon -d 'Output results as TOON (compact, LLM-friendly encoding of the same data as --json)'
|
|
21
21
|
complete -c kesha -n '__fish_use_subcommand' -l timestamps -d 'Include timestamped transcript segments in JSON/TOON output'
|
|
22
22
|
complete -c kesha -n '__fish_use_subcommand' -l speakers -d 'Include speaker labels in segments. Needs --json/--toon and darwin-arm64; run `kesha install --diarize` first (it installs VAD too). Implies --timestamps, and engages VAD windowing at any duration (so it cannot be combined with --no-vad).'
|
|
23
|
-
complete -c kesha -n '__fish_use_subcommand' -l
|
|
23
|
+
complete -c kesha -n '__fish_use_subcommand' -l itn -d 'Rewrite spoken-form numbers, money, dates and times to written form ("two hundred thirty two" -> "232"). English-only; other languages pass through unchanged.'
|
|
24
|
+
complete -c kesha -n '__fish_use_subcommand' -l include-errors -d 'With --json or --toon, output { results, errors } so scripts can read per-file failures without parsing stderr'
|
|
24
25
|
complete -c kesha -n '__fish_use_subcommand' -l verbose -d 'Show language detection details'
|
|
25
26
|
complete -c kesha -n '__fish_use_subcommand' -l format -r -d 'Output format: transcript | json | toon (long-form alias for --json / --toon)'
|
|
26
27
|
complete -c kesha -n '__fish_use_subcommand' -l lang -r -d 'Expected language code, e.g. en or en-us (see docs/languages.md); warn if mismatch'
|
|
@@ -65,6 +66,7 @@ complete -c kesha -n '__fish_seen_subcommand_from mcp' -s h -d 'Show help'
|
|
|
65
66
|
complete -c kesha -n '__fish_seen_subcommand_from record' -l help -d 'Show help'
|
|
66
67
|
complete -c kesha -n '__fish_seen_subcommand_from record' -s h -d 'Show help'
|
|
67
68
|
complete -c kesha -n '__fish_seen_subcommand_from record' -l out -r -d 'Write recorded WAV audio to this path'
|
|
69
|
+
complete -c kesha -n '__fish_seen_subcommand_from record' -l live -d 'Transcribe the microphone live and print the transcript to stdout (CoreML on Apple Silicon only)'
|
|
68
70
|
complete -c kesha -n '__fish_seen_subcommand_from record' -l max-seconds -r -d 'Maximum recording duration in seconds'
|
|
69
71
|
complete -c kesha -n '__fish_seen_subcommand_from record' -l debug -d 'Trace engine subprocess calls on stderr (or KESHA_DEBUG=1)'
|
|
70
72
|
complete -c kesha -n '__fish_seen_subcommand_from say' -l help -d 'Show help'
|
|
@@ -78,7 +80,7 @@ complete -c kesha -n '__fish_seen_subcommand_from say' -l ssml -d 'Parse input a
|
|
|
78
80
|
complete -c kesha -n '__fish_seen_subcommand_from say' -l format -r -d 'Output format: wav (default), ogg-opus (Telegram-ready voice note), or flac (lossless, plays in all browsers incl. Safari). Inferred from --out extension when omitted.'
|
|
79
81
|
complete -c kesha -n '__fish_seen_subcommand_from say' -l bitrate -r -d 'Opus bitrate in bits/sec (e.g. 32000). Only with --format ogg-opus.'
|
|
80
82
|
complete -c kesha -n '__fish_seen_subcommand_from say' -l sample-rate -r -d 'Opus encoder sample rate (8000/12000/16000/24000/48000). Only with --format ogg-opus.'
|
|
81
|
-
complete -c kesha -n '__fish_seen_subcommand_from say' -l no-expand-abbrev -d 'Disable
|
|
83
|
+
complete -c kesha -n '__fish_seen_subcommand_from say' -l no-expand-abbrev -d 'Disable acronym auto-expansion on ru-vosk-* voices (ВОЗ → \'вэ о зэ\') and English on ONNX engine builds (FBI → \'ef bee eye\'). No effect on macOS arm64 FluidAudio, macos-* or non-English voices, which spell initialisms in their own G2P; the engine warns when the flag is ignored. <say-as interpret-as=\'characters\'> still works.'
|
|
82
84
|
complete -c kesha -n '__fish_seen_subcommand_from say' -l verbose -d 'Log TTS synthesis time to stderr'
|
|
83
85
|
complete -c kesha -n '__fish_seen_subcommand_from say' -l debug -d 'Trace engine subprocess calls on stderr (or KESHA_DEBUG=1)'
|
|
84
86
|
complete -c kesha -n '__fish_seen_subcommand_from stats' -l help -d 'Show help'
|
package/completions/kesha.zsh
CHANGED
|
@@ -11,7 +11,7 @@ _kesha() {
|
|
|
11
11
|
'logs:Manage local privacy-safe diagnostic logs'
|
|
12
12
|
'manpage:Print the kesha(1) manpage'
|
|
13
13
|
'mcp:Run a Model Context Protocol server over stdio (transcribe_audio, synthesize_speech, list_voices, list_languages). Configure an MCP client with: { command: '\''kesha'\'', args: \['\''mcp'\''\] }.'
|
|
14
|
-
'record:Record microphone audio to a WAV file'
|
|
14
|
+
'record:Record microphone audio to a WAV file, or transcribe it live'
|
|
15
15
|
'say:Synthesize speech from text (TTS). Writes audio to stdout (or --out file). Defaults to WAV; use --format ogg-opus for messenger-ready voice notes.'
|
|
16
16
|
'stats:Manage local anonymous Kesha Stats'
|
|
17
17
|
'status:Show backend installation status'
|
|
@@ -28,7 +28,8 @@ _kesha() {
|
|
|
28
28
|
'--toon[Output results as TOON (compact, LLM-friendly encoding of the same data as --json)]' \
|
|
29
29
|
'--timestamps[Include timestamped transcript segments in JSON/TOON output]' \
|
|
30
30
|
'--speakers[Include speaker labels in segments. Needs --json/--toon and darwin-arm64; run `kesha install --diarize` first (it installs VAD too). Implies --timestamps, and engages VAD windowing at any duration (so it cannot be combined with --no-vad).]' \
|
|
31
|
-
'--
|
|
31
|
+
'--itn[Rewrite spoken-form numbers, money, dates and times to written form ("two hundred thirty two" -> "232"). English-only; other languages pass through unchanged.]' \
|
|
32
|
+
'--include-errors[With --json or --toon, output { results, errors } so scripts can read per-file failures without parsing stderr]' \
|
|
32
33
|
'--verbose[Show language detection details]' \
|
|
33
34
|
'--format=[Output format: transcript | json | toon (long-form alias for --json / --toon)]:format:' \
|
|
34
35
|
'--lang=[Expected language code, e.g. en or en-us (see docs/languages.md); warn if mismatch]:lang:' \
|
|
@@ -95,6 +96,7 @@ _kesha() {
|
|
|
95
96
|
_arguments '--help[Show help]' \
|
|
96
97
|
'-h[Show help]' \
|
|
97
98
|
'--out=[Write recorded WAV audio to this path]:out:' \
|
|
99
|
+
'--live[Transcribe the microphone live and print the transcript to stdout (CoreML on Apple Silicon only)]' \
|
|
98
100
|
'--max-seconds=[Maximum recording duration in seconds]:max seconds:' \
|
|
99
101
|
'--debug[Trace engine subprocess calls on stderr (or KESHA_DEBUG=1)]'
|
|
100
102
|
;;
|
|
@@ -110,7 +112,7 @@ _kesha() {
|
|
|
110
112
|
'--format=[Output format: wav (default), ogg-opus (Telegram-ready voice note), or flac (lossless, plays in all browsers incl. Safari). Inferred from --out extension when omitted.]:format:' \
|
|
111
113
|
'--bitrate=[Opus bitrate in bits/sec (e.g. 32000). Only with --format ogg-opus.]:bitrate:' \
|
|
112
114
|
'--sample-rate=[Opus encoder sample rate (8000/12000/16000/24000/48000). Only with --format ogg-opus.]:sample rate:' \
|
|
113
|
-
'--no-expand-abbrev[Disable
|
|
115
|
+
'--no-expand-abbrev[Disable acronym auto-expansion on ru-vosk-* voices (ВОЗ → '\''вэ о зэ'\'') and English on ONNX engine builds (FBI → '\''ef bee eye'\''). No effect on macOS arm64 FluidAudio, macos-* or non-English voices, which spell initialisms in their own G2P; the engine warns when the flag is ignored. <say-as interpret-as='\''characters'\''> still works.]' \
|
|
114
116
|
'--verbose[Log TTS synthesis time to stderr]' \
|
|
115
117
|
'--debug[Trace engine subprocess calls on stderr (or KESHA_DEBUG=1)]'
|
|
116
118
|
;;
|
|
@@ -140,7 +142,8 @@ _kesha() {
|
|
|
140
142
|
'--toon[Output results as TOON (compact, LLM-friendly encoding of the same data as --json)]' \
|
|
141
143
|
'--timestamps[Include timestamped transcript segments in JSON/TOON output]' \
|
|
142
144
|
'--speakers[Include speaker labels in segments. Needs --json/--toon and darwin-arm64; run `kesha install --diarize` first (it installs VAD too). Implies --timestamps, and engages VAD windowing at any duration (so it cannot be combined with --no-vad).]' \
|
|
143
|
-
'--
|
|
145
|
+
'--itn[Rewrite spoken-form numbers, money, dates and times to written form ("two hundred thirty two" -> "232"). English-only; other languages pass through unchanged.]' \
|
|
146
|
+
'--include-errors[With --json or --toon, output { results, errors } so scripts can read per-file failures without parsing stderr]' \
|
|
144
147
|
'--verbose[Show language detection details]' \
|
|
145
148
|
'--format=[Output format: transcript | json | toon (long-form alias for --json / --toon)]:format:' \
|
|
146
149
|
'--lang=[Expected language code, e.g. en or en-us (see docs/languages.md); warn if mismatch]:lang:' \
|
package/man/kesha.1
CHANGED
|
@@ -33,7 +33,7 @@ Print the kesha(1) manpage
|
|
|
33
33
|
Run a Model Context Protocol server over stdio (transcribe_audio, synthesize_speech, list_voices, list_languages). Configure an MCP client with: { command: 'kesha', args: ['mcp'] }.
|
|
34
34
|
.TP
|
|
35
35
|
.B record
|
|
36
|
-
Record microphone audio to a WAV file
|
|
36
|
+
Record microphone audio to a WAV file, or transcribe it live
|
|
37
37
|
.TP
|
|
38
38
|
.B say
|
|
39
39
|
Synthesize speech from text (TTS). Writes audio to stdout (or \-\-out file). Defaults to WAV; use \-\-format ogg\-opus for messenger\-ready voice notes.
|
|
@@ -60,8 +60,11 @@ Include timestamped transcript segments in JSON/TOON output
|
|
|
60
60
|
.B \-\-speakers
|
|
61
61
|
Include speaker labels in segments. Needs \-\-json/\-\-toon and darwin\-arm64; run `kesha install \-\-diarize` first (it installs VAD too). Implies \-\-timestamps, and engages VAD windowing at any duration (so it cannot be combined with \-\-no\-vad).
|
|
62
62
|
.TP
|
|
63
|
+
.B \-\-itn
|
|
64
|
+
Rewrite spoken\-form numbers, money, dates and times to written form ("two hundred thirty two" \-> "232"). English\-only; other languages pass through unchanged.
|
|
65
|
+
.TP
|
|
63
66
|
.B \-\-include\-errors
|
|
64
|
-
With \-\-json, output { results, errors } so scripts can read per\-file failures without parsing stderr
|
|
67
|
+
With \-\-json or \-\-toon, output { results, errors } so scripts can read per\-file failures without parsing stderr
|
|
65
68
|
.TP
|
|
66
69
|
.B \-\-verbose
|
|
67
70
|
Show language detection details
|
|
@@ -153,6 +156,9 @@ Output status as JSON
|
|
|
153
156
|
.B \-\-out
|
|
154
157
|
Write recorded WAV audio to this path
|
|
155
158
|
.TP
|
|
159
|
+
.B \-\-live
|
|
160
|
+
Transcribe the microphone live and print the transcript to stdout (CoreML on Apple Silicon only)
|
|
161
|
+
.TP
|
|
156
162
|
.B \-\-max\-seconds
|
|
157
163
|
Maximum recording duration in seconds
|
|
158
164
|
.TP
|
|
@@ -188,7 +194,7 @@ Opus bitrate in bits/sec (e.g. 32000). Only with \-\-format ogg\-opus.
|
|
|
188
194
|
Opus encoder sample rate (8000/12000/16000/24000/48000). Only with \-\-format ogg\-opus.
|
|
189
195
|
.TP
|
|
190
196
|
.B \-\-no\-expand\-abbrev
|
|
191
|
-
Disable
|
|
197
|
+
Disable acronym auto\-expansion on ru\-vosk\-* voices (ВОЗ → 'вэ о зэ') and English on ONNX engine builds (FBI → 'ef bee eye'). No effect on macOS arm64 FluidAudio, macos\-* or non\-English voices, which spell initialisms in their own G2P; the engine warns when the flag is ignored. <say\-as interpret\-as='characters'> still works.
|
|
192
198
|
.TP
|
|
193
199
|
.B \-\-verbose
|
|
194
200
|
Log TTS synthesis time to stderr
|
package/model-plan.json
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
{ "relPath": "models/silero-vad/silero_vad.onnx", "sizeBytes": 2327524 }
|
|
16
16
|
],
|
|
17
17
|
"g2pCharsiu": [
|
|
18
|
-
{ "relPath": "models/g2p/byt5-tiny/encoder_model.onnx", "sizeBytes":
|
|
19
|
-
{ "relPath": "models/g2p/byt5-tiny/decoder_model.onnx", "sizeBytes":
|
|
20
|
-
{ "relPath": "models/g2p/byt5-tiny/decoder_with_past_model.onnx", "sizeBytes":
|
|
18
|
+
{ "relPath": "models/g2p/byt5-tiny/encoder_model.onnx", "sizeBytes": 57234020 },
|
|
19
|
+
{ "relPath": "models/g2p/byt5-tiny/decoder_model.onnx", "sizeBytes": 26118052 },
|
|
20
|
+
{ "relPath": "models/g2p/byt5-tiny/decoder_with_past_model.onnx", "sizeBytes": 22960684 }
|
|
21
21
|
],
|
|
22
22
|
"kokoroGraph": { "relPath": "models/kokoro-82m/model.onnx", "sizeBytes": 325532387 },
|
|
23
23
|
"kokoroVoices": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
],
|
|
37
37
|
"diarize": [
|
|
38
38
|
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Manifest.json", "sizeBytes": 617 },
|
|
39
|
-
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/model.mlmodel", "sizeBytes":
|
|
40
|
-
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/weights/0-weight.bin", "sizeBytes":
|
|
41
|
-
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/weights/1-weight.bin", "sizeBytes":
|
|
39
|
+
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/model.mlmodel", "sizeBytes": 856521 },
|
|
40
|
+
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/weights/0-weight.bin", "sizeBytes": 8948544 },
|
|
41
|
+
{ "relPath": "models/diarize/SortformerNvidiaLow_v2.mlpackage/Data/com.apple.CoreML/weights/1-weight.bin", "sizeBytes": 235580992 }
|
|
42
42
|
]
|
|
43
43
|
}
|
package/openclaw-plugin.cjs
CHANGED
|
@@ -1,74 +1,36 @@
|
|
|
1
1
|
// Kesha Voice Kit — OpenClaw plugin entry.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// provider so
|
|
5
|
-
//
|
|
6
|
-
// 25 languages, no cloud
|
|
3
|
+
// Declares the locally-installed `kesha` CLI as an audio media-understanding
|
|
4
|
+
// provider so it is discoverable in `openclaw plugins inspect`
|
|
5
|
+
// (Shape: plain-capability) — Parakeet TDT via CoreML on Apple Silicon, ONNX
|
|
6
|
+
// elsewhere, 25 languages, no cloud.
|
|
7
|
+
//
|
|
8
|
+
// This registration is declaration-only and does NOT transcribe. OpenClaw only
|
|
9
|
+
// routes audio to a media-understanding provider once model auth resolves for it
|
|
10
|
+
// (an API key), which a local, keyless CLI cannot satisfy on any sane config, so
|
|
11
|
+
// this provider is never selected to run. Real transcription is wired by the
|
|
12
|
+
// user through the documented `type: "cli"` entry in tools.media.audio.models,
|
|
13
|
+
// which runs `kesha {{MediaPath}}` directly and reads its stdout — see
|
|
14
|
+
// docs/openclaw.md and docs/runbooks/openclaw-plugin.md.
|
|
7
15
|
//
|
|
8
16
|
// The same `kesha` CLI also produces messenger-ready voice notes via
|
|
9
|
-
// `kesha say "..." --format ogg-opus --out reply.ogg` (Telegram /
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
17
|
+
// `kesha say "..." --format ogg-opus --out reply.ogg` (Telegram / Discord ingest
|
|
18
|
+
// OGG/Opus directly — no transcoding needed). Not wired into OpenClaw's
|
|
19
|
+
// media-understanding capability here; invoke it from a hook or agent tool when
|
|
20
|
+
// you want Kesha to speak.
|
|
13
21
|
//
|
|
14
22
|
// Prerequisite: the `kesha` binary must be on PATH. Install it with:
|
|
15
23
|
// bun add -g @drakulavich/kesha-voice-kit
|
|
16
24
|
// kesha install # ASR models
|
|
17
25
|
// kesha install --tts # TTS models (Kokoro + Vosk-TTS), only if you use `kesha say`
|
|
18
26
|
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// the rule does not fire on this legitimate local-CLI wrapper.
|
|
24
|
-
const { spawnSync } = require("node:child_" + "process");
|
|
25
|
-
const fs = require("node:fs");
|
|
26
|
-
const os = require("node:os");
|
|
27
|
-
const path = require("node:path");
|
|
27
|
+
// Editing note: OpenClaw's `dangerous-exec` scanner is a naive per-file regex
|
|
28
|
+
// that also reads comments. Do not name the forbidden Node runtime module or a
|
|
29
|
+
// bare command-running call anywhere in this file — see
|
|
30
|
+
// docs/runbooks/openclaw-plugin.md.
|
|
28
31
|
|
|
29
|
-
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
30
32
|
const MODEL_ID = "parakeet-tdt-0.6b-v3";
|
|
31
33
|
|
|
32
|
-
function tempAudioPath(fileName) {
|
|
33
|
-
const ext = (fileName && path.extname(fileName)) || ".ogg";
|
|
34
|
-
return path.join(os.tmpdir(), `kesha-${process.pid}-${Date.now()}${ext}`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function transcribeAudio(req) {
|
|
38
|
-
if (!req || !req.buffer) {
|
|
39
|
-
return { text: "" };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const tmp = tempAudioPath(req.fileName);
|
|
43
|
-
fs.writeFileSync(tmp, req.buffer);
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
const result = spawnSync("kesha", ["--json", tmp], {
|
|
47
|
-
encoding: "utf8",
|
|
48
|
-
timeout: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
if (result.error || result.status !== 0) {
|
|
52
|
-
return { text: "" };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const parsed = JSON.parse(result.stdout || "[]");
|
|
56
|
-
const text = Array.isArray(parsed) && parsed[0] && typeof parsed[0].text === "string"
|
|
57
|
-
? parsed[0].text
|
|
58
|
-
: "";
|
|
59
|
-
|
|
60
|
-
return { text, model: MODEL_ID };
|
|
61
|
-
} catch {
|
|
62
|
-
return { text: "" };
|
|
63
|
-
} finally {
|
|
64
|
-
try {
|
|
65
|
-
fs.unlinkSync(tmp);
|
|
66
|
-
} catch {
|
|
67
|
-
// best effort cleanup
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
34
|
module.exports = {
|
|
73
35
|
id: "kesha-voice-kit",
|
|
74
36
|
name: "Kesha Voice Kit",
|
|
@@ -78,7 +40,6 @@ module.exports = {
|
|
|
78
40
|
capabilities: ["audio"],
|
|
79
41
|
defaultModels: { audio: MODEL_ID },
|
|
80
42
|
autoPriority: { audio: 50 },
|
|
81
|
-
transcribeAudio,
|
|
82
43
|
});
|
|
83
44
|
},
|
|
84
45
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drakulavich/kesha-voice-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0-alpha.1",
|
|
4
4
|
"description": "Give your tools a voice — speech to text and back, 25 languages, up to ~19× faster than Whisper. On your machine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"test": "bun test --timeout 30000",
|
|
47
47
|
"test:watch": "bun test --timeout 30000 --watch",
|
|
48
48
|
"test:unit": "bun test --timeout 30000 tests/unit/",
|
|
49
|
-
"test:cli-fast": "bun test --timeout 30000 tests/unit/ tests/integration/cli-contracts.test.ts tests/integration/
|
|
49
|
+
"test:cli-fast": "bun test --timeout 30000 tests/unit/ tests/integration/cli-contracts.test.ts tests/integration/say.test.ts",
|
|
50
50
|
"test:integration": "bun test --timeout 30000 tests/integration/",
|
|
51
51
|
"coverage:ts": "bun run test:cli-fast --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage/ts",
|
|
52
52
|
"coverage:check:ts": "bun .github/scripts/check-coverage.ts --preset=ts --lcov=coverage/ts/lcov.info --summary=coverage/ts/summary.md",
|
|
@@ -54,12 +54,14 @@
|
|
|
54
54
|
"coverage:check:rust": "bun .github/scripts/check-coverage.ts --preset=rust --lcov=coverage/rust/lcov.info --summary=coverage/rust/summary.md",
|
|
55
55
|
"generate:shell-artifacts": "bun scripts/generate-shell-artifacts.ts",
|
|
56
56
|
"lint": "bunx tsc --noEmit",
|
|
57
|
-
"check": "bun run lint && bun run check:versions && bun run test:cli-fast",
|
|
57
|
+
"check": "bun run lint && bun run check:versions && bun run check:recipes && bun run test:cli-fast",
|
|
58
58
|
"check:workflows": "bun .github/scripts/check-workflows.ts",
|
|
59
|
+
"check:recipes": "bun .github/scripts/check-recipes.ts",
|
|
59
60
|
"check:specs": "bunx @fission-ai/openspec@1.4.1 validate --specs --strict",
|
|
60
61
|
"check:release-manifest": "bun .github/scripts/release-manifest.mjs --check",
|
|
61
62
|
"check:versions": "bun .github/scripts/check-versions.ts",
|
|
62
|
-
"check:engine-targets": "bun .github/scripts/check-engine-targets.ts"
|
|
63
|
+
"check:engine-targets": "bun .github/scripts/check-engine-targets.ts",
|
|
64
|
+
"mutants:ts": "bun scripts/mutants-ts.ts"
|
|
63
65
|
},
|
|
64
66
|
"keywords": [
|
|
65
67
|
"asr",
|
|
@@ -87,6 +89,8 @@
|
|
|
87
89
|
"bun": ">=1.3.0"
|
|
88
90
|
},
|
|
89
91
|
"devDependencies": {
|
|
92
|
+
"@hughescr/stryker-bun-runner": "^1.3.8",
|
|
93
|
+
"@stryker-mutator/core": "^9.6.1",
|
|
90
94
|
"@types/bun": "latest",
|
|
91
95
|
"fast-xml-parser": "^5.8.0",
|
|
92
96
|
"typescript": "^7.0.2",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Bun's `with { type: "text" }` imports; tsc has no loader for these extensions.
|
|
2
|
+
declare module "*.bash" {
|
|
3
|
+
const content: string;
|
|
4
|
+
export default content;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
declare module "*.zsh" {
|
|
8
|
+
const content: string;
|
|
9
|
+
export default content;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare module "*.fish" {
|
|
13
|
+
const content: string;
|
|
14
|
+
export default content;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare module "*.1" {
|
|
18
|
+
const content: string;
|
|
19
|
+
export default content;
|
|
20
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { join, resolve, sep } from "path";
|
|
2
|
+
|
|
3
|
+
export interface CachePathEntry {
|
|
4
|
+
label: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Whether `child` is `parent` itself or lives under it — the one answer `status --disk` and
|
|
10
|
+
* `doctor` both need before deciding whether an engine dir is already inside the cache total.
|
|
11
|
+
* A bare `startsWith` reads the sibling `~/.cache/kesha-alt` as inside `~/.cache/kesha` and
|
|
12
|
+
* drops its size (#790); `KESHA_CACHE_DIR` and `KESHA_ENGINE_BIN` are taken verbatim, so both
|
|
13
|
+
* sides are resolved first.
|
|
14
|
+
*/
|
|
15
|
+
export function isInsideDir(child: string, parent: string): boolean {
|
|
16
|
+
const resolvedChild = resolve(child);
|
|
17
|
+
const resolvedParent = resolve(parent);
|
|
18
|
+
return resolvedChild === resolvedParent || resolvedChild.startsWith(`${resolvedParent}${sep}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The Kesha-managed directories both `kesha status --disk` and `kesha doctor` report, in one
|
|
23
|
+
* place so a new model dir cannot be added to only one of them. The two ASR rows are mutually
|
|
24
|
+
* exclusive: a CoreML engine never populates the ONNX dir, and instead roots FluidAudio's own
|
|
25
|
+
* subsystems under `<cache>/fluidaudio`, which is where the relocated bundles land (#688).
|
|
26
|
+
* Whatever stayed in FluidAudio's own trees is outside this cache and is reported separately
|
|
27
|
+
* by `fluidExternalRoots`.
|
|
28
|
+
*/
|
|
29
|
+
export function cacheComponentPaths(
|
|
30
|
+
cacheRoot: string,
|
|
31
|
+
engineDir: string,
|
|
32
|
+
coreml: boolean,
|
|
33
|
+
): CachePathEntry[] {
|
|
34
|
+
return [
|
|
35
|
+
{ label: "Engine", path: engineDir },
|
|
36
|
+
...(coreml
|
|
37
|
+
? [{ label: "FluidAudio (in cache)", path: join(cacheRoot, "fluidaudio") }]
|
|
38
|
+
: [{ label: "ASR (Parakeet)", path: join(cacheRoot, "models/parakeet-tdt-v3") }]),
|
|
39
|
+
{ label: "Language ID", path: join(cacheRoot, "models/lang-id-ecapa") },
|
|
40
|
+
{ label: "VAD (Silero)", path: join(cacheRoot, "models/silero-vad") },
|
|
41
|
+
{ label: "TTS (Kokoro)", path: join(cacheRoot, "models/kokoro-82m") },
|
|
42
|
+
{ label: "TTS (Vosk)", path: join(cacheRoot, "models/vosk-ru") },
|
|
43
|
+
];
|
|
44
|
+
}
|
package/src/cli/completions.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { defineCommand } from "citty";
|
|
2
2
|
import { log } from "../log";
|
|
3
|
+
// Inlined because import.meta.url escapes the embedded filesystem in the compiled .deb/.rpm binary (#914).
|
|
4
|
+
import bashCompletions from "../../completions/kesha.bash" with { type: "text" };
|
|
5
|
+
import zshCompletions from "../../completions/kesha.zsh" with { type: "text" };
|
|
6
|
+
import fishCompletions from "../../completions/kesha.fish" with { type: "text" };
|
|
3
7
|
|
|
4
|
-
const
|
|
5
|
-
bash:
|
|
6
|
-
zsh:
|
|
7
|
-
fish:
|
|
8
|
+
const SHELL_SCRIPTS = {
|
|
9
|
+
bash: bashCompletions,
|
|
10
|
+
zsh: zshCompletions,
|
|
11
|
+
fish: fishCompletions,
|
|
8
12
|
} as const;
|
|
9
13
|
|
|
10
|
-
type Shell = keyof typeof
|
|
14
|
+
type Shell = keyof typeof SHELL_SCRIPTS;
|
|
11
15
|
|
|
12
16
|
interface CompletionsCommandArgs {
|
|
13
17
|
shell?: string;
|
|
@@ -35,7 +39,6 @@ export const completionsCommand = defineCommand({
|
|
|
35
39
|
log.error("usage: kesha completions <bash|zsh|fish>");
|
|
36
40
|
process.exit(2);
|
|
37
41
|
}
|
|
38
|
-
|
|
39
|
-
process.stdout.write(await Bun.file(file).text());
|
|
42
|
+
process.stdout.write(SHELL_SCRIPTS[shell]);
|
|
40
43
|
},
|
|
41
44
|
});
|