ElevenLabs
ElevenLabs 어댑터는 음성 중심입니다. 다음 네 가지 기능을 제공합니다.
- 실시간 음성 에이전트 (
elevenlabsRealtime/elevenlabsRealtimeToken) — ElevenLabs Conversational AI 에이전트로 구동되는 양방향 음성 간 대화를 제공합니다. - 텍스트 음성 변환 (
elevenlabsSpeech) —generateSpeech()를 통한 일회성 음성 생성을 제공합니다. - 음악 및 음향 효과 (
elevenlabsAudio) —generateAudio()를 통한 일회성 오디오 생성을 제공합니다. - 전사 (
elevenlabsTranscription) —generateTranscription()을 통한 음성-텍스트 변환을 제공합니다.
텍스트 chat() 또는 summarize()는 지원하지 않습니다. 해당 기능에는 OpenAI, Anthropic 또는 Gemini를 사용합니다.
실시간 어댑터는 에이전트 기반 아키텍처를 사용합니다. ElevenLabs 대시보드에서 대화형 AI 에이전트(음성, 성격, 지식 베이스, 도구)를 구성한 다음 런타임에 연결합니다. 이 어댑터는 @elevenlabs/client SDK를 래핑하여 useRealtimeChat 및 RealtimeClient와 원활하게 통합합니다.
설치
npm install @tanstack/ai-elevenlabs
피어 종속성:
npm install @tanstack/ai @tanstack/ai-client
서버 설정
서버는 서명된 WebSocket URL을 생성하므로 API 키가 클라이언트에 전달되지 않습니다. 서명된 URL은 30분 동안 유효합니다.
import { realtimeToken } from '@tanstack/ai'
import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
// In your API route (Express, Hono, TanStack Start, etc.)
export async function POST() {
const token = await realtimeToken({
adapter: elevenlabsRealtimeToken({
agentId: process.env.ELEVENLABS_AGENT_ID!,
}),
})
return Response.json(token)
}
재정의 사용
대시보드 구성을 변경하지 않고 토큰 생성 시 에이전트 설정을 재정의할 수 있습니다.
const token = await realtimeToken({
adapter: elevenlabsRealtimeToken({
agentId: process.env.ELEVENLABS_AGENT_ID!,
overrides: {
voiceId: 'custom-voice-id',
systemPrompt: 'You are a helpful voice assistant.',
firstMessage: 'Hello! How can I help you today?',
language: 'en',
},
}),
})
클라이언트 설정
리액트 (useRealtimeChat)
import { useRealtimeChat } from '@tanstack/ai-react'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
function VoiceChat() {
const {
status,
mode,
messages,
connect,
disconnect,
pendingUserTranscript,
pendingAssistantTranscript,
inputLevel,
outputLevel,
} = useRealtimeChat({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
})
return (
<div>
<p>Status: {status}</p>
<p>Mode: {mode}</p>
<button onClick={status === 'idle' ? connect : disconnect}>
{status === 'idle' ? 'Start Conversation' : 'End Conversation'}
</button>
{pendingUserTranscript && <p>You: {pendingUserTranscript}...</p>}
{pendingAssistantTranscript && (
<p>AI: {pendingAssistantTranscript}...</p>
)}
{messages.map((msg) => (
<div key={msg.id}>
<strong>{msg.role}:</strong>
{msg.parts.map((part, i) => (
<span key={i}>
{part.type === 'text' ? part.content : null}
{part.type === 'audio' ? part.transcript : null}
</span>
))}
</div>
))}
</div>
)
}
비리액트 (RealtimeClient)
import { RealtimeClient } from '@tanstack/ai-client'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
const client = new RealtimeClient({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
onMessage: (message) => {
console.log(`${message.role}:`, message.parts)
},
onStatusChange: (status) => {
console.log('Status:', status)
},
onModeChange: (mode) => {
console.log('Mode:', mode)
},
})
await client.connect()
클라이언트 도구
ElevenLabs는 브라우저에서 실행되는 클라이언트 측 도구를 지원합니다. 표준 toolDefinition() API를 사용해 도구를 정의합니다.
import { toolDefinition } from '@tanstack/ai'
import { useRealtimeChat } from '@tanstack/ai-react'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
import { z } from 'zod'
const getWeatherDef = toolDefinition({
name: 'getWeather',
description: 'Get weather for a location',
inputSchema: z.object({
location: z.string(),
}),
outputSchema: z.object({
temperature: z.number(),
conditions: z.string(),
}),
})
const getWeather = getWeatherDef.client(async ({ location }) => {
const res = await fetch(`/api/weather?location=${location}`)
return res.json()
})
// Pass tools to the hook
const chat = useRealtimeChat({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
tools: [getWeather],
})
도구 결과는 자동으로 문자열로 직렬화되어 ElevenLabs 에이전트에 반환됩니다. 어댑터는 내부적으로 TanStack 도구 정의를 @elevenlabs/client의 clientTools 형식으로 변환합니다.
구성
elevenlabsRealtimeToken 옵션
서명된 WebSocket URL을 생성할 때 서버에서 사용합니다.
| 옵션 | 타입 | 필수 | 설명 |
|---|---|---|---|
agentId | string | 아니요* | ElevenLabs 대시보드에서 구성한 에이전트 ID입니다. *ELEVENLABS_AGENT_ID로 대체되며 해당 환경 변수가 설정되지 않은 경우에만 필요합니다. |
overrides.voiceId | string | 아니요 | 에이전트의 기본 음성을 재정의하는 사용자 지정 음성 ID입니다. |
overrides.systemPrompt | string | 아니요 | 에이전트의 기본 시스템 프롬프트를 재정의하는 사용자 지정 시스템 프롬프트입니다. |
overrides.firstMessage | string | 아니요 | 세션이 시작될 때 에이전트가 말하는 첫 번째 메시지입니다. |
overrides.language | string | 아니요 | 언어 코드입니다(예: 'en', 'es', 'fr'). |
elevenlabsRealtime 옵션
연결을 설정할 때 클라이언트에서 사용합니다.
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
connectionMode | 'websocket' | 'webrtc' | 자동 감지 | 연결에 사용할 전송 프로토콜입니다. |
debug | boolean | DebugConfig | false | 디버그 로깅을 활성화합니다. 모든 카테고리에는 true를 전달하고, 카테고리/싱크를 선택하려면 DebugConfig를 전달합니다. |
OpenAI Realtime과의 차이점
ElevenLabs와 OpenAI는 실시간 음성에 서로 다른 접근 방식을 사용합니다.
| ElevenLabs | OpenAI | |
|---|---|---|
| 구성 | 에이전트 기반입니다. ElevenLabs 대시보드 또는 토큰 생성 시 overrides를 통해 음성, 성격, 지식을 구성합니다. | 세션 기반입니다. instructions 옵션을 통해 세션별로 voice, temperature, useRealtimeChat 등을 구성합니다. |
| 토큰 유형 | 서명된 WebSocket URL(30분 동안 유효) | 임시 API 토큰(약 10분 동안 유효) |
| 전송 | WebSocket(기본값) 또는 WebRTC | WebRTC |
| 오디오 처리 | @elevenlabs/client SDK가 오디오 캡처와 재생을 자동으로 관리합니다. | TanStack AI가 WebRTC 피어 연결과 오디오 트랙을 관리합니다. |
| VAD | ElevenLabs 서버 측에서 처리합니다. | server, semantic, manual 모드를 지원합니다. |
| 런타임 업데이트 | 세션 생성 시 구성이 설정되며 세션 중간에는 변경할 수 없습니다. | 세션 중간 구성 변경을 위한 updateSession()을 지원합니다. |
| 이미지 입력 | 지원하지 않습니다. | sendImage()를 통해 지원합니다. |
| 시간 영역 데이터 | SDK에서 제공하지 않습니다. | 파형 시각화에 사용할 수 있습니다. |
오디오 시각화
ElevenLabs 어댑터는 다른 실시간 어댑터와 동일한 인터페이스를 통해 오디오 시각화 데이터를 제공합니다.
import { useRealtimeChat } from '@tanstack/ai-react'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
const {
inputLevel, // 0-1 normalized microphone volume
outputLevel, // 0-1 normalized speaker volume
getInputFrequencyData, // Uint8Array frequency spectrum
getOutputFrequencyData,
} = useRealtimeChat({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
})
참고: ElevenLabs는 볼륨 수준과 주파수 데이터를 제공하지만 시간 영역 데이터는 노출하지 않습니다. getInputTimeDomainData() 및 getOutputTimeDomainData() 메서드는 정적인 자리 표시자 배열을 반환합니다. 기본 오디오 샘플 레이트는 16kHz입니다.
환경 변수
서버 환경에 다음을 설정합니다.
ELEVENLABS_API_KEY=your-elevenlabs-api-key
ELEVENLABS_AGENT_ID=your-agent-id
| 변수 | 필수 | 설명 |
|---|---|---|
ELEVENLABS_API_KEY | 예 | 서명된 URL 생성에 서버 측에서 사용하는 ElevenLabs API 키입니다. |
ELEVENLABS_AGENT_ID | 아니요 | 기본 에이전트 ID입니다. elevenlabsRealtimeToken()에 직접 전달할 수도 있습니다. |
API 키는 ElevenLabs 대시보드에서 가져옵니다. 대시보드의 Conversational AI 섹션에서 에이전트를 생성하고 구성합니다.
텍스트 음성 변환
일회성 음성 생성(실시간 아님)에는 generateSpeech()와 함께 elevenlabsSpeech를 사용합니다.
import { generateSpeech } from "@tanstack/ai";
import { elevenlabsSpeech } from "@tanstack/ai-elevenlabs";
const result = await generateSpeech({
adapter: elevenlabsSpeech("eleven_v3"),
text: "Hello from ElevenLabs!",
voice: "Rachel",
format: "mp3",
});
console.log(result.audio); // Base64-encoded audio
음악 및 음향 효과
elevenlabsAudio는 모델에 따라 음악 생성과 음향 효과를 모두 지원합니다.
import { generateAudio } from "@tanstack/ai";
import { elevenlabsAudio } from "@tanstack/ai-elevenlabs";
// Music generation
const music = await generateAudio({
adapter: elevenlabsAudio("music_v1"),
prompt: "An upbeat synthwave track for a product launch",
});
// Sound effects
const sfx = await generateAudio({
adapter: elevenlabsAudio("eleven_text_to_sound_v2"),
prompt: "A glass shattering on concrete",
});
전사
elevenlabsTranscription으로 오디오를 전사합니다.
import { generateTranscription } from "@tanstack/ai";
import { elevenlabsTranscription } from "@tanstack/ai-elevenlabs";
import { audioFile } from "./audio";
const result = await generateTranscription({
adapter: elevenlabsTranscription("scribe_v1"),
audio: audioFile,
});
console.log(result.text);
API 레퍼런스
elevenlabsRealtimeToken(options)
realtimeToken()과 함께 서버 측에서 사용할 ElevenLabs 실시간 토큰 어댑터를 생성합니다.
매개변수:
options.agentId- ElevenLabs 대시보드의 에이전트 IDoptions.overrides?.voiceId- 사용자 지정 음성 IDoptions.overrides?.systemPrompt- 사용자 지정 시스템 프롬프트options.overrides?.firstMessage- 에이전트가 말하는 첫 번째 메시지options.overrides?.language- 언어 코드
반환값: realtimeToken()과 함께 사용할 RealtimeTokenAdapter입니다.
elevenlabsRealtime(options?)
useRealtimeChat 또는 RealtimeClient와 함께 사용할 ElevenLabs 실시간 클라이언트 어댑터를 생성합니다.
매개변수:
options.connectionMode?-'websocket'또는'webrtc'(기본값: 자동 감지)options.debug?- 디버그 로깅 활성화
반환값: useRealtimeChat() 또는 RealtimeClient와 함께 사용할 RealtimeAdapter입니다.
elevenlabsSpeech(model, config?) / createElevenLabsSpeech(model, apiKey, config?)
generateSpeech()와 함께 사용할 ElevenLabs 텍스트 음성 변환 어댑터를 생성합니다.
elevenlabsAudio(model, config?) / createElevenLabsAudio(model, apiKey, config?)
generateAudio()와 함께 사용할 ElevenLabs 오디오 어댑터를 생성합니다. 이 어댑터는 음악 생성과 음향 효과를 모두 지원하며 모델 ID로 선택합니다.
elevenlabsTranscription(model, config?) / createElevenLabsTranscription(model, apiKey, config?)
generateTranscription()과 함께 사용할 ElevenLabs 전사 어댑터를 생성합니다.
제한 사항
- 텍스트 채팅 미지원 --
chat()에는 OpenAI, Anthropic, Gemini 또는 다른 텍스트 어댑터를 사용합니다. - 요약 미지원 --
summarize()에는 텍스트 어댑터를 사용합니다. - 이미지 입력 미지원 (실시간) -- ElevenLabs 실시간 기능은 대화 중 이미지 전송을 지원하지 않습니다.
- 런타임 세션 업데이트 미지원 (실시간) -- 세션 구성은 연결 시 고정됩니다.
- 시간 영역 오디오 데이터 미지원 (실시간) -- 주파수 데이터와 볼륨 수준은 사용할 수 있지만 파형 데이터는 사용할 수 없습니다.
- 에이전트 필요 (실시간) -- 실시간 어댑터를 사용하기 전에 ElevenLabs 대시보드에서 에이전트를 생성하고 구성해야 합니다.
다음 단계
- 실시간 음성 채팅 가이드 - 실시간 음성 애플리케이션 구축에 대한 전체 가이드
- OpenAI 어댑터 - WebRTC를 사용하는 대체 실시간 음성 제공자
- 도구 가이드 - 동형 도구 시스템 알아보기