Krótki przewodnik po Speech Engine

Dodaj głos do agenta czatu za pomocą SDK ElevenLabs.

Ten przewodnik pokazuje, jak stworzyć agenta głosowego z użyciem Speech Engine. Skonfigurujesz serwer, który połączy Twój LLM z ElevenLabs, a potem klienta w przeglądarce, by użytkownicy mogli rozmawiać głosowo z agentem.

Użyj umiejętności ElevenLabs Speech Engine, aby dodać głos do agenta czatu:

npx skills add elevenlabs/skills --skill speech-engine

Jak działa Speech Engine

Speech Engine łączy Twój LLM z ElevenLabs, aby użytkownicy mogli rozmawiać z agentem i słyszeć jego odpowiedzi. ElevenLabs obsługuje zamianę mowy na tekst i zamianę tekstu na mowę, a Twój serwer zapewnia logikę LLM.

Każde połączenie WebSocket odpowiada jednej rozmowie. Gdy użytkownik mówi, ElevenLabs transkrybuje audio i wysyła transkrypcję na Twój serwer. Serwer przekazuje ją do LLM, a potem streamuje odpowiedź z powrotem. ElevenLabs zamienia tekst na mowę i odtwarza ją w przeglądarce. SDK obsługuje zarządzanie połączeniem, zmianę tur i wykrywanie przerwań.

Wymagania wstępne

Ten samouczek używa API OpenAI jako LLM. Potrzebujesz klucza API OpenAI ustawionego w zmiennej środowiskowej OPENAI_API_KEY.

Konfiguracja serwera

1

Utwórz klucz API

Utwórz klucz API w panelu tutaj, aby bezpiecznie uzyskać dostęp do API.

Przechowuj klucz jako zarządzany sekret i przekaż go do SDK jako zmienną środowiskową przez plik .env lub bezpośrednio w konfiguracji aplikacji — zależnie od preferencji.

.env
ELEVENLABS_API_KEY=<your_api_key_here>
2

Zainstaluj zależności

pip install elevenlabs openai python-dotenv
3

Udostępnij serwer

Speech Engine wymaga publicznie dostępnego URL-a. Użyj ngrok, aby udostępnić lokalny serwer. Serwer nie jest jeszcze gotowy, ale ngrok musi działać wcześniej, aby mieć URL do następnego kroku.

ngrok http 3001

Skopiuj URL przekierowania, np. https://abc123.ngrok.io.

4

Utwórz instancję Speech Engine

Użyj SDK, aby utworzyć instancję Speech Engine, przekazując URL ngrok z dopisaną ścieżką /ws jako URL WebSocket.

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

Uruchom ten skrypt i skopiuj ID Speech Engine, np. seng_8k3m9xr4hjnfg983brhmhkd98n6, do następnego kroku.

5

Utwórz serwer

Utwórz plik o nazwie server.py lub server.mts z poniższą zawartością. Skonfigurujesz w nim serwer, podłączysz Speech Engine pod ścieżką /ws i użyjesz OpenAI do generowania odpowiedzi.

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

Callback onTranscript / on_transcript otrzymuje pełną historię rozmowy i bieżącą sesję. TypeScript SDK udostępnia też AbortSignal, który uruchamia się, gdy użytkownik przerwie odpowiedź. Przekazanie signal do wywołania OpenAI automatycznie anuluje żądanie LLM po przerwaniu.

sendResponse() / send_response() przyjmuje ciąg znaków, asynchroniczny iterowalny obiekt lub stream z OpenAI, Anthropic albo Google Gemini. SDK automatycznie wyodrębnia treść tekstową.

W powyższym przykładzie do LLM przekazywana jest pełna transkrypcja użytkownika. W środowisku produkcyjnym dodaj zabezpieczenia, aby zapobiec próbom prompt injection lub manipulacji.

6

Uruchom serwer

python server.py

Konfiguracja klienta

1

Zainstaluj SDK klienta

npm install @elevenlabs/react
2

Utwórz endpoint tokenu

Dodaj endpoint po stronie serwera, który generuje token rozmowy. Dzięki temu klucz API nie trafia do przeglądarki, a WebRTC zapewnia najlepszą jakość audio.

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

Stwórz interfejs rozmowy

Pobierz token rozmowy z serwera i użyj go, aby rozpocząć sesję.

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>
);
}
4

Wypróbuj

Upewnij się, że działają trzy procesy:

  1. ngrok — przekierowuje na port 3001
  2. Twój serwer Speech Engine — python server.py lub npx tsx server.mts
  3. Serwer tokenów — npx tsx token-server.mts lub python token_server.py

Otwórz aplikację kliencką w przeglądarce i kliknij Rozpocznij rozmowę. Gdy pojawi się prośba, zezwól na dostęp do mikrofonu, a potem zacznij mówić. Odpowiedź agenta usłyszysz w głośnikach.

Jeśli na serwerze masz włączone debug: true, w konsoli zobaczysz logi przychodzących transkrypcji i wychodzących odpowiedzi.

Zdarzenia sesji

ZdarzenieCallback TypeScriptCallback PythonOpis
user_transcriptonTranscripton_transcriptTranskrypcja mowy użytkownika. Zawiera pełną historię rozmowy i sygnał przerwania.
initonIniton_initSesja zainicjowana z ID rozmowy.
closeonCloseon_closePrawidłowe rozłączenie z ElevenLabs.
disconnectedonDisconnecton_disconnectNieoczekiwane zerwanie WebSocket.
erroronErroron_errorBłąd protokołu lub WebSocket.

Konfiguracja pierwszej wiadomości agenta

Domyślnie agent czeka, aż użytkownik odezwie się pierwszy. Aby agent przywitał użytkownika na początku rozmowy, ustaw pierwszą wiadomość w opcji overrides klienta podczas uruchamiania sesji.

1

Aby agent mógł odezwać się pierwszy, musimy zaktualizować zasób Speech Engine, by można było ustawić to z klienta.

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

Następnie konfigurujemy pierwszą wiadomość w SDK klienta.

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

Pierwsza wiadomość jest wypowiadana przez agenta zaraz po nawiązaniu połączenia. Nie uruchamia callbacku onTranscript na serwerze — jest obsługiwana w całości po stronie ElevenLabs.

Kolejne kroki