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

# Szybki start z Speech Engine

Ten przewodnik pokaże ci, jak stworzyć agenta głosowego z Speech Engine. Skonfigurujesz serwer, który połączy twój LLM z ElevenLabs, a potem klienta w przeglądarce, aby użytkownicy mogli rozmawiać głosowo z twoim agentem.

> **Tip**
>
> Użyj [umiejętności ElevenLabs Speech Engine](https://github.com/elevenlabs/skills/tree/main/speech-engine), aby dodać głos do swojego agenta czatu:
>
> ```bash
> 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 mówić do twojego agenta i słyszeć jego odpowiedzi. ElevenLabs obsługuje zamianę mowy na tekst i zamianę tekstu na mowę, a twój serwer zapewnia logikę 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)
```

Każde połączenie WebSocket reprezentuje jedną rozmowę. Gdy użytkownik mówi, ElevenLabs transkrybuje dźwięk i wysyła transkrypcję na twój serwer. Twój serwer przekazuje ją do LLM, a następnie strumieniuje odpowiedź z powrotem. ElevenLabs zamienia tekst na mowę i odtwarza go w przeglądarce. SDK obsługuje zarządzanie połączeniem, zmianę tury i wykrywanie przerwań.

## Wymagania wstępne

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

## Konfiguracja serwera

#### Utwórz klucz API

[Utwórz klucz API w panelu tutaj](https://elevenlabs.io/app/api/api-keys), którego użyjesz, aby bezpiecznie [uzyskać dostęp do API](/docs/pl/api-reference/authentication).

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

**`.env`**

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

#### Zainstaluj zależności

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

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

#### Udostępnij serwer

Speech Engine potrzebuje publicznie dostępnego adresu URL. Użyj [ngrok](https://ngrok.com), aby udostępnić lokalny serwer. Serwer nie jest jeszcze gotowy, ale ngrok musi działać wcześniej, aby w kolejnym kroku mieć adres URL.

```bash
ngrok http 3001
```

Skopiuj adres URL przekierowania (np. `https://abc123.ngrok.io`).

#### Utwórz instancję Speech Engine

Użyj SDK, aby utworzyć instancję Speech Engine, przekazując adres URL ngrok z dodaną ścieżką `/ws` jako adres 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);
```

Uruchom ten skrypt i skopiuj identyfikator Speech Engine (np. `seng_8k3m9xr4hjnfg983brhmhkd98n6`) do kolejnego kroku.

#### Utwórz serwer

Utwórz plik o nazwie `server.py` lub `server.mts` z poniższą zawartością. Konfiguruje on serwer, podłącza Speech Engine pod ścieżką `/ws` i używa OpenAI do generowania odpowiedzi.

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

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

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

> **Warning**
>
> W powyższym przykładzie pełna transkrypcja od użytkownika jest przekazywana do LLM. W środowisku produkcyjnym dodaj zabezpieczenia, aby zapobiec próbom wstrzykiwania promptów i manipulacji.

#### Uruchom serwer

```python
python server.py
```

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

## Konfiguracja klienta

#### Zainstaluj SDK klienta

#### React

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

#### JavaScript

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

#### 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ść dźwięku.

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

#### Zbuduj interfejs rozmowy

Pobierz token rozmowy z serwera i użyj go do rozpoczęcia sesji.

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

#### Wypróbuj

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

1. **ngrok** – przekierowuje do portu 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ć. Powinieneś usłyszeć odpowiedź agenta w głośnikach.

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

## Zdarzenia sesji

| Zdarzenie         | Wywołanie zwrotne TypeScript | Wywołanie zwrotne Python | Opis                                                                                 |
| ----------------- | ---------------------------- | ------------------------ | ------------------------------------------------------------------------------------ |
| `user_transcript` | `onTranscript`               | `on_transcript`          | Mowa użytkownika transkrybowana. Zawiera pełną historię rozmowy i sygnał przerwania. |
| `init`            | `onInit`                     | `on_init`                | Sesja zainicjowana z identyfikatorem rozmowy.                                        |
| `close`           | `onClose`                    | `on_close`               | Poprawne rozłączenie z ElevenLabs.                                                   |
| `disconnected`    | `onDisconnect`               | `on_disconnect`          | WebSocket nieoczekiwanie przerwany.                                                  |
| `error`           | `onError`                    | `on_error`               | Błą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.

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

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

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

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

Pierwsza wiadomość jest wypowiadana przez agenta zaraz po nawiązaniu połączenia. Nie uruchamia wywołania zwrotnego `onTranscript` na twoim serwerze – jest obsługiwana w całości po stronie ElevenLabs.

## Konfiguracja maksymalnego czasu rozmowy

Domyślnie rozmowa kończy się po 600 sekundach (10 minutach). Speech Engine obsługuje rozmowy trwające do 2400 sekund (40 minut). Aby zezwolić na dłuższe rozmowy, zaktualizuj zasób Speech Engine, ustawiając wyższą wartość `max_duration_seconds`:

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

Możesz też ustawić to w panelu: otwórz Speech Engine, przejdź do karty **Zaawansowane** i ustaw **Maksymalny czas rozmowy** w sekcji **Zachowanie w rozmowie**.

> **Warning**
>
> Rozmowy dłuższe niż 40 minut nie są obsługiwane i mogą zostać rozłączone, nawet jeśli
> `max_duration_seconds` ma wyższą wartość. Jeśli potrzebujesz dłuższych rozmów, [skontaktuj się z naszym zespołem](https://elevenlabs.io/contact-sales).

## Kolejne kroki

#### [Dokumentacja SDK JavaScript](/docs/pl/eleven-api/resources/libraries/speech-engine/javascript-sdk-reference)

Klasy, metody i zdarzenia SDK JavaScript.

#### [Dokumentacja SDK Python](/docs/pl/eleven-api/resources/libraries/speech-engine/python-sdk-reference)

Klasy, metody i zdarzenia SDK Python.

#### [Dokumentacja API](/docs/pl/api-reference/speech-engine/create)

Poznaj wszystkie parametry Speech Engine i formaty odpowiedzi.

#### [Przykładowa aplikacja Next.js](https://github.com/elevenlabs/examples/tree/main/speech-engine/nextjs/quickstart)

Uruchom lokalnie kompletną aplikację szybkiego startu Speech Engine.