Pular para o conteúdo

Transcrição de Voz em Tempo Real em menos de 200ms: Guia de arquitetura

Publicado
Última atualização

OuvirOuça este artigo

A transcrição de voz em tempo real (STT) transcreve ativamente o áudio enquanto uma pessoa fala, retornando suas palavras em texto em poucas centenas de milissegundos. Mas manter a latência do STT baixa é tanto um desafio de arquitetura quanto de modelo. Os desenvolvedores precisam planejar o transporte, a divisão em chunks, a detecção de fim de fala e o caminho de captura, pois cada um adiciona latência à equação. A ineficiência em qualquer um deles pode estourar seu orçamento de 200 ms.

Este guia apresenta um sistema prático para criar pipelines de transcrição de voz em tempo real, começando pela camada de transporte. Vamos usar o Scribe v2 Realtime, que produz transcrições parciais com cerca de 150 ms de latência do modelo, oferece suporte a mais de 90 idiomas, aceita áudio PCM (8 kHz a 48 kHz) e mu-law e disponibiliza Detecção de Atividade de Voz, além de controle de confirmação manual para finalizar segmentos.

Vamos acompanhar como o áudio chega ao servidor, como as hipóteses evoluem para texto confirmado, qual é o custo dos recursos durante o streaming e como capturar e encaminhar áudio corretamente.

Resumo

  • A criação de sistemas de transcrição de voz em tempo real exige ajustes finos de arquitetura para garantir baixa latência em todo o pipeline.
  • WebSocket é a melhor opção padrão para a maioria dos pipelines, embora o WebRTC ofereça vários benefícios com maior complexidade.
  • A Detecção de Atividade de Voz faz a segmentação sem uso das mãos, enquanto a confirmação manual permite que seus aplicativos assumam o controle quando sabem que o turno terminou.
  • Os resultados parciais são provisórios e os finais são confirmados, portanto você deve exibi-los de formas diferentes. 
  • Chunks pequenos de PCM, de cerca de 100 ms, minimizam a latência até o primeiro resultado parcial.

WebSocket vs. WebRTC para transcrição de voz em tempo real

Antes de qualquer transcrição, o áudio precisa viajar da fonte até o reconhecedor. O canal escolhido define a latência mínima de tudo o que vem depois. Há duas opções viáveis para que o áudio chegue à camada de transcrição.

WebSocket é um canal bidirecional, confiável, ordenado e persistente sobre TCP. Você abre uma conexão, envia frames binários de áudio e recebe eventos de transcrição. Ele é simples tanto no cliente quanto no servidor, atravessa proxies corporativos e firewalls que já permitem HTTPS, e é compatível com todos os navegadores e runtimes de servidor. 

A limitação do WebSocket é que ele usa TCP. Se um pacote se perde, o TCP o retransmite e retém os dados posteriores até preencher a lacuna. Em boas condições de rede, isso não é perceptível. Com perda de pacotes, ocorre o bloqueio de início de fila: uma breve interrupção em que o áudio se acumula e depois chega em rajada.

O WebRTC foi desenvolvido para mídia em tempo real. Ele transmite mídia por UDP (via SRTP), portanto um pacote perdido não interrompe o fluxo; o pipeline continua. Inclui um buffer de jitter que absorve variações no momento de chegada dos pacotes, negocia a travessia de NAT com ICE/STUN/TURN para que pares atrás de roteadores possam se conectar e conta com seus próprios mecanismos de captura e codificação de áudio. 

Normalmente, você precisa de servidores TURN para clientes que não conseguem se conectar diretamente, e o servidor precisa encerrar um fluxo de mídia em vez de ler um fluxo de bytes.

Veja o equilíbrio entre as opções de relance:

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)

Para a maioria dos casos de uso, WebSocket é a opção certa. Use-o quando seus clientes têm boa conectividade e você controla o caminho de captura: pipelines de servidor para servidor, apps para desktop, apps de navegador em conexões de banda larga e a maioria dos back-ends de centrais de atendimento, em que o áudio já chega ao seu servidor por outro meio. 

Escolha WebRTC quando estiver capturando diretamente de dispositivos de consumidores em redes móveis instáveis, quando já estiver executando uma stack WebRTC para áudio bidirecional, como um agente de voz que também responde falando, ou quando o comportamento em tempo real tolerante a perdas for mais importante que a simplicidade de implementação.

O restante deste guia usa o transporte WebSocket para a conexão com o reconhecedor, pois ele mantém as partes do sistema visíveis e é o ponto de partida adequado para a maioria das equipes. Nada disso é específico do WebSocket, então você pode adicionar depois uma etapa de mídia WebRTC antes dele, decodificar o áudio para PCM no servidor e encaminhar os mesmos chunks ao pipeline.

Resultados parciais e transcrições finais: entenda os resultados intermediários

Um reconhecedor em tempo real não espera uma frase completa antes de gerar texto. Em vez disso, ele emite um fluxo contínuo de hipóteses que se refinam à medida que mais áudio chega e depois as confirma. Entender a diferença entre esses dois estados é o que separa uma transcrição que parece viva de uma que parece falha. 

Uma hipótese parcial, ou intermediária, é a melhor estimativa do modelo com base no áudio recebido até o momento. Os parciais são instáveis por definição. À medida que mais áudio chega, o modelo revisa palavras anteriores: "Eu quero" pode se tornar "Eu quero dois ingressos" quando o contexto posterior resolve a ambiguidade. Eles chegam rápido — é isso que descreve a latência de cerca de 150 ms — e devem ser substituídos.

Uma hipótese final é um segmento confirmado que não mudará. Depois que um segmento é finalizado, o reconhecedor segue adiante, e as hipóteses posteriores descrevem o áudio seguinte. Os finais são o que você persiste, envia a um LLM ou armazena como transcrição.

A distinção entre parciais e finais determina três aspectos que você errará se misturá-los:

  • Experiência do usuário: Exibir parciais faz a transcrição parecer ao vivo: o usuário vê as palavras surgirem enquanto fala, confirmando que o microfone funciona e que o sistema está ouvindo.
  • Detecção de fim de fala: Os parciais fornecem um sinal contínuo de atividade de fala. Combinados ao VAD, eles permitem decidir quando a pessoa realmente parou de falar.
  • Tempo das etapas seguintes: Em um pipeline de agente de voz, as etapas são: entrada de áudio, transcrição de voz, LLM, text to speech e saída de áudio. Você pode iniciar um trabalho especulativo com os parciais e confirmá-lo com os finais, reduzindo o tempo de resposta percebido, embora ocasionalmente seja necessário descartar esse trabalho.

Exiba os parciais e os finais de forma diferente. Um padrão simples e eficaz é manter uma única "linha atual" mutável vinculada ao parcial mais recente e confirmá-la em uma transcrição apenas para acréscimo quando um final chegar:

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

Visualmente, exiba o conteúdo confirmado como texto consolidado e o atual com uma aparência mais clara ou em itálico, para que o usuário entenda que ele ainda pode mudar.

Detecção de fim de fala e detecção de atividade de voz (VAD)

Saber o que foi dito é apenas metade do desafio. Um reconhecedor também precisa saber quando um pensamento terminou. Essa decisão determina quando você finaliza um segmento e, em um agente, quando o sistema começa a responder. 

A detecção de fim de fala é a decisão de que uma fala terminou. Finalizar cedo demais interrompe os usuários no meio da frase. Finalizar tarde demais deixa um agente em silêncio depois que o usuário claramente terminou.

O Scribe v2 Realtime oferece dois mecanismos complementares:

  • A Detecção de Atividade de Voz segmenta o áudio com base no silêncio: O reconhecedor detecta quando a fala dá lugar a um silêncio prolongado e usa esse limite para finalizar um segmento automaticamente. O VAD é a melhor opção padrão para interfaces conversacionais porque se adapta ao ritmo natural da fala sem que você precise acompanhar o tempo manualmente.
  • Controle de confirmação manual: O controle de confirmação manual permite que seu aplicativo decida quando finalizar o segmento atual, independentemente do silêncio. Você envia um sinal de confirmação, o reconhecedor fecha o segmento atual e emite um resultado final. É a ferramenta certa quando o aplicativo já sabe que o turno terminou: ao soltar um botão push-to-talk, executar uma ação de "enviar" ou seguir uma política externa de alternância de turnos.

Os dois funcionam bem juntos. Um agente de voz típico usa VAD para operação sem uso das mãos e disponibiliza a confirmação manual como substituição, para que um usuário que para para pensar não seja interrompido, enquanto um usuário que toca em um botão obtenha uma delimitação imediata.

O limite de silêncio envolve uma troca real, sem um valor universalmente correto:

  • Um tempo limite curto após o fim da fala, por exemplo, finalização após cerca de 200 a 400 ms de silêncio, faz o sistema parecer responsivo. Mas também interrompe usuários que fazem pausas naturais entre orações, dividindo um pensamento em vários segmentos e, em um agente, acionando uma resposta prematura.
  • Um tempo limite longo, por exemplo, cerca de 800 a 1.200 ms, tolera pausas naturais e mantém as falas intactas, mas causa um atraso perceptível antes de o sistema reagir.

Não há uma constante global para usar aqui; ajuste o limite à interação:

  • Ditado e tomada de notas toleram pausas mais longas porque os usuários pensam no meio da frase. Prefira tempos limite maiores e conte com o VAD.
  • Agentes de comando e controle e transacionais se beneficiam de tempos limite menores com confirmação manual, porque os turnos são curtos e objetivos.
  • Pessoas multilíngues ou que não falam o idioma nativamente fazem mais pausas, então reserve mais silêncio antes de finalizar.

Seguir estas orientações ajuda você a criar um sistema eficaz de detecção de fim de fala e avançar rumo à transcrição de voz em tempo real.

Recursos durante o streaming: detecção de idioma e diarização de locutores

O reconhecimento por streaming pode fazer mais do que produzir palavras. Ainda assim, cada sinal adicional solicitado afeta a latência e a estabilidade. A regra prática é ativar apenas o que a experiência ao vivo precisa e deixar o restante para um processamento em lote.

O reconhecimento automático de idioma permite que o Scribe v2 Realtime identifique o idioma falado entre seus mais de 90 idiomas compatíveis, em vez de exigir que você o declare antecipadamente. O custo é que o modelo precisa de um breve trecho de áudio para fazer uma determinação confiável, portanto os primeiros parciais de um fluxo podem ser menos estáveis enquanto o idioma é definido. Se você já souber o idioma, especificá-lo elimina essa ambiguidade e tende a gerar parciais iniciais mais estáveis.

Diarização de locutores atribui a fala a locutores distintos, identificando quem disse o quê. Em transcrição em lote, isso é relativamente simples porque o modelo vê o arquivo inteiro. No streaming, é mais difícil: o reconhecedor precisa atribuir um rótulo de locutor apenas com base no áudio disponível até então, e um rótulo atribuído ao áudio inicial pode precisar ser revisado quando mais da voz daquele locutor for ouvida. Trate os rótulos de locutor no streaming como trata o texto parcial: provisórios até a finalização do segmento.

A marcação de tempo por palavra e o contexto de entidades seguem a mesma lógica. Quanto mais metadados por token você solicitar, mais o modelo e a transmissão terão de carregar. Para a maioria das interfaces em tempo real, basta ter texto e limites de segmento ao vivo; você pode deixar os metadados detalhados para um processamento em lote pós-chamada com o Scribe v2.

Formatos de áudio para streaming: PCM e mu-law

A lógica de transporte e reconhecimento recebe a maior parte da atenção, mas uma parcela surpreendente dos erros do mundo real surge uma camada abaixo: na forma de codificar e dividir o áudio em chunks. Acertar o formato e o tamanho dos chunks é a forma mais econômica de reduzir a latência da transcrição de voz.

PCM (linear, com sinal de 16 bits, little-endian) é o formato a usar quando você controla a captura. Taxas de amostragem maiores carregam mais detalhes acústicos: 16 kHz é o mínimo padrão para reconhecimento de fala e normalmente é suficiente; 8 kHz é qualidade telefônica e perde conteúdo de alta frequência. Use a taxa que corresponde à sua fonte. Não há benefício em aumentar o áudio de telefonia de 8 kHz para 48 kHz, porque essa informação não existe para ser recuperada.

Mu-law a 8 kHz é o formato de telefonia. Se você recebe chamadas de um provedor como o Twilio, o áudio chega em mu-law de 8 kHz, e você deve encaminhá-lo nesse formato em vez de transcodificá-lo duas vezes. Corresponder ao formato da fonte evita artefatos de reamostragem e uma etapa de conversão desnecessária.

O tamanho dos chunks é o fator que molda mais diretamente a latência percebida. Você envia áudio em chunks, e o reconhecedor produz parciais conforme eles chegam. Chunks menores significam atualizações mais frequentes e menor latência até o primeiro parcial; chunks maiores significam menos mensagens e um pouco mais de contexto por inferência. Uma faixa prática é de 20 a 250 ms de áudio por chunk. Como referência concreta, em PCM mono de 16 bits a 16 kHz, um segundo de áudio corresponde a 32.000 bytes; portanto, um chunk de 100 ms tem cerca de 3.200 bytes.

Captura de entrada do microfone no navegador

No navegador, a ferramenta certa é a Web Audio API com um AudioWorklet. O worklet é executado na thread de renderização de áudio, recebe o áudio em frames pequenos e não sofre com travamentos da thread principal como o antigo ScriptProcessorNode. Sua função é converter as amostras float nativas do navegador em PCM de 16 bits e entregá-las à thread principal, que as encaminha pelo WebSocket.

O núcleo do processador do worklet é a conversão de float para 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);

O pipeline em código

O pipeline tem três partes: um cliente de navegador que captura o microfone e transmite PCM ao seu servidor, um servidor Node que encaminha o áudio ao Scribe v2 Realtime e devolve as transcrições, e um cliente programável que transmite PCM de um arquivo ou de uma ponte de telefonia.

O servidor encaminha, em vez de expor o reconhecedor diretamente ao navegador, por um motivo importante: sua chave da API da ElevenLabs é secreta e nunca deve aparecer em código do lado do cliente. O servidor mantém a chave. Se você precisar que o navegador fale diretamente com o reconhecedor, crie no servidor um token de uso único e curta duração e entregue-o ao cliente em vez da chave da API.

Cliente de navegador

O cliente abre um WebSocket para o servidor, captura o microfone pelo worklet acima e encaminha cada frame PCM assim que ele é produzido. Os eventos recebidos, já normalizados pelo servidor para { type, text }, controlam o estado parcial/final descrito anteriormente:

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

Encaminhamento pelo servidor

O servidor abre uma conexão com o reconhecedor por cliente, mantém a chave da API no servidor, encaminha o PCM binário diretamente e normaliza os eventos do reconhecedor para o formato estável { type, text } consumido pelo cliente:

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

Tudo o que é específico do endpoint fica restrito às duas funções adaptadoras abaixo. Substitua os nomes dos campos pelos nomes exatos da referência de Speech to Text; o restante do pipeline não muda:

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

Cliente de back-end programável

Para pipelines de back-end e para o benchmark abaixo, a mesma conexão com o reconhecedor funciona sem navegador: leia PCM de qualquer fonte, envie-o na cadência de chunks em tempo real e leia os eventos retornados. A chave da API e a URL vêm do ambiente, como no servidor.

// 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 de latência de transcrição de voz e taxa de erro de palavras

Tanto a latência quanto a taxa de erro de palavras variam conforme o locutor, o idioma, as condições acústicas, a duração do áudio, o caminho de rede até a região mais próxima de cada provedor e a carga atual de cada serviço. 

Um resultado medido em um laptop em uma cidade não pode ser generalizado para sua infraestrutura de produção em outra. Execute o harness em uma infraestrutura parecida com a de produção, com áudios que se pareçam com sua entrada real, e informe faixas e distribuições em vez de números isolados.

Os únicos números de latência e precisão que importam são os medidos em seu próprio áudio, em uma infraestrutura parecida com a de produção. Veja como fazer benchmark da latência de transcrição de voz.

O que medir para a latência de transcrição de voz

Estas são as principais métricas que você deve medir ao avaliar a latência da transcrição de voz em tempo real:

  • Tempo até o primeiro parcial: Do envio do primeiro chunk de áudio ao recebimento do primeiro parcial não vazio.
  • Atraso do parcial ao final: Do último chunk de áudio de uma fala até a hipótese final.
  • Taxa de erro de palavras (WER): WER da transcrição finalizada em comparação com uma referência humana, calculada de forma idêntica em todos os sistemas.
  • Variação de estabilidade: Quantos parciais são reescritos antes da finalização. Essa medida indica o quanto a interface ao vivo parecerá mudar.

Controles

Para evitar dados pouco confiáveis, implemente vários controles em seu experimento para manter a consistência.

Estes são os principais controles para usar no benchmark de latência de transcrição de voz:

  • Áudio idêntico: Use os mesmos arquivos, a mesma taxa de amostragem e a mesma codificação em todos os sistemas.
  • Cadência idêntica: Transmita para todos os sistemas na mesma cadência de chunks em tempo real, por exemplo, chunks de 100 ms.
  • Repita e informe distribuições: Execute cada arquivo muitas vezes ao longo do dia; informe a mediana e a cauda (p50/p95).
  • Referências e pontuação idênticas: Normalize o texto da mesma forma — maiúsculas e minúsculas, pontuação e números — antes de calcular a WER.
  • Informe a região e a rede: Indique onde o harness foi executado e o caminho até cada provedor.

Ao manter todos esses elementos iguais, você obterá métricas mais precisas.

Estrutura do harness

O núcleo de medição recebe um adaptador de provedor e registra o tempo até o primeiro parcial, o atraso de finalização e a variação dos parciais:

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

A taxa de erro de palavras é a distância de Levenshtein padrão, no nível de token, aplicada a texto normalizado. Converta para minúsculas e remova a pontuação de forma idêntica na referência e na hipótese antes de calculá-la; caso contrário, você medirá seu normalizador, e não o modelo. Execute essa medida em um loop que rode cada arquivo cerca de 10 vezes por provedor e informe a mediana do tempo até o primeiro parcial e a WER mediana (p50/p95), pois uma única amostra é muito influenciada pela variação de rede.

Para executar isso, você precisa fornecer duas coisas. Primeiro, escreva um adaptador StreamFn por sistema. O cliente programável acima já é um deles; os adaptadores dos demais seguem o mesmo contrato (audioPath, onEvent, result) e definem result.lastChunkSentAt quando o chunk final de áudio é enviado. Segundo, carregue seus arquivos de áudio e referências e chame as medições para todos eles. Execute-o em uma máquina que represente sua implantação, com áudios que representem seus usuários, e você terá uma comparação reproduzível.

Recapitulando como alcançar a transcrição de voz em tempo real 

Abordamos muitas mudanças de arquitetura neste artigo, permitindo que você melhore seu sistema de forma iterativa e avance rumo à transcrição de voz em tempo real.

Um sistema de STT em tempo real para produção se resume a algumas decisões:

  • Transporte: Escolha WebSocket pela simplicidade e para redes controladas; escolha WebRTC quando precisar de tolerância a perdas e estiver capturando de dispositivos de consumidores.
  • Parciais e finais: Trate os parciais como provisórios e os finais como confirmados, exibindo-os de forma diferente para que os usuários confiem no texto ao vivo.
  • Detecção de fim de fala: Use VAD para segmentação sem uso das mãos, a confirmação manual como substituição e ajuste o limite de silêncio à interação, em vez de usar uma constante.
  • Recursos durante o streaming: Ative esses recursos apenas quando a experiência ao vivo precisar deles e deixe o restante para um processamento em lote com o Scribe v2.
  • Formato de áudio: Capture em frames PCM pequenos, envie chunks de cerca de 100 ms e use o formato da fonte para telefonia.
  • Benchmark: Defina empiricamente os parâmetros de precisão versus latência usando seu próprio áudio e a métrica desejada.
  • Segurança da API: Mantenha sua chave da API no servidor ou crie tokens de uso único para conexões diretas do cliente.

Se quiser ver como otimizar a latência em um agente de voz, também escrevemos um guia para você.

Crie sistemas de transcrição de voz em tempo real com o Scribe v2 Realtime

O Scribe v2 Realtime produz parciais com cerca de 150 ms de latência do modelo. Seus usuários perceberem esse número ou algo maior depende da arquitetura ao redor dele, que é a parte que você controla. Ao usar as estratégias apresentadas neste artigo, você criará uma arquitetura de pipeline aprimorada que reduz a latência e melhora a experiência do cliente. 

Para se aprofundar, veja a visão geral dos recursos de Speech to Text, consulte nossa referência de modelos para ver a lista completa de recursos e idiomas e visite as páginas de produtos em tempo real: API de Speech to Text em tempo real e Speech to Text em tempo real.

Quando estiver pronto para criar, crie uma conta gratuita na ElevenLabs e transmita sua primeira transcrição hoje.

Perguntas frequentes sobre a latência da transcrição de voz em tempo real

Artigos relacionados

Crie com o áudio de IA da mais alta qualidade