Speech-to-text: Whisper e alternativas
- ⬜🎭 Multimodal mental model: além do texto(Voice, Vision & Multimodal)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
O panorama real em 2026
| Decisão | Opção A | Opção B | O que decide |
|---|---|---|---|
| Onde roda | API hospedada | Modelo local | Se o áudio pode sair do ambiente |
| Modo | Arquivo completo | Fluxo contínuo | Se alguém está esperando a transcrição aparecer |
| Áudio longo | Cortar no silêncio, com sobreposição | Enviar inteiro | Cortar no meio de frase degrada; sobrepor costura |
| Idioma | Detecção automática | Fixar o idioma | Fixar evita a troca no meio, que é o erro mais visível |
| Avaliação | Taxa de erro por palavra | Acerto em termos críticos | A taxa média trata todo erro como igual; errar um nome custa mais |
STT deixou de ser commodity. Três opções cobrem 95% dos casos: Whisper (OpenAI, open source, state-of-art em multilíngue), Deepgram Nova-2 (streaming + diarização, foco enterprise) e AssemblyAI (features de conversa: sentiment, summary, chapters). Cada um otimiza uma dimensão diferente.
Whisper API: o default razoável
Para transcrição batch de arquivos, Whisper API é difícil de bater em custo-qualidade. $0.006/minuto, PT-BR excelente, retorna word-level timestamps se você pedir.
import OpenAI from 'openai';
import fs from 'node:fs';
const client = new OpenAI();
const transcription = await client.audio.transcriptions.create({
file: fs.createReadStream('reuniao.mp3'),
model: 'whisper-1',
response_format: 'verbose_json',
timestamp_granularities: ['word'],
language: 'pt',
});
// transcription.words => [{ word, start, end }, ...]
// transcription.segments => blocos maiores com confidencePasse sempre o parâmetro language quando souber. Whisper gasta tokens adivinhando idioma e às vezes erra em áudios curtos ou com sotaque forte.
Self-host: faster-whisper e whisper.cpp
Quando volume justifica ou quando áudio não pode sair da rede, self-host é viável. faster-whisper (CTranslate2) roda 4x mais rápido que Whisper original em GPU. whisper.cpp roda até em CPU e em Apple Silicon com Metal.
from faster_whisper import WhisperModel
# large-v3 em GPU NVIDIA (compute_type float16)
model = WhisperModel('large-v3', device='cuda', compute_type='float16')
segments, info = model.transcribe(
'reuniao.mp3',
lang='pt',
vad_filter=True, # corta silêncio antes de processar
word_timestamps=True,
)
for seg in segments:
print(seg.start, seg.end, seg.text)Streaming de verdade: Deepgram / AssemblyAI
Whisper API não faz streaming (o modelo precisa do áudio inteiro para decodificar). Se o seu produto é legendagem ao vivo, call center ou voice agent, você precisa de WebSocket streaming — e aí Deepgram ou AssemblyAI são as escolhas.
import { createClient, LiveTranscriptionEvents } from '@deepgram/sdk';
const deepgram = createClient(process.env.DEEPGRAM_API_KEY!);
const live = deepgram.listen.live({
model: 'nova-2',
language: 'pt-BR',
smart_format: true,
interim_results: true,
diarize: true,
});
live.on(LiveTranscriptionEvents.Transcript, (data) => {
const alt = data.channel.alternatives[0];
if (alt.transcript) {
console.log('[' + (data.is_final ? 'final' : 'interim') + ']', alt.transcript);
}
});
// audioStream é um stream PCM ou WebM vindo do browser
audioStream.on('data', (chunk) => live.send(chunk));Por que modelos modernos de transcrição são treinados com áudio muito diverso e ruidoso?
Diarização: a feature que separa amador de profissional
Transcrever é fácil. Responder "quem disse o quê" é difícil. Whisper puro não faz — você precisa de um pipeline auxiliar. O stack de referência open-source é WhisperX (Whisper + pyannote.audio + alinhamento forçado).
import whisperx
audio = whisperx.load_audio('reuniao.wav')
# 1) Transcrição com Whisper
model = whisperx.load_model('large-v3', device='cuda', lang='pt')
result = model.transcribe(audio, batch_size=16)
# 2) Alinhamento forçado (word-level timestamps precisos)
align_model, meta = whisperx.load_align_model(language_code='pt', device='cuda')
result = whisperx.align(result['segments'], align_model, meta, audio, device='cuda')
# 3) Diarização (pyannote)
diarize = whisperx.DiarizationPipeline(use_auth_token=HF_TOKEN, device='cuda')
diarize_segments = diarize(audio, min_speakers=2, max_speakers=4)
# 4) Merge: cada palavra ganha speaker label
result = whisperx.assign_word_speakers(diarize_segments, result)Diarização tem WER próprio (DER — Diarization Error Rate). Em áudios com sobreposição pesada ou microfone compartilhado, DER passa de 20% facilmente. Sempre valide com sample humano antes de prometer feature.
Custos comparados (volume médio)
Para 10.000 minutos/mês:
whisper_api: # OpenAI
preco_por_min: 0.006
mensal_usd: 60
features: [batch only, timestamps]
deepgram_nova2:
preco_por_min: 0.0043 # streaming
mensal_usd: 43
features: [streaming, diarize, keyword_boost]
self_host_a10g:
gpu_hora: 1.00 # AWS/Runpod approx
minutos_por_gpu_hora: 600 # faster-whisper large-v3
mensal_usd: ~17 # se 24/7 saturada
features: [tudo custom, privacidade]Resumo operacional
Default: Whisper API para batch. Streaming ao vivo: Deepgram ou AssemblyAI. Diarização séria: WhisperX + pyannote ou use as labels built-in de Deepgram/AssemblyAI. Self-host só acima de ~50k min/mês ou por privacidade. E nunca prometa DER <10% sem rodar no seu áudio real primeiro.
Perguntas frequentes
❓ Modelo aberto ou serviço de transcrição?
❓ Transcrição em tempo real ou em arquivo?
❓ Como melhorar transcrição de áudio ruim?
Fixando
Qual cuidado é específico ao transcrever áudio longo?
Qual métrica se usa para avaliar transcrição, e qual é sua limitação?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…