Przesyłaj dialog w czasie rzeczywistym

Ten przewodnik pokazuje, jak przesyłać audio dialogu Eleven v3 przez WebSocket Text to Dialogue.

WebSocket Text to Dialogue (/v1/text-to-dialogue/stream-input) utrzymuje jedno połączenie otwarte, gdy wysyłasz kwestie dialogowe i odbierasz fragmenty audio zakodowane w base64. Jest przeznaczony wyłącznie dla modeli dialogowych Eleven v3 i Eleven v4 (model_id musi zaczynać się od eleven_v3 lub eleven_v4).

Ten przewodnik dotyczy WebSocketu Text to Dialogue. Dla modeli Flash, Multilingual v2 lub innych modeli TTS spoza v3 użyj WebSocketu Realtime TTS . Porównanie obu protokołów znajdziesz w WebSockety Text to Speech i Text to Dialogue .

Wymagania

  • Konto ElevenLabs z kluczem API (uwierzytelnianie).
  • Klucz API musi mieć uprawnienia Text to Speech.
  • Python lub Node.js zainstalowany na komputerze.

Konfiguracja

pip install python-dotenv websockets

Utwórz plik .env:

.env
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here

Wybierz ID głosu z Voice Library. Poniższe przykłady używają eleven_v4_turbo, który pozwala na jeden zarejestrowany głos na połączenie.

Otwórz WebSocket

Połącz się z wss://api.elevenlabs.io/v1/text-to-dialogue/stream-input, używając parametrów zapytania takich jak model_id i output_format. Klucz API możesz wysłać w nagłówku xi-api-key albo w pierwszej wiadomości JSON (tutaj pokazano go w treści, aby zachować jeden schemat we wszystkich językach).

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"
)

Zarejestruj głosy i przesyłaj tekst

Wyślij pierwszą wiadomość zawierającą voices (wymagane) oraz xi_api_key, jeśli nie ustawiono nagłówka xi-api-key. Następnie wyślij jedną lub więcej ramek z inputs: każdy element zawiera text, voice_id i opcjonalne new_turn.

Serwer buforuje tekst, aż będzie mieć dość kontekstu (około 40 znaków i 8 słów), a potem wysyła fragmenty audio. Pola odpowiedzi używają formatu snake_case (na przykład 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 opróżnia bufor tekstu, wysyła pozostałe audio, a następnie końcową ramkę z is_final: true, zanim połączenie zostanie zamknięte. Aby utrzymać połączenie otwarte między kwestiami, pomiń close_socket do końca sesji; użyj flush, aby wymusić audio dla krótszych buforów bez zamykania połączenia.

Uruchom skrypt

python text-to-dialogue-websocket.py

Plik MP3 znajdziesz w output/ (z nazwą jak w przykładzie powyżej).

Uwagi o działaniu

Buforowanie

W przeciwieństwie do chunk_length_schedule w WebSockecie TTS, przesyłanie dialogu używa stałego progu serwera (liczby znaków i słów) przed pierwszym częściowym audio. Jeśli wysyłasz krótkie kwestie i słyszysz opóźnienia, grupuj nieco więcej tekstu w każdej ramce inputs lub wyślij flush: true, aby wymusić generowanie bez zamykania połączenia.

Tury i głosy

Ustaw new_turn: true, gdy rozmówca kończy turę, aby płynnie zresetować prozodię. Zmiana voice_id między wpisami inputs także rozpoczyna nową turę. W przypadku eleven_v4_turbo zarejestruj dokładnie jeden głos w voices; eleven_v4 obsługuje do 10 zarejestrowanych głosów.

Brak aktywności

Jeśli serwer nie otrzyma wiadomości od klienta przez 20 sekund, połączenie zostanie zakończone. Wyślij {"keep_alive": true}, aby zresetować licznik bez syntezy audio.

Równoczesność

Każde otwarte połączenie utrzymuje jedną sesję dialogową tak długo, jak pozostaje otwarte, i korzysta z wydzielonej puli niezależnej od standardowego limitu równoczesności w twoim planie. Audio generowane przez połączenie nie wlicza się do standardowego limitu równoczesności. Zobacz równoczesność Text to Dialogue.

Wyrównanie

Dodaj sync_alignment=true do parametrów zapytania, aby otrzymywać obiekty alignment (tablice czasowe w formacie snake_case) w fragmentach, gdy są dostępne. Zobacz dokumentację API.

Kolejne kroki