Files
InkFlow/backend/inkflow/config.py

97 lines
3.6 KiB
Python

"""Configuration centrale d'InkFlow.
Toutes les constantes (chemins, identifiants de modeles MLX, parametres par
defaut) sont regroupees ici pour rester facilement surchargeables via variables
d'environnement.
"""
from __future__ import annotations
import os
from pathlib import Path
# --- Racines du projet -------------------------------------------------------
# config.py est dans backend/inkflow/, la racine projet est donc deux niveaux
# au-dessus de backend/.
BACKEND_DIR = Path(__file__).resolve().parents[1]
PROJECT_ROOT = BACKEND_DIR.parent
def _env_path(var: str, default: Path) -> Path:
return Path(os.environ.get(var, default)).expanduser().resolve()
# Donnees de travail (etat par livre : json, db, wav intermediaires)
DATA_DIR = _env_path("INKFLOW_DATA_DIR", PROJECT_ROOT / "data")
# Sortie finale (1 dossier par livre, 1 mp3 par chapitre)
OUTPUT_DIR = _env_path("INKFLOW_OUTPUT_DIR", PROJECT_ROOT / "output")
# Banque de voix de reference (clips + metadata.json)
VOICEBANK_DIR = _env_path("INKFLOW_VOICEBANK_DIR", PROJECT_ROOT / "voicebank")
# Echantillons fournis
SAMPLES_DIR = PROJECT_ROOT / "samples"
# --- Modeles MLX (HuggingFace mlx-community) ---------------------------------
# Analyse de texte : Gemma via mlx-lm.
GEMMA_MODEL = os.environ.get(
"INKFLOW_GEMMA_MODEL", "mlx-community/gemma-3-4b-it-4bit"
)
# TTS : Qwen3-TTS (rendu final, clonage) et Kokoro (preview rapide).
QWEN3_TTS_MODEL = os.environ.get(
"INKFLOW_QWEN3_MODEL", "mlx-community/Qwen3-TTS-12Hz-1.7B-Base-8bit"
)
KOKORO_MODEL = os.environ.get(
"INKFLOW_KOKORO_MODEL", "mlx-community/Kokoro-82M-bf16"
)
# --- Parametres TTS ----------------------------------------------------------
DEFAULT_LANGUAGE = os.environ.get("INKFLOW_LANGUAGE", "French")
# Code langue Kokoro (misaki) : 'f' = francais.
KOKORO_LANG_CODE = os.environ.get("INKFLOW_KOKORO_LANG", "f")
# Voix Kokoro par defaut pour les previews / mono-narrateur rapide.
KOKORO_DEFAULT_VOICE = os.environ.get("INKFLOW_KOKORO_VOICE", "ff_siwis")
# Voix Qwen3 par defaut (narrateur) si aucun clip de reference fourni.
QWEN3_DEFAULT_VOICE = os.environ.get("INKFLOW_QWEN3_VOICE", "Chelsie")
# Frequence d'echantillonnage cible pour la concatenation (Hz). Les backends
# renvoient leur propre sr ; postprocess reechantillonne au besoin.
TARGET_SAMPLE_RATE = int(os.environ.get("INKFLOW_SAMPLE_RATE", "24000"))
# Encodage mp3 final.
MP3_BITRATE = os.environ.get("INKFLOW_MP3_BITRATE", "128k")
# Cible de normalisation loudness (LUFS approx via pydub gain).
TARGET_DBFS = float(os.environ.get("INKFLOW_TARGET_DBFS", "-18.0"))
def book_data_dir(book_slug: str) -> Path:
"""Dossier de travail pour un livre (artefacts intermediaires)."""
return DATA_DIR / book_slug
def book_output_dir(book_title: str) -> Path:
"""Dossier de sortie final pour un livre (mp3 par chapitre)."""
return OUTPUT_DIR / book_title
def ensure_dirs() -> None:
for d in (DATA_DIR, OUTPUT_DIR, VOICEBANK_DIR):
d.mkdir(parents=True, exist_ok=True)
def setup_espeak() -> None:
"""Localise libespeak-ng pour phonemizer (requis par Kokoro non-anglais).
phonemizer ne trouve pas toujours la lib installee via brew ; on pointe
explicitement PHONEMIZER_ESPEAK_LIBRARY si la variable n'est pas deja fixee.
"""
if os.environ.get("PHONEMIZER_ESPEAK_LIBRARY"):
return
candidates = [
"/opt/homebrew/lib/libespeak-ng.dylib",
"/usr/local/lib/libespeak-ng.dylib",
"/opt/homebrew/lib/libespeak-ng.1.dylib",
]
for path in candidates:
if os.path.exists(path):
os.environ["PHONEMIZER_ESPEAK_LIBRARY"] = path
return