> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Transmite diálogos en tiempo real

El WebSocket de Texto a Diálogo (`/v1/text-to-dialogue/stream-input`) mantiene una única conexión abierta mientras envías líneas de diálogo y recibes fragmentos de audio codificados en base64. Está diseñado únicamente para los modelos de diálogo **Eleven v3** y **Eleven v4** (`model_id` debe empezar por `eleven_v3` o `eleven_v4`).

> **Note**
>
> Esta guía trata sobre el WebSocket de **Texto a Diálogo**. Para **Flash**, **Multilingual v2** u otros
> modelos de TTS que no sean v3, usa el [WebSocket de TTS en tiempo real](/docs/es/eleven-api/guides/how-to/websockets/realtime-tts). Para ver un resumen comparativo de
> ambos protocolos, consulta [WebSockets de Texto a Voz y Texto a Diálogo ](/docs/es/eleven-api/guides/how-to/websockets/tts-vs-ttd-websockets).

## Requisitos

* Una cuenta de ElevenLabs con una clave de API ([autenticación](/docs/es/api-reference/authentication)).
* La clave de API debe tener permisos de `Text to Speech`.
* Python o Node.js instalados en tu equipo.

## Configuración

**`Python`**

```python Python
pip install python-dotenv websockets
```

**`TypeScript`**

```typescript TypeScript
npm install dotenv ws
npm install @types/dotenv @types/ws --save-dev
```

Crea un archivo `.env`:

**`.env`**

```bash .env
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here
```

Elige un **ID de voz** de la [Biblioteca de voces](https://elevenlabs.io/voice-library). Los ejemplos siguientes usan `eleven_v4_turbo`, que permite **una** voz registrada por conexión.

## Abre el WebSocket

Conéctate a `wss://api.elevenlabs.io/v1/text-to-dialogue/stream-input` con parámetros de consulta como `model_id` y `output_format`. Puedes enviar la clave de API en la cabecera `xi-api-key` o en el primer mensaje JSON (aquí se muestra en el cuerpo para seguir un mismo patrón en todos los lenguajes).

**`text-to-dialogue-websocket.py`**

```python text-to-dialogue-websocket.py
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"
)
```

**`text-to-dialogue-websocket.ts`**

```typescript text-to-dialogue-websocket.ts
import * as dotenv from "dotenv";
import * as fs from "node:fs";
import WebSocket from "ws";

dotenv.config();
const ELEVENLABS_API_KEY = process.env.ELEVENLABS_API_KEY;
const voiceId = "21m00Tcm4TlvDq8ikWAM";
const modelId = "eleven_v4_turbo";

const uri = `wss://api.elevenlabs.io/v1/text-to-dialogue/stream-input?model_id=${modelId}&output_format=mp3_44100_128`;
const websocket = new WebSocket(uri);

const outputDir = "./output";
try {
  fs.accessSync(outputDir, fs.constants.R_OK | fs.constants.W_OK);
} catch {
  fs.mkdirSync(outputDir);
}
const writeStream = fs.createWriteStream(`${outputDir}/dialogue-ws.mp3`, { flags: "a" });
```

## Registra voces y transmite texto

Envía un **primer mensaje** que incluya `voices` (obligatorio) y `xi_api_key` si no configuraste la cabecera `xi-api-key`. Después, envía uno o varios frames con `inputs`: cada elemento tiene `text`, `voice_id` y `new_turn` opcional.

El servidor almacena el texto en búfer hasta tener suficiente contexto (unos **40 caracteres** y **8 palabras**) y, a continuación, emite fragmentos de `audio`. Los campos de respuesta usan **snake_case** (por ejemplo, `is_final`).

**`text-to-dialogue-websocket.py`**

```python text-to-dialogue-websocket.py
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())
```

**`text-to-dialogue-websocket.ts`**

```typescript text-to-dialogue-websocket.ts
websocket.on("open", () => {
  websocket.send(
    JSON.stringify({
      voices: [voiceId],
      xi_api_key: ELEVENLABS_API_KEY,
    })
  );

  const 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. ";

  websocket.send(
    JSON.stringify({
      inputs: [{ text: line, voice_id: voiceId, new_turn: false }],
    })
  );

  websocket.send(JSON.stringify({ close_socket: true }));
});

websocket.on("message", (data) => {
  const msg = JSON.parse(data.toString());
  if (msg.error) {
    console.error(msg);
    return;
  }
  if (msg.audio) {
    writeToLocal(msg.audio, writeStream);
  }
});

function writeToLocal(base64str: string, stream: fs.WriteStream) {
  stream.write(Buffer.from(base64str, "base64"));
}

websocket.on("close", () => {
  writeStream.end();
});
```

`close_socket` envía cualquier texto que quede en el búfer, el audio restante y, después, un frame final con `is_final: true` antes de que se cierre la conexión. Para **mantener la conexión abierta** entre líneas, omite `close_socket` hasta que termine la sesión; usa `flush` para forzar audio con búferes más cortos sin cerrar.

## Ejecuta el script

**`Python`**

```python Python
python text-to-dialogue-websocket.py
```

**`TypeScript`**

```typescript TypeScript
npx tsx text-to-dialogue-websocket.ts
```

Deberías obtener un archivo MP3 en `output/` (con el nombre de archivo del ejemplo anterior).

## Notas sobre el funcionamiento

### Almacenamiento en búfer

A diferencia de `chunk_length_schedule` del WebSocket de TTS, la transmisión de diálogos usa un **umbral fijo del servidor** (número de caracteres y palabras) antes del primer audio parcial. Si envías líneas cortas y percibes retrasos, agrupa un poco más de texto por frame de `inputs` o envía `flush: true` para forzar la generación sin cerrar el socket.

### Turnos y voces

Configura `new_turn: true` cuando un hablante termine su turno para que la prosodia se reinicie correctamente. Cambiar `voice_id` entre entradas de `inputs` también inicia un nuevo turno. Con `eleven_v4_turbo`, registra **exactamente una** voz en `voices`; `eleven_v4` admite hasta **10** voces registradas.

### Inactividad

Si el servidor no recibe **ningún mensaje del cliente durante 20 segundos**, la conexión se cierra. Envía `{"keep_alive": true}` para reiniciar el temporizador sin sintetizar audio.

### Concurrencia

Cada conexión abierta mantiene una sesión de diálogo mientras permanezca abierta y procede de un grupo dedicado independiente del límite de concurrencia estándar de tu plan. El audio generado a través de la conexión no cuenta para la concurrencia estándar. Consulta la [concurrencia de Texto a Diálogo](/docs/es/overview/models#text-to-dialogue-concurrency).

### Alineación

Añade `sync_alignment=true` a la cadena de consulta para recibir objetos `alignment` (matrices de temporización en snake_case) en los fragmentos cuando estén disponibles. Consulta la [referencia de la API](/docs/es/api-reference/text-to-dialogue/ttd-websocket).

## Próximos pasos

#### [WebSockets de TTS y TTD](/docs/es/eleven-api/guides/how-to/websockets/tts-vs-ttd-websockets)

Elige el WebSocket adecuado y compara los formatos de los mensajes.

#### [WebSocket de Texto a Diálogo (API)](/docs/es/api-reference/text-to-dialogue/ttd-websocket)

Parámetros de consulta, esquemas de mensajes y ejemplos.

#### [Transmitir diálogo (HTTP)](/docs/es/api-reference/text-to-dialogue/stream)

Para cuando tienes disponible el texto completo de la solicitud sin usar un WebSocket.

#### [WebSocket de TTS en tiempo real](/docs/es/eleven-api/guides/how-to/websockets/realtime-tts)

Transmisión por WebSockets de una única voz que no sea v3.