Découvrez Eleven v4Découvrez Eleven v4, notre modèle le plus expressif à ce jour. Avec 3× plus de crédits inclus avec Creator+ jusqu’au 12 octobre

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 activement l'audio pendant qu'une personne parle et restitue ses mots 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 segments, 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 présente une approche pratique pour créer des pipelines de transcription vocale en temps réel, à partir de la couche de transport. Il s'appuie sur Scribe v2 Realtime, qui produit des transcriptions partielles avec environ 150 ms de latence du modèle, prend en charge plus de 90 langues, accepte l'audio PCM (8 kHz à 48 kHz) et mu-law, et propose la détection d'activité vocale 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 transférer correctement l'audio.

Résumé

  • La création de systèmes de transcription vocale en temps réel exige un ajustement fin de l'architecture afin de maintenir une faible latence sur l'ensemble du pipeline.
  • WebSocket est le choix par défaut pour la plupart des pipelines, même si WebRTC offre plusieurs avantages au prix d'une plus grande complexité.
  • La détection d'activité vocale gère la segmentation mains libres, tandis que la validation manuelle permet à vos applications de reprendre le contrôle lorsqu'elles savent que le tour de parole est terminé.
  • Les résultats partiels sont provisoires et les résultats finaux sont validés : ils doivent donc être affichés différemment. 
  • De petits segments PCM d'environ 100 ms réduisent au minimum la latence avant le premier résultat 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 plancher de latence de tout ce qui suit. Deux options permettent d'acheminer l'audio jusqu'à la couche de transcription.

WebSocket est un canal TCP durable, ordonné, fiable et bidirectionnel. 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 qu'il repose sur TCP. Si un paquet est perdu, TCP le retransmet et retient les données suivantes jusqu'à ce que le manque soit comblé. Dans de bonnes conditions réseau, cela ne se remarque pas. En cas de perte de paquets, cela produit un blocage en tête de ligne : un bref arrêt où l'audio s'accumule avant d'arriver en rafale.

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

Des serveurs TURN sont généralement nécessaires pour les clients ne pouvant pas se connecter directement, et le serveur doit terminer un flux média plutôt que lire un flux d'octets.

Voici le 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)

Pour la plupart des cas d'usage, WebSocket est le bon choix. Utilisez-le lorsque vos clients disposent d'une connexion correcte et que vous contrôlez la chaîne de capture : pipelines de 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 peu fiables, si vous exploitez déjà une pile WebRTC pour l'audio bidirectionnel, par exemple un agent vocal qui répond aussi à voix haute, ou si le comportement temps réel tolérant aux pertes compte davantage que la simplicité d'implémentation.

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 couche média WebRTC en amont, décoder l'audio en PCM sur le serveur et transférer les mêmes segments dans le pipeline.

Résultats 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 produire du texte. Il émet plutôt un flux continu de propositions qui se précisent à mesure que l'audio arrive, puis les valide. Comprendre la différence entre ces deux états distingue une transcription vivante d'une transcription défaillante. 

Une hypothèse partielle, ou intermédiaire, est la meilleure estimation du modèle à partir de l'audio reçu jusqu'alors. Les résultats partiels sont instables par nature. À 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. Une fois le segment finalisé, le moteur de reconnaissance passe à la suite et les hypothèses suivantes décrivent l'audio ultérieur. Les résultats finaux sont ceux que vous conservez, envoyez à un LLM ou stockez comme transcription.

La distinction entre résultats partiels et finaux détermine trois aspects que vous gérerez mal si vous les confondez :

  • Expérience utilisateur : L'affichage des résultats partiels donne vie à la transcription : l'utilisateur voit les mots apparaître pendant qu'il parle, ce qui confirme que le microphone fonctionne et que le système écoute.
  • Détection de fin d'énoncé : Les résultats 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 : audio entrant, transcription vocale, LLM, puis synthèse vocale, puis audio sortant. Vous pouvez commencer un traitement spéculatif sur les résultats partiels et le confirmer sur les résultats finaux, afin de réduire le temps de réponse perçu, quitte à abandonner occasionnellement ce travail spéculatif.

Affichez différemment les résultats partiels et finaux. Un schéma simple et efficace consiste à conserver une unique « ligne actuelle » modifiable, liée au dernier résultat partiel, et à l'ajouter à une transcription en ajout seul lorsqu'un résultat 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é comme définitif et le texte actuel dans un style plus léger ou en 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 quand finaliser un segment et, pour un agent, quand le système commence à répondre. 

La détection de fin d'énoncé consiste à déterminer qu'une énonciation est terminée. Une finalisation trop précoce coupe les utilisateurs au milieu d'une phrase. Trop tardive, elle laisse un agent silencieux alors que l'utilisateur a clairement terminé.

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

  • La détection d'activité vocale segmente l'audio selon les silences : Le moteur de reconnaissance détecte quand 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 de reconnaissance ferme le segment en cours et émet un résultat final. C'est l'outil adapté lorsque votre application sait déjà que le tour de parole 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 bien. Un agent vocal typique utilise la VAD pour un fonctionnement mains libres et expose la validation manuelle comme mécanisme de remplacement. Ainsi, 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 implique un véritable compromis, sans valeur universellement correcte :

  • Un délai de fin de parole court, 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 font naturellement des pauses entre les propositions, scindant une même idée en plusieurs segments et, pour 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 énoncés, mais introduit un décalage perceptible avant que le système réagisse.

Il n'existe pas de constante globale à utiliser ici : 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 de leurs phrases. Privilégiez des délais plus longs et appuyez-vous sur la VAD.
  • Les agents de commande et de transaction bénéficient de délais plus courts associés à la validation manuelle, car les tours de parole sont brefs et nets.
  • Les locuteurs multilingues ou non natifs font davantage de pauses : prévoyez donc plus de silence avant la finalisation.

Ces conseils vous aideront à créer un système efficace de détection de fin d'énoncé et à vous rapprocher de la transcription vocale en temps réel.

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

La reconnaissance en flux peut faire bien plus que produire des mots. Toutefois, chaque signal supplémentaire demandé influe sur la latence et la stabilité. En règle générale, n'activez que ce dont l'expérience en direct a besoin et reportez le reste à un traitement par lot.

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 que vous ayez à la déclarer au préalable. Le modèle a toutefois besoin d'un court extrait audio pour l'identifier avec certitude : les premiers résultats partiels d'un flux peuvent donc être moins stables pendant que la langue est déterminée. Si vous connaissez déjà la langue, la spécifier élimine cette ambiguïté et tend à produire des résultats partiels initiaux plus stables.

La diarisation des locuteurs attribue la parole à différents locuteurs afin d'identifier qui a dit quoi. En transcription par lot, cela est relativement simple, car le modèle analyse l'intégralité du fichier. En flux, c'est plus difficile : le moteur de reconnaissance doit attribuer une étiquette de locuteur à partir du seul audio reçu jusqu'alors, et une étiquette associée à l'audio initial peut devoir être révisée après avoir entendu davantage la voix de ce locuteur. 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 en temps réel, vous n'avez besoin en direct que du texte et des limites de segments ; vous pouvez reporter les métadonnées détaillées à un traitement par lot après l'appel avec Scribe v2.

Formats audio pour le streaming : PCM et mu-law

La logique de transport et de reconnaissance capte 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 segment est le moyen le plus économique de réduire la latence de transcription vocale.

Le PCM, linéaire, signé sur 16 bits et little-endian, est le format à utiliser lorsque vous contrôlez la capture. Des fréquences d'échantillonnage plus élevées transportent davantage de détails acoustiques : 16 kHz constitue le minimum 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. Il est inutile de suréchantillonner un audio téléphonique à 8 kHz vers 48 kHz, car 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 d'un fournisseur tel que Twilio, l'audio arrive en mu-law à 8 kHz : transférez-le dans ce format au lieu de le transcoder deux fois. Adapter le format à la source évite les artefacts de rééchantillonnage et une étape de conversion inutile.

La taille des segments est le levier qui façonne le plus directement la latence perçue. Vous envoyez l'audio par segments, et le moteur de reconnaissance produit des résultats partiels à leur arrivée. Des segments plus petits offrent des mises à jour plus fréquentes et une latence réduite avant le premier résultat partiel ; des segments plus grands impliquent moins de messages et un peu plus de contexte par inférence. Une plage pratique va de 20 à 250 ms d'audio par segment. À titre indicatif, en PCM mono 16 bits à 16 kHz, une seconde d'audio représente 32 000 octets : un segment de 100 ms représente donc environ 3 200 octets.

Capturer l'entrée microphone dans le navigateur

Dans le navigateur, l'outil adapté est l'API Web Audio API avec un AudioWorklet. Le worklet s'exécute sur le thread de rendu audio, reçoit l'audio dans de petites trames et n'est pas soumis aux ralentissements du thread principal comme 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 des flottants 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 éléments : un client navigateur qui capture le microphone et envoie le PCM à votre serveur, un serveur Node qui relaie l'audio vers Scribe v2 Realtime et renvoie les transcriptions, et un client scriptable qui diffuse du PCM depuis un fichier ou une passerelle de téléphonie.

Le serveur fait office de relais plutôt que 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 le code côté client. Le serveur conserve la clé. Si le navigateur doit communiquer directement avec le moteur de reconnaissance, créez côté serveur un jeton à usage unique de courte durée et transmettez-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 transfère chaque trame PCM dès sa production. Les événements entrants, déjà normalisés par le serveur sous la forme { type, text }, alimentent l'état partiel/final présenté précédemment :

// 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, transfère directement le PCM binaire et normalise les événements du moteur de reconnaissance dans le format stable { type, text } consommé 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 est propre au point de terminaison 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 l'analyse comparative ci-dessous, la même connexion au moteur de reconnaissance fonctionne sans navigateur : lisez du PCM depuis n'importe quelle source, cadencez-le au rythme des segments temps réel et lisez les événements en retour. 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`);
});

Mesurer 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, votre chemin réseau jusqu'à 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 flotte de production dans une autre. Exécutez le banc d'essai depuis une infrastructure proche de la production, sur un audio similaire à vos entrées réelles, et présentez des plages et des distributions plutôt que des chiffres uniques.

Les seuls chiffres de latence et de précision pertinents sont ceux que vous mesurez sur vos propres audios, 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 résultat partiel : du premier segment audio envoyé au premier résultat partiel non vide reçu.
  • Délai entre résultat partiel et final : du dernier segment audio d'un énoncé à 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 sur tous les systèmes.
  • Variations de stabilité : nombre de résultats 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, intégrez plusieurs contrôles à votre expérience afin de maintenir la cohérence.

Voici les principaux contrôles à appliquer pour mesurer 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 : diffusez chaque système selon la même cadence de segments temps réel, par exemple des segments de 100 ms.
  • Répétition et distribution des résultats : exécutez chaque fichier plusieurs fois au cours de la journée ; indiquez la médiane et la queue de distribution (p50/p95).
  • Références et notation identiques : normalisez le texte de la même façon, casse, ponctuation et nombres, avant de calculer le WER.
  • Indiquez la région et le réseau : précisez où le banc d'essai a été 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 d'essai

Le cœur de la mesure utilise un adaptateur de fournisseur et enregistre le délai avant le premier résultat partiel, le délai de finalisation et les variations des résultats 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 sur un texte normalisé. Passez systématiquement en minuscules et supprimez la ponctuation de la même manière 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 exécutant chaque fichier environ 10 fois par fournisseur et indiquant le délai médian avant le premier résultat 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 adaptateurs des autres suivent le même contrat (audioPath, onEvent, result) et définissent result.lastChunkSentAt lors de l'envoi du dernier segment audio. Ensuite, chargez vos fichiers audio et références, puis appelez les mesures pour chacun. 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 couvert de nombreuses évolutions architecturales qui vous permettent d'améliorer progressivement votre système et de vous rapprocher de la transcription vocale en temps réel.

Un système STT en 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 contrôlés, et WebRTC lorsque vous avez besoin de tolérance aux pertes et capturez depuis des appareils grand public.
  • Résultats partiels et finaux : traitez les résultats partiels comme provisoires et les résultats finaux comme validés, et affichez-les différemment afin que les utilisateurs fassent confiance au texte en direct.
  • Détection de fin d'énoncé : utilisez la VAD pour la segmentation mains libres, la validation manuelle comme mécanisme de remplacement et ajustez le seuil de silence à l'interaction plutôt qu'à une constante.
  • Fonctionnalités en flux : activez-les uniquement lorsque l'expérience en direct les nécessite, et reportez le reste à un traitement par lot avec Scribe v2.
  • Format audio : capturez dans de petites trames PCM, envoyez des segments d'environ 100 ms et adaptez le format à la source pour la téléphonie.
  • Analyse comparative : réglez empiriquement les paramètres de précision et de latence à partir de vos propres audios et de votre métrique cible.
  • Sécurité de l'API : conservez votre clé API sur le serveur, ou créez des jetons à usage unique pour les connexions directes des clients.

Pour découvrir comment optimiser la latence d'un agent vocal, consultez également notre guide.

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

Scribe v2 Realtime produit des résultats partiels avec environ 150 ms de latence du modèle. La latence réellement perçue par vos utilisateurs dépend de l'architecture qui l'entoure, celle que vous maîtrisez. En appliquant les stratégies présentées dans cet article, vous créerez une architecture de pipeline plus performante qui réduit la latence et améliore l'expérience client. 

Pour aller plus loin, découvrez la présentation des capacités de Speech to Text, consultez notre guide des modèles pour obtenir la liste complète des fonctionnalités et langues, puis rendez-vous sur 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

Rédigé par

Tadas Petra est ingénieur en relations développeurs et aide les développeurs à utiliser la suite de produits ElevenLabs. Il est aussi le fondateur de Hungrimind, une plateforme d’apprentissage pour développeurs. Auparavant, il était Lead Developer Advocate chez Agora et formateur chez Zero To Mastery.

Articles similaires

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