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

# Speech Engine-snabbstart

Den här guiden visar hur du bygger en röststyrd agent med Speech Engine. Du konfigurerar en server som ansluter din LLM till ElevenLabs och kopplar sedan in en webbläsarklient så att användare kan ha röstkonversationer med din agent.

> **Tip**
>
> Använd [ElevenLabs Speech Engine-skill](https://github.com/elevenlabs/skills/tree/main/speech-engine) för att lägga till röst i din chattagent:
>
> ```bash
> npx skills add elevenlabs/skills --skill speech-engine
> ```

## Så fungerar Speech Engine

Speech Engine ansluter din LLM till ElevenLabs så att användare kan prata med din agent och höra den svara. ElevenLabs hanterar tal-till-text och text-till-tal; din server tillhandahåller LLM-logiken.

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

Varje WebSocket-anslutning representerar en konversation. När användaren talar transkriberar ElevenLabs ljudet och skickar transkriptet till din server. Din server skickar det till din LLM och streamar sedan svaret tillbaka. ElevenLabs omvandlar texten till tal och spelar upp den i webbläsaren. SDK:t hanterar anslutningar, turordning och avbrottsidentifiering.

## Förutsättningar

Den här självstudien använder OpenAI:s API för LLM:en. Du behöver en OpenAI API-nyckel som anges i miljövariabeln `OPENAI_API_KEY`.

## Serverkonfiguration

#### Skapa en API-nyckel

[Skapa en API-nyckel i kontrollpanelen här](https://elevenlabs.io/app/settings/api-keys), som du använder för att säkert [få åtkomst till API:et](/docs/sv/api-reference/authentication).

Spara nyckeln som en hanterad hemlighet och skicka den till SDK:erna antingen som en miljövariabel via en `.env`-fil eller direkt i appens konfiguration, beroende på vad du föredrar.

**`.env`**

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

#### Installera beroenden

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

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

#### Exponera servern

Speech Engine behöver en offentligt åtkomlig URL. Använd [ngrok](https://ngrok.com) för att exponera din lokala server. Servern är inte byggd än, men ngrok måste köras först så att du har URL:en för nästa steg.

```bash
ngrok http 3001
```

Kopiera vidarebefordrings-URL:en (t.ex. `https://abc123.ngrok.io`).

#### Skapa en Speech Engine-instans

Använd SDK:t för att skapa en Speech Engine-instans och skicka med din ngrok-URL med sökvägen `/ws` tillagd som WebSocket-URL.

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

Kör det här skriptet och kopiera Speech Engine-ID:t (t.ex. `seng_8k3m9xr4hjnfg983brhmhkd98n6`) till nästa steg.

#### Skapa servern

Skapa en fil med namnet `server.py` eller `server.mts` med följande innehåll. Det här konfigurerar en server, kopplar Speech Engine till sökvägen `/ws` och använder OpenAI för att generera svar.

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

Callbacken `onTranscript` / `on_transcript` tar emot hela konversationshistoriken och den aktuella sessionen. TypeScript SDK:t tillhandahåller också en `AbortSignal` som aktiveras om användaren avbryter mitt i ett svar. Om du skickar `signal` till OpenAI-anropet avbryts LLM-begäran automatiskt vid avbrott.

`sendResponse()` / `send_response()` accepterar en sträng, en asynkron itererbar samling eller en stream från OpenAI, Anthropic eller Google Gemini. SDK:t extraherar textinnehållet automatiskt.

> **Warning**
>
> I exemplet ovan skickas användarens fullständiga transkript till LLM:en. I en produktionsmiljö bör du lägga till skyddsräcken för att förhindra försök till promptinjektion eller manipulering.

#### Starta servern

```python
python server.py
```

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

## Klientkonfiguration

#### Installera klient-SDK:t

#### React

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

#### JavaScript

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

#### Skapa en tokenändpunkt

Lägg till en ändpunkt på serversidan som genererar en konversationstoken. Det håller din API-nyckel utanför webbläsaren och använder WebRTC för bästa ljudkvalitet.

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

#### Bygg konversationsgränssnittet

Hämta konversationstoken från din server och använd den för att starta en session.

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

#### Prova det

Kontrollera att tre processer körs:

1. **ngrok** - vidarebefordrar till port 3001
2. **Din Speech Engine-server** - `python server.py` eller `npx tsx server.mts`
3. **Tokenservern** - `npx tsx token-server.mts` eller `python token_server.py`

Öppna din klientapplikation i webbläsaren och klicka på **Starta konversation**. Ge åtkomst till mikrofonen när du uppmanas och börja sedan prata. Du bör höra agenten svara via dina högtalare.

Om du har `debug: true` aktiverat på servern visas inkommande transkript och utgående svar i konsolen.

## Sessionshändelser

| Händelse          | TypeScript-callback | Python-callback | Beskrivning                                                                                    |
| ----------------- | ------------------- | --------------- | ---------------------------------------------------------------------------------------------- |
| `user_transcript` | `onTranscript`      | `on_transcript` | Användartal transkriberat. Innehåller fullständig konversationshistorik och en avbrottssignal. |
| `init`            | `onInit`            | `on_init`       | Sessionen har initierats med ett konversations-ID.                                             |
| `close`           | `onClose`           | `on_close`      | Ren frånkoppling från ElevenLabs.                                                              |
| `disconnected`    | `onDisconnect`      | `on_disconnect` | WebSocket kopplades ned oväntat.                                                               |
| `error`           | `onError`           | `on_error`      | Protokoll- eller WebSocket-fel.                                                                |

## Konfigurera agentens första meddelande

Som standard väntar agenten på att användaren ska tala först. Om du vill att agenten ska hälsa användaren när konversationen startar anger du ett första meddelande i alternativet `overrides` på klienten när du startar sessionen.

För att låta agenten tala först behöver vi uppdatera Speech Engine-resursen så att detta kan ställas in från klienten.

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

Sedan konfigurerar vi det första meddelandet i klient-SDK:t.

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

Det första meddelandet uttalas av agenten så snart anslutningen har upprättats. Det aktiverar inte callbacken `onTranscript` på din server – det hanteras helt på ElevenLabs sida.

## Nästa steg

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

Klasser, metoder och händelser för JavaScript SDK:t.

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

Klasser, metoder och händelser för Python SDK:t.

#### [API-referens](/docs/sv/api-reference/speech-engine/create)

Utforska alla Speech Engine-parametrar och svarsformat.

#### [Exempelapp för Next.js](https://github.com/elevenlabs/examples/tree/main/speech-engine/nextjs/quickstart)

Kör en komplett Speech Engine-snabbstartsapp lokalt.