SDK React

useScribe : transcription parole-texte en temps réel avec React

Pour une présentation de Scribe et de ses fonctionnalités, consultez la présentation de Speech to Text . Pour des guides d’utilisation étape par étape, consultez le streaming côté client.

Installation

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

Utilisez la skill Speech to Text d’ElevenLabs pour transcrire l’audio depuis votre assistant de programmation IA :

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

@elevenlabs/react réexporte tous les éléments de @elevenlabs/client, vous n’avez donc pas besoin d’installer les deux packages.

Utilisation

Voici un exemple minimal fonctionnel qui se connecte à Scribe et affiche la transcription en temps réel :

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

Obtenir un jeton

Scribe nécessite un jeton à usage unique pour l’authentification. Créez un endpoint API sur votre serveur :

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

Votre clé API ElevenLabs est sensible. Ne l’exposez jamais côté client. Générez toujours le jeton sur le serveur.

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

Options du hook

Configurez le hook avec des options et des callbacks par défaut :

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

Options de connexion

PropriétéTypeDescription
tokenstringJeton à usage unique pour l’authentification WebSocket.
modelIdstringID du modèle (par ex., "scribe_v2_realtime").
baseUristringURI de base WebSocket personnalisée. Par défaut : wss://api.elevenlabs.io.

Options VAD

Ces options déterminent quand les transcriptions sont automatiquement validées avec la stratégie de validation VAD.

PropriétéTypePar défautDescription
commitStrategyCommitStrategy"manual""manual" ou "vad".
vadSilenceThresholdSecsnumber1.5Secondes de silence avant la validation VAD (0.3-3.0).
vadThresholdnumber0.4Sensibilité VAD (0.1-0.9, une valeur plus basse est plus sensible).
minSpeechDurationMsnumber100Durée minimale de parole en ms (50-2000).
minSilenceDurationMsnumber100Durée minimale de silence en ms (50-2000).

Options audio

PropriétéTypeDescription
languageCodestringCode de langue ISO-639-1 ou ISO-639-3. Laissez vide pour la détection automatique.
microphoneobjectParamètres du microphone pour le mode microphone. Voir ci-dessous.
audioFormatAudioFormatFormat d’encodage audio pour le mode manuel (par ex., AudioFormat.PCM_16000).
sampleRatenumberFréquence d’échantillonnage pour le mode manuel. Doit correspondre à audioFormat.

L’objet microphone accepte :

PropriétéTypeDescription
deviceIdstringID d’un périphérique microphone spécifique.
echoCancellationbooleanActiver l’annulation d’écho.
noiseSuppressionbooleanActiver la réduction du bruit.
autoGainControlbooleanActiver le contrôle automatique du gain.

Options de comportement

PropriétéTypePar défautDescription
autoConnectbooleanfalseSe connecter automatiquement au montage du composant.
includeTimestampsbooleanfalseRecevoir des horodatages au niveau des mots. Activé automatiquement lorsque onCommittedTranscriptWithTimestamps est fourni.

Callbacks

Tous les callbacks d’événements sont facultatifs et peuvent être fournis comme options du hook :

  • onConnect : gestionnaire appelé lorsque la connexion WebSocket est établie.
  • onDisconnect : gestionnaire appelé lorsque la connexion WebSocket est fermée.
  • onSessionStarted : gestionnaire appelé lorsque la session Scribe démarre.
  • onPartialTranscript : gestionnaire appelé avec les résultats de transcription provisoires. Reçoit { text: string }.
  • onCommittedTranscript : gestionnaire appelé avec les résultats de transcription finalisés. Reçoit { text: string }.
  • onCommittedTranscriptWithTimestamps : gestionnaire appelé avec les résultats de transcription finalisés, y compris le minutage au niveau des mots. Reçoit { text: string; words?: { start: number; end: number }[] }.
  • onError : gestionnaire d’erreurs générique pour toutes les erreurs. Reçoit Error | Event.
  • onAuthError : gestionnaire appelé en cas d’erreurs d’authentification. Reçoit { error: string }.

Callbacks d’erreur

Le callback générique onError se déclenche pour toutes les erreurs. Des callbacks d’erreur spécifiques sont également disponibles pour une gestion précise. Tous les callbacks d’erreur spécifiques reçoivent { error: string }.

CallbackDescription
onErrorGestionnaire d’erreurs générique pour toutes les erreurs.
onAuthErrorErreur d’authentification.
onQuotaExceededErrorQuota d’utilisation dépassé.
onCommitThrottledErrorRequête de validation limitée.
onTranscriberErrorErreur du moteur de transcription.
onUnacceptedTermsErrorConditions d’utilisation non acceptées.
onRateLimitedErrorLimite de débit atteinte.
onInputErrorFormat d’entrée non valide.
onQueueOverflowErrorFile de traitement pleine.
onResourceExhaustedErrorRessources serveur à capacité maximale.
onSessionTimeLimitExceededErrorDurée maximale de session atteinte.
onChunkSizeExceededErrorSegment audio trop volumineux.
onInsufficientAudioActivityErrorActivité audio insuffisante pour maintenir la connexion.

Mode microphone

Diffusez l’audio directement depuis le microphone de l’utilisateur :

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

Mode audio manuel (transcription de fichier)

Transcrivez des fichiers audio préenregistrés :

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

Valeurs renvoyées

État

  • status : état actuel de la connexion : "disconnected", "connecting", "connected", "transcribing" ou "error".
  • isConnected : booléen indiquant si la connexion est établie.
  • isTranscribing : booléen indiquant si une transcription est en cours.
  • partialTranscript : chaîne de transcription partielle actuelle (provisoire).
  • committedTranscripts : tableau d’objets TranscriptSegment (voir ci-dessous).
  • error : message d’erreur actuel, 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

Chaque segment de transcription validé présente la structure suivante :

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

Méthodes

connect(options?)

Connectez-vous à Scribe. Les options fournies ici remplacent les valeurs par défaut du hook :

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

disconnect()

Déconnectez-vous et libérez les ressources :

scribe.disconnect();

sendAudio(audioBase64, options?)

Envoyez des données audio (mode manuel uniquement) :

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

Le champ previousText ne peut être envoyé que dans le premier segment audio d’une session. Son envoi dans des segments ultérieurs entraîne une erreur.

commit()

Validez manuellement la transcription actuelle :

scribe.commit();

clearTranscripts()

Effacez toutes les transcriptions de l’état :

scribe.clearTranscripts();

getConnection()

Obtenez l’instance de connexion sous-jacente :

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

Stratégies de validation

Contrôlez le moment où les transcriptions sont validées :

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

Pour en savoir plus, consultez Transcriptions et stratégies de validation.

Exemple complet

Voici un exemple complet de composant React utilisant le hook useScribe avec une stratégie de validation basée sur la 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>
);
}