ITSkillsCenter
Intelligence Artificielle

ElevenLabs Flash v2.5 : synthèse vocale temps réel en Python

9 min de lecture

📍 Guide principal de la série : Agents vocaux IA en 2026 : architecture, modèles, latence.

Eleven Flash v2.5 affiche 75 millisecondes de time-to-first-audio sur 32 langues, à 0,05 USD pour mille caractères. C’est le moteur TTS le plus utilisé en production en 2026 dès qu’on cherche un compromis qualité-latence-prix raisonnable. Ce tutoriel câble Flash v2.5 dans une chaîne d’agent vocal Python : appel REST, streaming WebSocket pour la voix temps réel, choix de la voix, intégration dans LiveKit Agents et mesure réelle de la latence sur votre poste.

Prérequis

  • Python 3.10+ avec un environnement virtuel
  • Un compte ElevenLabs (l’offre Free permet de tester ; Creator à environ 22 USD/mois pour la production légère)
  • Une clé API ElevenLabs active
  • Une sortie audio fonctionnelle (haut-parleur ou casque)
  • FFmpeg installé pour le décodage audio (brew install ffmpeg, apt install ffmpeg ou équivalent)
  • Niveau attendu : Python intermédiaire, notions de WebSocket et asyncio
  • Temps estimé : 45 minutes

Étape 1 — Récupérer la clé API et installer le SDK

ElevenLabs publie un SDK Python officiel qui encapsule à la fois les appels REST et le streaming WebSocket. La clé API se génère dans Profile → API Keys du tableau de bord ; elle commence par xi_ et reste secrète.

python -m venv .venv && source .venv/bin/activate
pip install --upgrade elevenlabs
pip install python-dotenv
echo "ELEVENLABS_API_KEY=xi_xxxxxxxxxxxx" >> .env

Le SDK installe en cascade websockets, requests et un module utilitaire play qui passe par FFmpeg pour la lecture locale. Vérifier que tout est en place : python -c "from elevenlabs.client import ElevenLabs; print('ok')" ne doit afficher aucune erreur. Si une erreur d’import remonte, c’est presque toujours qu’on a oublié l’environnement virtuel ou qu’on tourne sur un Python < 3.10.

Étape 2 — Premier appel REST en synthèse simple

L’appel le plus basique génère un MP3 complet à partir d’un texte court. C’est pratique pour générer des fichiers à la volée (annonces, voicemail, sous-titres audio), mais inadapté à un agent vocal puisqu’on attend la fin de génération avant de jouer le moindre son.

# tts_simple.py
import os
from dotenv import load_dotenv
from elevenlabs.client import ElevenLabs
from elevenlabs import play

load_dotenv()
client = ElevenLabs(api_key=os.environ["ELEVENLABS_API_KEY"])

audio = client.text_to_speech.convert(
    text="Bonjour, je suis Aïda, votre assistante vocale.",
    voice_id="21m00Tcm4TlvDq8ikWAM",      # voix "Rachel" par défaut
    model_id="eleven_flash_v2_5",
    output_format="mp3_44100_128",
)
play(audio)

21m00Tcm4TlvDq8ikWAM est l’identifiant public de la voix Rachel — pratique pour le démarrage. eleven_flash_v2_5 est le modèle Flash v2.5, optimisé pour la latence ; ses alternatives sont eleven_v3 (qualité maximale, 70+ langues, latence supérieure) et eleven_multilingual_v2 (qualité haute, 29 langues). Le modèle eleven_turbo_v2_5 est désormais déprécié et remplacé par Flash v2.5. Sur cette première exécution, on doit entendre la phrase prononcée 1 à 2 secondes après le lancement du script — la majorité du temps étant la génération complète du MP3 et son décodage par FFmpeg.

Étape 3 — Streaming pour entendre l’audio dès les premières syllabes

Pour un agent vocal, ce qui compte c’est le time-to-first-audio : combien de temps après l’envoi du texte on commence à entendre quelque chose. Le SDK propose text_to_speech.stream() qui retourne un générateur de chunks audio qu’on peut envoyer directement vers la sortie audio ou vers le client WebRTC.

# tts_stream.py
import os, time
from dotenv import load_dotenv
from elevenlabs.client import ElevenLabs
from elevenlabs import stream

load_dotenv()
client = ElevenLabs(api_key=os.environ["ELEVENLABS_API_KEY"])

t0 = time.perf_counter()
audio_stream = client.text_to_speech.stream(
    text="Bonjour, je suis Aïda, votre assistante vocale.",
    voice_id="21m00Tcm4TlvDq8ikWAM",
    model_id="eleven_flash_v2_5",
    output_format="mp3_44100_128",
)
first = True
for chunk in audio_stream:
    if first:
        print(f"TTFA: {(time.perf_counter()-t0)*1000:.0f} ms")
        first = False
stream(audio_stream)

Sur une connexion européenne moyenne, le premier chunk arrive entre 150 et 250 ms après l’envoi du texte (la fameuse latence de 75 ms est mesurée côté serveur, à laquelle s’ajoute le RTT réseau et le SDK overhead). On entend la voix avant la fin de la génération de la phrase, ce qui donne à l’agent l’impression d’être réellement réactif. Pour un agent vocal en production, cette mesure de TTFA est la métrique opérationnelle clé : tout dépassement systématique au-dessus de 350 ms doit déclencher une alerte.

Étape 4 — WebSocket bidirectionnel pour l’agent vocal

Le streaming REST suffit quand on connaît tout le texte d’avance. Pour un agent vocal, la phrase est produite par le LLM token par token, et on veut envoyer chaque token au TTS dès qu’il est disponible. C’est le rôle du WebSocket stream-input : on garde la connexion ouverte et on push le texte au fur et à mesure.

# tts_ws.py
import asyncio, json, os, base64, time
import websockets
from dotenv import load_dotenv

load_dotenv()
API_KEY = os.environ["ELEVENLABS_API_KEY"]
VOICE   = "21m00Tcm4TlvDq8ikWAM"
URI = (
    f"wss://api.elevenlabs.io/v1/text-to-speech/{VOICE}/stream-input"
    f"?model_id=eleven_flash_v2_5&output_format=pcm_16000"
)

async def speak_streaming(token_iter):
    async with websockets.connect(URI) as ws:
        # message d'init obligatoire
        await ws.send(json.dumps({
            "text": " ",
            "voice_settings": {"stability": 0.4, "similarity_boost": 0.75},
            "xi_api_key": API_KEY,
        }))
        async def sender():
            async for tok in token_iter:
                await ws.send(json.dumps({"text": tok}))
            await ws.send(json.dumps({"text": ""}))   # flush
        async def receiver():
            t0 = time.perf_counter()
            first = True
            async for raw in ws:
                msg = json.loads(raw)
                if msg.get("audio"):
                    if first:
                        print(f"TTFA WS: {(time.perf_counter()-t0)*1000:.0f} ms")
                        first = False
                    pcm = base64.b64decode(msg["audio"])
                    yield pcm
                if msg.get("isFinal"):
                    break
        await asyncio.gather(sender(), receiver().__anext__())

Trois points importants. Le message d’init avec un espace simple est obligatoire pour ouvrir la session ; les voice_settings y sont fixés une fois pour toute la session. La sortie pcm_16000 évite le décodage MP3 et fait économiser 30 à 50 ms côté client : c’est le format qu’attend la plupart des transports WebRTC. L’envoi d’un texte vide {"text":""} signale au serveur qu’on a fini d’envoyer du texte et qu’il peut clôturer la génération. En production, le TTFA via WebSocket descend à 100-180 ms quand le LLM streame phrase par phrase.

Étape 5 — Choisir et personnaliser la voix

Le catalogue ElevenLabs offre plus de 5 000 voix communautaires plus toutes celles que vous clonez vous-même. Pour un agent vocal francophone, deux options se présentent : choisir une voix existante au timbre francophone, ou cloner une voix sur 5 minutes d’enregistrement.

from elevenlabs.client import ElevenLabs
client = ElevenLabs(api_key=os.environ["ELEVENLABS_API_KEY"])

# 1) Lister les voix disponibles
for v in client.voices.get_all().voices:
    print(v.voice_id, v.name, v.labels)

# 2) Cloner une voix à partir d'un fichier audio
cloned = client.voices.add(
    name="Aida-Senegal",
    files=["voix_locuteur_5min.wav"],
    description="Voix féminine francophone, ton chaleureux, 28 ans",
)
print("Voice ID :", cloned.voice_id)

Le clonage prend une trentaine de secondes côté serveur. Une fois cloné, la voix est immédiatement utilisable avec son voice_id dans toutes les méthodes vues précédemment. Pour la qualité, viser un enregistrement studio sur 5 à 10 minutes plutôt que 30 secondes : le modèle apprend la prosodie aussi bien que le timbre, et un échantillon long capte mieux les variations de débit et d’intonation.

Étape 6 — Régler stability et similarity pour la cohérence

Deux paramètres principaux gouvernent la régularité de la voix synthétisée. stability contrôle la variabilité de la prosodie : à 0,1 la voix devient très expressive mais peut dévier ; à 0,9 elle est monotone mais reproductible. similarity_boost renforce la fidélité au timbre original au prix d’un léger artefact métallique.

voice_settings = {
    "stability":         0.4,    # 0.3-0.5 pour la conversation
    "similarity_boost":  0.75,   # 0.7-0.85 pour les voix clonées
    "style":             0.0,    # 0 = neutre, > 0 amplifie l'émotion
    "use_speaker_boost": True,
}

La combinaison qui fonctionne le mieux pour la conversation 1-1 est stability 0,4 / similarity 0,75 : suffisamment d’expressivité pour ne pas paraître robotique, suffisamment stable pour ne pas dériver en milieu de phrase. Pour un narrateur ou une voix-off, monter stability à 0,7 et baisser similarity_boost à 0,5. style au-dessus de 0,3 amplifie les émotions perçues mais augmente sensiblement la latence — à éviter en temps réel.

Étape 7 — Brancher Flash v2.5 dans LiveKit Agents

Une fois l’API maîtrisée, l’intégration dans LiveKit Agents tient en deux lignes : un pip install du plugin et un elevenlabs.TTS(...) dans la session. L’avantage de passer par le plugin officiel est qu’il gère la conversion de format, le cache et la gestion d’erreurs.

pip install "livekit-plugins-elevenlabs"
from livekit.plugins import elevenlabs

session = AgentSession(
    stt=openai.STT(model="gpt-4o-mini-transcribe", language="fr"),
    llm=openai.LLM(model="gpt-4o-mini"),
    tts=elevenlabs.TTS(
        voice_id="21m00Tcm4TlvDq8ikWAM",
        model_id="eleven_flash_v2_5",
        voice_settings=elevenlabs.VoiceSettings(stability=0.4, similarity_boost=0.75),
    ),
    vad=silero.VAD.load(),
)

Le plugin se branche en lieu et place du openai.TTS du tutoriel précédent. La latence end-to-end perçue par l’utilisateur baisse en général de 150 à 250 ms par rapport à OpenAI TTS, ce qui fait franchir la barre symbolique des 800 ms à la plupart des agents en pipeline standard. Côté logs, on observe que la première trame audio sort vers 150-200 ms après le premier token LLM — soit pratiquement la latence pure du modèle Flash v2.5.

Erreurs fréquentes

Symptôme Cause Solution
HTTP 401 sur tous les appels Clé API mal recopiée ou expirée Régénérer la clé dans Profile → API Keys
HTTP 429 en pic Quota du plan dépassé Passer au plan supérieur ou throttler côté client
Latence TTFA > 500 ms Format MP3 + décodage local Demander pcm_16000 et streamer brut
Voix qui dérive en milieu de phrase stability trop faible Remonter à 0,5-0,6
Clip métallique sur les sifflantes similarity_boost à 1,0 Redescendre à 0,7-0,8
Coupures audio en streaming Buffer client trop petit Buffer 200 ms minimum côté lecteur

Pour explorer plus loin

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité