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

# Skicka genererat ljud via Twilio

> **Note**
>
> **Guide** · Förutsätter att du har slutfört [ElevenAPI- snabbstarten](/docs/sv/eleven-api/quickstart) och har ett Twilio-konto.

I den här guiden lär du dig hur du skickar ett AI-genererat meddelande via ett telefonsamtal med Twilio och ElevenLabs. Med den här processen kan du skicka röstmeddelanden av hög kvalitet direkt till dina uppringare.

## Skapa konton hos Twilio och ngrok

Vi använder Twilio och ngrok i den här guiden, så skapa konton hos dem.

* [twilio.com](https://www.twilio.com)
* [ngrok.com](https://ngrok.com)

## Skapa servern med Express

### Initiera projektet

Skapa en ny mapp för projektet

```
mkdir elevenlabs-twilio
cd elevenlabs-twilio
npm init -y
```

### Installera beroenden

```
npm install @elevenlabs/elevenlabs-js express express-ws twilio
```

### Installera utvecklingsberoenden

```
npm i @types/node @types/express @types/express-ws @types/ws dotenv tsx typescript
```

### Skapa filer

```ts
// src/app.ts
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";
import express, { Response } from "express";
import ExpressWs from "express-ws";
import { Readable } from "stream";
import VoiceResponse from "twilio/lib/twiml/VoiceResponse";
import { type WebSocket } from "ws";

const app = ExpressWs(express()).app;
const PORT: number = parseInt(process.env.PORT || "5000");

const elevenlabs = new ElevenLabsClient();
const voiceId = "aMSt68OGf4xUZAnLpTU8";
const outputFormat = "ulaw_8000";
const text = "This is a test. You can now hang up. Thank you.";

function startApp() {
  app.post("/call/incoming", (_, res: Response) => {
    const twiml = new VoiceResponse();

    twiml.connect().stream({
      url: `wss://${process.env.SERVER_DOMAIN}/call/connection`,
    });

    res.writeHead(200, { "Content-Type": "text/xml" });
    res.end(twiml.toString());
  });

  app.ws("/call/connection", (ws: WebSocket) => {
    ws.on("message", async (data: string) => {
      const message: {
        event: string;
        start?: { streamSid: string; callSid: string };
      } = JSON.parse(data);

      if (message.event === "start" && message.start) {
        const streamSid = message.start.streamSid;
        const response = await elevenlabs.textToSpeech.convert(voiceId, {
          modelId: "eleven_flash_v2_5",
          outputFormat: outputFormat,
          text,
        });

        const readableStream = Readable.from(response);
        const audioArrayBuffer = await streamToArrayBuffer(readableStream);

        ws.send(
          JSON.stringify({
            streamSid,
            event: "media",
            media: {
              payload: Buffer.from(audioArrayBuffer as any).toString("base64"),
            },
          })
        );
      }
    });

    ws.on("error", console.error);
  });

  app.listen(PORT, () => {
    console.log(`Local: http://localhost:${PORT}`);
    console.log(`Remote: https://${process.env.SERVER_DOMAIN}`);
  });
}

function streamToArrayBuffer(readableStream: Readable) {
  return new Promise((resolve, reject) => {
    const chunks: Buffer[] = [];

    readableStream.on("data", (chunk) => {
      chunks.push(chunk);
    });

    readableStream.on("end", () => {
      resolve(Buffer.concat(chunks).buffer);
    });

    readableStream.on("error", reject);
  });
}

startApp();
```

```env
# .env
SERVER_DOMAIN=
ELEVENLABS_API_KEY=
```

## Förstå koden

### Hantera inkommande samtal

När du ringer ditt nummer skickar Twilio en POST-begäran till din slutpunkt på `/call/incoming`.
Vi använder sedan twiml.connect för att tala om för Twilio att vi vill hantera samtalet via vår websocket genom att ange URL:en till vår `/call/connection`-slutpunkt.

```ts
function startApp() {
  app.post('/call/incoming', (_, res: Response) => {
    const twiml = new VoiceResponse();

    twiml.connect().stream({
      url: `wss://${process.env.SERVER_DOMAIN}/call/connection`,
    });

    res.writeHead(200, { 'Content-Type': 'text/xml' });
    res.end(twiml.toString());
  });
```

### Skapa text till tal

Här lyssnar vi efter meddelanden som Twilio skickar till vår websocket-slutpunkt. När vi tar emot en `start`-meddelandehändelse genererar vi ljud med ElevenLabs [TypeScript SDK](https://github.com/elevenlabs/elevenlabs-js).

```ts
  app.ws('/call/connection', (ws: WebSocket) => {
    ws.on('message', async (data: string) => {
      const message: {
        event: string;
        start?: { streamSid: string; callSid: string };
      } = JSON.parse(data);

      if (message.event === 'start' && message.start) {
        const streamSid = message.start.streamSid;
        const response = await elevenlabs.textToSpeech.convert(voiceId, {
          modelId: 'eleven_flash_v2_5',
          outputFormat: outputFormat,
          text,
        });
```

### Skicka meddelandet

När vi får tillbaka ljudet från ElevenLabs konverterar vi det till en arraybuffer och skickar ljudet till Twilio via websocketen.

```ts
const readableStream = Readable.from(response);
const audioArrayBuffer = await streamToArrayBuffer(readableStream);

ws.send(
  JSON.stringify({
    streamSid,
    event: "media",
    media: {
      payload: Buffer.from(audioArrayBuffer as any).toString("base64"),
    },
  })
);
```

## Peka ngrok till din applikation

Twilio kräver en offentligt tillgänglig URL. Vi använder ngrok för att vidarebefordra den lokala porten för vår applikation och exponera den som en offentlig URL.

Kör följande kommando i terminalen:

```
ngrok http 5000
```

Kopiera ngrok-domänen (utan https\://) för att använda den i dina miljövariabler.

![](/docs/_fern-files/elevenlabs.docs.buildwithfern.com/830a701ecee4b2bd32f44a891806a91e00f27dcf263c5917fa20a91a3353d6a1/assets/images/cookbooks/ngrok.webp)

## Uppdatera miljövariablerna

Uppdatera `.env`-filen med din ngrok-domän och ElevenLabs API-nyckel.

```
# .env
SERVER_DOMAIN=*******.ngrok.app
ELEVENLABS_API_KEY=*************************
```

## Starta applikationen

Kör följande kommando för att starta appen:

```
npm run dev
```

## Konfigurera Twilio

Följ Twilios guider för att skapa ett nytt nummer. När du har skapat numret går du till fliken "Configure" i Phone Numbers -> Manage -> Active numbers

I avsnittet "A call comes in" anger du den fullständiga URL:en till din applikation (se till att lägga till sökvägen `/call/incoming`):

T.ex. https\://**\*\*\***&#x6E;grok.app/call/incoming

![](/docs/_fern-files/elevenlabs.docs.buildwithfern.com/8f57f550bca8ac451980d98482ff5877c4f8fac30035e712cd0375a6527686ff/assets/images/cookbooks/twilio.webp)

## Ring ett samtal

Ring ditt nummer. Du bör höra ett meddelande med ElevenLabs-rösten.

## Tips för driftsättning i produktion

När du kör applikationen i produktion ska du se till att ange miljövariabeln `SERVER_DOMAIN` till serverns domän. Se också till att uppdatera URL:en i Twilio så att den pekar på produktionsservern.

## Slutsats

Du bör nu ha en grundläggande förståelse för hur du integrerar Twilio med ElevenLabs-röster. Om du har fler frågor eller förslag på hur vi kan förbättra det här blogginlägget kan du välja knappen "Suggest edits" eller "Raise issue" nedan.