Twilio를 통한 생성 오디오 전송

Twilio를 사용하여 생성된 음성을 전화 통화에 통합하는 방법을 알아보세요.

사용 방법 가이드 · ElevenAPI 빠른 시작을 완료했고 Twilio 계정이 있다고 가정합니다.

이 가이드에서는 Twilio와 ElevenLabs를 사용해 AI로 생성한 메시지를 전화 통화로 전송하는 방법을 알아봅니다. 이 과정을 통해 발신자에게 고품질 음성 메시지를 직접 보낼 수 있습니다.

Twilio 및 ngrok 계정 만들기

이 가이드에서는 Twilio와 ngrok를 사용하므로 먼저 계정을 만드세요.

Express로 서버 만들기

프로젝트 초기화

프로젝트용 새 폴더를 만드세요.

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

종속성 설치

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

개발 종속성 설치

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

파일 만들기

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

코드 이해하기

수신 통화 처리

번호로 전화하면 Twilio가 /call/incoming 엔드포인트로 POST 요청을 보냅니다. 그런 다음 url을 /call/connection 엔드포인트로 설정하여 웹소켓을 통해 통화를 처리하도록 twiml.connect를 사용해 Twilio에 알립니다.

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

텍스트 음성 변환 생성

여기서는 Twilio가 웹소켓 엔드포인트로 보내는 메시지를 수신합니다. start 메시지 이벤트를 수신하면 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,
});

메시지 전송

ElevenLabs에서 오디오를 받으면 배열 버퍼로 변환한 후 웹소켓을 통해 Twilio로 전송합니다.

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

애플리케이션에 ngrok 연결하기

Twilio는 공개적으로 액세스할 수 있는 URL을 요구합니다. ngrok를 사용해 애플리케이션의 로컬 포트를 전달하고 공개 URL로 노출합니다.

터미널에서 다음 명령어를 실행하세요.

ngrok http 5000

환경 변수에 사용할 ngrok 도메인(https:// 제외)을 복사하세요.

환경 변수 업데이트

.env 파일에 ngrok 도메인과 ElevenLabs API 키를 업데이트하세요.

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

애플리케이션 시작

다음 명령어를 실행해 앱을 시작하세요.

npm run dev

Twilio 설정

Twilio 가이드에 따라 새 번호를 만드세요. 번호를 만든 후 Phone Numbers -> Manage -> Active numbers에서 “Configure” 탭으로 이동하세요.

“A call comes in” 섹션에 애플리케이션의 전체 URL을 입력하세요( /call/incoming 경로를 반드시 추가하세요).

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

전화 걸기

번호로 전화를 거세요. ElevenLabs 음성을 사용한 메시지가 들립니다.

프로덕션 배포 팁

프로덕션에서 애플리케이션을 실행할 때는 SERVER_DOMAIN 환경 변수를 서버 도메인으로 설정하세요. Twilio의 URL도 프로덕션 서버를 가리키도록 업데이트해야 합니다.

마무리

이제 Twilio를 ElevenLabs 음성과 통합하는 기본 방법을 이해했을 것입니다. 추가 질문이 있거나 이 블로그 게시물을 개선할 제안이 있다면 아래의 “Suggest edits” 또는 “Raise issue” 버튼을 선택해 주세요.