React SDK

useScribe: transkrypcja mowy na tekst w czasie rzeczywistym w React

Przegląd Scribe i jego możliwości znajdziesz w przeglądzie Speech to Text overview. Instrukcje krok po kroku znajdziesz w sekcji Client-side streaming.

Instalacja

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

Użyj umiejętności ElevenLabs speech-to-text, aby transkrybować audio za pomocą asystenta AI do kodowania:

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

@elevenlabs/react ponownie eksportuje wszystko z @elevenlabs/client, więc nie musisz instalować obu pakietów.

Użycie

Oto minimalny działający przykład, który łączy się z Scribe i wyświetla transkrypcję w czasie rzeczywistym:

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

Pobieranie tokenu

Scribe wymaga tokenu jednorazowego do uwierzytelniania. Utwórz endpoint API na serwerze:

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

Twój klucz API ElevenLabs jest poufny. Nigdy nie udostępniaj go klientowi. Zawsze generuj token na serwerze.

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

Opcje hooka

Skonfiguruj hook za pomocą domyślnych opcji i callbacków:

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

Opcje połączenia

WłaściwośćTypOpis
tokenstringToken jednorazowy do uwierzytelniania WebSocket.
modelIdstringID modelu (np. "scribe_v2_realtime").
baseUristringNiestandardowy bazowy URI WebSocket. Domyślnie wss://api.elevenlabs.io.

Opcje VAD

Te opcje określają, kiedy transkrypcje są automatycznie zatwierdzane przy użyciu strategii zatwierdzania VAD.

WłaściwośćTypDomyślnieOpis
commitStrategyCommitStrategy"manual""manual" lub "vad".
vadSilenceThresholdSecsnumber1.5Sekundy ciszy przed zatwierdzeniem przez VAD (0.3-3.0).
vadThresholdnumber0.4Czułość VAD (0.1-0.9, niższa wartość oznacza większą czułość).
minSpeechDurationMsnumber100Minimalny czas mowy w ms (50-2000).
minSilenceDurationMsnumber100Minimalny czas ciszy w ms (50-2000).

Opcje audio

WłaściwośćTypOpis
languageCodestringKod języka ISO-639-1 lub ISO-639-3. Pozostaw puste, aby wykryć język automatycznie.
microphoneobjectUstawienia mikrofonu dla trybu mikrofonu. Zobacz niżej.
audioFormatAudioFormatFormat kodowania audio dla trybu ręcznego (np. AudioFormat.PCM_16000).
sampleRatenumberCzęstotliwość próbkowania dla trybu ręcznego. Musi pasować do audioFormat.

Obiekt microphone przyjmuje:

WłaściwośćTypOpis
deviceIdstringID konkretnego urządzenia mikrofonowego.
echoCancellationbooleanWłącz usuwanie echa.
noiseSuppressionbooleanWłącz redukcję szumów.
autoGainControlbooleanWłącz automatyczną regulację wzmocnienia.

Opcje działania

WłaściwośćTypDomyślnieOpis
autoConnectbooleanfalseAutomatycznie połącz po zamontowaniu komponentu.
includeTimestampsbooleanfalseOtrzymuj znaczniki czasu na poziomie słów. Włącza się automatycznie po podaniu onCommittedTranscriptWithTimestamps.

Callbacki

Wszystkie callbacki zdarzeń są opcjonalne i można je przekazać jako opcje hooka:

  • onConnect - handler wywoływany po ustanowieniu połączenia WebSocket.
  • onDisconnect - handler wywoływany po zamknięciu połączenia WebSocket.
  • onSessionStarted - handler wywoływany po rozpoczęciu sesji Scribe.
  • onPartialTranscript - handler wywoływany z pośrednimi wynikami transkrypcji. Otrzymuje { text: string }.
  • onCommittedTranscript - handler wywoływany z ukończonymi wynikami transkrypcji. Otrzymuje { text: string }.
  • onCommittedTranscriptWithTimestamps - handler wywoływany z ukończonymi wynikami transkrypcji, w tym czasem na poziomie słów. Otrzymuje { text: string; words?: { start: number; end: number }[] }.
  • onError - ogólny handler wszystkich błędów. Otrzymuje Error | Event.
  • onAuthError - handler wywoływany przy błędach uwierzytelniania. Otrzymuje { error: string }.

Callbacki błędów

Ogólny callback onError uruchamia się przy wszystkich błędach. Dostępne są też konkretne callbacki błędów, które pozwalają je obsługiwać bardziej szczegółowo. Wszystkie konkretne callbacki błędów otrzymują { error: string }.

CallbackOpis
onErrorOgólny handler wszystkich błędów.
onAuthErrorBłąd uwierzytelniania.
onQuotaExceededErrorPrzekroczono limit użycia.
onCommitThrottledErrorŻądanie zatwierdzenia zostało ograniczone.
onTranscriberErrorBłąd silnika transkrypcji.
onUnacceptedTermsErrorRegulamin nie został zaakceptowany.
onRateLimitedErrorOsiągnięto limit żądań.
onInputErrorNieprawidłowy format wejściowy.
onQueueOverflowErrorKolejka przetwarzania jest pełna.
onResourceExhaustedErrorZasoby serwera są wyczerpane.
onSessionTimeLimitExceededErrorOsiągnięto maksymalny czas sesji.
onChunkSizeExceededErrorFragment audio jest zbyt duży.
onInsufficientAudioActivityErrorZa mała aktywność audio, aby utrzymać połączenie.

Tryb mikrofonu

Przesyłaj audio bezpośrednio z mikrofonu użytkownika:

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

Ręczny tryb audio (transkrypcja pliku)

Transkrybuj nagrane wcześniej pliki audio:

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

Zwracane wartości

Stan

  • status - bieżący stan połączenia: "disconnected", "connecting", "connected", "transcribing" lub "error".
  • isConnected - wartość logiczna wskazująca, czy połączono.
  • isTranscribing - wartość logiczna wskazująca, czy transkrypcja jest aktywna.
  • partialTranscript - bieżący częściowy (pośredni) ciąg transkrypcji.
  • committedTranscripts - tablica obiektów TranscriptSegment (zobacz niżej).
  • error - bieżący komunikat błędu lub 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

Każdy zatwierdzony segment transkrypcji ma następującą strukturę:

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

Metody

connect(options?)

Połącz z Scribe. Opcje podane tutaj zastępują domyślne opcje hooka:

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

disconnect()

Rozłącz i zwolnij zasoby:

scribe.disconnect();

sendAudio(audioBase64, options?)

Wyślij dane audio (tylko tryb ręczny):

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

Pole previousText można wysłać tylko w pierwszym fragmencie audio sesji. Wysłanie go w kolejnych fragmentach powoduje błąd.

commit()

Ręcznie zatwierdź bieżącą transkrypcję:

scribe.commit();

clearTranscripts()

Usuń wszystkie transkrypcje ze stanu:

scribe.clearTranscripts();

getConnection()

Pobierz instancję bazowego połączenia:

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

Strategie zatwierdzania

Określ, kiedy transkrypcje są zatwierdzane:

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

Więcej informacji znajdziesz w Transcripts and commit strategies.

Pełny przykład

Oto pełny przykład komponentu React używającego hooka useScribe ze strategią zatwierdzania opartą na VAD:

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