# Stimmen-Inventar (TTS) — eine Quelle der Wahrheit Diese Datei listet **alle** TTS-Stimmen je Provider, Sprache und Geschlecht: Stimmenname, Datei bzw. UUID und die Stelle im Code/Config, an der sie definiert ist. Ziel: Schluss mit dem Suchen über mehrere Dateien. > **Wer wählt die Stimme?** `app/dependencies.py::voice_for_route(tts_provider, language, voice_gender)`. > Es liest `voice_gender` aus der aufgelösten Route (`resolve_route`), die es wiederum aus den > Nutzer-Prefs zieht. Die Geschlechtswahl im Web-UI wird über `PUT /api/me/prefs` gespeichert — > dafür **muss** `voice_gender` im Schema `app/schemas.py::UserPrefs` stehen (sonst verwirft > pydantic das Feld still → Nutzer hört immer „any" = weiblich). Legende: ♀ = weiblich, ♂ = männlich · „—" = nicht vorhanden/keine Geschlechtswahl. --- ## 1. Piper (lokal, Standard im Profil `jamulix`) - **Definition Geschlecht→Stimme:** `app/dependencies.py` → `PIPER_VOICE_GENDERED` (mit Geschlecht) und `LANG_TO_PIPER_VOICE` (geschlechtsloser Fallback). - **Modelldateien:** `config/voices/.onnx` (+ `.onnx.json`); Verzeichnis aus `config/voice-assistant.toml::piper_voices_dir`. | Sprache | ♀ Stimme | Datei (.onnx) | ♂ Stimme | Datei (.onnx) | |---|---|---|---|---| | de | de_DE-kerstin-low | `de_DE-kerstin-low` | de_DE-thorsten-high | `de_DE-thorsten-high` | | en | en_US-amy-medium | `en_US-amy-medium` | en_US-lessac-high | `en_US-lessac-high` | | fr | fr_FR-siwis-medium | `fr_FR-siwis-medium` | fr_FR-tom-medium | `fr_FR-tom-medium` | | es | es_ES-sharvard-medium **#1** | `es_ES-sharvard-medium` (Speaker 1=F) | es_ES-sharvard-medium **#0** | `es_ES-sharvard-medium` (Speaker 0=M) | | it | it_IT-paola-medium | `it_IT-paola-medium` | it_IT-riccardo-x_low | `it_IT-riccardo-x_low` | | ru | ru_RU-irina-medium | `ru_RU-irina-medium` | ru_RU-ruslan-medium | `ru_RU-ruslan-medium` | | pl | pl_PL-gosia-medium | `pl_PL-gosia-medium` | pl_PL-darkman-medium | `pl_PL-darkman-medium` | | pt | — *(keine ♀ in Piper)* | — | pt_BR-faber-medium | `pt_BR-faber-medium` | | ar | — *(keine ♀ in Piper)* | — | ar_JO-kareem-medium | `ar_JO-kareem-medium` | | zh / cmn | zh_CN-huayan-medium | `zh_CN-huayan-medium` | — *(kein ♂ nutzbar)* | — | Hinweise: - `es` ist ein Multi-Speaker-Modell: Speaker-Index `#0`=männlich, `#1`=weiblich (`speaker_id_map`). - `pt`/`ar`/`zh` haben in Piper **keine** Geschlechts-Varianten → beide Schalterstellungen liefern dieselbe Stimme (Fallback aus `LANG_TO_PIPER_VOICE`). - **zh ♂** wäre nur über `zh_CN-chaowen-medium` möglich, das aber `phoneme_type=pinyin` (g2pW) braucht — in dieser Installation **nicht** lauffähig (erzeugt kein Audio). --- ## 2. Cartesia (Cloud, Modell sonic-turbo) - **Definition:** `config/voice-assistant.toml::cartesia_voices`, Format `lang:gender:uuid:name`. - **Auflösung UUID:** `app/providers/tts/cartesia.py::_resolve_voice_id` (Fallback-Kette f→m→any→`cartesia_voice_id`). | Sprache | Geschlecht | Name | UUID | |---|---|---|---| | de | ♂ | Sebastian | `b7187e84-fe22-4344-ba4a-bc013fcb533e` | | de | ♀ | Alina | `38aabb6a-f52b-4fb0-a3d1-988518f4dc06` | | en | ♂ | Caspar | `4f7f1324-1853-48a6-b294-4e78e8036a83` | | en | ♀ | Gemma | `62ae83ad-4f6a-430b-af41-a9bede9286ca` | | fr | ♂ | Antoine | `0418348a-0ca2-4e90-9986-800fb8b3bbc0` | | fr | ♀ | Amélie | `7c58f4a4-a72c-42fa-a503-41b9408820f3` | | es | ♂ | Augustin (mx) | `2695b6b5-5543-4be1-96d9-3967fb5e7fec` | | es | ♀ | Daniela (mx) | `5c5ad5e7-1020-476b-8b91-fdcbe9cc313c` | | pt | ♂ | Bruno | `b603811e-54c2-4a0a-8854-09eab9ffa63f` | | pt | ♀ | Isabella | `c9611be8-aae9-4a93-bb1c-98dd6b7d52a4` | | it | — | sonic-turbo unterstützt IT nicht (auskommentiert) | — | | pl | — | sonic-turbo unterstützt PL nicht (auskommentiert) | — | | ru | — | sonic-turbo unterstützt RU nicht (auskommentiert) | — | | ar | — | Cartesia unterstützt Arabic-TTS nicht | — | | zh | — | nicht konfiguriert | — | > Für it/pl/ru/ar/zh greift bei Cartesia die globale Fallback-Kette → letztlich `tts_fallback` > (`config/voice-assistant.toml`, aktuell `piper`). --- ## 3. OpenRouter (Cloud, Modell `openai/gpt-4o-mini-tts`) - **Definition:** `app/config.py::openrouter_tts_voice` (Default `alloy`), `openrouter_tts_model`. - **Keine** Geschlechts- oder Sprachauswahl: **eine** feste Stimme für alle Sprachen. `voice_for_route` gibt für OpenRouter `None` zurück → Default-Stimme. | Sprache | ♀ | ♂ | |---|---|---| | alle | — (eine feste Stimme `alloy`) | — | --- ## 4. Chatterbox (lokaler GPU-Dienst, Voice-Cloning) - **Definition:** `app/config.py::chatterbox_*`; Referenz-WAV je Sprache unter `chatterbox_voices_dir` als `config/voices/.wav`. - **Keine** Geschlechtswahl: pro Sprache **eine** geklonte Stimme (Geschlecht = Aufnahme). | vorhandene Referenz-WAVs | en, es, fr, it, nl, ru, zh | |---|---| | ohne `.wav` → globale Default-Stimme | de, pt, pl, ar, … | --- ## Lücken-Überblick (welche Kombination fehlt) | Sprache | Piper | Cartesia | OpenRouter | Chatterbox | |---|---|---|---|---| | de, en, fr, es | ♀+♂ | ♀+♂ | nur 1 fix | 1 (Klon) | | pt | nur ♂ | ♀+♂ | nur 1 fix | Default | | it, pl, ru | ♀+♂ | — | nur 1 fix | teils 1 | | ar | nur ♂ | — | nur 1 fix | Default | | zh | nur ♀ | — | nur 1 fix | 1 (Klon) | Für die echten Lücken (pt ♀ / ar ♀ / zh ♂) braucht es **sprach-/geschlechtsabhängiges Provider-Routing** (z. B. pt ♀ → Cartesia Isabella) plus UI-Ausgrauen nicht verfügbarer Kombinationen. Siehe `MULTITOOL_AUSBAU_PLAN.md` / offene Aufgaben.