WebSocket

Erstellen Sie Echtzeit-, interaktive Sprachgespräche mit KI-Agenten

Diese Dokumentation richtet sich an Entwickler, die direkt die ElevenLabs WebSocket API integrieren. Der Einfachheit halber empfehlen wir die offiziellen SDKs von ElevenLabs.

Die ElevenAgents WebSocket API ermöglicht Echtzeit-, interaktive Sprachgespräche mit KI-Agenten. Durch eine WebSocket-Verbindung können Sie Audioeingaben senden und Audioantworten in Echtzeit empfangen. So entstehen realistische Gesprächserlebnisse.

Endpunkt: wss://api.elevenlabs.io/v1/convai/conversation?agent_id={agent_id}

Authentifizierung

Agent-ID verwenden

Bei öffentlichen Agenten können Sie die agent_id direkt in der WebSocket-URL verwenden, ohne zusätzliche Authentifizierung:

wss://api.elevenlabs.io/v1/convai/conversation?agent_id=<your-agent-id>

Signierte URL verwenden

Für private Agenten oder Gespräche, die eine Autorisierung erfordern, rufen Sie von Ihrem Server eine signierte URL ab. Dieser kommuniziert über Ihren API-Schlüssel sicher mit der ElevenLabs API.

Beispiel mit cURL

Anfrage:

curl -X GET "https://api.elevenlabs.io/v1/convai/conversation/get-signed-url?agent_id=<your-agent-id>" \
-H "xi-api-key: <your-api-key>"

Antwort:

{
"signed_url": "wss://api.elevenlabs.io/v1/convai/conversation?agent_id=<your-agent-id>&token=<token>"
}
Geben Sie Ihren ElevenLabs API-Schlüssel niemals clientseitig preis.

WebSocket-Ereignisse

Ereignisse vom Client zum Server

Der Client kann folgende Ereignisse an den Server senden:

Senden Sie nicht unterbrechende Kontextinformationen, um den Gesprächsstatus zu aktualisieren. So können Sie zusätzlichen Kontext bereitstellen, ohne den laufenden Gesprächsfluss zu stören.

{
"type": "contextual_update",
"text": "User clicked on pricing page"
}

Anwendungsfälle:

  • Nutzerstatus oder Präferenzen aktualisieren
  • Umgebungskontext bereitstellen
  • Hintergrundinformationen hinzufügen
  • Interaktionen mit der Benutzeroberfläche verfolgen

Wichtige Punkte:

  • Unterbricht den aktuellen Gesprächsfluss nicht
  • Aktualisierungen werden als Tool-Aufrufe in den Gesprächsverlauf aufgenommen
  • Hilft, den Kontext zu wahren, ohne den natürlichen Dialog zu unterbrechen

Kontextuelle Aktualisierungen werden asynchron verarbeitet und erfordern keine direkte Antwort vom Server.

Implementierungsbeispiel für Next.js

Dieses Beispiel zeigt, wie Sie einen WebSocket-basierten Client für einen Gesprächsagenten in Next.js mit der ElevenLabs WebSocket API implementieren.

Dieses Beispiel verwendet zwar das Paket voice-stream zur Verarbeitung von Mikrofoneingaben, Sie können jedoch auch eine eigene Lösung zum Erfassen und Kodieren von Audio implementieren. Der Schwerpunkt liegt hier auf der Demonstration der WebSocket-Verbindung und Ereignisverarbeitung mit der ElevenLabs API.

1

Erforderliche Abhängigkeiten installieren

Installieren Sie zuerst die erforderlichen Pakete:

npm install voice-stream

Das Paket voice-stream verarbeitet Mikrofonzugriff und Audio-Streaming und kodiert das Audio automatisch im von der ElevenLabs API benötigten Base64-Format.

Dieses Beispiel verwendet Tailwind CSS für das Styling. So fügen Sie Tailwind Ihrem Next.js-Projekt hinzu:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Folgen Sie anschließend der offiziellen Tailwind-CSS-Einrichtungsanleitung für Next.js.

Alternativ können Sie die className-Attribute durch eigene CSS-Stile ersetzen.

2

WebSocket-Typen erstellen

Definieren Sie die Typen für WebSocket-Ereignisse:

app/types/websocket.ts
type BaseEvent = {
type: string;
};
type UserTranscriptEvent = BaseEvent & {
type: "user_transcript";
user_transcription_event: {
user_transcript: string;
};
};
type AgentResponseEvent = BaseEvent & {
type: "agent_response";
agent_response_event: {
agent_response: string;
};
};
type AgentResponseCorrectionEvent = BaseEvent & {
type: "agent_response_correction";
agent_response_correction_event: {
original_agent_response: string;
corrected_agent_response: string;
};
};
type AudioResponseEvent = BaseEvent & {
type: "audio";
audio_event: {
audio_base_64: string;
event_id: number;
alignment: {
chars: string[];
char_durations_ms: number[];
char_start_times_ms: number[];
};
};
};
type InterruptionEvent = BaseEvent & {
type: "interruption";
interruption_event: {
reason: string;
};
};
type PingEvent = BaseEvent & {
type: "ping";
ping_event: {
event_id: number;
ping_ms?: number;
};
};
type AgentChatResponsePartEvent = BaseEvent & {
type: "agent_chat_response_part";
text_response_part: {
type: "start" | "delta" | "stop";
text: string;
event_id: number;
response_id: string;
};
};
export type ElevenLabsWebSocketEvent =
| UserTranscriptEvent
| AgentResponseEvent
| AgentResponseCorrectionEvent
| AudioResponseEvent
| InterruptionEvent
| PingEvent
| AgentChatResponsePartEvent;
3

WebSocket-Hook erstellen

Erstellen Sie einen benutzerdefinierten Hook zur Verwaltung der WebSocket-Verbindung:

app/hooks/useAgentConversation.ts
'use client';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useVoiceStream } from 'voice-stream';
import type { ElevenLabsWebSocketEvent } from '../types/websocket';
const sendMessage = (websocket: WebSocket, request: object) => {
if (websocket.readyState !== WebSocket.OPEN) {
return;
}
websocket.send(JSON.stringify(request));
};
export const useAgentConversation = () => {
const websocketRef = useRef<WebSocket>(null);
const [isConnected, setIsConnected] = useState<boolean>(false);
const { startStreaming, stopStreaming } = useVoiceStream({
onAudioChunked: (audioData) => {
if (!websocketRef.current) return;
sendMessage(websocketRef.current, {
user_audio_chunk: audioData,
});
},
});
const startConversation = useCallback(async () => {
if (isConnected) return;
const websocket = new WebSocket("wss://api.elevenlabs.io/v1/convai/conversation");
websocket.onopen = async () => {
setIsConnected(true);
sendMessage(websocket, {
type: "conversation_initiation_client_data",
});
await startStreaming();
};
websocket.onmessage = async (event) => {
const data = JSON.parse(event.data) as ElevenLabsWebSocketEvent;
// Handle ping events to keep connection alive
if (data.type === "ping") {
setTimeout(() => {
sendMessage(websocket, {
type: "pong",
event_id: data.ping_event.event_id,
});
}, data.ping_event.ping_ms);
}
if (data.type === "user_transcript") {
const { user_transcription_event } = data;
console.log("User transcript", user_transcription_event.user_transcript);
}
if (data.type === "agent_response") {
const { agent_response_event } = data;
console.log("Agent response", agent_response_event.agent_response);
}
if (data.type === "agent_response_correction") {
const { agent_response_correction_event } = data;
console.log("Agent response correction", agent_response_correction_event.corrected_agent_response);
}
if (data.type === "interruption") {
// Handle interruption
}
if (data.type === "audio") {
const { audio_event } = data;
// Implement your own audio playback system here
// Note: You'll need to handle audio queuing to prevent overlapping
// as the WebSocket sends audio events in chunks
}
if (data.type === "agent_chat_response_part") {
const { text_response_part } = data;
const { type: partType, text, response_id } = text_response_part;
// Handle the agent's response text as it is generated. Enable
// agent_chat_response_part in the agent's client_events to receive
// this during voice conversations.
console.log("Chat response part:", partType, text, response_id);
}
};
websocketRef.current = websocket;
websocket.onclose = async () => {
websocketRef.current = null;
setIsConnected(false);
stopStreaming();
};
}, [startStreaming, isConnected, stopStreaming]);
const stopConversation = useCallback(async () => {
if (!websocketRef.current) return;
websocketRef.current.close();
}, []);
useEffect(() => {
return () => {
if (websocketRef.current) {
websocketRef.current.close();
}
};
}, []);
return {
startConversation,
stopConversation,
isConnected,
};
};
4

Gesprächskomponente erstellen

Erstellen Sie eine Komponente, die den WebSocket-Hook verwendet:

app/components/Conversation.tsx
'use client';
import { useCallback } from 'react';
import { useAgentConversation } from '../hooks/useAgentConversation';
export function Conversation() {
const { startConversation, stopConversation, isConnected } = useAgentConversation();
const handleStart = useCallback(async () => {
try {
await navigator.mediaDevices.getUserMedia({ audio: true });
await startConversation();
} catch (error) {
console.error('Failed to start conversation:', error);
}
}, [startConversation]);
return (
<div className="flex flex-col items-center gap-4">
<div className="flex gap-2">
<button
onClick={handleStart}
disabled={isConnected}
className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-300"
>
Start Conversation
</button>
<button
onClick={stopConversation}
disabled={!isConnected}
className="px-4 py-2 bg-red-500 text-white rounded disabled:bg-gray-300"
>
Stop Conversation
</button>
</div>
<div className="flex flex-col items-center">
<p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
</div>
</div>
);
}

Nächste Schritte

  1. Audiowiedergabe: Implementieren Sie ein eigenes Audiowiedergabesystem mit der Web Audio API oder einer Bibliothek. Berücksichtigen Sie die Audiowarteschlange, um Überlappungen zu vermeiden, da WebSocket Audioereignisse in Blöcken sendet.
  2. Fehlerbehandlung: Fügen Sie Wiederholungslogik und Mechanismen zur Fehlerbehebung hinzu
  3. UI-Feedback: Fügen Sie visuelle Anzeigen für Sprachaktivität und Verbindungsstatus hinzu

Latenzmanagement

Für reibungslose Gespräche implementieren Sie diese Strategien:

  • Adaptives Buffering: Passen Sie die Audiopufferung an die Netzwerkbedingungen an.
  • Jitter-Puffer: Implementieren Sie einen Jitter-Puffer, um Schwankungen bei den Paketankunftszeiten auszugleichen.
  • Ping-Pong-Überwachung: Verwenden Sie Ping- und Pong-Ereignisse, um die Round-Trip-Zeit zu messen und entsprechend anzupassen.

Sicherheits-Best-Practices

  • Rotieren Sie API-Schlüssel regelmäßig und speichern Sie sie in Umgebungsvariablen.
  • Implementieren Sie Ratenbegrenzungen, um Missbrauch zu verhindern.
  • Erklären Sie klar den Zweck, wenn Sie Nutzer um Mikrofonzugriff bitten.
  • Optimierte Blockbildung: Passen Sie die Dauer der Audioblöcke an, um Latenz und Effizienz auszubalancieren.

Zusätzliche Ressourcen