@drakulavich/kesha-voice-kit 1.9.0 → 1.10.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 CHANGED
@@ -86,6 +86,27 @@ kesha say --voice ru-vosk-m02 --ssml \
86
86
 
87
87
  Detection rule: auto-expand fires when the token cannot be pronounced as a natural Russian syllable — length ≤ 2 (ИП, ЕС), 0 vowels (ФСБ, СНГ), 2+ consecutive vowels (ОАЭ), or 2+ consecutive consonants (США, ЦСКА). Tokens with strict CVC/CVCV alternation pass through (ВОЗ → "воз", НАТО → "нато", ОПЕК → "опек"). Small stop-list for common short words (ОН, МЫ, ВЫ, КАК, ЧТО, …) and Ъ/Ь-containing tokens are always skipped. See [#232](https://github.com/drakulavich/kesha-voice-kit/issues/232).
88
88
 
89
+ **English acronyms** (`en-*` voices, Kokoro-82M):
90
+
91
+ ```bash
92
+ # Auto-expand on by default — FBI reads as "ef bee eye"
93
+ kesha say --voice en-am_michael 'The FBI is investigating.'
94
+
95
+ # Force a literal reading (Kokoro fuses unknown caps tokens to one syllable)
96
+ kesha say --voice en-am_michael --no-expand-abbrev 'FBI.'
97
+
98
+ # Explicit SSML control (overrides the rule and the stop-list)
99
+ kesha say --voice en-am_michael --ssml \
100
+ '<speak><say-as interpret-as="characters">NASA</say-as></speak>'
101
+ ```
102
+
103
+ Three-table mechanism:
104
+ - **Letter-spell** — uppercase Latin tokens 2–5 chars (no digits, no mixed case) get expanded letter-by-letter (FBI → "ef bee eye"). Disable with `--no-expand-abbrev`.
105
+ - **`STOP_LIST`** (30 entries) — natural-English caps words pass through unchanged: NASA, NATO, AIDS, OPEC, IKEA, ASCII, NAFTA, LASER, RADAR, SCUBA + emphatic length-2 caps (OK, NO, GO, IT, IS, AS, AT, BY, IN, ON, OR, OF, TO, WE, US, MY, ME, HE, BE, DO).
106
+ - **`IPA_LEXICON`** (20 entries) — case-sensitive token → IPA-phoneme map that bypasses G2P entirely. Covers all-caps acronyms with industry pronunciations (EPAM, JSON, JPEG, SQL, ASAP, GIF, CRUD, JWT) AND mixed-case proper nouns (Anthropic, Microsoft, Claude, NVIDIA, Kubernetes, PostgreSQL, GraphQL, Linux, Tokio, macOS, Granola, OAuth). IPA hits fire even with `--no-expand-abbrev` — they're intent-explicit, parallel to `<say-as>`.
107
+
108
+ Override per-token via SSML `<say-as interpret-as="characters">…</say-as>` (always letter-spells via the table). See [#244](https://github.com/drakulavich/kesha-voice-kit/issues/244).
109
+
89
110
  **Russian word stress** (`ru-vosk-*` voices):
90
111
 
91
112
  ```bash
package/SKILL.md CHANGED
@@ -45,11 +45,21 @@ kesha --json voice.ogg
45
45
 
46
46
  Use `lang` (or the more detailed `audioLanguage`/`textLanguage`) to decide how to respond.
47
47
 
48
+ Need timestamped transcript segments for navigation, chapters, or downstream editing:
49
+
50
+ ```bash
51
+ kesha --json --timestamps voice.ogg > voice.timestamps.json
52
+ jq '.[0].segments' voice.timestamps.json
53
+ ```
54
+
55
+ Each segment has `start`, `end`, and `text` fields. `--timestamps` is available for machine-readable output (`--json`, `--toon`, or `--format json`).
56
+
48
57
  **Formats:** .ogg, .opus, .mp3, .m4a, .wav, .flac, .webm — decoded via symphonia, no ffmpeg required.
49
58
 
50
59
  **Other output modes:**
51
60
  - `kesha audio.ogg` — plain transcript on stdout
52
61
  - `kesha --format transcript audio.ogg` — transcript + `[lang: ru, confidence: 0.99]` footer
62
+ - `kesha --json --timestamps audio.ogg` — JSON with timestamped `segments`
53
63
  - `kesha --verbose audio.ogg` — human-readable with language info
54
64
  - `kesha --lang en audio.ogg` — warn if detected language differs (useful sanity check)
55
65
 
@@ -76,6 +86,8 @@ Format is also inferred from `--out` extension (`.ogg` / `.opus` / `.oga` → OG
76
86
 
77
87
  **Russian abbreviation handling** (`ru-vosk-*` only): all-uppercase Cyrillic tokens (length 2–5) auto-expand letter-by-letter when the token cannot be pronounced as a natural Russian syllable — `ФСБ объявила` → `эф-эс-бэ объявила`. Tokens with strict CVC/CVCV alternation pass through (ВОЗ → "воз", НАТО → "нато"). Disable per call with `--no-expand-abbrev`. Override per-token via SSML `<say-as interpret-as="characters">…</say-as>` (always wins, even with `--no-expand-abbrev`). Stop-list for common short words (ОН, МЫ, ВЫ, КАК, ЧТО) prevents false positives. Closes [#232](https://github.com/drakulavich/kesha-voice-kit/issues/232).
78
88
 
89
+ **English acronym handling** (`en-*` Kokoro-82M only). Three tables: (1) **letter-spell** for uppercase 2–5-char tokens not on the stop-list (FBI → "ef bee eye", HTTP → "aitch tee tee pee"); (2) **`STOP_LIST`** (30 entries) — natural-English caps words pass through (NASA, NATO, AIDS, OPEC, IKEA, ASCII, NAFTA, LASER, RADAR, SCUBA + 20 emphatic length-2 caps); (3) **`IPA_LEXICON`** (20 entries) — case-sensitive token → IPA-phoneme map that bypasses G2P entirely. Covers industry-pronunciation acronyms (EPAM /ˈiːpæm/, JSON /ˈdʒeɪsən/, JPEG, SQL, ASAP, GIF, CRUD, JWT, OAuth) AND mixed-case proper nouns (Anthropic /ænˈθrɒpɪk/, Microsoft, Claude, NVIDIA, Kubernetes, PostgreSQL, GraphQL, Linux, Tokio, macOS, Granola). Disable letter-spell with `--no-expand-abbrev` — IPA hits still fire (intent-explicit). Override per-token via SSML `<say-as interpret-as="characters">…</say-as>` (always wins). Closes [#244](https://github.com/drakulavich/kesha-voice-kit/issues/244).
90
+
79
91
  **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).
80
92
 
81
93
  ## Language detection standalone
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drakulavich/kesha-voice-kit",
3
- "version": "1.9.0",
3
+ "version": "1.10.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 + 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": {
@@ -30,7 +30,7 @@
30
30
  ]
31
31
  },
32
32
  "keshaEngine": {
33
- "version": "1.9.0"
33
+ "version": "1.10.0"
34
34
  },
35
35
  "scripts": {
36
36
  "test": "bun test",
package/src/cli/say.ts CHANGED
@@ -86,7 +86,7 @@ export const sayCommand = defineCommand({
86
86
  type: "boolean",
87
87
  description:
88
88
  "Disable Russian acronym auto-expansion (ВОЗ → 'вэ о зэ') for ru-vosk-* voices. " +
89
- "<say-as interpret-as='characters'> still works. No effect for non-ru-vosk voices.",
89
+ "<say-as interpret-as='characters'> still works. Applies to Russian (ru-vosk-*) and English (en-*) voices.",
90
90
  },
91
91
  verbose: {
92
92
  type: "boolean",
package/src/say.ts CHANGED
@@ -39,9 +39,9 @@ export interface SayOptions {
39
39
  */
40
40
  sampleRate?: number;
41
41
  /**
42
- * Disable Russian acronym auto-expansion for `ru-vosk-*` voices.
42
+ * Disable acronym auto-expansion for `ru-vosk-*` and `en-*` voices.
43
43
  * When true, passes `--no-expand-abbrev` to the engine (requires engine
44
- * capability `tts.ru_acronym_expansion`; silently dropped for older engines).
44
+ * capability `tts.ru_acronym_expansion` or `tts.en_acronym_expansion`; silently dropped for older engines).
45
45
  * `<say-as interpret-as="characters">` still works regardless of this flag.
46
46
  */
47
47
  noExpandAbbrev?: boolean;
@@ -59,12 +59,14 @@ export function buildSayArgs(o: SayOptions, capabilities?: EngineCapabilities |
59
59
  if (o.bitrate !== undefined) args.push("--bitrate", String(o.bitrate));
60
60
  if (o.sampleRate !== undefined) args.push("--sample-rate", String(o.sampleRate));
61
61
  if (o.noExpandAbbrev) {
62
- const supportsRuExpand = capabilities?.features?.includes("tts.ru_acronym_expansion") ?? false;
63
- if (supportsRuExpand) {
62
+ const supportsExpand = capabilities?.features?.some(
63
+ (f) => f === "tts.ru_acronym_expansion" || f === "tts.en_acronym_expansion",
64
+ ) ?? false;
65
+ if (supportsExpand) {
64
66
  args.push("--no-expand-abbrev");
65
67
  } else {
66
68
  log.debug(
67
- "kesha-engine does not advertise tts.ru_acronym_expansion; dropping --no-expand-abbrev",
69
+ "kesha-engine does not advertise tts.ru_acronym_expansion or tts.en_acronym_expansion; dropping --no-expand-abbrev",
68
70
  );
69
71
  }
70
72
  }