Presentiamo Eleven v4Scopri Eleven v4, il nostro modello più espressivo di sempre.

Vai al contenuto

Trascrizione vocale in tempo reale sotto i 200 ms: guida all’architettura

Pubblicato
Ultimo aggiornamento

AscoltaAscolta questo articolo

La trascrizione vocale in tempo reale (STT) trascrive attivamente l'audio mentre una persona parla, restituendo le sue parole come testo entro poche centinaia di millisecondi. Ma mantenere bassa la latenza STT è un problema tanto architetturale quanto di modello. Gli ingegneri devono pianificare trasporto, chunking, end-pointing e percorso di acquisizione, ciascuno dei quali aumenta la latenza. L'inefficienza in uno solo di questi aspetti può sforare il budget di 200 ms.

Questa guida propone un approccio pratico per creare pipeline di trascrizione vocale in tempo reale, a partire dal livello di trasporto. Useremo come riferimento Scribe v2 Realtime, che produce trascrizioni parziali con circa 150 ms di latenza del modello, supporta oltre 90 lingue, accetta audio PCM (8 kHz-48 kHz) e mu-law e offre Voice Activity Detection e il controllo manuale del commit per finalizzare i segmenti.

Vedremo come l'audio raggiunge il server, come le ipotesi diventano testo confermato, quale costo comportano le funzionalità in-stream e come acquisire e inoltrare correttamente l'audio.

  • Per creare sistemi di trascrizione vocale in tempo reale è necessaria una messa a punto dell'architettura, per mantenere bassa la latenza nell'intera pipeline.
  • WebSocket è la scelta predefinita giusta per la maggior parte delle pipeline, anche se WebRTC offre vari vantaggi a fronte di una maggiore complessità.
  • Voice Activity Detection gestisce la segmentazione hands-free, mentre il commit manuale consente alle applicazioni di intervenire quando sanno che il turno è concluso.
  • Le trascrizioni parziali sono provvisorie e quelle finali sono confermate: devi quindi visualizzarle in modo diverso. 
  • Piccoli chunk PCM di circa 100 ms riducono al minimo la latenza fino alla prima trascrizione parziale.

WebSocket e WebRTC per la trascrizione vocale in tempo reale

Prima che avvenga qualsiasi trascrizione, l'audio deve viaggiare dalla sorgente al riconoscitore. Il canale che scegli stabilisce la soglia minima di latenza per tutto ciò che segue. Esistono due opzioni valide per portare l'audio al livello di trascrizione.

WebSocket è un canale TCP persistente, ordinato, affidabile e bidirezionale. Apri una connessione, invii frame audio binari e ricevi eventi di trascrizione. È semplice sia sul client sia sul server, attraversa proxy aziendali e firewall che già consentono HTTPS ed è supportato da ogni browser e runtime server. 

Il vincolo di WebSocket è che si basa su TCP. Se un pacchetto si perde, TCP lo ritrasmette e trattiene i dati successivi finché il divario non viene colmato. In buone condizioni di rete questo non si nota. In caso di perdita di pacchetti, genera head-of-line blocking: una breve interruzione in cui l'audio si accumula e poi arriva in blocco.

WebRTC è progettato per i media in tempo reale. Trasporta i media su UDP (tramite SRTP), quindi un pacchetto perso non blocca lo stream e la pipeline prosegue. Include un jitter buffer che assorbe le variazioni nei tempi di arrivo dei pacchetti, negozia l'attraversamento NAT con ICE/STUN/TURN affinché i peer dietro i router possano connettersi e integra i propri meccanismi di acquisizione e codifica audio. 

In genere servono server TURN per i client che non possono connettersi direttamente e il lato server deve terminare uno stream multimediale anziché leggere uno stream di byte.

Ecco il compromesso in sintesi:

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)

Per la maggior parte dei casi d'uso, WebSocket è l'opzione giusta. Usalo quando i client hanno una buona connettività e controlli il percorso di acquisizione: pipeline server-to-server, app desktop, app browser su connessioni a banda larga e la maggior parte dei backend dei contact center, in cui l'audio arriva già al server in altro modo. 

Scegli WebRTC quando acquisisci direttamente da dispositivi consumer su reti mobili inaffidabili, quando usi già uno stack WebRTC per audio bidirezionale, ad esempio un agente vocale che risponde a voce, oppure quando il comportamento in tempo reale tollerante alle perdite è più importante della semplicità di implementazione.

Il resto della guida usa il trasporto WebSocket per la connessione al riconoscitore, perché rende visibili le parti in gioco ed è il punto di partenza giusto per la maggior parte dei team. Nulla è specifico di WebSocket, quindi in seguito puoi aggiungere a monte un collegamento multimediale WebRTC, decodificare l'audio in PCM sul server e inoltrare gli stessi chunk nella pipeline.

Trascrizioni parziali e finali: spiegazione dei risultati intermedi

Un riconoscitore in tempo reale non aspetta una frase completa prima di restituire testo. Emette invece un flusso continuo di ipotesi che diventano più precise man mano che arriva altro audio, per poi confermarle. Capire la differenza tra questi due stati distingue una trascrizione che sembra viva da una che sembra difettosa. 

Un'ipotesi parziale (intermedia) è la migliore stima del modello in base all'audio ricevuto finora. Le trascrizioni parziali sono instabili per natura. Con l'arrivo di altro audio, il modello rivede le parole precedenti: "Voglio" può diventare "Voglio due biglietti" quando il contesto successivo risolve l'ambiguità. Arrivano rapidamente, come indica la latenza di circa 150 ms, e sono pensate per essere sovrascritte.

Un'ipotesi finale è un segmento confermato che non cambierà. Una volta finalizzato un segmento, il riconoscitore prosegue e le ipotesi successive descrivono l'audio seguente. Le trascrizioni finali sono quelle che salvi, invii a un LLM o archivi come trascrizione.

La distinzione tra trascrizioni parziali e finali determina tre aspetti che sbaglierai se la confondi:

  • Esperienza utente: mostrare le trascrizioni parziali rende la trascrizione più dinamica: l'utente vede apparire le parole mentre parla, confermando che il microfono funziona e il sistema sta ascoltando.
  • End-pointing: le trascrizioni parziali forniscono un segnale continuo dell'attività vocale. Insieme al VAD, ti permettono di stabilire quando chi parla si è davvero fermato.
  • Tempistiche a valle: in una pipeline di agenti vocali i passaggi sono audio in ingresso, poi trascrizione vocale, poi un LLM, poi text to speech, infine audio in uscita. Puoi iniziare il lavoro speculativo sulle trascrizioni parziali e confermarlo su quelle finali, riducendo il tempo di risposta percepito a costo di dover occasionalmente scartare lavoro speculativo.

Visualizza in modo diverso le trascrizioni parziali e finali. Un modello semplice ed efficace consiste nel mantenere un'unica "riga corrente" modificabile, associata all'ultima trascrizione parziale, e confermarla in una trascrizione a cui puoi solo aggiungere testo quando arriva una trascrizione finale:

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

Visivamente, mostra il testo confermato in modo stabile e quello corrente con uno stile più leggero o in corsivo, così l'utente capisce che potrebbe ancora cambiare.

End-pointing e rilevamento dell'attività vocale (VAD)

Sapere cosa è stato detto è solo metà del lavoro. Un riconoscitore deve anche sapere quando un pensiero è concluso. Questa decisione determina quando finalizzare un segmento e, in un agente, quando il sistema inizia a rispondere. 

L'end-pointing è la decisione che un enunciato sia terminato. Finalizzare troppo presto interrompe gli utenti a metà frase. Finalizzare troppo tardi lascia un agente in silenzio dopo che l'utente ha chiaramente finito.

Scribe v2 Realtime offre due meccanismi complementari:

  • Voice Activity Detection segmenta l'audio in base ai silenzi: il riconoscitore rileva quando la voce lascia spazio a un silenzio prolungato e usa quel confine per finalizzare automaticamente un segmento. Il VAD è l'impostazione predefinita più adatta per le interfacce conversazionali perché si adatta al ritmo naturale del parlato senza dover monitorare manualmente i tempi.
  • Controllo manuale del commit: il controllo manuale del commit consente all'applicazione di decidere quando finalizzare il segmento corrente, indipendentemente dal silenzio. Invi un segnale di commit, il riconoscitore chiude il segmento corrente ed emette un risultato finale. È lo strumento giusto quando l'applicazione sa già che il turno è terminato: al rilascio di un pulsante push-to-talk, con un'azione "invia" o tramite una policy esterna di gestione dei turni.

I due meccanismi si combinano bene. Un tipico agente vocale usa il VAD per il funzionamento hands-free ed espone il commit manuale come override, così un utente che fa una pausa per pensare non viene interrotto, mentre uno che tocca un pulsante ottiene un confine immediato.

La soglia di silenzio comporta un vero compromesso e non esiste un valore universalmente corretto:

  • Un timeout breve di fine parlato, ad esempio la finalizzazione dopo circa 200-400 ms di silenzio, rende il sistema reattivo. Tuttavia può interrompere gli utenti che fanno pause naturali tra le proposizioni, dividendo un pensiero in più segmenti e, in un agente, attivando una risposta prematura.
  • Un timeout lungo, ad esempio circa 800-1200 ms, tollera le pause naturali e mantiene intatti gli enunciati, a costo di un ritardo percepibile prima che il sistema reagisca.

Non esiste una costante globale da usare: adatta la soglia all'interazione:

  • Dettatura e presa di appunti tollerano pause più lunghe, perché gli utenti riflettono a metà frase. Prediligi timeout più lunghi e affidati al VAD.
  • Gli agenti di comando e controllo e transazionali traggono vantaggio da timeout più brevi con il commit manuale, perché i turni sono brevi e netti.
  • Chi parla più lingue o non è madrelingua fa più pause, quindi considera più silenzio prima di finalizzare.

Questi suggerimenti ti aiutano a creare un sistema di end-pointing efficace e ad avvicinarti alla trascrizione vocale in tempo reale.

Funzionalità in-stream: rilevamento della lingua e diarizzazione dei parlanti

Il riconoscimento in streaming può fare più che produrre parole. Tuttavia, ogni segnale aggiuntivo richiesto influisce su latenza e stabilità. Come regola generale, attiva solo ciò che serve all'esperienza live e rimanda il resto a un'elaborazione batch.

Il riconoscimento automatico della lingua consente a Scribe v2 Realtime di identificare la lingua parlata tra le oltre 90 supportate, senza richiederti di dichiararla in anticipo. Il compromesso è che il modello ha bisogno di un breve intervallo audio per determinarla con sicurezza, quindi le prime trascrizioni parziali di uno stream possono essere meno stabili mentre la lingua viene identificata. Se conosci già la lingua, specificarla elimina l'ambiguità e tende a produrre trascrizioni parziali iniziali più stabili.

La diarizzazione dei parlanti attribuisce il parlato a parlanti distinti, identificando chi ha detto cosa. Nella trascrizione batch, è relativamente semplice perché il modello vede l'intero file. In streaming è più difficile: il riconoscitore deve assegnare un'etichetta al parlante basandosi soltanto sull'audio ricevuto finora, e un'etichetta assegnata all'audio iniziale potrebbe dover essere rivista una volta ascoltata una porzione maggiore della voce di quel parlante. Tratta le etichette dei parlanti in streaming come il testo parziale: provvisorie finché il segmento non viene finalizzato.

Le tempistiche a livello di parola e il contesto delle entità seguono la stessa logica. Più metadati per token richiedi, più dati devono gestire sia il modello sia la rete. Per la maggior parte delle UI in tempo reale ti servono solo il testo e i confini dei segmenti in diretta; puoi rimandare i metadati dettagliati a un'elaborazione batch post-chiamata con Scribe v2.

Formati audio per lo streaming: PCM e mu-law

Trasporto e logica di riconoscimento ricevono gran parte dell'attenzione, ma una quota sorprendente dei bug reali ha origine un livello più in basso, nel modo in cui codifichi e suddividi l'audio in chunk. Scegliere il formato e la dimensione dei chunk corretti è il modo più economico per ridurre la latenza della trascrizione vocale.

PCM lineare, signed a 16 bit e little-endian, è il formato da usare quando controlli l'acquisizione. Frequenze di campionamento più alte trasportano più dettagli acustici: 16 kHz è lo standard minimo per il riconoscimento vocale ed è in genere sufficiente; 8 kHz è di qualità telefonica e perde il contenuto ad alta frequenza. Usa la frequenza corrispondente alla sorgente. Non c'è alcun vantaggio nell'upsampling dell'audio telefonico da 8 kHz a 48 kHz, perché le informazioni non sono recuperabili.

Mu-law a 8 kHz è il formato della telefonia. Se acquisisci chiamate da un provider come Twilio, l'audio arriva in mu-law a 8 kHz e dovresti inoltrarlo in quel formato anziché transcodificarlo due volte. Corrispondere al formato sorgente evita artefatti di ricampionamento e un passaggio di conversione superfluo.

La dimensione dei chunk è la leva che influenza più direttamente la latenza percepita. Invi l'audio in chunk e il riconoscitore produce trascrizioni parziali man mano che arrivano. Chunk più piccoli comportano aggiornamenti più frequenti e minore latenza fino alla prima trascrizione parziale; chunk più grandi implicano meno messaggi e un po' più di contesto per inferenza. Un intervallo pratico va da 20 a 250 ms di audio per chunk. Come riferimento concreto, con PCM mono a 16 bit e 16 kHz, un secondo di audio corrisponde a 32.000 byte, quindi un chunk da 100 ms è di circa 3.200 byte.

Acquisire l'input del microfono nel browser

Nel browser, lo strumento giusto è la Web Audio API con un AudioWorklet. Il worklet viene eseguito sul thread di rendering audio, riceve l'audio in piccoli frame e non è soggetto ai rallentamenti del main thread come il vecchio ScriptProcessorNode. Il suo compito è convertire i campioni float nativi del browser in PCM a 16 bit e passarli al main thread, che li inoltra tramite WebSocket.

Il nucleo del processore worklet è la conversione da float a 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);

La pipeline nel codice

La pipeline ha tre componenti: un client browser che acquisisce il microfono e invia PCM in streaming al server, un server Node che inoltra l'audio a Scribe v2 Realtime e restituisce le trascrizioni, e un client scriptabile che invia PCM in streaming da un file o un bridge telefonico.

Il server inoltra l'audio anziché esporre direttamente il riconoscitore al browser per un motivo importante: la tua API key ElevenLabs è segreta e non deve mai comparire nel codice lato client. La chiave resta sul server. Se hai bisogno che il browser comunichi direttamente con il riconoscitore, genera lato server un token monouso a breve durata e passa quello al client al posto della API key.

Client browser

Il client apre un WebSocket verso il server, acquisisce il microfono tramite il worklet precedente e inoltra ogni frame PCM non appena viene prodotto. Gli eventi in arrivo, già normalizzati dal server nel formato { type, text }, aggiornano lo stato parziale/finale descritto in precedenza:

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

Relay del server

Il server apre una connessione al riconoscitore per ogni client, mantiene la API key sul server, inoltra direttamente il PCM binario e normalizza gli eventi del riconoscitore nel formato stabile { type, text } usato dal 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
});

Tutto ciò che è specifico dell'endpoint è limitato alle due funzioni adapter seguenti. Sostituisci i nomi dei campi con quelli esatti del riferimento Speech to Text; il resto della pipeline non cambia:

// 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 scriptabile

Per le pipeline backend e per il benchmark seguente, la stessa connessione al riconoscitore funziona senza browser: leggi il PCM da qualsiasi sorgente, scandiscilo alla cadenza dei chunk in tempo reale e ricevi gli eventi. La API key e l'URL provengono dall'ambiente, come sul server.

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

Benchmark della latenza di trascrizione vocale e del word error rate

La latenza e il word error rate variano entrambi in base al parlante, alla lingua, alle condizioni acustiche, alla durata dell'audio, al percorso di rete verso la regione più vicina di ciascun provider e al carico corrente di ogni servizio. 

Un risultato misurato da un laptop in una città non è generalizzabile alla tua infrastruttura di produzione in un'altra. Esegui l'harness da un'infrastruttura simile a quella di produzione, con audio simile all'input reale, e riporta intervalli e distribuzioni anziché singoli valori.

Le uniche metriche di latenza e accuratezza che contano sono quelle misurate sul tuo audio, da un'infrastruttura simile alla produzione. Ecco una guida al benchmark della latenza della trascrizione vocale.

Cosa misurare per la latenza della trascrizione vocale

Di seguito trovi le principali metriche da misurare durante il benchmark della latenza della trascrizione vocale in tempo reale:

  • Tempo alla prima trascrizione parziale: dall'invio del primo chunk audio alla ricezione della prima trascrizione parziale non vuota.
  • Ritardo da parziale a finale: dall'ultimo chunk audio di un enunciato all'ipotesi finale.
  • Word error rate (WER): WER della trascrizione finalizzata rispetto a un riferimento umano, calcolato in modo identico per tutti i sistemi.
  • Variazione della stabilità: quante trascrizioni parziali vengono riscritte prima della finalizzazione. Questa misura indica indirettamente quanto la UI live sembrerà cambiare.

Controlli

Per evitare dati inaffidabili, implementa diversi controlli nell'esperimento per mantenere la coerenza.

Ecco i principali controlli da usare per il benchmark della latenza di trascrizione vocale:

  • Audio identico: usa gli stessi file, la stessa frequenza di campionamento e la stessa codifica per ogni sistema.
  • Cadenza identica: invia in streaming ogni sistema con la stessa cadenza di chunk in tempo reale, ad esempio chunk da 100 ms.
  • Ripeti e riporta le distribuzioni: esegui ogni file molte volte nel corso della giornata e riporta mediana e coda (p50/p95).
  • Riferimenti e punteggi identici: normalizza il testo nello stesso modo, incluse maiuscole, punteggiatura e numeri, prima di calcolare il WER.
  • Indica regione e rete: specifica dove è stato eseguito l'harness e il percorso verso ciascun provider.

Mantenendo identici tutti questi elementi, otterrai metriche più precise.

Struttura dell'harness

Il nucleo della misurazione riceve un adapter del provider e registra il tempo alla prima trascrizione parziale, il ritardo di finalizzazione e le variazioni delle trascrizioni parziali:

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

Il word error rate è una distanza di Levenshtein standard a livello di token sul testo normalizzato. Converti in minuscolo e rimuovi la punteggiatura allo stesso modo sia dal riferimento sia dall'ipotesi prima di calcolarlo, altrimenti misurerai il normalizzatore anziché il modello. Inserisci questa misura in un loop che esegue ogni file circa 10 volte per provider e riporta la mediana del tempo alla prima trascrizione parziale e del WER (p50/p95), poiché un singolo campione è dominato dalla variabilità della rete.

Per eseguirlo, devi fornire due elementi. Prima di tutto, scrivi un adapter StreamFn per ogni sistema. Il client scriptabile sopra è già un adapter; quelli per gli altri seguono lo stesso contratto (audioPath, onEvent, result) e impostano result.lastChunkSentAt quando viene inviato l'ultimo chunk audio. In secondo luogo, carica i file audio e i riferimenti e richiama le misurazioni su di essi. Eseguilo da una macchina rappresentativa del deployment, con audio rappresentativo dei tuoi utenti, e avrai un confronto riproducibile.

Riepilogo: come ottenere la trascrizione vocale in tempo reale 

In questo articolo abbiamo trattato molti cambiamenti architetturali che ti permettono di migliorare iterativamente il sistema e avvicinarti alla trascrizione vocale in tempo reale.

Un sistema STT in tempo reale pronto per la produzione dipende da alcune decisioni fondamentali:

  • Trasporto: scegli WebSocket per semplicità e reti controllate, e WebRTC quando ti serve tolleranza alle perdite e acquisisci da dispositivi consumer.
  • Trascrizioni parziali e finali: tratta le trascrizioni parziali come provvisorie e quelle finali come confermate, e visualizzale in modo diverso affinché gli utenti si fidino del testo live.
  • End-pointing: usa il VAD per la segmentazione hands-free, il commit manuale come override e adatta la soglia di silenzio all'interazione anziché a una costante.
  • Funzionalità in-stream: attivale solo dove servono all'esperienza live e rimanda il resto a un'elaborazione batch con Scribe v2.
  • Formato audio: acquisisci in piccoli frame PCM, invia chunk da circa 100 ms e usa il formato sorgente per la telefonia.
  • Benchmark: imposta empiricamente i parametri di accuratezza e latenza rispetto al tuo audio e alla metrica di riferimento.
  • Sicurezza API: mantieni la tua API key sul server, oppure genera token monouso per le connessioni dirette dei client.

Se vuoi scoprire come ottimizzare la latenza in un agente vocale, abbiamo scritto anche una guida dedicata.

Crea sistemi di trascrizione vocale in tempo reale con Scribe v2 Realtime

Scribe v2 Realtime produce trascrizioni parziali con circa 150 ms di latenza del modello. Se gli utenti percepiscono questo valore o uno superiore dipende dall'architettura circostante, che è la parte sotto il tuo controllo. Usando le strategie illustrate in questo articolo, creerai un'architettura di pipeline più efficace che riduce la latenza e migliora l'esperienza cliente. 

Per approfondire, scopri la panoramica delle funzionalità Speech to Text, consulta il nostro riferimento dei modelli per l'elenco completo di funzionalità e lingue e visita le pagine dei prodotti in tempo reale: API Speech to Text in tempo reale e Speech to Text in tempo reale.

Quando sei pronto per iniziare a sviluppare, crea un account ElevenLabs gratuito e invia in streaming la tua prima trascrizione oggi stesso.

FAQ sulla latenza della trascrizione vocale in tempo reale

Scritto da

Tadas Petra è Developer Relations Engineer e aiuta gli sviluppatori a creare con la suite di prodotti ElevenLabs. È anche il fondatore di Hungrimind, una piattaforma di formazione per sviluppatori. In passato è stato Lead Developer Advocate in Agora e docente presso Zero To Mastery.

Articoli simili

Crea con l'audio IA della massima qualità