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

# Démarrage rapide de Speech Engine

Ce guide vous accompagne dans la création d'un agent vocal avec Speech Engine. Vous configurez un serveur qui connecte votre LLM à ElevenLabs, puis un client navigateur afin que les utilisateurs puissent avoir des conversations vocales avec votre agent.

> **Tip**
>
> Utilisez la [skill ElevenLabs Speech Engine](https://github.com/elevenlabs/skills/tree/main/speech-engine) pour ajouter la voix à votre agent conversationnel :
>
> ```bash
> npx skills add elevenlabs/skills --skill speech-engine
> ```

## Fonctionnement de Speech Engine

Speech Engine connecte votre LLM à ElevenLabs afin que les utilisateurs puissent parler à votre agent et entendre ses réponses. ElevenLabs gère la transcription et la synthèse vocale ; votre serveur fournit la logique du 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)
```

Chaque connexion WebSocket représente une conversation. Lorsque l'utilisateur parle, ElevenLabs transcrit l'audio et envoie la transcription à votre serveur. Votre serveur la transmet à votre LLM, puis diffuse la réponse en continu. ElevenLabs convertit le texte en parole et le lit dans le navigateur. Le SDK gère les connexions, les tours de parole et la détection des interruptions.

## Prérequis

Ce tutoriel utilise l'API d'OpenAI pour le LLM. Vous devez définir une clé API OpenAI dans la variable d'environnement `OPENAI_API_KEY`.

## Configuration du serveur

#### Créer une clé API

[Créez une clé API dans le Dashboard ici](https://elevenlabs.io/app/api/api-keys), que vous utiliserez pour [accéder à l’API](/docs/fr/api-reference/authentication) en toute sécurité.

Stockez la clé comme secret géré et transmettez-la aux SDK, soit sous forme de variable d’environnement via un fichier `.env`, soit directement dans la configuration de votre application, selon vos préférences.

**`.env`**

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

#### Installer les dépendances

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

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

#### Exposer le serveur

Speech Engine nécessite une URL accessible publiquement. Utilisez [ngrok](https://ngrok.com) pour exposer votre serveur local. Le serveur n'est pas encore créé, mais ngrok doit d'abord être exécuté afin que vous disposiez de l'URL pour l'étape suivante.

```bash
ngrok http 3001
```

Copiez l'URL de transfert, par exemple `https://abc123.ngrok.io`.

#### Créer une instance Speech Engine

Utilisez le SDK pour créer une instance Speech Engine, en indiquant votre URL ngrok avec le chemin `/ws` ajouté comme URL 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);
```

Exécutez ce script et copiez l'ID Speech Engine, par exemple `seng_8k3m9xr4hjnfg983brhmhkd98n6`, pour l'étape suivante.

#### Créer le serveur

Créez un fichier nommé `server.py` ou `server.mts` avec le contenu suivant. Il configure un serveur, associe Speech Engine au chemin `/ws` et utilise OpenAI pour générer les réponses.

**`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");
});
```

Le rappel `onTranscript` / `on_transcript` reçoit l'historique complet de la conversation et la session actuelle. Le SDK TypeScript fournit également un `AbortSignal` qui se déclenche si l'utilisateur interrompt la réponse en cours. Transmettre `signal` à l'appel OpenAI annule automatiquement la requête du LLM en cas d'interruption.

`sendResponse()` / `send_response()` accepte une chaîne de caractères, un itérable asynchrone ou un flux provenant d'OpenAI, Anthropic ou Google Gemini. Le SDK extrait automatiquement le contenu textuel.

> **Warning**
>
> Dans l'exemple ci-dessus, la transcription complète de l'utilisateur est transmise au LLM. Dans un environnement de production, vous devez ajouter des garde-fous pour prévenir toute tentative d'injection ou de manipulation de prompt.

#### Démarrer le serveur

```python
python server.py
```

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

## Configuration du client

#### Installer le SDK client

#### React

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

#### JavaScript

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

#### Créer un endpoint de jeton

Ajoutez un endpoint côté serveur qui génère un jeton de conversation. Votre clé API reste ainsi hors du navigateur et WebRTC garantit la meilleure qualité audio.

**`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");
});
```

#### Créer l'interface de conversation

Récupérez le jeton de conversation depuis votre serveur et utilisez-le pour démarrer une session.

#### 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();
});
```

#### Tester

Assurez-vous que trois processus sont en cours d'exécution :

1. **ngrok** - transfert vers le port 3001
2. **Votre serveur Speech Engine** - `python server.py` ou `npx tsx server.mts`
3. **Le serveur de jetons** - `npx tsx token-server.mts` ou `python token_server.py`

Ouvrez votre application cliente dans le navigateur et cliquez sur **Démarrer la conversation**. Autorisez l'accès au microphone lorsque cela vous est demandé, puis parlez. Vous devriez entendre la réponse de l'agent via vos haut-parleurs.

Si `debug: true` est activé sur le serveur, les transcriptions entrantes et les réponses sortantes s'affichent dans la console.

## Événements de session

| Événement         | Rappel TypeScript | Rappel Python   | Description                                                                                                   |
| ----------------- | ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------- |
| `user_transcript` | `onTranscript`    | `on_transcript` | Parole de l'utilisateur transcrite. Inclut l'historique complet de la conversation et un signal d'annulation. |
| `init`            | `onInit`          | `on_init`       | Session initialisée avec un ID de conversation.                                                               |
| `close`           | `onClose`         | `on_close`      | Déconnexion propre d'ElevenLabs.                                                                              |
| `disconnected`    | `onDisconnect`    | `on_disconnect` | Connexion WebSocket interrompue de manière inattendue.                                                        |
| `error`           | `onError`         | `on_error`      | Erreur de protocole ou WebSocket.                                                                             |

## Configurer le premier message de l'agent

Par défaut, l'agent attend que l'utilisateur parle en premier. Pour que l'agent salue l'utilisateur au début de la conversation, définissez un premier message dans l'option `overrides` du client au démarrage de la session.

Pour permettre à l'agent de parler en premier, nous devons mettre à jour la ressource Speech Engine afin d'autoriser ce paramétrage depuis le client.

```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,
  },
});
```

Configurez ensuite le premier message dans le SDK client.

#### 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?",
    },
  },
});
```

Le premier message est prononcé par l'agent dès que la connexion est établie. Il ne déclenche pas le rappel `onTranscript` sur votre serveur : il est entièrement géré par ElevenLabs.

## Configurer la durée maximale de conversation

Par défaut, une conversation se termine après 600 secondes (10 minutes). Speech Engine prend en charge des conversations allant jusqu'à 2 400 secondes (40 minutes). Pour autoriser des conversations plus longues, mettez à jour la ressource Speech Engine avec une valeur `max_duration_seconds` plus élevée :

```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,
  },
});
```

Vous pouvez également définir ce paramètre dans le Dashboard : ouvrez votre Speech Engine, accédez à l'onglet **Avancé**, puis définissez **Durée maximale de conversation** dans **Comportement conversationnel**.

> **Warning**
>
> Les conversations de plus de 40 minutes ne sont pas prises en charge et peuvent être interrompues, même si
> `max_duration_seconds` est défini sur une valeur plus élevée. Si vous avez besoin de conversations plus longues, [contactez notre équipe](https://elevenlabs.io/contact-sales).

## Étapes suivantes

#### [Référence du SDK JavaScript](/docs/fr/eleven-api/resources/libraries/speech-engine/javascript-sdk-reference)

Classes, méthodes et événements du SDK JavaScript.

#### [Référence du SDK Python](/docs/fr/eleven-api/resources/libraries/speech-engine/python-sdk-reference)

Classes, méthodes et événements du SDK Python.

#### [Guide de l'API](/docs/fr/api-reference/speech-engine/create)

Explorez tous les paramètres et formats de réponse de Speech Engine.

#### [Application exemple Next.js](https://github.com/elevenlabs/examples/tree/main/speech-engine/nextjs/quickstart)

Exécutez localement une application de démarrage rapide Speech Engine complète.