React SDK

useScribe:Reactでリアルタイムのスピーチtoテキスト文字起こし

Scribeとその機能の概要については、スピーチtoテキストの 概要を参照してください。ステップごとの使い方については、クライアント側 ストリーミングを参照してください。

インストール

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

ElevenLabs speech-to-text skillを使用すると、AIコーディングアシスタントでオーディオを文字起こしできます。

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

@elevenlabs/reactは@elevenlabs/clientのすべてを再エクスポートするため、 両方のパッケージをインストールする必要はありません。

使い方

Scribeに接続し、リアルタイムの文字起こしを表示する最小限の動作例を紹介します。

import { useScribe } from "@elevenlabs/react";
import { useEffect } from "react";
function MyComponent() {
const scribe = useScribe({
modelId: "scribe_v2_realtime",
onPartialTranscript: (data) => {
console.log("Partial:", data.text);
},
onCommittedTranscript: (data) => {
console.log("Committed:", data.text);
},
});
// Start recording
const handleStart = async () => {
try {
const token = await fetchTokenFromServer();
await scribe.connect({
token,
microphone: {
echoCancellation: true,
noiseSuppression: true,
},
});
} catch (err) {
console.error("Failed to start recording:", err);
}
};
// Stop recording
const handleDisconnect = () => {
scribe.disconnect();
};
// Disconnect on unmount
useEffect(() => {
return () => {
if (scribe.isConnected) {
scribe.disconnect();
}
};
}, [scribe]);
return (
<div>
<button onClick={handleStart} disabled={scribe.isConnected}>
Start Recording
</button>
<button onClick={handleDisconnect} disabled={!scribe.isConnected}>
Stop
</button>
{scribe.partialTranscript && <p>Live: {scribe.partialTranscript}</p>}
<div>
{scribe.committedTranscripts.map((t) => (
<p key={t.id}>{t.text}</p>
))}
</div>
</div>
);
}

トークンの取得

Scribeでは、認証に1回限りのトークンが必要です。サーバーに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;
};

フックのオプション

デフォルトオプションとコールバックを指定してフックを設定します。

const scribe = useScribe({
// Connection options (can be overridden in connect())
token: "optional-default-token",
modelId: "scribe_v2_realtime",
baseUri: "wss://api.elevenlabs.io",
// VAD options
commitStrategy: CommitStrategy.VAD,
vadSilenceThresholdSecs: 0.5,
vadThreshold: 0.5,
minSpeechDurationMs: 100,
minSilenceDurationMs: 500,
languageCode: "en",
// Microphone options (for automatic mode)
microphone: {
deviceId: "optional-device-id",
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
},
// Manual audio options (for file transcription)
audioFormat: AudioFormat.PCM_16000,
sampleRate: 16000,
// Auto-connect on mount
autoConnect: false,
// Event callbacks
onSessionStarted: () => console.log("Session started"),
onPartialTranscript: (data) => console.log("Partial:", data.text),
onCommittedTranscript: (data) => console.log("Committed:", data.text),
onCommittedTranscriptWithTimestamps: (data) => console.log("With timestamps:", data),
onError: (error) => console.error("Error:", error),
onAuthError: (data) => console.error("Auth error:", data.error),
onQuotaExceededError: (data) => console.error("Quota exceeded:", data.error),
onConnect: () => console.log("Connected"),
onDisconnect: () => console.log("Disconnected"),
});

接続オプション

プロパティ型説明
tokenstringWebSocket認証用の1回限りのトークン。
modelIdstringモデルID(例:"scribe_v2_realtime")。
baseUristringカスタムWebSocketベースURI。デフォルトはwss://api.elevenlabs.ioです。

VADオプション

これらのオプションは、VADコミット戦略の使用時に文字起こしを自動的にコミットするタイミングを制御します。

プロパティ型デフォルト説明
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の言語コード。自動検出する場合は空のままにします。
microphoneobjectマイクモード用のマイク設定。以下を参照してください。
audioFormatAudioFormat手動モードのオーディオエンコード形式(例:AudioFormat.PCM_16000)。
sampleRatenumber手動モードのサンプルレート。audioFormatと一致する必要があります。

microphoneオブジェクトでは、次を指定できます。

プロパティ型説明
deviceIdstring特定のマイクデバイスID。
echoCancellationbooleanエコーキャンセルを有効にします。
noiseSuppressionbooleanノイズ抑制を有効にします。
autoGainControlboolean自動ゲイン制御を有効にします。

動作オプション

プロパティ型デフォルト説明
autoConnectbooleanfalseコンポーネントのマウント時に自動接続します。
includeTimestampsbooleanfalse単語レベルのタイムスタンプを受信します。onCommittedTranscriptWithTimestampsが指定されている場合は自動的に有効になります。

コールバック

すべてのイベントコールバックは任意で、フックのオプションとして指定できます。

  • onConnect - WebSocket接続が確立されたときに呼び出されるハンドラー。
  • onDisconnect - WebSocket接続が閉じられたときに呼び出されるハンドラー。
  • onSessionStarted - Scribeセッションの開始時に呼び出されるハンドラー。
  • onPartialTranscript - 暫定的な文字起こし結果を受け取るハンドラー。{ text: string }を受け取ります。
  • onCommittedTranscript - 確定した文字起こし結果を受け取るハンドラー。{ text: string }を受け取ります。
  • onCommittedTranscriptWithTimestamps - 単語レベルのタイミングを含む確定した文字起こし結果を受け取るハンドラー。{ text: string; words?: { start: number; end: number }[] }を受け取ります。
  • onError - すべてのエラーに対応する汎用エラーハンドラー。Error | Eventを受け取ります。
  • onAuthError - 認証エラー時に呼び出されるハンドラー。{ error: string }を受け取ります。

エラーコールバック

汎用のonErrorコールバックは、すべてのエラーで実行されます。より細かく処理するための特定エラー用コールバックも利用できます。すべての特定エラー用コールバックは{ error: string }を受け取ります。

コールバック説明
onErrorすべてのエラーに対応する汎用エラーハンドラー。
onAuthError認証エラー。
onQuotaExceededError使用量の上限を超過。
onCommitThrottledErrorコミットリクエストがスロットリングされた。
onTranscriberError文字起こしエンジンエラー。
onUnacceptedTermsError利用規約が承諾されていない。
onRateLimitedErrorレート制限。
onInputError無効な入力形式。
onQueueOverflowError処理キューが満杯。
onResourceExhaustedErrorサーバーリソースが上限に達している。
onSessionTimeLimitExceededError最大セッション時間に達した。
onChunkSizeExceededErrorオーディオチャンクが大きすぎる。
onInsufficientAudioActivityError接続を維持するためのオーディオアクティビティが不足している。

マイクモード

ユーザーのマイクからオーディオを直接ストリーミングします。

function MicrophoneTranscription() {
const scribe = useScribe({
modelId: "scribe_v2_realtime",
});
const startRecording = async () => {
const token = await fetchToken();
await scribe.connect({
token,
microphone: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
},
});
};
return (
<div>
<button onClick={startRecording} disabled={scribe.isConnected}>
{scribe.status === "connecting" ? "Connecting..." : "Start"}
</button>
<button onClick={scribe.disconnect} disabled={!scribe.isConnected}>
Stop
</button>
{scribe.partialTranscript && (
<div>
<strong>Speaking:</strong> {scribe.partialTranscript}
</div>
)}
{scribe.committedTranscripts.map((transcript) => (
<div key={transcript.id}>{transcript.text}</div>
))}
</div>
);
}

手動オーディオモード(ファイルの文字起こし)

事前に録音したオーディオファイルを文字起こしします。

import { useScribe, AudioFormat } from "@elevenlabs/react";
import { useState } from "react";
function FileTranscription() {
const [file, setFile] = useState<File | null>(null);
const scribe = useScribe({
modelId: "scribe_v2_realtime",
audioFormat: AudioFormat.PCM_16000,
sampleRate: 16000,
});
const transcribeFile = async () => {
if (!file) return;
const token = await fetchToken();
await scribe.connect({ token });
// 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));
scribe.sendAudio(base64);
await new Promise((resolve) => setTimeout(resolve, 50));
}
// Commit transcription
scribe.commit();
};
return (
<div>
<input type="file" accept="audio/*" onChange={(e) => setFile(e.target.files?.[0] || null)} />
<button onClick={transcribeFile} disabled={!file || scribe.isConnected}>
Transcribe
</button>
{scribe.committedTranscripts.map((transcript) => (
<div key={transcript.id}>{transcript.text}</div>
))}
</div>
);
}

戻り値

状態

  • status - 現在の接続ステータス:"disconnected"、"connecting"、"connected"、"transcribing"、または"error"。
  • isConnected - 接続中かどうかを示すブール値。
  • isTranscribing - アクティブに文字起こし中かどうかを示すブール値。
  • partialTranscript - 現在の部分的(暫定)文字起こし文字列。
  • committedTranscripts - TranscriptSegmentオブジェクトの配列(以下を参照)。
  • error - 現在のエラーメッセージ、またはnull。
const scribe = useScribe(/* options */);
console.log(scribe.status); // "connected"
console.log(scribe.isConnected); // true
console.log(scribe.partialTranscript); // "hello world"
console.log(scribe.committedTranscripts); // [{ id: "...", text: "...", words: ..., isFinal: true }]
console.log(scribe.error); // null or error string

各確定済み文字起こしセグメントは、次の構造を持ちます。

interface TranscriptSegment {
id: string; // Unique identifier
text: string; // Transcript text
timestamp: number; // Unix timestamp
isFinal: boolean; // Always true for committed transcripts
}

メソッド

connect(options?)

Scribeに接続します。ここで指定したオプションはフックのデフォルトを上書きします。

await scribe.connect({
token: "your-token", // Required
microphone: {
/* ... */
}, // For microphone mode
// OR
audioFormat: AudioFormat.PCM_16000, // For manual mode
sampleRate: 16000,
});

disconnect()

接続を切断し、リソースをクリーンアップします。

scribe.disconnect();

sendAudio(audioBase64, options?)

オーディオデータを送信します(手動モードのみ)。

scribe.sendAudio(base64AudioChunk, {
commit: false, // Optional: commit immediately
sampleRate: 16000, // Optional: override sample rate
previousText: "Previous transcription text", // Optional: context from a previous transcription. Can only be sent in the first audio chunk.
});

previousTextフィールドは、セッションの最初のオーディオチャンクでのみ送信できます。後続の チャンクで送信するとエラーになります。

commit()

現在の文字起こしを手動でコミットします。

scribe.commit();

clearTranscripts()

状態からすべての文字起こしをクリアします。

scribe.clearTranscripts();

getConnection()

基盤となる接続インスタンスを取得します。

const connection = scribe.getConnection();
// Returns RealtimeConnection | null

コミット戦略

文字起こしをコミットするタイミングを制御します。

import { CommitStrategy } from '@elevenlabs/react';
// Manual (default) - you control when to commit
const scribe = useScribe({
commitStrategy: CommitStrategy.MANUAL,
});
// Later...
scribe.commit(); // Commit transcription
// Voice Activity Detection - model detects silences and automatically commits
const scribe = useScribe({
commitStrategy: CommitStrategy.VAD,
});

詳細については、文字起こしとコミット戦略を参照してください。

完全な例

VADベースのコミット戦略でuseScribeフックを使用するReactコンポーネントの完全な例を紹介します。

import { useScribe, CommitStrategy } from "@elevenlabs/react";
import { useEffect } from "react";
function ScribeDemo() {
const scribe = useScribe({
modelId: "scribe_v2_realtime",
commitStrategy: CommitStrategy.VAD,
onSessionStarted: () => console.log("Started"),
onCommittedTranscript: (data) => console.log("Committed:", data.text),
onError: (error) => console.error("Error:", error),
});
const startMicrophone = async () => {
const token = await fetchToken();
await scribe.connect({
token,
microphone: {
echoCancellation: true,
noiseSuppression: true,
},
});
};
const handleDisconnect = () => scribe.disconnect();
const handleClearTranscripts = () => scribe.clearTranscripts();
useEffect(() => {
return () => {
handleDisconnect();
};
}, []);
return (
<div>
<h1>Scribe Demo</h1>
{/* Status */}
<div>
Status: {scribe.status}
{scribe.error && <span>Error: {scribe.error}</span>}
</div>
{/* Controls */}
<div>
{!scribe.isConnected ? (
<button onClick={startMicrophone}>Start Recording</button>
) : (
<button onClick={handleDisconnect}>Stop</button>
)}
<button onClick={handleClearTranscripts}>Clear</button>
</div>
{/* Live Transcript */}
{scribe.partialTranscript && (
<div>
<strong>Live:</strong> {scribe.partialTranscript}
</div>
)}
{/* Committed Transcripts */}
<div>
<h2>Transcripts ({scribe.committedTranscripts.length})</h2>
{scribe.committedTranscripts.map((t) => (
<div key={t.id}>
<span>{new Date(t.timestamp).toLocaleTimeString()}</span>
<p>{t.text}</p>
</div>
))}
</div>
</div>
);
}