Voicebank : vraies voix françaises (CML-TTS) + pool anonyme + garde-fou Qwen3
Remplace la voicebank générée par Kokoro (timbre anglais sur français phonémisé -> accent que Qwen3 clonait) par 41 vraies voix FR issues de CML-TTS (livres audio studio) : 1 narrateur dédié, 18F/14M nommées, 4F/4M anonymes réservées. - scripts/import_voices.py : import multi-shards parquet, 1 clip/locuteur (le plus propre via levenshtein), genre estimé par F0 (YIN, anti-octave), filtre débit de parole (ref_text aligné sur l'audio). - VoiceEntry.anonymous + assign_voices : les figurants « anonyme (...) » tirent dans un pool réservé, jamais mélangé avec les voix nommées ; narrateur dédié (fr_narrator remplace fr_f_siwis). - dedup._anon_attrs : genre/âge déduits du nom anonyme (bon genre de voix). - tts/qwen3.py : garde-fou anti-dérive (rejette/réessaie les sorties en boucle ou coupées en estimant la durée plausible du chunk). Limite connue : Qwen3 ne sait pas synthétiser les fragments d'1-2 mots (incises, titres) -> trous ; à traiter (repli Kokoro ou fusion des incises). Inclut aussi du travail en cours antérieur (refacto backend LLM pluggable mlx/lmstudio, benchmark, ajustements frontend/API). Claude-Session: https://claude.ai/code/session_01XSVvcy1mfb4k1xDgib9vVU
This commit is contained in:
@@ -58,7 +58,7 @@ render → output/<titre>/NN-....mp3 (pipeline/render.py + audio/postproc
|
||||
### Deux niveaux de configuration (distinction importante)
|
||||
|
||||
- **`config.py`** : constantes figées lues à l'import, surchargeables **uniquement** par variables d'environnement au démarrage (`INKFLOW_*`). Chemins, IDs de modèles MLX par défaut, params audio.
|
||||
- **`settings.py`** : objet `Settings` **persisté** dans `data/settings.json`, éditable au runtime depuis l'UI. Contient aussi les **prompts système Gemma** (éditables). Le pipeline consulte `get_settings()` au moment de l'exécution. `save_settings()` invalide les caches modèles (`get_backend.cache_clear()`, `gemma._load.cache_clear()`) pour appliquer les changements **sans redémarrage**.
|
||||
- **`settings.py`** : objet `Settings` **persisté** dans `data/settings.json`, éditable au runtime depuis l'UI. Contient aussi les **prompts système Gemma** (éditables). Le pipeline consulte `get_settings()` au moment de l'exécution. `save_settings()` invalide les caches modèles (`get_backend.cache_clear()`, `analysis.llm.factory.reset_llm_cache()`) pour appliquer les changements **sans redémarrage**.
|
||||
|
||||
### Orchestration (UI temps réel)
|
||||
|
||||
@@ -83,6 +83,12 @@ Cette logique est **pure et testée** (`tests/test_incises.py`, 30+ cas sans Gem
|
||||
|
||||
`tts/base.py` définit `TTSBackend.synthesize(text, VoiceSpec) -> (audio mono float32, sample_rate)` et `VoiceSpec` (preset pour Kokoro, ref_audio/ref_text pour le clonage Qwen3). `tts/factory.get_backend(name)` est `lru_cache` par **nom** (pas par id de modèle — d'où l'invalidation explicite dans settings). `pipeline/render.py` construit des `RenderUnit` (mono ou multi-voix), où `glued_to_prev` réduit le silence pour les incises rattachées à la réplique précédente.
|
||||
|
||||
### LLM d'analyse pluggable
|
||||
|
||||
`analysis/llm/` suit le **même pattern que le TTS**. La façade `client.LLM` (anciennement `Gemma`) expose `generate`/`generate_json` consommés par tout le pipeline ; elle porte toute la logique agnostique du moteur (calcul des params depuis `Settings`, retrait de la pensée des modèles à raisonnement, extraction JSON tolérante — helpers dans `_text.py`, testés purs dans `tests/test_gemma_reasoning.py`). Sous elle, `base.LLMBackend.complete(messages, ...) -> str` (texte brut) a deux implémentations : **`mlx_backend`** (mlx-lm, défaut) et **`lmstudio_backend`** (API OpenAI locale de LM Studio, sert GGUF *et* MLX). Sélection par nom via `factory.get_llm_backend(backend, model_ref)` (`lru_cache`, `reset_llm_cache()` pour invalider). Backend choisi dans `settings.gemma_backend` (`mlx`/`lmstudio`), surchargeable par `--backend`/`--model` sur les commandes CLI `analyze`/`pronounce`/`cast`/`benchmark`. LM Studio doit tourner avec son serveur local actif (onglet Developer).
|
||||
|
||||
**Qui possède la config de génération ?** Les réglages `gemma_temperature`/`gemma_max_tokens`/`gemma_reasoning*` pilotent le backend **MLX** (seule source de config pour `mlx-lm`). Pour **LM Studio**, c'est la config du modèle **dans LM Studio** qui prime : par défaut (`settings.lmstudio_defer_config=True`) le backend **n'impose ni `temperature` ni `max_tokens`** dans la requête — imposer `max_tokens` tronquait la réponse des modèles à raisonnement (pensée non terminée → « aucun JSON »). Le **contexte** se règle aussi côté LM Studio (au chargement : `lms load <m> --context-length N` ou l'UI) — InkFlow ne peut pas le porter, d'où l'erreur « context length » si le modèle est JIT-chargé avec un contexte trop court pour un chapitre. Mettre `lmstudio_defer_config=False` pour réimposer les réglages InkFlow (benchmarks reproductibles). LM Studio sépare déjà la pensée (`reasoning_content`) de la réponse (`content`) : le backend ne renvoie que `content`.
|
||||
|
||||
## Fichiers de référence (vérité terrain pour l'attribution)
|
||||
|
||||
`data/<slug>/reference/chNN.json` contient des **versions corrigées à la main** de la sortie d'analyse `analysis/chNN.json` — **même schéma `ChapterAnalysis`** (`index`, `title`, `segments` avec `type`/`text`/`speaker`/`incises`). Ce sont des **fixtures de vérité terrain** servant à juger la qualité de la segmentation, des incises et de l'attribution des locuteurs : on compare la sortie réelle du pipeline à la référence.
|
||||
|
||||
Reference in New Issue
Block a user