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

# Quickstart di Speech Engine

Questa guida ti accompagna nella creazione di un agente con funzionalità vocali usando Speech Engine. Configurerai un server che collega il tuo LLM a ElevenLabs, quindi un client per browser che permette agli utenti di conversare a voce con il tuo agente.

> **Tip**
>
> Usa la [skill Speech Engine di ElevenLabs](https://github.com/elevenlabs/skills/tree/main/speech-engine) per aggiungere la voce al tuo agente di chat:
>
> ```bash
> npx skills add elevenlabs/skills --skill speech-engine
> ```

## Come funziona Speech Engine

Speech Engine collega il tuo LLM a ElevenLabs, così gli utenti possono parlare con il tuo agente e ascoltarne le risposte. ElevenLabs gestisce speech-to-text e text-to-speech; il tuo server fornisce la logica 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)
```

Ogni connessione WebSocket rappresenta una conversazione. Quando l'utente parla, ElevenLabs trascrive l'audio e invia la trascrizione al tuo server. Il server la passa al tuo LLM, quindi trasmette la risposta in streaming. ElevenLabs converte il testo in parlato e lo riproduce nel browser. L'SDK gestisce la connessione, i turni di conversazione e il rilevamento delle interruzioni.

## Prerequisiti

Questo tutorial usa l'API di OpenAI per l'LLM. Devi impostare una chiave API OpenAI nella variabile d'ambiente `OPENAI_API_KEY`.

## Configurazione del server

#### Crea una chiave API

[Crea qui una chiave API nella dashboard](https://elevenlabs.io/app/settings/api-keys), che userai per [accedere all'API](/docs/it/api-reference/authentication) in modo sicuro.

Archivia la chiave come secret gestito e passala agli SDK come variabile d'ambiente tramite un file `.env` oppure direttamente nella configurazione della tua app, a seconda delle tue preferenze.

**`.env`**

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

#### Installa le dipendenze

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

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

#### Esponi il server

Speech Engine richiede un URL accessibile pubblicamente. Usa [ngrok](https://ngrok.com) per esporre il tuo server locale. Il server non è ancora stato creato, ma ngrok deve essere già in esecuzione per avere l'URL necessario al passaggio successivo.

```bash
ngrok http 3001
```

Copia l'URL di inoltro (ad es. `https://abc123.ngrok.io`).

#### Crea un'istanza di Speech Engine

Usa l'SDK per creare un'istanza di Speech Engine, passando l'URL ngrok con il path `/ws` aggiunto come URL 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);
```

Esegui questo script e copia l'ID di Speech Engine (ad es. `seng_8k3m9xr4hjnfg983brhmhkd98n6`) per il passaggio successivo.

#### Crea il server

Crea un file denominato `server.py` o `server.mts` con il seguente contenuto. Questo configura un server, collega Speech Engine al path `/ws` e usa OpenAI per generare risposte.

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

Il callback `onTranscript` / `on_transcript` riceve l'intera cronologia della conversazione e la sessione corrente. L'SDK TypeScript fornisce anche un `AbortSignal` che si attiva se l'utente interrompe la risposta a metà. Passando `signal` alla chiamata OpenAI, la richiesta LLM viene annullata automaticamente in caso di interruzione.

`sendResponse()` / `send_response()` accetta una stringa, un iterabile asincrono o uno stream da OpenAI, Anthropic o Google Gemini. L'SDK estrae automaticamente il contenuto testuale.

> **Warning**
>
> Nell'esempio precedente, la trascrizione completa dell'utente viene passata all'LLM. In un ambiente di produzione dovresti aggiungere guardrail per prevenire tentativi di prompt injection o manipolazione.

#### Avvia il server

```python
python server.py
```

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

## Configurazione del client

#### Installa l'SDK client

#### React

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

#### JavaScript

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

#### Crea un endpoint token

Aggiungi un endpoint lato server che genera un token di conversazione. In questo modo la chiave API non viene esposta nel browser e puoi usare WebRTC per la migliore qualità audio.

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

#### Crea l'interfaccia della conversazione

Recupera il token di conversazione dal tuo server e usalo per avviare una sessione.

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

#### Provalo

Assicurati che siano in esecuzione tre processi:

1. **ngrok** - inoltro alla porta 3001
2. **Il tuo server Speech Engine** - `python server.py` o `npx tsx server.mts`
3. **Il server token** - `npx tsx token-server.mts` o `python token_server.py`

Apri la tua applicazione client nel browser e fai clic su **Avvia conversazione**. Quando richiesto, autorizza l'accesso al microfono, poi parla. Dovresti sentire l'agente rispondere dagli altoparlanti.

Se hai attivato `debug: true` sul server, vedrai le trascrizioni in entrata e le risposte in uscita registrate nella console.

## Eventi della sessione

| Evento            | Callback TypeScript | Callback Python | Descrizione                                                                                                      |
| ----------------- | ------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------- |
| `user_transcript` | `onTranscript`      | `on_transcript` | Parlato dell'utente trascritto. Include la cronologia completa della conversazione e un segnale di annullamento. |
| `init`            | `onInit`            | `on_init`       | Sessione inizializzata con un ID conversazione.                                                                  |
| `close`           | `onClose`           | `on_close`      | Disconnessione pulita da ElevenLabs.                                                                             |
| `disconnected`    | `onDisconnect`      | `on_disconnect` | WebSocket interrotto in modo imprevisto.                                                                         |
| `error`           | `onError`           | `on_error`      | Errore del protocollo o di WebSocket.                                                                            |

## Configurare il primo messaggio dell'agente

Per impostazione predefinita, l'agente attende che l'utente parli per primo. Per fare in modo che saluti l'utente all'avvio della conversazione, imposta un primo messaggio nell'opzione `overrides` del client all'avvio della sessione.

Per consentire all'agente di parlare per primo, dobbiamo aggiornare la risorsa Speech Engine per permettere di impostarlo dal client.

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

Configuriamo quindi il primo messaggio nell'SDK client.

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

Il primo messaggio viene pronunciato dall'agente non appena viene stabilita la connessione. Non attiva il callback `onTranscript` sul tuo server: viene gestito interamente da ElevenLabs.

## Passaggi successivi

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

Classi, metodi ed eventi per l'SDK JavaScript.

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

Classi, metodi ed eventi per l'SDK Python.

#### [Riferimento API](/docs/it/api-reference/speech-engine/create)

Esplora tutti i parametri e i formati di risposta di Speech Engine.

#### [App di esempio Next.js](https://github.com/elevenlabs/examples/tree/main/speech-engine/nextjs/quickstart)

Esegui localmente un'app quickstart completa di Speech Engine.