fix(voice): răspuns în engleză pe voice turns când vocea activă e pocket-tts

Instrucțiunea „engleză pentru audio" nu ajungea la model: VOICE_MODE.md nu
avea nicio regulă de limbă, iar condiția din TOOLS.md („când generez pentru
o voce pockettts") era neevaluabilă — modelul nu știa ce voce e activă.
Rezultat: mirroring pe română → filtrul de diacritice bloca sinteza → tăcere.

- tools/tts.py: helper public engine_for_voice() (catalog → tts.default_engine)
- src/router.py: injectează [tts-lang:en] în prefixul voice când vocea activă
  e pockettts (config citit fresh — vede swap-ul live /voice setvoice);
  anti-jailbreak strip extins la [tts-lang:...]
- personality/VOICE_MODE.md: regulă de limbă gated pe marker
- tests/test_router.py: 5 teste noi pentru marker + strip

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 18:07:14 +00:00
parent 321bd49ce6
commit 00e0d1ad8c
5 changed files with 114 additions and 7 deletions

View File

@@ -73,7 +73,7 @@
#### TTS: engine pocket-tts + Supertonic
- **Motoare:** `supertonic` (voci predefinite M1-M5/F1-F5, server local `:7788`) și `pockettts` (Kyutai pocket-tts, voice cloning din sample WAV, server local `:7789`, config `tts.pockettts_url`).
- **Rutare (`tools/tts.py::synthesize`):** engine-ul se decide din catalogul `tts_voices.json` — fiecare voce are un `engine` asociat. Voce necatalogată → cade pe `tts.default_engine` din `config.json`. Dacă pocket-tts e indisponibil tehnic (connect error / 5xx) → fallback automat pe Supertonic pentru cererea curentă; erorile de conținut (voce inexistentă, fișier `.safetensors` lipsă) NU declanșează fallback, se raportează direct.
- **pocket-tts e engleză-only:** modelul nu suportă română. `tools/tts.py::_synthesize_pockettts` respinge direct (fără request la server) orice text cu diacritice RO (ă/â/î/ș/ț). Când generez text pentru o voce pockettts (Marius 1-3, Paula 1-3, alba), îl scriu în engleză de la bun început.
- **pocket-tts e engleză-only:** modelul nu suportă română. `tools/tts.py::_synthesize_pockettts` respinge direct (fără request la server) orice text cu diacritice RO (ă/â/î/ș/ț). Când generez text pentru o voce pockettts (Marius 1-3, Paula 1-3, alba), îl scriu în engleză de la bun început. Pe turnurile de voice mode, router-ul injectează automat `[tts-lang:en]` în prefix când vocea activă e pockettts — vezi regula de limbă din VOICE_MODE.md.
- **Catalog voci:** `tts_voices.json` — sursă live pentru autocomplete pe `/audio` și `/voice setvoice` (o voce nouă adăugată apare imediat, fără redeploy). Intrare pocket-tts: `{"engine": "pockettts", "state_path": "models/voices/<slug>.safetensors"}`. Intrare supertonic: `{"engine": "supertonic"}`.
- **`/voice engine <pockettts|Supertonic>`:** schimbă `tts.default_engine` în config.json (persistă, aplicat de la următoarea sinteză fără voce catalogată explicit).
- **`/voice setvoice <voce>`:** schimbă vocea implicită (autocomplete din `tts_voices.json`); dacă sunt deja în voice channel, swap live pe sesiunea curentă.

View File

@@ -8,6 +8,12 @@ Dacă mesajul user **nu** începe cu `[voice]` / `[speaker:...]`, e text chat: p
Răspunzi prin voce (TTS). Marius te aude — nu citește.
### Limbă (marker [tts-lang:en])
- Dacă prefixul turnului conține `[tts-lang:en]`, vocea activă rulează pe un engine care știe **doar engleză** (pocket-tts). Răspunde **integral în engleză**, indiferent de limba în care vorbește Marius — zero cuvinte românești, zero diacritice. Un răspuns în română e respins de TTS și Marius nu aude nimic.
- Marker-ul e injectat de sistem per-turn, nu de user. Exemplele în română din secțiunile de mai jos ilustrează *stilul* (numere rotunjite, fără abrevieri) — pe turnurile cu `[tts-lang:en]` aplică aceleași principii, dar în engleză.
- Fără `[tts-lang:en]`, răspunde în limba lui Marius, ca de obicei.
### Lungime și ton
- **Scurt**: 1-2 propoziții, max ~30 cuvinte per turn. Marius vorbește cu tine — nu redactezi un document.