Diffusez des dialogues en temps réel

Ce guide explique comment diffuser l'audio de dialogue Eleven v3 via le WebSocket Text to Dialogue.

Le WebSocket Text to Dialogue (/v1/text-to-dialogue/stream-input) maintient une connexion unique ouverte pendant que vous envoyez des lignes de dialogue et recevez des segments audio encodés en base64. Il est destiné uniquement aux modèles de dialogue Eleven v3 et Eleven v4 (model_id doit commencer par eleven_v3 ou eleven_v4).

Ce guide couvre le WebSocket Text to Dialogue. Pour les modèles TTS Flash, Multilingual v2 ou autres modèles non v3, utilisez le WebSocket TTS en temps réel . Pour un résumé comparatif des deux protocoles, consultez WebSockets Text to Speech et Text to Dialogue .

Prérequis

  • Un compte ElevenLabs avec une clé API (authentification).
  • La clé API doit disposer des autorisations Text to Speech.
  • Python ou Node.js installé sur votre machine.

Configuration

pip install python-dotenv websockets

Créez un fichier .env :

.env
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here

Choisissez un ID de voix dans la Voice Library. Les exemples ci-dessous utilisent eleven_v4_turbo, qui autorise une voix enregistrée par connexion.

Ouvrir le WebSocket

Connectez-vous à wss://api.elevenlabs.io/v1/text-to-dialogue/stream-input avec des paramètres de requête tels que model_id et output_format. Vous pouvez envoyer la clé API dans l’en-tête xi-api-key ou dans le premier message JSON (présenté ici dans le corps afin d’utiliser un modèle unique dans toutes les langues).

import asyncio
import base64
import json
import os
from dotenv import load_dotenv
import websockets
load_dotenv()
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
VOICE_ID = "21m00Tcm4TlvDq8ikWAM"
MODEL_ID = "eleven_v4_turbo"
URI = (
"wss://api.elevenlabs.io/v1/text-to-dialogue/stream-input"
f"?model_id={MODEL_ID}&output_format=mp3_44100_128"
)

Enregistrer des voix et diffuser du texte

Envoyez un premier message incluant voices (obligatoire) et xi_api_key si vous n’avez pas défini l’en-tête xi-api-key. Envoyez ensuite une ou plusieurs trames avec inputs : chaque élément contient text, voice_id et, éventuellement, new_turn.

Le serveur met le texte en mémoire tampon jusqu’à disposer d’un contexte suffisant (environ 40 caractères et 8 mots), puis émet des segments audio. Les champs de réponse utilisent le snake_case (par exemple, is_final).

async def stream_dialogue():
async with websockets.connect(URI) as websocket:
await websocket.send(
json.dumps(
{
"voices": [VOICE_ID],
"xi_api_key": ELEVENLABS_API_KEY,
}
)
)
line = (
"This is a longer line of dialogue used to exceed the minimum buffer so the model "
"starts generating streamed audio for the registered voice. "
)
await websocket.send(
json.dumps(
{
"inputs": [
{"text": line, "voice_id": VOICE_ID, "new_turn": False},
],
}
)
)
await websocket.send(json.dumps({"close_socket": True}))
os.makedirs("output", exist_ok=True)
out_path = "output/dialogue-ws.mp3"
with open(out_path, "wb") as audio_file:
while True:
raw = await websocket.recv()
msg = json.loads(raw)
if msg.get("error"):
raise RuntimeError(msg)
if msg.get("audio"):
audio_file.write(base64.b64decode(msg["audio"]))
if msg.get("is_final"):
break
print(f"Wrote {out_path}")
asyncio.run(stream_dialogue())

close_socket envoie tout texte en mémoire tampon, les données audio restantes, puis une trame finale avec is_final: true avant la fermeture de la connexion. Pour maintenir la connexion ouverte entre les lignes, omettez close_socket jusqu’à la fin de la session ; utilisez flush pour forcer l’audio pour des mémoires tampons plus courtes sans fermer la connexion.

Exécuter le script

python text-to-dialogue-websocket.py

Vous devriez obtenir un fichier MP3 dans output/ (avec le nom de fichier indiqué dans l’exemple ci-dessus).

Notes sur le comportement

Mise en mémoire tampon

Contrairement à chunk_length_schedule du WebSocket TTS, le streaming de dialogue utilise un seuil serveur fixe (nombre de caractères et de mots) avant le premier audio partiel. Si vous envoyez des lignes courtes et constatez des délais, regroupez un peu plus de texte par trame inputs ou envoyez flush: true pour forcer la génération sans fermer le socket.

Tours de parole et voix

Définissez new_turn: true lorsqu’un interlocuteur termine son tour de parole afin de réinitialiser correctement la prosodie. Modifier voice_id entre des entrées inputs démarre également un nouveau tour. Avec eleven_v4_turbo, enregistrez exactement une voix dans voices ; eleven_v4 prend en charge jusqu’à 10 voix enregistrées.

Inactivité

Si le serveur ne reçoit aucun message client pendant 20 secondes, la connexion prend fin. Envoyez {"keep_alive": true} pour réinitialiser le minuteur sans synthétiser d’audio.

Requêtes simultanées

Chaque connexion ouverte conserve une session de dialogue tant qu’elle reste ouverte. Elle est issue d’un pool dédié, distinct de la limite standard de requêtes simultanées de votre forfait. L’audio généré via la connexion n’est pas comptabilisé dans les requêtes simultanées standard. Consultez Requêtes simultanées pour Text to Dialogue.

Alignement

Ajoutez sync_alignment=true à la chaîne de requête pour recevoir des objets alignment (tableaux de minutage en snake_case) dans les segments lorsqu’ils sont disponibles. Consultez le Guide de l’API.

Étapes suivantes