Introducing Eleven v4Introducing Eleven v4, our fastest and most emotive voice model

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 in testo entro poche centinaia di millisecondi. Tuttavia, mantenere bassa la latenza STT è tanto un problema architetturale quanto di modello. Gli sviluppatori devono pianificare trasporto, chunking, end-pointing e percorso di acquisizione, ognuno dei quali aggiunge latenza. L'inefficienza in uno solo di questi aspetti può superare il budget di 200 ms.

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

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

  • Per creare sistemi di trascrizione vocale in tempo reale devi ottimizzare l'architettura, assicurandoti che la latenza resti bassa nell'intera pipeline.
  • WebSocket è l'opzione predefinita giusta per la maggior parte delle pipeline, anche se WebRTC offre diversi vantaggi a fronte di una maggiore complessità.
  • Voice Activity Detection gestisce la segmentazione hands-free, mentre il commit manuale offre alle applicazioni un controllo aggiuntivo quando sanno che il turno è terminato.
  • I parziali sono provvisori e i finali sono confermati, quindi dovresti visualizzarli in modo diverso. 
  • Piccoli chunk PCM di circa 100 ms riducono al minimo la latenza del primo 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 scelto 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 bidirezionale su TCP, persistente, ordinato e affidabile. Apri una connessione, invii frame audio binari e ricevi eventi di trascrizione. È semplice sia sul client sia sul server, attraversa i proxy aziendali e i 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 va perso, TCP lo ritrasmette e trattiene i dati successivi finché il vuoto non viene colmato. In buone condizioni di rete non è percepibile. In presenza di perdita di pacchetti, genera head-of-line blocking: una breve pausa in cui l'audio si accumula e arriva poi tutto insieme.

WebRTC è progettato per i media in tempo reale. Trasporta i media su UDP (tramite SRTP), quindi la perdita di un pacchetto 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 tramite ICE/STUN/TURN per consentire la connessione di peer dietro router e include meccanismi propri 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 banda larga e la maggior parte dei backend dei contact center, in cui l'audio raggiunge già il 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, o quando il comportamento in tempo reale resistente alle perdite è più importante della semplicità di implementazione.

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

Parziali e trascrizioni finali: spiegazione dei risultati intermedi

Un riconoscitore in tempo reale non aspetta una frase completa prima di produrre testo. Emette invece un flusso continuo di ipotesi che si affinano man mano che arriva altro audio, per poi confermarle. Comprendere la differenza tra questi due stati distingue una trascrizione che sembra viva da una che sembra frammentata. 

Un'ipotesi parziale (intermedia) è la migliore stima del modello in base all'audio ricevuto finora. I parziali sono instabili per natura. Con l'arrivo di altro audio, il modello rivede le parole precedenti: "Vorrei" può diventare "Vorrei due biglietti" quando il contesto successivo risolve l'ambiguità. Arrivano rapidamente, ed è questo che descrive la latenza di circa 150 ms, e sono pensati per essere sovrascritti.

Un'ipotesi finale è un segmento confermato che non cambierà. Una volta finalizzato un segmento, il riconoscitore passa oltre e le ipotesi successive descrivono l'audio seguente. I finali sono ciò che persisti, invii a un LLM o archivi come trascrizione.

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

  • Esperienza utente: Visualizzare i parziali rende viva una trascrizione: l'utente vede le parole comparire mentre parla, confermando che il microfono funziona e che il sistema ascolta.
  • End-pointing: I parziali forniscono un segnale continuo dell'attività vocale. Insieme al VAD, consentono di decidere quando chi parla si è effettivamente fermato.
  • Tempistiche downstream: In una pipeline di un agente vocale i passaggi sono: audio in ingresso, trascrizione vocale, LLM, sintesi vocale, quindi audio in uscita. Puoi iniziare il lavoro speculativo sui parziali e confermarlo sui finali, riducendo il tempo di risposta percepito a costo di dover occasionalmente scartare il lavoro speculativo.

Visualizza parziali e finali in modo diverso. Un modello semplice ed efficace consiste nel mantenere un'unica "riga corrente" modificabile associata all'ultimo parziale e aggiungerla a una trascrizione a sola aggiunta quando arriva un 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: "" });

A livello visivo, mostra il testo confermato come definitivo e quello corrente con uno stile più chiaro 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 è terminato. 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 concluso.

Scribe v2 Realtime offre due meccanismi complementari:

  • Voice Activity Detection segmenta l'audio in base al silenzio: Il riconoscitore rileva quando il parlato lascia spazio a un silenzio prolungato e usa quel confine per finalizzare automaticamente un segmento. Il VAD è la scelta predefinita giusta per le interfacce conversazionali perché si adatta al ritmo naturale del parlato senza dover gestire manualmente i tempi.
  • Controllo di commit manuale: Il controllo di commit manuale permette alla tua applicazione di decidere quando finalizzare il segmento corrente, indipendentemente dal silenzio. Inviando un segnale di commit, il riconoscitore chiude il segmento corrente ed emette un 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 in base a una policy esterna di gestione dei turni.

I due meccanismi funzionano bene insieme. Un tipico agente vocale usa il VAD per il funzionamento hands-free e mette a disposizione il commit manuale come controllo aggiuntivo: così chi fa una pausa per pensare non viene interrotto, mentre chi tocca un pulsante ottiene un confine immediato.

La soglia di silenzio è un compromesso reale, senza 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:

  • La dettatura e la presa di appunti tollerano pause più lunghe perché gli utenti riflettono a metà frase. Privilegia timeout più lunghi e affidati al VAD.
  • Gli agenti di comando e controllo e transazionali traggono vantaggio da timeout più brevi e dal 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. Detto questo, ogni segnale aggiuntivo richiesto influisce su latenza e stabilità. La regola generale è attivare solo ciò che serve all'esperienza live e rimandare 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 doverla dichiarare in anticipo. Il modello deve però ricevere un breve intervallo di audio per determinarla con sicurezza, quindi i primi parziali di uno stream possono essere meno stabili mentre la lingua viene identificata. Se conosci già la lingua, specificarla elimina questa ambiguità e tende a produrre parziali iniziali più stabili.

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 solo sull'audio ricevuto finora e un'etichetta assegnata all'audio iniziale può dover essere rivista quando viene ascoltata una porzione maggiore della voce di quel parlante. Tratta le etichette dei parlanti in streaming come il testo parziale: sono provvisorie fino alla finalizzazione del segmento.

La temporizzazione 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 connessione. Per la maggior parte delle UI in tempo reale servono live il testo e i confini dei segmenti, nulla di più; puoi rimandare i metadati dettagliati a un'elaborazione batch post-chiamata con Scribe v2.

Formati audio per lo streaming: PCM e mu-law

La logica di trasporto e riconoscimento attira gran parte dell'attenzione, ma una quota sorprendente di bug reali ha origine a un livello inferiore, nel modo in cui codifichi e suddividi l'audio in chunk. Usare il formato e la dimensione dei chunk giusti è il modo più economico per ridurre la latenza della trascrizione vocale.

Il PCM, lineare, firmato a 16 bit e little-endian, è il formato da usare quando controlli l'acquisizione. Frequenze di campionamento più alte offrono maggiori dettagli acustici: 16 kHz è il minimo standard per il riconoscimento vocale ed è di solito sufficiente; 8 kHz è di qualità telefonica e perde contenuti ad alta frequenza. Usa la frequenza che corrisponde alla sorgente. Non c'è alcun vantaggio nel fare upsampling dell'audio telefonico a 8 kHz fino a 48 kHz, perché le informazioni non possono essere recuperate.

Il mu-law a 8 kHz è il formato telefonico. 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 parziali quando li riceve. Chunk più piccoli comportano aggiornamenti più frequenti e una minore latenza al primo parziale; chunk più grandi comportano meno messaggi e un po' più contesto per ogni 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 equivale a 32.000 byte, quindi un chunk di 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 nel thread di rendering audio, riceve l'audio in piccoli frame e non è soggetto ai rallentamenti del main thread come il precedente ScriptProcessorNode. Il suo compito è convertire i sample 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 da un bridge telefonico.

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

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 }, determinano 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 chiave API 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 è racchiuso nelle due funzioni adapter qui sotto. Sostituisci i nomi dei campi con quelli esatti del Riferimento API 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 qui sotto, la stessa connessione al riconoscitore funziona senza browser: leggi PCM da qualsiasi sorgente, invialo alla cadenza dei chunk in tempo reale e ricevi gli eventi. La chiave API 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 della 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 attuale 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, su audio simile al tuo input reale, e riporta intervalli e distribuzioni anziché singoli valori.

Gli unici valori di latenza e accuratezza rilevanti sono quelli che misuri 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 nel benchmark della latenza della trascrizione vocale in tempo reale:

  • Tempo al primo parziale: Dall'invio del primo chunk audio alla ricezione del primo parziale non vuoto.
  • Ritardo dal parziale al 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 in tutti i sistemi.
  • Variazione di stabilità: Quanti parziali vengono riscritti prima della finalizzazione. Questa misura indica quanto la UI live sembrerà cambiare.

Controlli

Per evitare dati inaffidabili, dovresti introdurre diversi controlli nell'esperimento per mantenere condizioni coerenti.

Ecco i principali controlli da usare nel benchmark della latenza della trascrizione vocale:

  • Audio identico: Usa gli stessi file, la stessa frequenza di campionamento e la stessa codifica per ogni sistema.
  • Cadenza identica: Trasmetti ogni sistema alla stessa cadenza di chunk in tempo reale, ad esempio chunk da 100 ms.
  • Ripeti e riporta le distribuzioni: Esegui ogni file molte volte durante la giornata; riporta mediana e coda (p50/p95).
  • Riferimenti e punteggi identici: Normalizza il testo allo stesso modo, incluse maiuscole/minuscole, 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 uguali tutti questi elementi, otterrai metriche più precise.

Struttura dell'harness

Il nucleo della misurazione riceve un adapter del provider e registra il tempo al primo parziale, il ritardo di finalizzazione e la variazione dei 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 calcolata su testo normalizzato. Applica minuscole e rimuovi la punteggiatura nello stesso modo sia al riferimento sia all'ipotesi prima di calcolarlo, altrimenti misurerai il normalizzatore anziché il modello. Inserisci questa misura in un ciclo che esegue ogni file circa 10 volte per provider e riporta il tempo mediano al primo parziale e il WER mediano (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 sistema. Il client scriptabile precedente è già un adapter, mentre quelli per gli altri seguono lo stesso contratto (audioPath, onEvent, result) e impostano result.lastChunkSentAt quando viene inviato il chunk audio finale. Poi carica i file audio e i riferimenti e chiama measure su tutti. Esegui il test da una macchina che rappresenti il tuo 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 esaminato molte modifiche architetturali che ti consentono 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.
  • Parziali e finali: Tratta i parziali come provvisori e i finali come confermati e visualizzali in modo diverso, così gli utenti si fidano del testo live.
  • End-pointing: Usa il VAD per la segmentazione hands-free, il commit manuale come controllo aggiuntivo e adatta la soglia di silenzio all'interazione anziché a una costante.
  • Funzionalità in-stream: Attiva le funzionalità in-stream solo quando servono all'esperienza live e rimanda il resto a un'elaborazione batch con Scribe v2.
  • Formato audio: Acquisisci in piccoli frame PCM, invia chunk di circa 100 ms e usa il formato della sorgente per la telefonia.
  • Benchmark: Imposta empiricamente i parametri di accuratezza e latenza sul tuo audio e sulla metrica obiettivo.
  • Sicurezza API: Mantieni la tua chiave API sul server, oppure genera token monouso per le connessioni dirette del 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 parziali con una latenza del modello di circa 150 ms. Che gli utenti percepiscano questa latenza o una maggiore dipende dall'architettura che la circonda, la parte su cui hai il controllo. Usando le strategie descritte in questo articolo, creerai un'architettura della pipeline migliore 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 delle funzionalità e delle 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 a iniziare, crea un account ElevenLabs gratuito e invia oggi stesso in streaming la tua prima trascrizione.

FAQ sulla latenza della trascrizione vocale in tempo reale

Articoli simili

Crea con l'audio IA della massima qualità