speech-engine

Par elevenlabs · skills

Ajoutez des conversations vocales en temps réel à un LLM personnalisé, OpenClaw ou un runtime d'agent similaire avec ElevenLabs Speech Engine. À utiliser pour créer des serveurs Speech Engine, des handlers WebSocket, des clients navigateur WebRTC, des endpoints de tokens de conversation, des réponses en streaming sensibles aux interruptions, ou des agents de chat vocaux qui connectent un LLM appartenant au développeur aux services de speech-to-text et text-to-speech d'ElevenLabs.

npx skills add https://github.com/elevenlabs/skills --skill speech-engine

Moteur de Synthèse Vocale ElevenLabs

Ajoutez une interface vocale en temps réel à un agent custom alimenté par un LLM. ElevenLabs gère l'audio du microphone, la reconnaissance vocale, la gestion des tours de parole, la synthèse vocale et la lecture dans le navigateur ; votre serveur expose un endpoint WebSocket Speech Engine et renvoie le texte de la réponse LLM en streaming.

Configuration : Consultez le guide d'installation. Pour JavaScript, utilisez uniquement les packages @elevenlabs/*. Pour plus de détails sur le SDK, lisez la référence SDK JavaScript ou la référence SDK Python.

Quand l'utiliser

Utilisez Speech Engine quand l'utilisateur souhaite :

  • Ajouter la voix à une application de chat existante ou à un pipeline LLM custom
  • Ajouter la voix à OpenClaw, Hermes ou un runtime d'agent similaire tout en gardant la logique de l'agent sur le serveur du développeur
  • Construire un serveur WebSocket hébergé par le développeur pour des conversations vocales ElevenLabs
  • Renvoyer les réponses OpenAI, Anthropic, Gemini ou LLM custom en audio parlé
  • Gérer les interruptions utilisateur pendant le streaming d'une réponse LLM
  • Construire un client navigateur avec @elevenlabs/react ou @elevenlabs/client en utilisant un token de conversation émis par le serveur

Utilisez plutôt la skill agents quand l'utilisateur crée ou configure un agent IA conversationnel ElevenLabs hébergé avec des prompts gérés par la plateforme, des outils, des workflows, des numéros de téléphone ou des widgets.

Comment ça marche

Chaque connexion WebSocket Speech Engine représente une conversation.

  1. Le navigateur envoie l'audio utilisateur à ElevenLabs.
  2. ElevenLabs transcrit la parole et envoie la transcription complète à votre serveur.
  3. Votre serveur appelle le LLM avec cet historique de conversation.
  4. Votre serveur renvoie du texte en streaming par le SDK.
  5. ElevenLabs convertit la réponse en parole et la joue dans le navigateur.

Le SDK gère le routage WebSocket, la vérification des requêtes, le cycle de vie de la session, le ping/pong, la gestion des tours de parole et des interruptions. sendResponse() / send_response() accepte une chaîne, un itérable asynchrone ou les streams des fournisseurs OpenAI, Anthropic ou Google Gemini.

Flux d'implémentation

  1. Installez les dépendances serveur et configurez ELEVENLABS_API_KEY plus la clé du fournisseur LLM.
  2. Exposez votre serveur Speech Engine via une URL HTTPS publique pour le développement local, par exemple avec ngrok http 3001.
  3. Créez une ressource Speech Engine avec ws_url / wsUrl pointant vers l'URL publique plus /ws.
  4. Stockez l'ID Speech Engine retourné, par exemple dans ELEVENLABS_SPEECH_ENGINE_ID.
  5. Démarrez un serveur Speech Engine avec engine.serve(...) en Python ou speechEngine.attach(...) en TypeScript.
  6. Émettez des tokens de conversation navigateur depuis un endpoint serveur. Ne mettez jamais ELEVENLABS_API_KEY dans le code navigateur.
  7. Démarrez la session client avec conversationToken ; définissez optionnellement overrides.agent.firstMessage si l'agent doit saluer en premier.

Créer un Speech Engine

Python

import asyncio
import os

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={"ws_url": os.environ["PUBLIC_WS_URL"]},
    )
    print(engine.engine_id)

asyncio.run(main())

TypeScript

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: { wsUrl: process.env.PUBLIC_WS_URL! },
});

console.log(engine.engineId);

PUBLIC_WS_URL devrait ressembler à https://example.ngrok.app/ws localement ou à votre route WebSocket de production au déploiement.

La requête create peut aussi configurer tts, asr, turn, speech_engine.request_headers / speechEngine.requestHeaders et privacy pour des voix custom, des mots-clés de transcription, la gestion des tours de parole, les en-têtes d'authentification serveur et le comportement d'enregistrement. Consultez les fichiers de référence SDK pour des exemples détaillés.

Exemples de serveur

Python

import asyncio
import os

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

load_dotenv()

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

async def on_transcript(transcript, session):
    stream = await openai.responses.create(
        model=os.environ["OPENAI_MODEL"],
        instructions="You are a concise, conversational voice assistant.",
        input=[
            {
                "role": "assistant" if message.role == "agent" else message.role,
                "content": message.content,
            }
            for message in transcript
        ],
        stream=True,
    )
    await session.send_response(stream)

async def main():
    engine = await elevenlabs.speech_engine.get(os.environ["ELEVENLABS_SPEECH_ENGINE_ID"])
    await engine.serve(
        port=3001,
        path="/ws",
        debug=True,
        on_transcript=on_transcript,
    )

asyncio.run(main())

TypeScript

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createServer } from "node:http";
import OpenAI from "openai";
import "dotenv/config";

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(
  process.env.ELEVENLABS_SPEECH_ENGINE_ID!,
  httpServer,
  "/ws",
  {
    debug: true,
    async onTranscript(transcript, signal, session) {
      const response = await openai.responses.create(
        {
          model: process.env.OPENAI_MODEL!,
          instructions: "You are a concise, conversational voice assistant.",
          input: transcript.map((message) => ({
            role: message.role === "agent" ? "assistant" : message.role,
            content: message.content,
          })),
          stream: true,
        },
        { signal },
      );

      session.sendResponse(response);
    },
  },
);

httpServer.listen(3001);

En TypeScript, passez le AbortSignal de onTranscript à la requête LLM pour que les interruptions utilisateur annulent la réponse en cours. En Python, le SDK annule le gestionnaire de transcription précédent quand une nouvelle transcription arrive.

Client navigateur

Créez un endpoint token côté serveur et faites en sorte que le navigateur demande un token avant de démarrer la session microphone. Gardez l'ID Speech Engine et la clé API sur le serveur.

import express from "express";
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";

const app = express();
const elevenlabs = new ElevenLabsClient();

app.get("/api/token", async (_req, res) => {
  const response = await elevenlabs.conversationalAi.conversations.getWebrtcToken({
    agentId: process.env.ELEVENLABS_SPEECH_ENGINE_ID!,
  });
  res.json({ token: response.token });
});

Les clients React peuvent utiliser @elevenlabs/react :

import { useConversation } from "@elevenlabs/react";

export function VoiceControls() {
  const conversation = useConversation({
    onConnect: () => console.log("connected"),
    onDisconnect: () => console.log("disconnected"),
    onError: (error) => console.error(error),
  });

  async function startConversation() {
    await navigator.mediaDevices.getUserMedia({ audio: true });
    const { token } = await fetch("/api/token").then((res) => res.json());

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

  return <button onClick={startConversation}>Start conversation</button>;
}

Si une session navigateur WebRTC s'arrête ou affiche des logs /rtc/v1 404, v1 RTC path not found ou could not establish pc connection, épinglez livekit-client à 2.16.1 dans le package.json de l'app jusqu'à ce que le problème de compatibilité LiveKit en amont soit résolu :

{
  "overrides": {
    "livekit-client": "2.16.1"
  }
}

Callbacks et événements

Événement Callback TypeScript Callback Python Notes
user_transcript onTranscript(transcript, signal, session) on_transcript(transcript, session) Historique de conversation complet pour le tour actuel
init onInit(conversationId, session) on_init(conversation_id, session) L'ID de conversation devient disponible
close onClose(session) on_close(session) Déconnexion propre
disconnected onDisconnect(session) on_disconnect(session) Chute WebSocket inattendue
error onError(error, session) on_error(error, session) Erreur de protocole ou WebSocket

Les messages de transcription utilisent le rôle "user" ou "agent". Mappez "agent" à "assistant" quand vous passez l'historique à des APIs LLM qui s'attendent à des rôles de style OpenAI.

Références

Skills similaires