Hoppa till navigering

Skicka genererat ljud via Twilio

Lär dig hur du integrerar genererat tal i telefonsamtal med Twilio.

Guide · Förutsätter att du har slutfört ElevenAPI- snabbstarten 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.

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

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

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.

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.

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.

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://***ngrok.app/call/incoming

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.