diff --git a/CLAUDE.md b/CLAUDE.md index db491d9..2d0e1a2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -302,6 +302,27 @@ Reachability from the `open_notebook` container requires **two things**, both al Registered in Open Notebook as `openai_compatible` credentials with `base_url=http://host.docker.internal:8901` (TTS) / `:8902` (STT), and set as `default_text_to_speech_model` / `default_speech_to_text_model`. +#### Pronunciation (English terms, proper names) + +German TTS mispronounces English technical terms and foreign names ("Repository", "Donald Trump"). +The fix lives **upstream in `~/chatterbox-tts-cli/`**, not here: `pronunciation.py` (a torch-free +module) plus the curated `pronunciation/de.json`, which `chatterbox_cli_v4.preprocess_tts_text()` +applies automatically for `lang="de"`. `services/tts_server.py` needs **no code** for this — it +already calls that function, so podcasts get the corrections for free. + +The mechanism is **respelling in German orthography** ("Repository" → "Ripositori"), not phonetics. +Chatterbox is grapheme-based (tokenizer: `grapheme_mtl_merged_expanded_v1`); its vocabulary does +contain IPA symbols and an `[ipa]` language token, but that was tested and does **not** work — +`ɹɪˈpɑzɪˌtɔɹi` comes out audibly as "Ripacitari". Splitting the sentence and switching to `[en]` +per term works phonetically but glues segments together without crossfade: 4 seams cost 0.5–0.8 s +of silence each, growing a 3.9 s sentence to 7.1 s. Respelling is the only usable route. + +To add project-specific terms without touching the shared file, point +`CHATTERBOX_PRONUNCIATION_DICT` at a JSON file (it is read by `load_pronunciation_dict()` and +overrides the shipped list). Find candidates in a real transcript with +`~/chatterbox-tts-cli/pronunciation_candidates.py` (lists words hunspell's German dictionary +doesn't know and that aren't in the dictionary yet). + #### Voice cloning `tts_server.py` resolves the incoming `voice` field via `services/voices/*.wav` (gitignored — personal voice recordings): `.wav` becomes a selectable voice `""`, cloned via chatterbox's `audio_prompt_path`. Unknown/omitted voices fall back to `"default"`; a bare language code (e.g. `"en"`) still works and skips cloning (built-in voice for that language). All cloned voices are generated in German (`CLONE_LANG` in the script) since only German reference clips exist here — add entries to `VOICE_LANG_OVERRIDES` in the script if you add clips in other languages.