Aller au contenu

Speech to Text en temps réel sous 200 ms : guide d’architecture

Publié
Dernière mise à jour

ÉcouterÉcouter cet article

La transcription vocale en temps réel (STT) transcrit l’audio à mesure qu’une personne parle et renvoie ses paroles sous forme de texte en quelques centaines de millisecondes. Mais maintenir une faible latence STT relève autant de l’architecture que du modèle. Les ingénieurs doivent planifier le transport, le découpage en blocs, la détection de fin d’énoncé et la chaîne de capture, qui ajoutent tous de la latence. L’inefficacité d’un seul de ces éléments peut dépasser votre budget de 200 ms.

Ce guide propose une approche concrète pour concevoir des pipelines de transcription vocale en temps réel, depuis la couche de transport. Nous nous appuierons sur Scribe v2 Realtime, qui produit des transcriptions partielles avec environ 150 ms de latence de modèle, prend en charge plus de 90 langues, accepte l’audio PCM (8 kHz à 48 kHz) et mu-law, et propose Voice Activity Detection ainsi qu’un contrôle de validation manuelle pour finaliser les segments.

Nous verrons comment l’audio atteint le serveur, comment les hypothèses deviennent du texte validé, le coût des fonctionnalités en flux et comment capturer puis transmettre l’audio correctement.

En résumé

  • La création de systèmes de transcription vocale en temps réel exige un réglage précis de l’architecture afin de maintenir une faible latence sur l’ensemble du pipeline.
  • WebSocket constitue le meilleur choix par défaut pour la plupart des pipelines ; WebRTC offre plusieurs avantages, mais reste plus complexe.
  • Voice Activity Detection gère la segmentation mains libres, tandis que la validation manuelle permet à vos applications de reprendre la main lorsqu’elles savent que le tour est terminé.
  • Les partiels sont provisoires et les finals sont validés : affichez-les différemment.
  • De petits blocs PCM d’environ 100 ms réduisent la latence avant le premier partiel.

WebSocket ou WebRTC pour la transcription vocale en temps réel

Avant toute transcription, l’audio doit parvenir de sa source au moteur de reconnaissance. Le canal choisi fixe le seuil minimal de latence pour tout ce qui suit. Deux options permettent d’acheminer l’audio vers la couche de transcription.

WebSocket est un canal TCP bidirectionnel, fiable, ordonné et persistant. Vous ouvrez une connexion, envoyez des trames audio binaires et recevez des événements de transcription. Il est simple côté client comme côté serveur, traverse les proxys et pare-feux d’entreprise qui autorisent déjà HTTPS, et est pris en charge par tous les navigateurs et environnements serveur.

La contrainte de WebSocket est son fonctionnement sur TCP. En cas de perte de paquet, TCP le retransmet et retient les données suivantes jusqu’à ce que le manque soit comblé. Dans de bonnes conditions réseau, cela passe inaperçu. En cas de pertes, cela crée un blocage en tête de ligne : l’audio s’accumule brièvement puis arrive par rafale.

WebRTC est conçu pour les médias en temps réel. Il transporte les médias sur UDP (via SRTP) : un paquet perdu ne bloque donc pas le flux. Il intègre un tampon de gigue qui absorbe les variations d’arrivée des paquets, négocie la traversée NAT avec ICE/STUN/TURN pour connecter des pairs derrière des routeurs, et inclut ses propres mécanismes de capture et d’encodage audio.

Vous avez généralement besoin de serveurs TURN pour les clients qui ne peuvent pas se connecter directement, et le serveur doit terminer un flux média plutôt que lire un flux d’octets.

Voici les compromis en un coup d’œil :

WebSocket
Transport
TCP (reliable, ordered)
Behavior under packet loss
Head-of-line blocking, bursty recovery
Jitter handling
Your responsibility
NAT traversal
Not needed (client-initiated)
Browser support
Universal, trivial
Server complexity
Low
WebRTC
Transport
UDP/SRTP (real-time, loss-tolerant)
Behavior under packet loss
Graceful degradation
Jitter handling
Built-in jitter buffer
NAT traversal
Requires ICE/STUN/TURN
Browser support
Universal, but more API surface
Server complexity
High (media server or SFU)

Dans la plupart des cas, WebSocket est le bon choix. Privilégiez-le si vos clients disposent d’une connectivité correcte et que vous contrôlez la chaîne de capture : pipelines serveur à serveur, applications de bureau, applications navigateur sur haut débit et la plupart des backends de centres de contact, où l’audio arrive déjà sur votre serveur par un autre moyen.

Choisissez WebRTC si vous capturez directement depuis des appareils grand public sur des réseaux mobiles instables, si vous exploitez déjà une pile WebRTC pour l’audio bidirectionnel — par exemple un agent vocal qui répond à l’oral — ou si le comportement temps réel tolérant aux pertes importe davantage que la simplicité de mise en œuvre.

La suite de ce guide utilise WebSocket pour la connexion au moteur de reconnaissance, car il rend les composants visibles et constitue le bon point de départ pour la plupart des équipes. Rien n’est propre à WebSocket : vous pourrez ensuite ajouter une étape média WebRTC en amont, décoder l’audio en PCM sur le serveur et transmettre les mêmes blocs au pipeline.

Partiels et transcriptions finales : comprendre les résultats intermédiaires

Un moteur de reconnaissance en temps réel n’attend pas une phrase complète avant de s’exprimer. Il émet un flux continu d’hypothèses qui s’affinent à mesure que l’audio arrive, puis les valide. Comprendre la différence entre ces deux états distingue une transcription vivante d’une transcription qui semble défaillante.

Une hypothèse partielle (intermédiaire) est la meilleure estimation du modèle à partir de l’audio reçu jusque-là. Les partiels sont instables par conception. À mesure que l’audio arrive, le modèle révise les mots précédents : « Je voudrais » peut devenir « Je voudrais deux billets » lorsque le contexte ultérieur lève l’ambiguïté. Ils arrivent rapidement — c’est ce que décrit la latence d’environ 150 ms — et sont destinés à être remplacés.

Une hypothèse finale est un segment validé qui ne changera plus. Lorsqu’un segment est finalisé, le moteur de reconnaissance passe à la suite et les hypothèses suivantes décrivent l’audio ultérieur. Ce sont les finals que vous conservez, envoyez à un LLM ou stockez comme transcription.

La distinction entre partiels et finals détermine trois éléments que vous risquez de mal gérer si vous les confondez :

  • Expérience utilisateur : Afficher les partiels donne une impression de direct : l’utilisateur voit les mots apparaître en parlant, ce qui confirme que le microphone fonctionne et que le système l’écoute.
  • Détection de fin d’énoncé : Les partiels fournissent un signal continu d’activité vocale. Associés à la VAD, ils permettent de déterminer quand le locuteur s’est réellement arrêté.
  • Synchronisation en aval : Dans un pipeline d’agent vocal, les étapes sont les suivantes : audio entrant, transcription vocale, LLM, puis synthèse vocale, et enfin audio sortant. Vous pouvez lancer un travail spéculatif sur les partiels et le confirmer sur les finals afin de réduire le temps de réponse perçu, quitte à abandonner parfois ce travail spéculatif.

Affichez les partiels et les finals différemment. Un modèle simple et efficace consiste à conserver une seule « ligne actuelle » modifiable, liée au dernier partiel, puis à l’ajouter à une transcription en ajout seul lorsqu’un final arrive :

type TranscriptState = {
  committed: string[]; // finalized segments, never rewritten
  current: string;     // latest partial, overwritten on each update
};

const onPartial = (s: TranscriptState, text: string): TranscriptState =>
  ({ ...s, current: text });

const onFinal = (s: TranscriptState, text: string): TranscriptState =>
  ({ committed: [...s.committed, text], current: "" });

Visuellement, affichez le texte validé de façon établie et le texte actuel dans un style plus léger ou italique, afin que l’utilisateur comprenne qu’il peut encore changer.

Détection de fin d’énoncé et détection d’activité vocale (VAD)

Savoir ce qui a été dit ne représente que la moitié du travail. Un moteur de reconnaissance doit aussi savoir quand une idée est terminée. Cette décision détermine le moment où vous finalisez un segment et, dans un agent, celui où le système commence à répondre.

La détection de fin d’énoncé consiste à décider qu’une intervention est terminée. Finaliser trop tôt interrompt les utilisateurs au milieu de leur phrase. Finaliser trop tard laisse un agent silencieux alors que l’utilisateur a clairement terminé.

Scribe v2 Realtime propose deux mécanismes complémentaires :

  • Voice Activity Detection segmente l’audio selon les silences : Le moteur de reconnaissance détecte le moment où la parole laisse place à un silence prolongé et utilise cette limite pour finaliser automatiquement un segment. La VAD est le bon choix par défaut pour les interfaces conversationnelles, car elle s’adapte au rythme naturel de la parole sans suivi manuel du temps.
  • Contrôle de validation manuelle : Le contrôle de validation manuelle permet à votre application de décider quand finaliser le segment en cours, indépendamment du silence. Vous envoyez un signal de validation, le moteur ferme le segment actuel et émet un final. C’est l’outil approprié lorsque votre application sait déjà que le tour est terminé : relâchement d’un bouton push-to-talk, action « envoyer » ou politique externe de gestion des tours de parole.

Les deux mécanismes se combinent efficacement. Un agent vocal type utilise la VAD en mode mains libres et propose la validation manuelle comme contrôle prioritaire : un utilisateur qui fait une pause pour réfléchir n’est pas interrompu, tandis qu’un utilisateur qui appuie sur un bouton obtient une limite immédiate.

Le seuil de silence est un véritable compromis, sans valeur universellement correcte :

  • Un délai court de fin de parole — par exemple une finalisation après environ 200 à 400 ms de silence — rend le système réactif. Mais il interrompt aussi les utilisateurs qui marquent naturellement des pauses entre les propositions, divisant une même idée en plusieurs segments et, dans un agent, déclenchant une réponse prématurée.
  • Un délai long — par exemple environ 800 à 1 200 ms — tolère les pauses naturelles et préserve les interventions, au prix d’un délai perceptible avant la réaction du système.

Il n’existe pas de constante globale : ajustez le seuil à l’interaction.

  • La dictée et la prise de notes tolèrent des pauses plus longues, car les utilisateurs réfléchissent au milieu d’une phrase. Préférez des délais plus longs et appuyez-vous sur la VAD.
  • Les agents transactionnels et de commande bénéficient de délais plus courts associés à la validation manuelle, car les tours sont brefs et nets.
  • Les locuteurs multilingues ou non natifs font davantage de pauses : prévoyez donc plus de silence avant la finalisation.

Ces principes vous aideront à construire un système efficace de détection de fin d’énoncé et à vous rapprocher d’une transcription vocale en temps réel.

Fonctionnalités en flux : détection de langue et diarisation des locuteurs

La reconnaissance en flux ne se limite pas à produire des mots. Chaque signal supplémentaire demandé influe toutefois sur la latence et la stabilité. En règle générale, activez uniquement ce dont l’expérience en direct a besoin et reportez le reste à un traitement par lots.

La reconnaissance automatique de la langue permet à Scribe v2 Realtime d’identifier la langue parlée parmi plus de 90 langues prises en charge, sans vous obliger à la déclarer à l’avance. Le modèle a besoin d’un court extrait audio pour l’identifier avec certitude ; les premiers partiels d’un flux peuvent donc être moins stables pendant que la langue est déterminée. Si vous connaissez déjà la langue, l’indiquer élimine cette ambiguïté et stabilise généralement les premiers partiels.

La diarisation des locuteurs attribue la parole à différents locuteurs et identifie qui a dit quoi. En transcription par lots, c’est relativement simple, car le modèle voit le fichier entier. En flux, c’est plus difficile : le moteur doit attribuer une étiquette de locuteur à partir du seul audio reçu jusque-là, et une étiquette donnée à un audio précoce peut devoir être révisée après avoir entendu davantage cette voix. Traitez les étiquettes de locuteur en flux comme le texte partiel : elles restent provisoires jusqu’à la finalisation du segment.

L’horodatage au niveau des mots et le contexte des entités suivent la même logique. Plus vous demandez de métadonnées par jeton, plus le modèle et le réseau doivent en transporter. Pour la plupart des interfaces temps réel, seul le texte et les limites de segments sont nécessaires en direct ; reportez les métadonnées détaillées à un traitement par lots après l’appel avec Scribe v2.

Formats audio en flux : PCM et mu-law

Le transport et la logique de reconnaissance retiennent l’essentiel de l’attention, mais une part surprenante des bugs réels provient de la couche inférieure : l’encodage et le découpage de l’audio. Choisir le bon format et la bonne taille de bloc est le moyen le plus simple de réduire la latence de transcription vocale.

Le PCM (linéaire, signé 16 bits, little-endian) est le format à utiliser lorsque vous contrôlez la capture. Des fréquences d’échantillonnage plus élevées apportent davantage de détails acoustiques : 16 kHz est le seuil standard pour la reconnaissance vocale et suffit généralement ; 8 kHz correspond à la qualité téléphonique et perd les hautes fréquences. Utilisez la fréquence correspondant à votre source. Inutile de suréchantillonner un audio téléphonique à 8 kHz vers 48 kHz : l’information ne peut pas être récupérée.

Le mu-law à 8 kHz est le format de téléphonie. Si vous ingérez des appels depuis un fournisseur de téléphonie, l’audio arrive en mu-law à 8 kHz ; transmettez-le dans ce format plutôt que de le transcoder deux fois. Respecter le format source évite les artefacts de rééchantillonnage et une étape de conversion inutile.

La taille des blocs est le levier qui influence le plus directement la latence perçue. Vous envoyez l’audio par blocs et le moteur produit des partiels à leur arrivée. Des blocs plus petits produisent des mises à jour plus fréquentes et réduisent la latence avant le premier partiel ; des blocs plus grands réduisent le nombre de messages et fournissent un peu plus de contexte à chaque inférence. Une plage pratique va de 20 à 250 ms d’audio par bloc. À titre concret, en PCM mono 16 bits à 16 kHz, une seconde d’audio représente 32 000 octets ; un bloc de 100 ms représente donc environ 3 200 octets.

Capturer l’entrée microphone dans le navigateur

Dans le navigateur, l’outil approprié est la Web Audio API avec un AudioWorklet. Le worklet s’exécute sur le thread de rendu audio, reçoit l’audio sous forme de petites trames et n’est pas soumis aux ralentissements du thread principal, contrairement à l’ancien ScriptProcessorNode. Il convertit les échantillons flottants natifs du navigateur en PCM 16 bits et les transmet au thread principal, qui les envoie via WebSocket.

Le cœur du processeur worklet est la conversion de valeurs flottantes en PCM :

// pcm-worklet.ts - registered via audioContext.audioWorklet.addModule()
class PCMWorklet extends AudioWorkletProcessor {
  process(inputs: Float32Array[][]) {
    const channel = inputs[0]?.[0]; // mono; Float32, range [-1, 1]
    if (!channel) return true;
    const pcm = new Int16Array(channel.length);
    for (let i = 0; i < channel.length; i++) {
      const s = Math.max(-1, Math.min(1, channel[i]));
      pcm[i] = s < 0 ? s * 0x8000 : s * 0x7fff;
    }
    // Transfer the buffer to the main thread without copying.
    this.port.postMessage(pcm.buffer, [pcm.buffer]);
    return true;
  }
}
registerProcessor("pcm-worklet", PCMWorklet);

Le pipeline en code

Le pipeline comporte trois composants : un client navigateur qui capture le microphone et transmet le PCM à votre serveur, un serveur Node qui relaie l’audio vers Scribe v2 Realtime puis renvoie les transcriptions, et un client scriptable qui transmet du PCM depuis un fichier ou une passerelle de téléphonie.

Le serveur relaie les données au lieu d’exposer directement le moteur de reconnaissance au navigateur pour une raison essentielle : votre clé API ElevenLabs est secrète et ne doit jamais apparaître dans du code côté client. Le serveur conserve la clé. Si le navigateur doit communiquer directement avec le moteur, générez côté serveur un jeton à usage unique et de courte durée, puis remettez-le au client à la place de la clé API.

Client navigateur

Le client ouvre un WebSocket vers votre serveur, capture le microphone via le worklet ci-dessus et transmet chaque trame PCM dès sa production. Les événements entrants — déjà normalisés par le serveur au format { type, text } — pilotent l’état partiel/final présenté plus haut :

// client.ts - runs in the browser. ws is an open WebSocket to your server.
const audioContext = new AudioContext({ sampleRate: 16000 });
await audioContext.audioWorklet.addModule("pcm-worklet.js");

const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: { channelCount: 1, echoCancellation: true, noiseSuppression: true },
});

const source = audioContext.createMediaStreamSource(mediaStream);
const worklet = new AudioWorkletNode(audioContext, "pcm-worklet");

// Forward each PCM frame to the server the moment it is produced.
worklet.port.onmessage = (e: MessageEvent<ArrayBuffer>) => {
  if (ws.readyState === WebSocket.OPEN) ws.send(e.data);
};
source.connect(worklet);

// Manual commit: tell the server to finalize the current segment.
const commit = () => ws.send(JSON.stringify({ type: "commit" }));

Relais serveur

Le serveur ouvre une connexion au moteur de reconnaissance par client, conserve la clé API sur le serveur, transmet directement le PCM binaire et normalise les événements du moteur dans le format stable { type, text } utilisé par le client :

// server.ts - Node, using the `ws` library. ELEVENLABS_API_KEY and the
// recognizer URL come from the environment; see the Speech to Text reference
// for the exact path and query parameters.
import { WebSocketServer, WebSocket } from "ws";

new WebSocketServer({ port: 8080 }).on("connection", (client) => {
  // The API key stays on the server, never on the wire to the browser.
  const recognizer = new WebSocket(process.env.RECOGNIZER_WSS_URL!, {
    headers: { "xi-api-key": process.env.ELEVENLABS_API_KEY! },
  });

  // Browser -> recognizer: forward binary PCM, translate control messages.
  client.on("message", (data, isBinary) => {
    if (recognizer.readyState !== WebSocket.OPEN) return;
    if (isBinary) recognizer.send(data); // raw PCM bytes
    else if (JSON.parse(data.toString()).type === "commit")
      recognizer.send(sendCommit());
  });

  // Recognizer -> browser: normalize events into a stable shape.
  recognizer.on("message", (raw) => {
    const event = parseRecognizerEvent(raw.toString());
    if (event && client.readyState === WebSocket.OPEN)
      client.send(JSON.stringify(event));
  });

  // ... open handshake, queueing pre-open audio, and teardown on close/error
});

Tout ce qui dépend de l’endpoint est isolé dans les deux fonctions d’adaptation ci-dessous. Remplacez les noms de champs par ceux indiqués dans le Guide de l’API Speech to Text ; le reste du pipeline ne change pas :

// The single place that knows the recognizer's wire format.
const sendCommit = (): string => JSON.stringify({ type: "commit" });

type NormalizedEvent =
  | { type: "partial"; text: string }
  | { type: "final"; text: string }
  | { type: "vad"; speaking: boolean };

function parseRecognizerEvent(raw: string): NormalizedEvent | null {
  const msg = JSON.parse(raw);
  if (msg.is_final === true || msg.type === "final")
    return { type: "final", text: msg.text ?? "" };
  if (msg.type === "vad") return { type: "vad", speaking: !!msg.speaking };
  if (typeof msg.text === "string")
    return { type: "partial", text: msg.text };
  return null;
}

Client backend scriptable

Pour les pipelines backend et le benchmark ci-dessous, la même connexion au moteur de reconnaissance fonctionne sans navigateur : lisez le PCM depuis n’importe quelle source, cadencez-le selon le rythme des blocs en temps réel et recevez les événements. La clé API et l’URL proviennent de l’environnement, comme sur le serveur.

// stream-stt.ts - pace ~100ms chunks at real time, then commit the tail.
const SAMPLE_RATE = 16000, CHUNK_MS = 100;
const CHUNK_BYTES = (SAMPLE_RATE * 2 * CHUNK_MS) / 1000; // 3200 bytes
const ws = new WebSocket(process.env.RECOGNIZER_WSS_URL!, {
  headers: { "xi-api-key": process.env.ELEVENLABS_API_KEY! },
});

// Send: walk the PCM buffer in 100ms chunks, sleeping between to mimic a
// live source. For audio that already arrives in real time, drop the sleep.
async function sendAudio(pcm: Buffer) {
  for (let off = 0; off < pcm.length; off += CHUNK_BYTES) {
    ws.send(pcm.subarray(off, off + CHUNK_BYTES));
    await new Promise((r) => setTimeout(r, CHUNK_MS));
  }
  ws.send(JSON.stringify({ type: "commit" })); // finalize the trailing segment
}

// Receive: print partials in place, append finals.
ws.on("message", (raw) => {
  const e = parseRecognizerEvent(raw.toString());
  if (e?.type === "final") console.log(`[final]   ${e.text}`);
  else if (e?.type === "partial") process.stdout.write(`[partial] ${e.text}\r`);
});

Évaluer la latence de transcription vocale et le taux d’erreur sur les mots

La latence et le taux d’erreur sur les mots varient selon le locuteur, la langue, les conditions acoustiques, la durée de l’audio, le chemin réseau vers la région la plus proche de chaque fournisseur et la charge actuelle de chaque service.

Un résultat mesuré depuis un ordinateur portable dans une ville ne se généralise pas à votre infrastructure de production dans une autre. Exécutez le banc de test depuis une infrastructure proche de la production, sur un audio proche de vos entrées réelles, et communiquez des plages et des distributions plutôt que des chiffres uniques.

Les seuls chiffres de latence et de précision qui comptent sont ceux que vous mesurez sur votre propre audio, depuis une infrastructure proche de la production. Voici comment évaluer la latence de transcription vocale.

Mesures de latence pour la transcription vocale

Voici les principales métriques à mesurer lors de l’évaluation de la latence de transcription vocale en temps réel :

  • Délai avant le premier partiel : du premier bloc audio envoyé à la réception du premier partiel non vide.
  • Délai entre partiel et final : du dernier bloc audio d’une intervention à l’hypothèse finale.
  • Taux d’erreur sur les mots (WER) : WER de la transcription finalisée par rapport à une référence humaine, calculé de manière identique pour tous les systèmes.
  • Variations de stabilité : nombre de partiels réécrits avant finalisation. Cette mesure indique dans quelle mesure l’interface en direct semblera changer.

Contrôles

Pour éviter des données peu fiables, mettez en place plusieurs contrôles afin de garantir la cohérence de l’expérience.

Voici les principaux contrôles à appliquer à l’évaluation de la latence de transcription vocale :

  • Audio identique : utilisez les mêmes fichiers, la même fréquence d’échantillonnage et le même encodage pour chaque système.
  • Cadence identique : transmettez les données à chaque système selon la même cadence de blocs en temps réel — par exemple des blocs de 100 ms.
  • Répéter et présenter les distributions : exécutez chaque fichier de nombreuses fois au cours de la journée ; indiquez la médiane et la queue de distribution (p50/p95).
  • Références et évaluation identiques : normalisez le texte de la même façon — casse, ponctuation, nombres — avant de calculer le WER.
  • Indiquer la région et le réseau : précisez où le banc de test s’est exécuté et le chemin vers chaque fournisseur.

En conservant tous ces éléments identiques, vous obtiendrez des métriques plus précises.

Structure du banc de test

Le cœur de la mesure reçoit un adaptateur de fournisseur et enregistre le délai avant le premier partiel, le délai de finalisation et les variations des partiels :

// benchmark.ts - measurement core; one StreamFn adapter per provider.
type StreamFn = (
  audioPath: string,
  onEvent: (kind: "partial" | "final", text: string) => void,
  result: RunResult
) => Promise<void>; // adapter sets result.lastChunkSentAt on the final chunk

interface RunResult {
  firstPartialMs?: number;
  finalLagMs?: number;
  hypothesis: string;
  partialEdits: number;
  lastChunkSentAt: number;
  startedAt: number;
}

async function measure(streamFn: StreamFn, audioPath: string): Promise<RunResult> {
  const result: RunResult = {
    hypothesis: "", partialEdits: 0, lastChunkSentAt: 0,
    startedAt: performance.now(),
  };
  let prevPartial = "";

  await streamFn(audioPath, (kind, text) => {
    const now = performance.now();
    if (kind === "partial") {
      if (text && result.firstPartialMs === undefined)
        result.firstPartialMs = now - result.startedAt;
      if (text !== prevPartial) { result.partialEdits++; prevPartial = text; }
    } else { // final
      result.hypothesis = result.hypothesis ? `${result.hypothesis} ${text}` : text;
      if (result.lastChunkSentAt)
        result.finalLagMs = now - result.lastChunkSentAt;
    }
  }, result);

  return result;
}

Le taux d’erreur sur les mots est une distance de Levenshtein standard au niveau des jetons, calculée sur du texte normalisé. Mettez en minuscules et retirez la ponctuation de façon identique dans la référence et l’hypothèse avant de le calculer ; sinon, vous mesurerez votre normaliseur plutôt que le modèle. Intégrez cette mesure dans une boucle qui exécute chaque fichier environ 10 fois par fournisseur et indique le délai médian avant le premier partiel ainsi que le WER médian (p50/p95), car un échantillon unique est dominé par la variance réseau.

Pour l’exécuter, vous devez fournir deux éléments. D’abord, écrivez un adaptateur StreamFn par système. Le client scriptable ci-dessus en constitue déjà un ; les autres adaptateurs suivent le même contrat (audioPath, onEvent, result) et définissent result.lastChunkSentAt lors de l’envoi du dernier bloc audio. Ensuite, chargez vos fichiers audio et références, puis appelez les mesures sur l’ensemble. Exécutez-le depuis une machine représentative de votre déploiement, sur un audio représentatif de vos utilisateurs, et vous obtiendrez une comparaison reproductible.

Récapitulatif : atteindre la transcription vocale en temps réel

Cet article a présenté de nombreuses évolutions architecturales pour améliorer progressivement votre système et vous rapprocher de la transcription vocale en temps réel.

Un système STT temps réel prêt pour la production repose sur quelques décisions clés :

  • Transport : choisissez WebSocket pour sa simplicité et les réseaux maîtrisés ; choisissez WebRTC lorsque vous avez besoin de tolérance aux pertes et capturez l’audio depuis des appareils grand public.
  • Partiels et finals : traitez les partiels comme provisoires et les finals comme validés, puis affichez-les différemment pour que les utilisateurs fassent confiance au texte en direct.
  • Détection de fin d’énoncé : utilisez la VAD pour une segmentation mains libres, la validation manuelle comme contrôle prioritaire et ajustez le seuil de silence à l’interaction plutôt qu’à une constante.
  • Fonctionnalités en flux : activez-les seulement lorsque l’expérience en direct les requiert et reportez le reste à un traitement par lots avec Scribe v2.
  • Format audio : capturez de petites trames PCM, envoyez des blocs d’environ 100 ms et respectez le format source pour la téléphonie.
  • Évaluation : ajustez empiriquement les paramètres de précision et de latence à partir de votre propre audio et de votre métrique cible.
  • Sécurité de l’API : conservez votre clé API sur le serveur ou générez des jetons à usage unique pour les connexions directes des clients.

Si vous souhaitez savoir comment optimiser la latence d’un agent vocal, nous avons également rédigé un guide sur le sujet.

Concevez des systèmes de transcription vocale en temps réel avec Scribe v2 Realtime

Scribe v2 Realtime produit des partiels avec environ 150 ms de latence de modèle. Que vos utilisateurs perçoivent cette latence ou une valeur supérieure dépend de l’architecture qui l’entoure — et c’est la partie que vous contrôlez. En appliquant les stratégies présentées dans cet article, vous construirez une architecture de pipeline plus efficace, qui réduit la latence et améliore l’expérience client.

Pour aller plus loin, découvrez la présentation des fonctionnalités Speech to Text, consultez notre référence des modèles pour la liste complète des fonctionnalités et langues, et visitez les pages produit en temps réel : API Speech to Text en temps réel et Speech to Text en temps réel.

Lorsque vous êtes prêt à créer, créez gratuitement un compte ElevenLabs et diffusez votre première transcription dès aujourd’hui.

FAQ sur la latence de transcription vocale en temps réel

Articles similaires

Créez avec l'audio IA de la plus haute qualité