Vai alla navigazione

SDK React

useScribe: trascrizione vocale in tempo reale in React

Per una panoramica di Scribe e delle sue funzionalità, consulta la panoramica di Speech to Text . Per guide pratiche passo passo, consulta lo streaming lato client.

Installazione

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

Usa la skill Speech to Text di ElevenLabs per trascrivere l’audio dal tuo assistente di coding IA:

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

@elevenlabs/react riesporta tutto da @elevenlabs/client, quindi non devi installare entrambi i pacchetti.

Utilizzo

Ecco un esempio minimo funzionante che si connette a Scribe e mostra la trascrizione in tempo reale:

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

Ottenere un token

Scribe richiede un token monouso per l’autenticazione. Crea un endpoint API sul tuo server:

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

La tua chiave API di ElevenLabs è sensibile. Non esporla mai al client. Genera sempre il token sul server.

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

Opzioni dell’hook

Configura l’hook con opzioni e callback predefiniti:

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

Opzioni di connessione

ProprietàTipoDescrizione
tokenstringToken monouso per l’autenticazione WebSocket.
modelIdstringID del modello (ad es. "scribe_v2_realtime").
baseUristringURI di base WebSocket personalizzato. Il valore predefinito è wss://api.elevenlabs.io.

Opzioni VAD

Queste opzioni controllano quando le trascrizioni vengono confermate automaticamente usando la strategia di conferma VAD.

ProprietàTipoPredefinitoDescrizione
commitStrategyCommitStrategy"manual""manual" o "vad".
vadSilenceThresholdSecsnumber1.5Secondi di silenzio prima della conferma VAD (0,3-3,0).
vadThresholdnumber0.4Sensibilità VAD (0,1-0,9; valori più bassi sono più sensibili).
minSpeechDurationMsnumber100Durata minima del parlato in ms (50-2000).
minSilenceDurationMsnumber100Durata minima del silenzio in ms (50-2000).

Opzioni audio

ProprietàTipoDescrizione
languageCodestringCodice lingua ISO-639-1 o ISO-639-3. Lascia vuoto per il rilevamento automatico.
microphoneobjectImpostazioni del microfono per la modalità microfono. Vedi sotto.
audioFormatAudioFormatFormato di codifica audio per la modalità manuale (ad es. AudioFormat.PCM_16000).
sampleRatenumberFrequenza di campionamento per la modalità manuale. Deve corrispondere a audioFormat.

L’oggetto microphone accetta:

ProprietàTipoDescrizione
deviceIdstringID di un dispositivo microfono specifico.
echoCancellationbooleanAbilita l’eliminazione dell’eco.
noiseSuppressionbooleanAbilita la soppressione del rumore.
autoGainControlbooleanAbilita il controllo automatico del guadagno.

Opzioni di comportamento

ProprietàTipoPredefinitoDescrizione
autoConnectbooleanfalseSi connette automaticamente al montaggio del componente.
includeTimestampsbooleanfalseRiceve timestamp a livello di parola. Si abilita automaticamente quando viene fornito onCommittedTranscriptWithTimestamps.

Callback

Tutte le callback degli eventi sono facoltative e possono essere fornite come opzioni dell’hook:

  • onConnect - handler chiamato quando viene stabilita la connessione WebSocket.
  • onDisconnect - handler chiamato quando viene chiusa la connessione WebSocket.
  • onSessionStarted - handler chiamato quando inizia la sessione Scribe.
  • onPartialTranscript - handler chiamato con risultati di trascrizione provvisori. Riceve { text: string }.
  • onCommittedTranscript - handler chiamato con risultati di trascrizione finalizzati. Riceve { text: string }.
  • onCommittedTranscriptWithTimestamps - handler chiamato con risultati di trascrizione finalizzati, inclusa la temporizzazione a livello di parola. Riceve { text: string; words?: { start: number; end: number }[] }.
  • onError - handler di errore generico per tutti gli errori. Riceve Error | Event.
  • onAuthError - handler chiamato in caso di errori di autenticazione. Riceve { error: string }.

Callback degli errori

La callback generica onError viene attivata per tutti gli errori. Sono disponibili anche callback di errore specifiche per una gestione più dettagliata. Tutte le callback di errore specifiche ricevono { error: string }.

CallbackDescrizione
onErrorHandler di errore generico per tutti gli errori.
onAuthErrorErrore di autenticazione.
onQuotaExceededErrorQuota di utilizzo superata.
onCommitThrottledErrorRichiesta di conferma limitata.
onTranscriberErrorErrore del motore di trascrizione.
onUnacceptedTermsErrorTermini di servizio non accettati.
onRateLimitedErrorLimite di frequenza raggiunto.
onInputErrorFormato di input non valido.
onQueueOverflowErrorCoda di elaborazione piena.
onResourceExhaustedErrorRisorse del server al limite della capacità.
onSessionTimeLimitExceededErrorTempo massimo della sessione raggiunto.
onChunkSizeExceededErrorChunk audio troppo grande.
onInsufficientAudioActivityErrorAttività audio insufficiente per mantenere la connessione.

Modalità microfono

Trasmetti l’audio direttamente dal microfono dell’utente:

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

Modalità audio manuale (trascrizione di file)

Trascrivi file audio preregistrati:

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

Valori restituiti

Stato

  • status - stato attuale della connessione: "disconnected", "connecting", "connected", "transcribing" o "error".
  • isConnected - valore booleano che indica se la connessione è attiva.
  • isTranscribing - valore booleano che indica se la trascrizione è attiva.
  • partialTranscript - stringa della trascrizione parziale (provvisoria) corrente.
  • committedTranscripts - array di oggetti TranscriptSegment (vedi sotto).
  • error - messaggio di errore corrente oppure 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

Ogni segmento di trascrizione confermato ha la seguente struttura:

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

Metodi

connect(options?)

Connettiti a Scribe. Le opzioni fornite qui sovrascrivono i valori predefiniti dell’hook:

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

disconnect()

Disconnettiti e libera le risorse:

scribe.disconnect();

sendAudio(audioBase64, options?)

Invia dati audio (solo modalità manuale):

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

Il campo previousText può essere inviato solo nel primo chunk audio di una sessione. Se lo invii nei chunk successivi, si verifica un errore.

commit()

Conferma manualmente la trascrizione corrente:

scribe.commit();

clearTranscripts()

Cancella tutte le trascrizioni dallo stato:

scribe.clearTranscripts();

getConnection()

Ottieni l’istanza della connessione sottostante:

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

Strategie di conferma

Controlla quando vengono confermate le trascrizioni:

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

Per maggiori dettagli, consulta Trascrizioni e strategie di conferma.

Esempio completo

Ecco un esempio completo di un componente React che usa l’hook useScribe con una strategia di conferma basata su 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>
);
}