Files
2026-04-07 22:06:36 +02:00

55 lines
1.6 KiB
Python

import base64
from mistralai.client import Mistral
from . import config
_client = Mistral(api_key=config.MISTRAL_API_KEY)
_default_voice_id: str | None = None
def _get_default_voice_id() -> str:
"""
Récupère et met en cache l'ID d'une voix preset.
Priorise les voix supportant la langue configurée (VOICE_LANGUAGE).
"""
global _default_voice_id
if _default_voice_id is not None:
return _default_voice_id
voices = _client.audio.voices.list(type_="preset", limit=50)
if not voices.items:
raise RuntimeError(
"Aucune voix disponible. Configurez VOICE_ID dans .env ou créez une voix "
"avec scripts/register_voice.py"
)
# Cherche une voix supportant la langue configurée
preferred_lang = config.VOICE_LANGUAGE
matching = [
v for v in voices.items
if v.languages and preferred_lang in v.languages
]
chosen = matching[0] if matching else voices.items[0]
_default_voice_id = chosen.id
print(f"[TTS] Voix sélectionnée : {chosen.name} (langues: {chosen.languages}) — id: {_default_voice_id}")
return _default_voice_id
def text_to_speech(text: str, voice_id: str | None = None) -> bytes:
"""
Convertit du texte en audio WAV via Voxtral TTS.
WAV est lu nativement par aplay (Linux) et afplay (macOS) sans conversion.
"""
effective_voice_id = voice_id or config.VOICE_ID or _get_default_voice_id()
response = _client.audio.speech.complete(
model=config.TTS_MODEL,
input=text,
voice_id=effective_voice_id,
response_format="wav",
)
return base64.b64decode(response.audio_data)