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

# WebSocket z wieloma kontekstami

> **Zaawansowane**
>
> Orkiestracja agentów głosowych za pomocą tego API WebSocket z wieloma kontekstami to złożone zadanie,
> zalecane zaawansowanym deweloperom. Jeśli szukasz bardziej zarządzanego rozwiązania, sprawdź nasz
> [produkt Agents Platform](/docs/pl/eleven-agents/overview), który upraszcza wiele z tych wyzwań.

## Przegląd

Tworzenie responsywnych agentów głosowych wymaga dynamicznego zarządzania strumieniami audio, sprawnego obsługiwania przerwań i zachowania naturalnie brzmiącej mowy w kolejnych turach rozmowy. Nasze API WebSocket z wieloma kontekstami dla Text to Speech (TTS) zostało stworzone właśnie do takich zastosowań.

To API rozszerza nasze [standardowe funkcje TTS WebSocket](/docs/pl/eleven-api/guides/how-to/websockets/realtime-tts), wprowadzając pojęcie „kontekstów”. Każdy kontekst działa jako niezależny strumień generowania audio w ramach jednego połączenia WebSocket. Dzięki temu możesz:

* Zarządzać równocześnie wieloma wypowiedziami (np. gdy agent mówi, a jednocześnie przygotowuje odpowiedź na przerwanie przez użytkownika).
* Płynnie obsługiwać wtrącenia użytkownika, zamykając bieżący kontekst mowy i rozpoczynając nowy.
* Zachować spójność prozodyczną wypowiedzi w tym samym kontekście logicznym.
* Optymalizować użycie zasobów, zamykając konteksty, które nie są już potrzebne.

> **Warning**
>
> API WebSocket z wieloma kontekstami jest zoptymalizowane dla aplikacji głosowych i nie służy do
> jednoczesnego generowania wielu niepowiązanych strumieni audio. Dlatego każde połączenie obsługuje maksymalnie 5
> aktywnych kontekstów.

Ten przewodnik przeprowadzi cię przez łączenie z WebSocketem z wieloma kontekstami, zarządzanie kontekstami i dobre praktyki tworzenia angażujących agentów głosowych.

### Dobre praktyki

> **Note**
>
> Te dobre praktyki są kluczowe przy tworzeniu responsywnych i wydajnych agentów głosowych z naszym
> API WebSocket z wieloma kontekstami.

#### Używaj jednego połączenia WebSocket

Utwórz jedno połączenie WebSocket dla każdej sesji użytkownika końcowego. Zmniejsza to narzut i opóźnienia
w porównaniu z tworzeniem wielu połączeń. W ramach tego jednego połączenia możesz zarządzać
wieloma kontekstami dla różnych części rozmowy.

#### Przesyłaj odpowiedzi fragmentami, generuj zdania

Przy generowaniu długich odpowiedzi przesyłaj tekst w mniejszych fragmentach i używaj flagi `flush: true`
na końcu pełnych zdań. Poprawia to jakość generowanego audio i zwiększa
responsywność.

#### Sprawnie obsługuj przerwania

Przesyłaj tekst do jednego kontekstu, aż nastąpi przerwanie, a następnie utwórz nowy kontekst i zamknij
poprzedni. Takie podejście zapewnia płynne przejścia, gdy zmienia się tok rozmowy.

#### Zarządzaj cyklem życia kontekstu

Szybko zamykaj nieużywane konteksty. Serwer może utrzymywać do 5 aktywnych kontekstów na
połączenie, ale należy zamykać konteksty, gdy nie są już potrzebne.

#### Zapobiegaj przekroczeniu limitu czasu kontekstów

Domyślnie konteksty przekraczają limit czasu po 20 sekundach i są automatycznie zamykane. Limit bezczynności
to parametr na poziomie websocketu, który dotyczy wszystkich kontekstów i w razie potrzeby może wynosić do 180 sekund.
Wyślij pustą wiadomość tekstową do kontekstu, aby zresetować licznik czasu.

### Obsługa przerwań

Gdy użytkownik przerwie agentowi, należy [zamknąć bieżący kontekst](/docs/pl/api-reference/text-to-speech/v-1-text-to-speech-voice-id-multi-stream-input#send.Close-Context) i [utworzyć nowy](/docs/pl/api-reference/text-to-speech/v-1-text-to-speech-voice-id-multi-stream-input#send.Initialise-Context):

```python
async def handle_interruption(websocket, old_context_id, new_context_id, new_response):
    # Close the existing context that was interrupted
    await websocket.send(json.dumps({
        "context_id": old_context_id,
        "close_context": True
    }))
    print(f"Closed interrupted context '{old_context_id}'")

    # Create a new context for the new response
    await send_text_in_context(websocket, new_response, new_context_id)
```

```javascript
function handleInterruption(websocket: WebSocket, oldContextId: string, newContextId: string, newResponse: string) {
  // Close the existing context that was interrupted
  websocket.send(JSON.stringify({
    context_id: oldContextId,
    close_context: true
  }));
  console.log(`Closed interrupted context '${oldContextId}'`);

  // Create a new context for the new response
  sendTextInContext(websocket, newResponse, newContextId);
}
```

### Utrzymywanie aktywnego kontekstu

Konteksty automatycznie przekraczają limit czasu po [domyślnych 20 sekundach bezczynności](/docs/pl/api-reference/text-to-speech/v-1-text-to-speech-voice-id-multi-stream-input#request.query.inactivity_timeout). Jeśli chcesz utrzymać aktywny kontekst bez generowania tekstu (na przykład podczas opóźnienia przetwarzania), możesz wysłać pustą wiadomość tekstową, aby zresetować licznik czasu.

```python
async def keep_context_alive(websocket, context_id):
    await websocket.send(json.dumps({
        "context_id": context_id,
        "text": ""
    }))
```

```javascript
function handleInterruption(websocket: WebSocket, contextId: string) {
  // Close the existing context that was interrupted
  websocket.send(JSON.stringify({
    context_id: oldContextId,
    text: ""
  }));
}
```

### Zamykanie połączenia WebSocket

Gdy rozmowa się kończy, możesz zamknąć wszystkie konteksty, [zamykając socket](/docs/pl/api-reference/text-to-speech/v-1-text-to-speech-voice-id-multi-stream-input#send.Close-Socket):

```python
async def end_conversation(websocket):
    # This will close all contexts and close the connection
    await websocket.send(json.dumps({
        "close_socket": True
    }))
    print("Ending conversation and closing WebSocket")`
```

```javascript
function endConversation(websocket: WebSocket) {
  // This will close all contexts and close the connection
  websocket.send(JSON.stringify({
    close_socket: true
  }));
  console.log("Ending conversation and closing WebSocket");
}
```

## Pełny przykład agenta konwersacyjnego

### Wymagania

* Konto ElevenLabs z kluczem API (dowiedz się, jak [znaleźć klucz API](/docs/pl/api-reference/authentication)).
* Python lub Node.js (albo inne środowisko JavaScript) zainstalowane na komputerze.
* Znajomość komunikacji WebSocket. W ramach wprowadzenia polecamy nasz [przewodnik po standardowym streamingu WebSocket](/docs/pl/eleven-api/guides/how-to/websockets/realtime-tts).

### Konfiguracja

Zainstaluj wymagane zależności dla wybranego języka:

```python
pip install python-dotenv websockets
```

```javascript
npm install dotenv ws
for TypeScript, you might also want types:
npm install @types/dotenv @types/ws --save-dev
```

Utwórz plik .env w katalogu projektu, aby przechowywać klucz API:

**`.env`**

```python .env
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here
```

### Przykładowy agent głosowy

> **Note**
>
> Ten kod jest przykładem i nie jest przeznaczony do użycia produkcyjnego

```python maxLines=100
import os
import json
import asyncio
import websockets
from dotenv import load_dotenv

load_dotenv()
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
VOICE_ID = "your_voice_id"
MODEL_ID = "eleven_flash_v2_5"

WEBSOCKET_URI = f"wss://api.elevenlabs.io/v1/text-to-speech/{VOICE_ID}/multi-stream-input?model_id={MODEL_ID}"

async def send_text_in_context(websocket, text, context_id, voice_settings=None):
    """Send text to be synthesized in the specified context."""
    message = {
        "text": text,
        "context_id": context_id,
    }

    # Only include voice_settings for the first message in a context
    if voice_settings:
        message["voice_settings"] = voice_settings

    await websocket.send(json.dumps(message))

async def continue_context(websocket, text, context_id):
    """Add more text to an existing context."""
    await websocket.send(json.dumps({
        "text": text,
        "context_id": context_id
    }))

async def flush_context(websocket, context_id):
    """Force generation of any buffered audio in the context."""
    await websocket.send(json.dumps({
        "context_id": context_id,
        "flush": True
    }))

async def handle_interruption(websocket, old_context_id, new_context_id, new_response):
    """Handle user interruption by closing current context and starting a new one."""
    # Close the existing context that was interrupted
    await websocket.send(json.dumps({
        "context_id": old_context_id,
        "close_context": True
    }))

    # Create a new context for the new response
    await send_text_in_context(websocket, new_response, new_context_id)

async def end_conversation(websocket):
    """End the conversation and close the WebSocket connection."""
    await websocket.send(json.dumps({
        "close_socket": True
    }))

async def receive_messages(websocket):
    """Process incoming WebSocket messages."""
    context_audio = {}
    try:
        async for message in websocket:
            data = json.loads(message)
            context_id = data.get("contextId", "default")

            if data.get("audio"):
                print(f"Received audio for context '{context_id}'")

            if data.get("is_final"):
                print(f"Context '{context_id}' completed")
    except (websockets.exceptions.ConnectionClosed, asyncio.CancelledError):
        print("Message receiving stopped")

async def conversation_agent_demo():
    """Run a complete conversational agent demo."""
    # Connect with API key in headers
    async with websockets.connect(
        WEBSOCKET_URI,
        max_size=16 * 1024 * 1024,
        additional_headers={"xi-api-key": ELEVENLABS_API_KEY}
    ) as websocket:
        # Start receiving messages in background
        receive_task = asyncio.create_task(receive_messages(websocket))

        # Initial agent response
        await send_text_in_context(
            websocket,
            "Hello! I'm your virtual assistant. I can help you with a wide range of topics. What would you like to know about today?",
            "greeting"
        )

        # Wait a bit (simulating user listening)
        await asyncio.sleep(2)

        # Simulate user interruption
        print("USER INTERRUPTS: 'Can you tell me about the weather?'")

        # Handle the interruption by closing current context and starting new one
        await handle_interruption(
            websocket,
            "greeting",
            "weather_response",
            "I'd be happy to tell you about the weather. Currently in your area, it's 72 degrees and sunny with a slight chance of rain later this afternoon."
        )

        # Add more to the weather context
        await continue_context(
            websocket,
            " If you're planning to go outside, you might want to bring a light jacket just in case.",
            "weather_response"
        )

        # Flush at the end of this turn to ensure all audio is generated
        await flush_context(websocket, "weather_response")

        # Wait a bit (simulating user listening)
        await asyncio.sleep(3)

        # Simulate user asking another question
        print("USER: 'What about tomorrow?'")

        # Create a new context for this response
        await send_text_in_context(
            websocket,
            "Tomorrow's forecast shows temperatures around 75 degrees with partly cloudy skies. It should be a beautiful day overall!",
            "tomorrow_weather"
        )

        # Flush and close this context
        await flush_context(websocket, "tomorrow_weather")
        await websocket.send(json.dumps({
            "context_id": "tomorrow_weather",
            "close_context": True
        }))

        # End the conversation
        await asyncio.sleep(2)
        await end_conversation(websocket)

        # Cancel the receive task
        receive_task.cancel()
        try:
            await receive_task
        except asyncio.CancelledError:
            pass

if __name__ == "__main__":
    asyncio.run(conversation_agent_demo())

```

```javascript maxLines=100
// Import required modules
import dotenv from "dotenv";
import fs from "fs";
import WebSocket from "ws";

// Load environment variables
dotenv.config();
const ELEVENLABS_API_KEY = process.env.ELEVENLABS_API_KEY;
const VOICE_ID = "your_voice_id";
const MODEL_ID = "eleven_flash_v2_5";

const WEBSOCKET_URI = `wss://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}/multi-stream-input?model_id=${MODEL_ID}`;

// Function to send text in a specific context
function sendTextInContext(websocket, text, contextId, voiceSettings = null) {
  const message = {
    text: text,
    context_id: contextId,
  };

  // Only include voice_settings for the first message in a context
  if (voiceSettings) {
    message.voice_settings = voiceSettings;
  }

  websocket.send(JSON.stringify(message));
}

// Function to continue an existing context with more text
function continueContext(websocket, text, contextId) {
  websocket.send(
    JSON.stringify({
      text: text,
      context_id: contextId,
    })
  );
}

// Function to flush a context, forcing generation of buffered audio
function flushContext(websocket, contextId) {
  websocket.send(
    JSON.stringify({
      context_id: contextId,
      flush: true,
    })
  );
}

// Function to handle user interruption
function handleInterruption(websocket, oldContextId, newContextId, newResponse) {
  // Close the existing context that was interrupted
  websocket.send(
    JSON.stringify({
      context_id: oldContextId,
      close_context: true,
    })
  );

  // Create a new context for the new response
  sendTextInContext(websocket, newResponse, newContextId);
}

// Function to end the conversation and close the connection
function endConversation(websocket) {
  websocket.send(
    JSON.stringify({
      close_socket: true,
    })
  );
}

// Function to run the conversation agent demo
async function conversationAgentDemo() {
  // Connect to WebSocket with API key in headers
  const websocket = new WebSocket(WEBSOCKET_URI, {
    headers: {
      "xi-api-key": ELEVENLABS_API_KEY,
    },
    maxPayload: 16 * 1024 * 1024,
  });

  // Set up event handlers
  websocket.on("open", () => {
    // Initial agent response
    sendTextInContext(
      websocket,
      "Hello! I'm your virtual assistant. I can help you with a wide range of topics. What would you like to know about today?",
      "greeting"
    );

    // Simulate wait time (user listening)
    setTimeout(() => {
      // Simulate user interruption
      console.log("USER INTERRUPTS: 'Can you tell me about the weather?'");

      // Handle the interruption
      handleInterruption(
        websocket,
        "greeting",
        "weather_response",
        "I'd be happy to tell you about the weather. Currently in your area, it's 72 degrees and sunny with a slight chance of rain later this afternoon."
      );

      // Add more to the weather context
      setTimeout(() => {
        continueContext(
          websocket,
          " If you're planning to go outside, you might want to bring a light jacket just in case.",
          "weather_response"
        );

        // Flush at the end of this turn
        flushContext(websocket, "weather_response");

        // Simulate wait time (user listening)
        setTimeout(() => {
          // Simulate user asking another question
          console.log("USER: 'What about tomorrow?'");

          // Create a new context for this response
          sendTextInContext(
            websocket,
            "Tomorrow's forecast shows temperatures around 75 degrees with partly cloudy skies. It should be a beautiful day overall!",
            "tomorrow_weather"
          );

          // Flush and close this context
          flushContext(websocket, "tomorrow_weather");
          websocket.send(
            JSON.stringify({
              context_id: "tomorrow_weather",
              close_context: true,
            })
          );

          // End the conversation
          setTimeout(() => {
            endConversation(websocket);
          }, 2000);
        }, 3000);
      }, 500);
    }, 2000);
  });

  // Handle incoming messages
  websocket.on("message", (message) => {
    try {
      const data = JSON.parse(message);
      const contextId = data.contextId || "default";

      if (data.audio) {
        //do stuff
      }

      if (data.is_final) {
        console.log(`Context '${contextId}' completed`);
      }
    } catch (error) {
      console.error("Error parsing message:", error);
    }
  });

  // Handle WebSocket closure
  websocket.on("close", () => {
    console.log("WebSocket connection closed");
  });

  // Handle WebSocket errors
  websocket.on("error", (error) => {
    console.error("WebSocket error:", error);
  });
}

// Run the demo
conversationAgentDemo();
```

## Kolejne kroki

#### [ElevenAgents](/docs/pl/eleven-agents/quickstart)

Twórz gotowych do produkcji agentów głosowych na pełnej platformie ElevenAgents.

#### [Jak działa streaming audio](/docs/pl/eleven-api/concepts/audio-streaming)

Dowiedz się, jak działa streaming WebSocket i co wpływa na opóźnienia.