SDK para React

useScribe: transcrição de fala para texto em tempo real no React

Para ter uma visão geral do Scribe e dos recursos dele, consulte a visão geral do Speech to Text . Para ver guias de uso passo a passo, consulte streaming no lado do cliente.

Instalação

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

Use a skill de speech-to-text da ElevenLabs para transcrever áudio com seu assistente de programação com IA:

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

@elevenlabs/react reexporta tudo de @elevenlabs/client, então você não precisa instalar os dois pacotes.

Uso

Aqui está um exemplo mínimo funcional que se conecta ao Scribe e exibe a transcrição em tempo real:

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

Como obter um token

O Scribe exige um token de uso único para autenticação. Crie um endpoint de API no seu servidor:

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

Sua chave de API da ElevenLabs é confidencial. Nunca a exponha ao cliente. Sempre gere o token no servidor.

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

Opções do hook

Configure o hook com opções e callbacks padrão:

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

Opções de conexão

PropriedadeTipoDescrição
tokenstringToken de uso único para autenticação WebSocket.
modelIdstringID do modelo (por exemplo, "scribe_v2_realtime").
baseUristringURI base personalizada do WebSocket. O padrão é wss://api.elevenlabs.io.

Opções de VAD

Estas opções controlam quando as transcrições são confirmadas automaticamente ao usar a estratégia de confirmação VAD.

PropriedadeTipoPadrãoDescrição
commitStrategyCommitStrategy"manual""manual" ou "vad".
vadSilenceThresholdSecsnumber1.5Segundos de silêncio antes da confirmação pelo VAD (0.3-3.0).
vadThresholdnumber0.4Sensibilidade do VAD (0.1-0.9; valores menores são mais sensíveis).
minSpeechDurationMsnumber100Duração mínima de fala em ms (50-2000).
minSilenceDurationMsnumber100Duração mínima de silêncio em ms (50-2000).

Opções de áudio

PropriedadeTipoDescrição
languageCodestringCódigo de idioma ISO-639-1 ou ISO-639-3. Deixe vazio para detecção automática.
microphoneobjectConfigurações do microfone para o modo microfone. Veja abaixo.
audioFormatAudioFormatFormato de codificação de áudio para o modo manual (por exemplo, AudioFormat.PCM_16000).
sampleRatenumberTaxa de amostragem para o modo manual. Deve corresponder a audioFormat.

O objeto microphone aceita:

PropriedadeTipoDescrição
deviceIdstringID de um dispositivo de microfone específico.
echoCancellationbooleanAtiva o cancelamento de eco.
noiseSuppressionbooleanAtiva a supressão de ruído.
autoGainControlbooleanAtiva o controle automático de ganho.

Opções de comportamento

PropriedadeTipoPadrãoDescrição
autoConnectbooleanfalseConecta automaticamente ao montar o componente.
includeTimestampsbooleanfalseRecebe timestamps por palavra. É ativado automaticamente quando onCommittedTranscriptWithTimestamps é fornecido.

Callbacks

Todos os callbacks de eventos são opcionais e podem ser fornecidos como opções do hook:

  • onConnect - manipulador chamado quando a conexão WebSocket é estabelecida.
  • onDisconnect - manipulador chamado quando a conexão WebSocket é fechada.
  • onSessionStarted - manipulador chamado quando a sessão do Scribe começa.
  • onPartialTranscript - manipulador chamado com resultados de transcrição provisórios. Recebe { text: string }.
  • onCommittedTranscript - manipulador chamado com resultados de transcrição finalizados. Recebe { text: string }.
  • onCommittedTranscriptWithTimestamps - manipulador chamado com resultados de transcrição finalizados, incluindo a temporização por palavra. Recebe { text: string; words?: { start: number; end: number }[] }.
  • onError - manipulador de erros genérico para todos os erros. Recebe Error | Event.
  • onAuthError - manipulador chamado em erros de autenticação. Recebe { error: string }.

Callbacks de erro

O callback genérico onError é acionado para todos os erros. Callbacks específicos de erro também estão disponíveis para um tratamento mais detalhado. Todos os callbacks específicos de erro recebem { error: string }.

CallbackDescrição
onErrorManipulador de erros genérico para todos os erros.
onAuthErrorErro de autenticação.
onQuotaExceededErrorCota de uso excedida.
onCommitThrottledErrorSolicitação de confirmação limitada.
onTranscriberErrorErro do mecanismo de transcrição.
onUnacceptedTermsErrorTermos de serviço não aceitos.
onRateLimitedErrorLimite de taxa atingido.
onInputErrorFormato de entrada inválido.
onQueueOverflowErrorFila de processamento cheia.
onResourceExhaustedErrorRecursos do servidor sem capacidade disponível.
onSessionTimeLimitExceededErrorTempo máximo de sessão atingido.
onChunkSizeExceededErrorBloco de áudio grande demais.
onInsufficientAudioActivityErrorAtividade de áudio insuficiente para manter a conexão.

Modo microfone

Transmita áudio diretamente do microfone do usuário:

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

Modo de áudio manual (transcrição de arquivos)

Transcreva arquivos de áudio pré-gravados:

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

Valores retornados

Estado

  • status - status atual da conexão: "disconnected", "connecting", "connected", "transcribing" ou "error".
  • isConnected - booleano que indica se está conectado.
  • isTranscribing - booleano que indica se está transcrevendo ativamente.
  • partialTranscript - string da transcrição parcial atual (provisória).
  • committedTranscripts - array de objetos TranscriptSegment (veja abaixo).
  • error - mensagem de erro atual ou 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

Cada segmento de transcrição confirmado tem a seguinte estrutura:

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

Métodos

connect(options?)

Conecte-se ao Scribe. As opções fornecidas aqui substituem os padrões do hook:

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

disconnect()

Desconecte e libere os recursos:

scribe.disconnect();

sendAudio(audioBase64, options?)

Envie dados de áudio (somente no modo manual):

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

O campo previousText só pode ser enviado no primeiro bloco de áudio de uma sessão. Enviá-lo em blocos subsequentes resulta em erro.

commit()

Confirme manualmente a transcrição atual:

scribe.commit();

clearTranscripts()

Limpe todas as transcrições do estado:

scribe.clearTranscripts();

getConnection()

Obtenha a instância de conexão subjacente:

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

Estratégias de confirmação

Controle quando as transcrições são confirmadas:

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

Para mais detalhes, consulte Transcrições e estratégias de confirmação.

Exemplo completo

Aqui está um exemplo completo de um componente React que usa o hook useScribe com uma estratégia de confirmação baseada em 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>
);
}