55 lines
1.6 KiB
Python
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)
|