Envoyer de l’audio généré via Twilio

Découvrez comment intégrer de la parole générée dans des appels téléphoniques avec Twilio.

Guide pratique · Suppose que vous avez terminé le guide de démarrage rapide ElevenAPI et que vous disposez d’un compte Twilio.

Dans ce guide, vous apprendrez à envoyer un message généré par IA lors d’un appel téléphonique avec Twilio et ElevenLabs. Ce processus vous permet d’envoyer des messages vocaux de haute qualité directement à vos appelants.

Créer des comptes Twilio et ngrok

Nous utiliserons Twilio et ngrok dans ce guide. Créez donc des comptes sur ces plateformes.

Créer le serveur avec Express

Initialiser votre projet

Créez un nouveau dossier pour votre projet.

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

Installer les dépendances

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

Installer les dépendances de développement

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

Créer vos fichiers

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

Comprendre le code

Gérer l’appel entrant

Lorsque vous appelez votre numéro, Twilio envoie une requête POST à votre point de terminaison /call/incoming. Nous utilisons ensuite twiml.connect pour indiquer à Twilio que nous voulons gérer l’appel via notre websocket, en définissant l’URL de notre point de terminaison /call/connection.

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

Créer la synthèse vocale

Ici, nous écoutons les messages que Twilio envoie à notre point de terminaison websocket. Lorsque nous recevons un événement de message start, nous générons l’audio à l’aide du SDK TypeScript ElevenLabs.

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

Envoyer le message

Après réception de l’audio d’ElevenLabs, nous le convertissons en array buffer et l’envoyons à Twilio via le websocket.

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

Diriger ngrok vers votre application

Twilio requiert une URL accessible publiquement. Nous utiliserons ngrok pour transférer le port local de notre application et l’exposer via une URL publique.

Exécutez la commande suivante dans votre terminal :

ngrok http 5000

Copiez le domaine ngrok, sans https://, pour l’utiliser dans vos variables d’environnement.

Mettre à jour vos variables d’environnement

Mettez à jour le fichier .env avec votre domaine ngrok et votre clé API ElevenLabs.

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

Démarrer l’application

Exécutez la commande suivante pour démarrer l’application :

npm run dev

Configurer Twilio

Suivez les guides de Twilio pour créer un nouveau numéro. Une fois votre numéro créé, accédez à l’onglet « Configure » dans Phone Numbers -> Manage -> Active numbers.

Dans la section « A call comes in », saisissez l’URL complète de votre application, en veillant à ajouter le chemin /call/incoming :

Ex. https://***ngrok.app/call/incoming

Passer un appel téléphonique

Appelez votre numéro. Vous devriez entendre un message utilisant une voix ElevenLabs.

Conseils pour le déploiement en production

Lorsque vous exécutez l’application en production, veillez à définir la variable d’environnement SERVER_DOMAIN sur le domaine de votre serveur. Mettez également à jour l’URL dans Twilio afin qu’elle pointe vers votre serveur de production.

Conclusion

Vous devriez désormais comprendre les bases de l’intégration de Twilio avec les voix ElevenLabs. Pour toute question ou suggestion d’amélioration de cet article de blog, vous pouvez sélectionner le bouton « Suggest edits » ou « Raise issue » ci-dessous.