JavaScript SDK

Scribe: JavaScript에서 실시간 음성 텍스트 변환

Scribe 및 해당 기능의 개요는 음성 텍스트 변환 개요를 참조하세요. 단계별 사용 가이드는 클라이언트 측 스트리밍을 참조하세요.

설치

npm install @elevenlabs/client
# or
yarn add @elevenlabs/client
# or
pnpm install @elevenlabs/client

ElevenLabs 음성 텍스트 변환 스킬을 사용하여 AI 코딩 어시스턴트에서 오디오를 텍스트로 변환하세요.

npx skills add elevenlabs/skills --skill speech-to-text

이 라이브러리는 모든 JavaScript 기반 프로젝트에서 사용할 수 있습니다. React를 사용한다면, 기본 상태 관리 및 수명 주기 처리를 제공하는 useScribe 훅을 고려해 보세요.

사용법

다음은 Scribe에 연결하고 트랜스크립션 결과를 기록하는 최소 작동 예시입니다.

import { Scribe, RealtimeEvents } from "@elevenlabs/client";
const token = await fetchTokenFromServer();
const connection = Scribe.connect({
token,
modelId: "scribe_v2_realtime",
microphone: {
echoCancellation: true,
noiseSuppression: true,
},
});
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (data) => {
console.log("Partial:", data.text);
});
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (data) => {
console.log("Committed:", data.text);
});
// Later, close the connection
connection.close();

토큰 가져오기

Scribe는 인증을 위해 일회용 토큰이 필요합니다. 서버에 API 엔드포인트를 만드세요.

// Node.js server
app.get("/scribe-token", yourAuthMiddleware, async (req, res) => {
const response = await fetch("https://api.elevenlabs.io/v1/single-use-token/realtime_scribe", {
method: "POST",
headers: {
"xi-api-key": process.env.ELEVENLABS_API_KEY,
},
});
const data = await response.json();
res.json({ token: data.token });
});

ElevenLabs API 키는 민감한 정보입니다. 절대 클라이언트에 노출하지 마세요. 항상 서버에서 토큰을 생성하세요.

// Client
const fetchToken = async () => {
const response = await fetch("/scribe-token");
const { token } = await response.json();
return token;
};

연결 옵션

Scribe.connect()는 마이크 옵션 또는 수동 오디오 옵션을 받습니다. 두 옵션은 공통 기본 옵션 세트를 공유합니다.

기본 옵션

속성유형기본값설명
tokenstringWebSocket 인증을 위한 일회용 토큰입니다.
modelIdstring모델 ID입니다(예: "scribe_v2_realtime").
baseUristring"wss://api.elevenlabs.io"사용자 지정 WebSocket 기본 URI입니다.
commitStrategyCommitStrategy"manual""manual" 또는 "vad"입니다.
vadSilenceThresholdSecsnumber1.5VAD가 커밋하기 전의 무음 시간(초)입니다(0.3~3.0).
vadThresholdnumber0.4VAD 민감도입니다(0.1~0.9, 낮을수록 민감함).
minSpeechDurationMsnumber100최소 음성 길이(ms)입니다(50~2000).
minSilenceDurationMsnumber100최소 무음 길이(ms)입니다(50~2000).
languageCodestringISO-639-1 또는 ISO-639-3 언어 코드입니다. 자동 감지를 위해 비워 두세요.
includeTimestampsbooleanfalseCOMMITTED_TRANSCRIPT_WITH_TIMESTAMPS 이벤트를 통해 단어 수준 타임스탬프를 받습니다.

마이크 옵션

microphone 객체를 전달하면 사용자의 마이크에서 오디오를 직접 스트리밍합니다. 연결이 getUserMedia와 오디오 인코딩을 자동으로 처리합니다.

const connection = Scribe.connect({
token,
modelId: "scribe_v2_realtime",
microphone: {
deviceId: "optional-device-id",
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
},
});
속성유형설명
deviceIdstring특정 마이크 기기 ID입니다.
echoCancellationboolean에코 제거를 활성화합니다.
noiseSuppressionboolean노이즈 억제를 활성화합니다.
autoGainControlboolean자동 게인 제어를 활성화합니다.

수동 오디오 옵션

audioFormat 및 sampleRate를 전달하면 connection.send()를 통해 오디오 데이터를 수동으로 보낼 수 있습니다.

import { AudioFormat } from "@elevenlabs/client";
const connection = Scribe.connect({
token,
modelId: "scribe_v2_realtime",
audioFormat: AudioFormat.PCM_16000,
sampleRate: 16000,
});
속성유형설명
audioFormatAudioFormat오디오 인코딩 형식입니다(예: AudioFormat.PCM_16000).
sampleRatenumberHz 단위의 샘플 레이트입니다. audioFormat과 일치해야 합니다.

AudioFormat 열거형

enum AudioFormat {
PCM_8000 = "pcm_8000",
PCM_16000 = "pcm_16000",
PCM_22050 = "pcm_22050",
PCM_24000 = "pcm_24000",
PCM_44100 = "pcm_44100",
PCM_48000 = "pcm_48000",
ULAW_8000 = "ulaw_8000",
}

마이크 모드

사용자의 마이크에서 오디오를 직접 스트리밍합니다.

import { Scribe, RealtimeEvents } from "@elevenlabs/client";
async function transcribeFromMicrophone() {
const token = await fetchToken();
const connection = Scribe.connect({
token,
modelId: "scribe_v2_realtime",
microphone: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
},
});
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (data) => {
document.getElementById("live").textContent = data.text;
});
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (data) => {
const el = document.createElement("p");
el.textContent = data.text;
document.getElementById("transcripts").appendChild(el);
document.getElementById("live").textContent = "";
});
document.getElementById("stop").addEventListener("click", () => {
connection.close();
});
}

수동 오디오 모드(파일 트랜스크립션)

오디오 데이터를 수동으로 전송하여 사전 녹음된 오디오 파일을 텍스트로 변환합니다.

import { Scribe, RealtimeEvents, AudioFormat } from "@elevenlabs/client";
async function transcribeFile(file) {
const token = await fetchToken();
const connection = Scribe.connect({
token,
modelId: "scribe_v2_realtime",
audioFormat: AudioFormat.PCM_16000,
sampleRate: 16000,
});
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (data) => {
console.log("Transcript:", data.text);
});
// Decode audio file
const arrayBuffer = await file.arrayBuffer();
const audioContext = new AudioContext({ sampleRate: 16000 });
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
// Convert to PCM16
const channelData = audioBuffer.getChannelData(0);
const pcmData = new Int16Array(channelData.length);
for (let i = 0; i < channelData.length; i++) {
const sample = Math.max(-1, Math.min(1, channelData[i]));
pcmData[i] = sample < 0 ? sample * 32768 : sample * 32767;
}
// Send in chunks
const chunkSize = 4096;
for (let offset = 0; offset < pcmData.length; offset += chunkSize) {
const chunk = pcmData.slice(offset, offset + chunkSize);
const bytes = new Uint8Array(chunk.buffer);
const base64 = btoa(String.fromCharCode(...bytes));
connection.send({ audioBase64: base64 });
await new Promise((resolve) => setTimeout(resolve, 50));
}
// Commit and close
connection.commit();
}

RealtimeConnection

Scribe.connect()는 다음 메서드를 갖는 RealtimeConnection 인스턴스를 반환합니다.

on(event, listener)

이벤트 리스너를 등록합니다. 사용 가능한 이벤트 유형은 이벤트를 참조하세요.

connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (data) => {
console.log("Committed:", data.text);
});

off(event, listener)

이전에 등록한 이벤트 리스너를 제거합니다.

const handler = (data) => console.log(data.text);
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, handler);
// Later
connection.off(RealtimeEvents.COMMITTED_TRANSCRIPT, handler);

send(data)

Scribe로 오디오 데이터를 전송합니다(수동 오디오 모드 전용).

connection.send({
audioBase64: base64AudioChunk,
commit: false, // Optional: commit immediately
sampleRate: 16000, // Optional: override sample rate
previousText: "Previous transcription text", // Optional: context from a previous transcription
});

previousText 필드는 세션의 첫 번째 오디오 청크에서만 전송할 수 있습니다. 이후 청크에서 전송하면 오류가 발생합니다.

commit()

현재 트랜스크립션을 수동으로 커밋합니다. CommitStrategy.MANUAL을 사용할 때만 필요합니다.

connection.commit();

close()

WebSocket 연결을 닫고 리소스(마이크 스트림, 오디오 컨텍스트)를 정리합니다.

connection.close();

이벤트

connection.on(event, listener)를 사용하여 이벤트 리스너를 등록합니다. 모든 이벤트는 RealtimeEvents 열거형의 상수로 제공됩니다.

트랜스크립션 이벤트

이벤트데이터설명
SESSION_STARTED{ session_id: string }Scribe 세션이 시작되었습니다.
PARTIAL_TRANSCRIPT{ text: string }중간 트랜스크립션 결과입니다.
COMMITTED_TRANSCRIPT{ text: string }확정된 트랜스크립션 결과입니다.
COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS{ text: string; language_code?: string; words?: WordsItem[] }단어 수준 타이밍이 포함된 확정 결과입니다.

WordsItem 유형에는 단어 수준 타이밍 정보가 포함됩니다.

interface WordsItem {
text?: string; // Word text
start?: number; // Start time in seconds
end?: number; // End time in seconds
type?: "word" | "spacing"; // Token type
speaker_id?: string; // Speaker identifier
}

연결 이벤트

이벤트데이터설명
OPENEventWebSocket 연결이 열렸습니다.
CLOSEEventWebSocket 연결이 닫혔습니다.
ERRORError | Event일반 오류입니다.

오류 이벤트

모든 오류 이벤트는 { error: string }을 받습니다.

이벤트설명
AUTH_ERROR인증 오류입니다.
QUOTA_EXCEEDED사용량 할당량을 초과했습니다.
COMMIT_THROTTLED커밋 요청이 제한되었습니다.
TRANSCRIBER_ERROR트랜스크립션 엔진 오류입니다.
UNACCEPTED_TERMS서비스 약관에 동의하지 않았습니다.
RATE_LIMITED요청 한도에 도달했습니다.
INPUT_ERROR잘못된 입력 형식입니다.
QUEUE_OVERFLOW처리 큐가 가득 찼습니다.
RESOURCE_EXHAUSTED서버 리소스가 최대 용량에 도달했습니다.
SESSION_TIME_LIMIT_EXCEEDED최대 세션 시간에 도달했습니다.
CHUNK_SIZE_EXCEEDED오디오 청크가 너무 큽니다.
INSUFFICIENT_AUDIO_ACTIVITY연결을 유지하기 위한 오디오 활동이 부족합니다.

커밋 전략

트랜스크립션을 커밋할 시점을 제어합니다.

import { Scribe, CommitStrategy } from '@elevenlabs/client';
// Manual (default): you control when to commit
const connection = Scribe.connect({
token,
modelId: 'scribe_v2_realtime',
audioFormat: AudioFormat.PCM_16000,
sampleRate: 16000,
commitStrategy: CommitStrategy.MANUAL,
});
// Send audio, then commit when ready
connection.send({ audioBase64: chunk });
connection.commit();
// Voice Activity Detection: Scribe detects silences and commits automatically
const connection = Scribe.connect({
token,
modelId: 'scribe_v2_realtime',
microphone: { echoCancellation: true },
commitStrategy: CommitStrategy.VAD,
});

자세한 내용은 트랜스크립트 및 커밋 전략을 참조하세요.

전체 예시

다음은 VAD 기반 커밋 전략으로 마이크 오디오를 텍스트로 변환하는 전체 예시입니다.

import { Scribe, RealtimeEvents, CommitStrategy } from "@elevenlabs/client";
async function startTranscription() {
const token = await fetchToken();
const connection = Scribe.connect({
token,
modelId: "scribe_v2_realtime",
commitStrategy: CommitStrategy.VAD,
microphone: {
echoCancellation: true,
noiseSuppression: true,
},
});
connection.on(RealtimeEvents.SESSION_STARTED, (data) => {
console.log("Session started:", data.session_id);
});
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (data) => {
document.getElementById("live").textContent = data.text;
});
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (data) => {
const el = document.createElement("p");
el.textContent = data.text;
document.getElementById("transcripts").appendChild(el);
document.getElementById("live").textContent = "";
});
connection.on(RealtimeEvents.ERROR, (error) => {
console.error("Scribe error:", error);
});
// Stop button
document.getElementById("stop").addEventListener("click", () => {
connection.close();
});
}
document.getElementById("start").addEventListener("click", startTranscription);