> 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.

# Início rápido do Speech Engine

Este guia mostra como criar um agente com voz usando o Speech Engine. Você configura um servidor que conecta seu LLM à ElevenLabs e, depois, integra um cliente de navegador para que os usuários possam ter conversas por voz com seu agente.

> **Tip**
>
> Use a [skill do ElevenLabs Speech Engine](https://github.com/elevenlabs/skills/tree/main/speech-engine) para adicionar voz ao seu agente de chat:
>
> ```bash
> npx skills add elevenlabs/skills --skill speech-engine
> ```

## Como o Speech Engine funciona

O Speech Engine conecta seu LLM à ElevenLabs para que os usuários possam falar com seu agente e ouvir as respostas dele. A ElevenLabs processa a conversão de voz em texto e de texto em voz; seu servidor fornece a lógica do LLM.

```mermaid
sequenceDiagram
    participant Browser
    participant ElevenLabs

    box Your Server
        participant SDK as Speech Engine SDK
        participant LLM
    end

    Browser->>ElevenLabs: User speaks (audio)
    ElevenLabs->>SDK: Transcript (WebSocket)
    SDK->>LLM: Conversation history
    LLM->>SDK: Streamed response
    SDK->>ElevenLabs: Text chunks
    ElevenLabs->>Browser: Agent speaks (audio)
```

Cada conexão WebSocket representa uma conversa. Quando o usuário fala, a ElevenLabs transcreve o áudio e envia a transcrição para seu servidor. Seu servidor a encaminha ao LLM e, em seguida, transmite a resposta de volta. A ElevenLabs converte o texto em voz e o reproduz no navegador. O SDK gerencia a conexão, os turnos de fala e a detecção de interrupções.

## Pré-requisitos

Este tutorial usa a API da OpenAI para o LLM. Você precisa ter uma chave de API da OpenAI definida na variável de ambiente `OPENAI_API_KEY`.

## Configuração do servidor

#### Crie uma chave de API

[Crie uma chave de API no painel aqui](https://elevenlabs.io/app/settings/api-keys), que você usará para [acessar a API](/docs/pt/api-reference/authentication) com segurança.

Armazene a chave como um segredo gerenciado e passe-a aos SDKs como uma variável de ambiente por meio de um arquivo `.env` ou diretamente na configuração do seu app, conforme sua preferência.

**`.env`**

```js title=".env"
ELEVENLABS_API_KEY=<your_api_key_here>
```

#### Instale as dependências

```python
pip install elevenlabs openai python-dotenv
```

```typescript
npm install @elevenlabs/elevenlabs-js openai
```

#### Exponha o servidor

O Speech Engine precisa de uma URL acessível publicamente. Use o [ngrok](https://ngrok.com) para expor seu servidor local. O servidor ainda não foi criado, mas o ngrok precisa estar em execução primeiro para que você tenha a URL para a próxima etapa.

```bash
ngrok http 3001
```

Copie a URL de encaminhamento (por exemplo, `https://abc123.ngrok.io`).

#### Crie uma instância do Speech Engine

Use o SDK para criar uma instância do Speech Engine, passando sua URL do ngrok com o caminho `/ws` adicionado como URL do WebSocket.

**`create_engine.py`**

```python title="create_engine.py"
import asyncio
from dotenv import load_dotenv
from elevenlabs import AsyncElevenLabs

load_dotenv()

elevenlabs = AsyncElevenLabs(
    api_key=os.getenv("ELEVENLABS_API_KEY"),
)


async def main():
    engine = await elevenlabs.speech_engine.create(
        name="My Speech Engine",
        speech_engine={
            # Note we use the wss protocol instead of https
            "ws_url": "wss://abc123.ngrok.io/ws",
        },
    )

    print(f"Speech Engine ID: {engine.engine_id}")


if __name__ == "__main__":
    asyncio.run(main())
```

**`create-engine.mts`**

```typescript title="create-engine.mts"
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";

const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});

const engine = await elevenlabs.speechEngine.create({
  name: "My Speech Engine",
  speechEngine: {
    // Note we use the wss protocol instead of https
    wsUrl: "wss://abc123.ngrok.io/ws",
  },
});

console.log("Speech Engine ID:", engine.engineId);
```

Execute este script e copie o ID do Speech Engine (por exemplo, `seng_8k3m9xr4hjnfg983brhmhkd98n6`) para a próxima etapa.

#### Crie o servidor

Crie um arquivo chamado `server.py` ou `server.mts` com o conteúdo a seguir. Isso configura um servidor, conecta o Speech Engine no caminho `/ws` e usa a OpenAI para gerar respostas.

**`server.py`**

```python maxLines=0 title="server.py"
import asyncio
import os

from dotenv import load_dotenv
from openai import AsyncOpenAI
from elevenlabs import AsyncElevenLabs

load_dotenv()

# Replace with your Speech Engine ID from step 4
SPEECH_ENGINE_ID = "seng_8k3m9xr4hjnfg983brhmhkd98n6"

openai = AsyncOpenAI(
  api_key=os.getenv("OPENAI_API_KEY"),
)
elevenlabs = AsyncElevenLabs(
  api_key=os.getenv("ELEVENLABS_API_KEY"),
)


def on_init(conversation_id, session):
    print(f"Session started: {conversation_id}")


async def on_transcript(transcript, session):
    stream = await openai.responses.create(
        model="gpt-4o",
        instructions="You are a helpful voice assistant. Keep responses concise and conversational.",
        input=[
            {"role": "assistant" if m.role == "agent" else m.role, "content": m.content}
            for m in transcript
        ],
        stream=True,
    )

    await session.send_response(stream)


def on_close(session):
    print(f"Session ended: {session.conversation_id}")


def on_error(err, session):
    print(f"Error: {err}")


async def main():
    engine = await elevenlabs.speech_engine.get(SPEECH_ENGINE_ID)

    await engine.serve(
        port=3001,
        path="/ws",
        debug=True,
        on_init=on_init,
        on_transcript=on_transcript,
        on_close=on_close,
        on_error=on_error,
    )


if __name__ == "__main__":
    asyncio.run(main())
```

**`server.mts`**

```typescript maxLines=0 title="server.mts"
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createServer } from "node:http";
import OpenAI from "openai";
import "dotenv/config";

// Replace with your Speech Engine ID from step 4
const SPEECH_ENGINE_ID = "seng_8k3m9xr4hjnfg983brhmhkd98n6";

const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const httpServer = createServer();

await elevenlabs.speechEngine.attach(SPEECH_ENGINE_ID, httpServer, "/ws", {
  debug: true,

  onInit(conversationId) {
    console.log("Session started:", conversationId);
  },

  async onTranscript(transcript, signal, session) {
    const response = await openai.responses.create(
      {
        model: "gpt-4o",
        instructions:
          "You are a helpful voice assistant. Keep responses concise and conversational.",
        input: transcript.map((m) => ({
          role: m.role === "agent" ? "assistant" : m.role,
          content: m.content,
        })),
        stream: true,
      },
      { signal },
    );

    session.sendResponse(response);
  },

  onClose(session) {
    console.log("Session ended:", session.conversationId);
  },

  onError(err) {
    console.error("Error:", err);
  },
});

httpServer.listen(3001, () => {
  console.log("Speech Engine server listening on port 3001");
});
```

O callback `onTranscript` / `on_transcript` recebe o histórico completo da conversa e a sessão atual. O SDK TypeScript também fornece um `AbortSignal` que é acionado se o usuário interromper durante uma resposta. Passar `signal` para a chamada da OpenAI cancela automaticamente a solicitação ao LLM em caso de interrupção.

`sendResponse()` / `send_response()` aceita uma string, um iterável assíncrono ou um stream da OpenAI, Anthropic ou Google Gemini. O SDK extrai o conteúdo de texto automaticamente.

> **Warning**
>
> No exemplo acima, a transcrição completa do usuário é enviada ao LLM. Em um ambiente de produção, adicione proteções para evitar tentativas de injeção ou manipulação de prompts.

#### Inicie o servidor

```python
python server.py
```

```typescript
npx tsx server.mts
```

## Configuração do cliente

#### Instale o SDK do cliente

#### React

```bash
npm install @elevenlabs/react
```

#### JavaScript

```bash
npm install @elevenlabs/client
```

#### Crie um endpoint de token

Adicione um endpoint no servidor que gere um token de conversa. Isso mantém sua chave de API fora do navegador e usa WebRTC para obter a melhor qualidade de áudio.

**`token_server.py`**

```python title="token_server.py"
import os

from dotenv import load_dotenv
from flask import Flask, jsonify
from elevenlabs import ElevenLabs

load_dotenv()

app = Flask(__name__)
elevenlabs = ElevenLabs(
    api_key=os.getenv("ELEVENLABS_API_KEY"),
)


@app.route("/api/token")
def get_token():
    # Replace with your Speech Engine ID from step 4 of the server setup
    speech_engine_id = "seng_8k3m9xr4hjnfg983brhmhkd98n6"

    response = elevenlabs.conversational_ai.conversations.get_webrtc_token(
        agent_id=speech_engine_id,
    )

    return jsonify(token=response.token)


if __name__ == "__main__":
    app.run(port=3002)
```

**`token-server.mts`**

```typescript title="token-server.mts"
import express from "express";
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";

const app = express();
const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});

app.get("/api/token", async (req, res) => {
  // Replace with your Speech Engine ID from step 4 of the server setup
  const speechEngineId = "seng_8k3m9xr4hjnfg983brhmhkd98n6";

  const response = await elevenlabs.conversationalAi.conversations.getWebrtcToken({
    agentId: speechEngineId,
  });

  res.json({ token: response.token });
});

app.listen(3002, () => {
  console.log("Token server listening on port 3002");
});
```

#### Crie a interface da conversa

Busque o token de conversa no seu servidor e use-o para iniciar uma sessão.

#### React

**`App.tsx`**

```tsx title="App.tsx"
import { useConversation } from "@elevenlabs/react";
import { useCallback } from "react";

async function getToken(): Promise<string> {
  const response = await fetch("/api/token");
  if (!response.ok) {
    throw Error("Failed to get conversation token");
  }
  const data = await response.json();
  return data.token;
}

export default function App() {
  const conversation = useConversation({
    onConnect: () => console.log("Connected"),
    onDisconnect: () => console.log("Disconnected"),
    onError: (error: Error) => console.error("Error:", error),
  });

  const startConversation = useCallback(async () => {
    await navigator.mediaDevices.getUserMedia({ audio: true });
    const token = await getToken();
    await conversation.startSession({ conversationToken: token });
  }, [conversation]);

  const stopConversation = useCallback(async () => {
    await conversation.endSession();
  }, [conversation]);

  return (
    <div>
      <p>Status: {conversation.status}</p>
      <button onClick={startConversation} disabled={conversation.status === "connected"}>
        Start conversation
      </button>
      <button onClick={stopConversation} disabled={conversation.status !== "connected"}>
        End conversation
      </button>
    </div>
  );
}
```

#### JavaScript

**`main.ts`**

```typescript title="main.ts"
import { Conversation } from "@elevenlabs/client";

let conversation: Conversation | null = null;

async function getToken(): Promise<string> {
  const response = await fetch("/api/token");
  if (!response.ok) throw Error("Failed to get conversation token");
  const data = await response.json();
  return data.token;
}

document.getElementById("start")!.addEventListener("click", async () => {
  await navigator.mediaDevices.getUserMedia({ audio: true });
  const token = await getToken();

  conversation = await Conversation.startSession({
    conversationToken: token,
    onConnect: () => {
      document.getElementById("status")!.textContent = "Connected";
      (document.getElementById("start") as HTMLButtonElement).disabled = true;
      (document.getElementById("stop") as HTMLButtonElement).disabled = false;
    },
    onDisconnect: () => {
      document.getElementById("status")!.textContent = "Disconnected";
      (document.getElementById("start") as HTMLButtonElement).disabled = false;
      (document.getElementById("stop") as HTMLButtonElement).disabled = true;
    },
    onError: (error) => console.error("Error:", error),
  });
});

document.getElementById("stop")!.addEventListener("click", () => {
  if (conversation) conversation.endSession();
});
```

#### Experimente

Verifique se três processos estão em execução:

1. **ngrok** - encaminhando para a porta 3001
2. **Seu servidor do Speech Engine** - `python server.py` ou `npx tsx server.mts`
3. **O servidor de tokens** - `npx tsx token-server.mts` ou `python token_server.py`

Abra seu aplicativo cliente no navegador e clique em **Iniciar conversa**. Conceda acesso ao microfone quando solicitado e comece a falar. Você deverá ouvir a resposta do agente pelos alto-falantes.

Se `debug: true` estiver ativado no servidor, você verá as transcrições recebidas e as respostas enviadas registradas no console.

## Eventos de sessão

| Evento            | Callback TypeScript | Callback Python | Descrição                                                                                     |
| ----------------- | ------------------- | --------------- | --------------------------------------------------------------------------------------------- |
| `user_transcript` | `onTranscript`      | `on_transcript` | Voz do usuário transcrita. Inclui o histórico completo da conversa e um sinal de interrupção. |
| `init`            | `onInit`            | `on_init`       | Sessão inicializada com um ID de conversa.                                                    |
| `close`           | `onClose`           | `on_close`      | Desconexão limpa da ElevenLabs.                                                               |
| `disconnected`    | `onDisconnect`      | `on_disconnect` | WebSocket interrompido inesperadamente.                                                       |
| `error`           | `onError`           | `on_error`      | Erro de protocolo ou WebSocket.                                                               |

## Configurando a primeira mensagem do agente

Por padrão, o agente espera o usuário falar primeiro. Para que o agente cumprimente o usuário quando a conversa começar, defina uma primeira mensagem na opção `overrides` do cliente ao iniciar a sessão.

Para permitir que o agente fale primeiro, precisamos atualizar o recurso do Speech Engine para permitir essa configuração pelo cliente.

```python
engine = await elevenlabs.speech_engine.update(
    speech_engine_id="seng_8k3m9xr4hjnfg983brhmhkd98n6",
    overrides={
      "first_message": True,
    },
)
```

```typescript
const engine = await elevenlabs.speechEngine.update("seng_8k3m9xr4hjnfg983brhmhkd98n6", {
  overrides: {
    firstMessage: true,
  },
});
```

Em seguida, configuramos a primeira mensagem no SDK do cliente.

#### React

```tsx
conversation.startSession({
  conversationToken: token,
  overrides: {
    agent: {
      firstMessage: "Hello! How can I help you today?",
    },
  },
});
```

#### JavaScript

```typescript
const conversation = await Conversation.startSession({
  conversationToken: token,
  overrides: {
    agent: {
      firstMessage: "Hello! How can I help you today?",
    },
  },
});
```

A primeira mensagem é falada pelo agente assim que a conexão é estabelecida. Ela não aciona o callback `onTranscript` no seu servidor — é processada inteiramente pela ElevenLabs.

## Configurando a duração máxima da conversa

Por padrão, uma conversa termina após 600 segundos (10 minutos). O Speech Engine aceita conversas de até 2.400 segundos (40 minutos). Para permitir conversas mais longas, atualize o recurso do Speech Engine com um `max_duration_seconds` maior:

```python
engine = await elevenlabs.speech_engine.update(
    speech_engine_id="seng_8k3m9xr4hjnfg983brhmhkd98n6",
    conversation={
        "max_duration_seconds": 2400,
    },
)
```

```typescript
const engine = await elevenlabs.speechEngine.update("seng_8k3m9xr4hjnfg983brhmhkd98n6", {
  conversation: {
    maxDurationSeconds: 2400,
  },
});
```

Você também pode configurar isso no painel: abra seu Speech Engine, acesse a guia **Avançado** e defina a **Duração máxima da conversa** em **Comportamento conversacional**.

> **Warning**
>
> Conversas com mais de 40 minutos não são compatíveis e podem ser desconectadas, mesmo que
> `max_duration_seconds` esteja definido com um valor maior. Se precisar de conversas mais longas, [entre em contato com nossa equipe](https://elevenlabs.io/contact-sales).

## Próximas etapas

#### [Referência do SDK JavaScript](/docs/pt/eleven-api/resources/libraries/speech-engine/javascript-sdk-reference)

Classes, métodos e eventos do SDK JavaScript.

#### [Referência do SDK Python](/docs/pt/eleven-api/resources/libraries/speech-engine/python-sdk-reference)

Classes, métodos e eventos do SDK Python.

#### [Referência da API](/docs/pt/api-reference/speech-engine/create)

Explore todos os parâmetros e formatos de resposta do Speech Engine.

#### [Exemplo de app em Next.js](https://github.com/elevenlabs/examples/tree/main/speech-engine/nextjs/quickstart)

Execute localmente um app completo de início rápido do Speech Engine.