Tutorial · IA local
Whisper: transcrição local do zero
Transcrição rodando na sua máquina e no seu servidor, de graça, sem mandar o áudio pra ninguém. Aqui tem qual versão do modelo escolher (com o consumo real que eu medi, não o que a tabela oficial diz), ditado por atalho em qualquer campo de texto, a instalação completa numa VPS de dois núcleos, e os três ajustes que separam um resultado bom de um resultado excelente.
Sumário Começo
- Por que rodar na sua máquina
- Qual Whisper é o seu
- Os números que eu medi
- Ditado no desktop com o Handy
- Montando no servidor
- O script de transcrição
- Ajuste 1: vocabulário
- Ajuste 2: o loop infinito
- Ajuste 3: fala inventada no silêncio
- A receita final, junta
- O que montar com isso
- Servidor compatível com a API da OpenAI
- Deu errado? Comece por aqui
- Próximos passos
01
Por que rodar na sua máquina
O Whisper é um modelo de transcrição da OpenAI, aberto desde 2022, com licença MIT. Ele pega áudio e devolve texto. E ao contrário de praticamente tudo que a OpenAI lançou depois dele, esse aqui você baixa e roda na sua máquina, de graça, quantas vezes quiser.
Isso importa por três motivos práticos. O primeiro é custo: serviço de transcrição cobra por hora de áudio, e quem transcreve live, aula ou reunião com frequência sente isso rápido. O segundo é privacidade: usar serviço na nuvem significa subir a gravação da sua reunião, da sua consulta ou da sua apuração pro servidor de outra pessoa. O terceiro é que ele não precisa de placa de vídeo. Roda em processador comum, e é isso que abre a porta pra ele viver num servidor barato ligado o tempo todo.
02
Qual Whisper é o seu
O Whisper é uma família, não um modelo só. E é aqui que quase todo mundo tropeça, porque a tabela oficial do repositório lista a memória que cada tamanho pede e os números assustam:
| Modelo | Parâmetros | Memória na tabela oficial |
|---|---|---|
| tiny | 39 M | ~1 GB |
| base | 74 M | ~1 GB |
| small | 244 M | ~2 GB |
| medium | 769 M | ~5 GB |
| large-v3 | 1550 M | ~10 GB |
| large-v3-turbo | 809 M | ~6 GB |
Se você olhar essa tabela e olhar pro seu servidor de oito giga com outras coisas rodando, fecha a aba e desiste. Foi o que eu quase fiz.
O detalhe que muda tudo: essa tabela é medida em precisão cheia (fp16), que é o formato pra rodar em placa de vídeo. Quando você roda em processador comum, o modelo é quantizado pra int8, que é uma versão comprimida dele. O texto que sai é praticamente o mesmo, e o consumo cai pela metade ou mais.
A escolha real é entre dois
Depois de medir a família inteira, sobrou o small e o large-v3-turbo. E o eliminado surpreende: o medium, que todo mundo recomenda como meio-termo sensato, não tem mais função. Medi ele contra o turbo e o turbo ganha nos dois eixos que custam dinheiro, é mais rápido e usa menos memória, e no acerto de palavra difícil os dois empatam.
Isso acontece porque o turbo é o modelo grande podado. A OpenAI cortou a parte dele que escreve o texto, o decoder, de 32 camadas pra 4, e retreinou. Ele ficou com o ouvido do modelo grande e a boca de um modelo pequeno. É mais novo que o medium e foi feito exatamente pra ocupar esse lugar.
| Se você… | Use | Por quê |
|---|---|---|
| Quer ditar no computador | small | Frase de ditado é curta e falada limpo, perto do microfone. O small resolve e responde na hora. |
| Vai transcrever coisa longa num servidor, de madrugada | turbo | Você não está esperando na frente da tela, então o dobro de tempo não custa nada e o acerto é melhor. |
| Tem jargão pesado no áudio | small + vocabulário | Ver o Ajuste 1. O small com lista acerta mais que o turbo sem lista. |
| Está pensando no medium | turbo | Mais rápido, mais leve e empata no acerto. O medium não ganha em nada. |
03
Os números que eu medi
Tudo daqui pra frente vem de uma bateria própria de 90 execuções, rodada em julho de 2026 em duas máquinas, sempre com o mesmo trecho de 90 segundos de áudio dos meus próprios vídeos, e sempre reportando a mediana de nove repetições por configuração. A ideia é que você escolha com número atrás, não com achismo.
Numa VPS de 2 vCPU, sem placa de vídeo
Plano KVM 2 da Hostinger: dois núcleos EPYC 9354P, 8 GB de RAM, quantização int8, e com doze containers meus já rodando na mesma máquina (site, dashboards, o sistema do Lorcana). Ou seja, é medição em máquina ocupada, não em laboratório vazio.
| Modelo | Tempo (áudio de 90s) | Velocidade | Pico de RAM |
|---|---|---|---|
| small | 36,77 s | 2,4× tempo real | 771 MB |
| large-v3-turbo | 66,55 s | 1,4× tempo real | 1.654 MB |
Compare com a tabela oficial: o small “pede 2 GB” e usou 771 MB. O turbo “pede 6 GB” e usou 1,65 GB. O topo da família cabe com folga num servidor de oito giga que já está fazendo outras cinco coisas. E “2,4× tempo real” quer dizer que ele transcreve mais rápido do que o áudio toca, que é o que importa.
Num MacBook Pro M4 Max
Mesmo áudio, rodando via MLX (a biblioteca da Apple pro chip da própria Apple):
| Modelo | Tempo | Velocidade | Pico de RAM |
|---|---|---|---|
| small | 2,87 s | 31× tempo real | 881 MB |
| medium | 4,95 s | 18× tempo real | 1.971 MB |
| large-v3-turbo | 3,68 s | 25× tempo real | 1.789 MB |
Repare no medium: mais lento e mais pesado que o turbo. É o dado que o elimina.
Traduzindo pro seu caso
Extrapolando o tempo medido pra material longo, numa VPS de 2 vCPU:
| Material | small | turbo |
|---|---|---|
| Reunião de 30 min | ~13 min | ~22 min |
| Aula de 1 h | ~25 min | ~43 min |
| Live de 3 h | ~1 h 15 | ~2 h 10 |
04
Ditado no desktop com o Handy
Esse é o uso que mudou a minha rotina: falar em vez de digitar, em qualquer campo de texto do sistema. O ditado que já vem no macOS é pobre, erra pontuação e não entende quase nenhuma palavra em inglês, o que pra quem fala de tecnologia significa que metade das palavras que importam sai errada.
A solução é o Handy: aberto, gratuito, roda em Windows, macOS e Linux, e faz uma coisa só. Você segura um atalho, fala, solta, e o texto aparece onde o cursor estiver. Por baixo, ele roda o Whisper, e o áudio não sai da sua máquina.
Baixe e instale
Pegue o instalador da sua plataforma em handy.computer. No macOS ele vai pedir permissão de Acessibilidade e de Microfone nas Configurações do Sistema. Precisa das duas: a de microfone pra ouvir, a de acessibilidade pra conseguir escrever dentro de outro aplicativo.
Escolha o modelo
Nas configurações do Handy, escolha o modelo. Comece pelo small: pra ditado ele já resolve, porque frase de ditado é curta e você está falando limpo, perto do microfone. Se a sua máquina aguentar, o turbo dita ainda melhor. O download acontece na primeira vez que você usa.
Defina o atalho e teste
Escolha uma tecla que você não usa pra mais nada. Abra qualquer campo de texto, segure o atalho, fale uma frase, solte. O texto aparece. Funciona no navegador, no terminal, no campo de busca do sistema, em qualquer lugar, porque ele escreve onde o cursor está em vez de ter uma janela própria.
05
Montando no servidor
O seu computador é o pior lugar do mundo pra fazer trabalho pesado de transcrição. Ele desliga, ele viaja com você, e ele tem coisa mais importante pra fazer do que passar quarenta minutos moendo o áudio de uma live enquanto você tenta trabalhar.
Um servidor ligado o tempo todo resolve isso. Eu uso uma VPS da Hostinger, plano KVM 2 (2 vCPU, 8 GB de RAM, 100 GB de disco), que é a mesma máquina onde rodam os meus doze containers. Serve qualquer VPS Linux, e serve também um mini PC em casa. O que importa é ficar ligado e ter uns 2 GB de RAM livres.
Os quatro passos
Conecte no servidor por SSH e rode, em ordem. São quatro passos: criar um ambiente isolado, instalar o motor, criar o script, e transcrever.
Ambiente isolado do Python
Isso cria uma caixa separada pras bibliotecas deste projeto, pra não bagunçar o Python do sistema. Se algo der errado depois, você apaga a pasta e recomeça sem quebrar mais nada.
python3 -m venv ~/whisper-tests/.venv
source ~/whisper-tests/.venv/bin/activate
Deu certo se o seu prompt passou a começar com (.venv). Toda vez que você abrir um terminal novo, precisa rodar a linha do source de novo antes de usar o script.
O motor que roda o Whisper em CPU
O faster-whisper é uma reimplementação do Whisper que roda muito mais rápido em processador comum e aceita quantização int8. É ele que faz os números da tabela lá em cima acontecerem.
pip install faster-whisper
Leva cerca de um minuto na primeira vez. Deu certo se apareceu Successfully installed com ctranslate2 e faster-whisper na lista.
Crie o script
Esse é o arquivo mínimo que funciona. Crie ele com nano transcrever.py, cole, e salve com Ctrl+O e depois Ctrl+X. A explicação de cada linha está na próxima seção.
import sys
from faster_whisper import WhisperModel
# 'small' ou 'large-v3-turbo'. device='cpu' e compute_type='int8'
# são o que faz caber em 771 MB sem placa de vídeo.
modelo = WhisperModel('small', device='cpu', compute_type='int8')
segmentos, info = modelo.transcribe(
sys.argv[1],
language='pt',
beam_size=5,
)
for s in segmentos:
print(s.text.strip())
Transcreva
Mande um áudio pro servidor e rode:
python transcrever.py audio.wav
Na primeira execução ele baixa o modelo sozinho, uns 484 MB pro small, e guarda em cache. Da segunda em diante começa na hora.
06
O script de transcrição
O transcrever.py que você criou no passo 3 é a versão mínima que
funciona. Linha por linha, o que cada coisa faz:
| Parâmetro | O que faz |
|---|---|
'small' | Qual modelo carregar. Troque por 'large-v3-turbo' pra ganhar acerto e pagar o dobro de tempo. |
device='cpu' | Roda em processador. Se você tem placa NVIDIA, 'cuda' fica muito mais rápido. |
compute_type='int8' | A quantização. É o que corta a memória pela metade. |
language='pt' | Fixa o idioma. Sem isso ele tenta adivinhar, gasta tempo e às vezes erra em áudio com sotaque ou com palavra em inglês no meio. |
beam_size=5 | Quantos caminhos ele considera antes de escolher a palavra. Mais alto acerta um pouco mais e demora um pouco mais. 5 é o padrão sensato. |
07
Ajuste 1: entregue o vocabulário antes
O erro mais comum de todos: o modelo escreve errado nome próprio e jargão. Não é burrice dele, é que ele nunca ouviu falar do assunto que você fala.
No meu teste, peguei o áudio de um vídeo sobre Path of Exile 2 e
mandei o small transcrever. Toda vez que eu falo “endgame”, que é o termo mais
importante de um jogo desses, ele escreveu “indie game”. Todas as
vezes. “Early Access” virou “Aliacias”. Em outro vídeo, llama.cpp
virou “Lhamma ponto CPP” e “Gemma” virou “Gema”.
A correção é uma linha. O Whisper aceita que você entregue uma lista de palavras
antes de ele começar, no parâmetro initial_prompt.
É literalmente escrever os termos que vão aparecer.
VOCABULARIO = (
'Vocabulário: Path of Exile 2, endgame, Early Access, GGG, '
'llama.cpp, Gemma, LFM2.5, Liquid AI, ZimaCube, ZimaBoard, '
'Ollama, VPS, Diablo 4, cubo Horádrico, Cerrigar, Paragon.'
)
segmentos, info = modelo.transcribe(
sys.argv[1],
language='pt',
beam_size=5,
initial_prompt=VOCABULARIO,
)
O resultado medido, com a mesma lista e o mesmo áudio:
| Teste | Sem vocabulário | Com vocabulário |
|---|---|---|
| small, áudio de games | 4 de 6 | 6 de 6 |
| small, áudio de IA | 5 de 7 | 7 de 7 |
| turbo, áudio de IA | 5 de 7 | 6 de 7 |
Monte a sua lista com os termos que aparecem no seu áudio: nomes de produto, siglas da sua área, nomes de pessoas da sua equipe, jargão do seu nicho. Vale escrever uma frase de exemplo junto, com a pontuação do jeito que você quer, porque o modelo também copia o estilo de escrita do prompt.
08
Ajuste 2: o loop infinito
Esse é assustador de ver. Aconteceu comigo com o turbo, num áudio que eu tinha cortado no meio de uma frase. Ele transcreveu tudo certinho e, quando chegou no corte, escreveu “Muito obrigado” vinte e oito vezes seguidas.
A explicação ensina como ele pensa. O Whisper usa o que já transcreveu como pista pro que vem em seguida, e é isso que dá coerência ao texto. Só que, quando o áudio termina de forma abrupta, ele fica sem pista nova, se agarra na última frase que produziu e entra em ciclo. É um modelo mordendo o próprio rabo.
A correção desliga essa realimentação:
condition_on_previous_text=False
Rodei três vezes com a chave desligada e o loop não aconteceu nenhuma vez.
O custo é pequeno: sem a realimentação, o modelo perde um pouco de coerência entre um bloco e outro, tipo repetir uma palavra que já tinha estabelecido. Na prática, trocar isso por não ter loop é um bom negócio.
09
Ajuste 3: fala inventada no silêncio
O mais esquisito dos três. Eu gerei trinta segundos de silêncio absoluto, um arquivo de áudio com nada dentro, e mandei transcrever.
O small respondeu corretamente: nada. O medium também. O turbo, o modelo mais capaz da família, me devolveu com toda a confiança do mundo a frase “Legenda Adriana Zanotto”. Rodei três vezes pra ter certeza. Três vezes o mesmo nome.
Isso é um fantasma do treinamento. O modelo foi treinado com legendas de filme e de novela, e legenda termina com os créditos de quem legendou. Quando ele não tem nada pra ouvir, ele preenche o vazio com o que viu mais vezes no fim de arquivos parecidos. Ele te dá o nome de uma legendista brasileira que existe, que trabalha, e que nunca teve nada a ver com o seu áudio.
A correção liga um detector de voz na frente do modelo. Ele checa se tem alguém falando antes de deixar o Whisper trabalhar:
vad_filter=True
Liguei, rodei o mesmo silêncio, e voltou vazio, como tem que ser.
10
A receita final, junta
Esse é o script que eu de fato uso. Ele tem os três ajustes ligados, salva o texto num arquivo ao lado do áudio, e imprime quanto tempo levou.
import sys
import time
from pathlib import Path
from faster_whisper import WhisperModel
# ── Ajuste 1: os termos do SEU mundo. Edite esta lista. ──────────────
VOCABULARIO = (
'Vocabulário: Path of Exile 2, endgame, Early Access, GGG, '
'llama.cpp, Gemma, LFM2.5, Liquid AI, ZimaCube, ZimaBoard, '
'Ollama, VPS, Diablo 4, cubo Horádrico, Cerrigar, Paragon.'
)
MODELO = 'small' # ou 'large-v3-turbo'
entrada = Path(sys.argv[1])
inicio = time.time()
modelo = WhisperModel(MODELO, device='cpu', compute_type='int8')
segmentos, info = modelo.transcribe(
str(entrada),
language='pt',
beam_size=5,
initial_prompt=VOCABULARIO, # Ajuste 1: vocabulário
condition_on_previous_text=False, # Ajuste 2: não entra em loop
vad_filter=True, # Ajuste 3: não inventa no silêncio
)
saida = entrada.with_suffix('.txt')
with open(saida, 'w', encoding='utf-8') as f:
for s in segmentos:
linha = s.text.strip()
print(linha)
f.write(linha + '\n')
print(f'\n--- {saida.name} · {time.time() - inicio:.1f}s ---')
Quer legenda com tempo em vez de texto corrido?
Cada segmento tem s.start e s.end em segundos. Trocando o
laço de escrita por isto, sai um arquivo .srt que qualquer player abre:
def hms(seg):
h, resto = divmod(seg, 3600)
m, s = divmod(resto, 60)
return f'{int(h):02d}:{int(m):02d}:{int(s):02d},{int(s % 1 * 1000):03d}'
saida = entrada.with_suffix('.srt')
with open(saida, 'w', encoding='utf-8') as f:
for i, s in enumerate(segmentos, 1):
f.write(f'{i}\n{hms(s.start)} --> {hms(s.end)}\n{s.text.strip()}\n\n')
Rodando de madrugada, sozinho
A graça de ter isso num servidor é não precisar estar na frente. Coloque no
crontab pra varrer uma pasta toda noite às duas da manhã:
0 2 * * * cd ~/whisper-tests && ./.venv/bin/python varrer.py ~/audios >> ~/whisper.log 2>&1
Onde varrer.py é o script acima num laço sobre os arquivos da pasta
que ainda não têm .txt ao lado. Você joga os áudios lá durante o dia e
de manhã o texto está pronto.
11
O que montar com isso
Cinco coisas que ficam possíveis quando você tem transcrição de graça e ilimitada num servidor. As duas primeiras rodam na minha VPS há meses.
Transcrição automática de live
Quando termina a live, o servidor pega o áudio e transcreve sozinho. O texto inteiro fica pesquisável, e é dali que saem os cortes. Não preciso reassistir duas horas procurando o momento bom: eu leio o texto e acho na hora. O gargalo do canal de cortes nunca foi editar, era achar.
Uma página de transcrição pra outra pessoa
Meu pai é jornalista, e entrevista precisa virar texto. Ele usava serviço que cobra por minuto e que pede pra subir o áudio da apuração pro servidor de outra pessoa. Montei uma página na minha VPS: ele arrasta o arquivo e o texto aparece. Sem conta, sem assinatura, sem limite. E a apuração dele não sai de casa.
Nota de voz do celular caindo no seu sistema de notas
Um atalho no celular grava, manda pro servidor e recebe o texto de volta. Você fala na rua e a nota aparece no Obsidian, no Notion, onde for. Isso depende de expor o servidor com uma API, que é a próxima seção.
Legenda automática em lote
Você joga a pasta de vídeos no servidor e ele devolve os arquivos .srt prontos. Se você produz vídeo, isso resolve acessibilidade e alcance no mesmo movimento. Quem tem servidor de mídia em casa pode plugar direto nele com o subgen, que legenda automaticamente o que não tem legenda.
Busca no que foi falado
Essa quase ninguém monta e devia. Transcreva tudo que você consome (podcast, aula, reunião) e pesquise por texto. Aquele “onde foi mesmo que eu ouvi isso” deixa de ser uma hora garimpando e vira uma busca.
12
Servidor compatível com a API da OpenAI
Esse é o pulo do gato pra ligar o resto das suas ferramentas nisso. Em vez de um script que você chama na mão, você sobe um servidor que fala a mesma língua da API de transcrição da OpenAI. Qualquer programa que já saiba conversar com a OpenAI passa a funcionar apontando pro seu servidor, sem reescrever nada. Você troca o endereço e pronto.
A opção mais direta é o Speaches, que sobe em Docker:
docker run -d --name speaches \
-p 8000:8000 \
-v ~/.cache/huggingface:/home/ubuntu/.cache/huggingface \
ghcr.io/speaches-ai/speaches:latest-cpu
E o teste, que é o mesmo formato de chamada da OpenAI:
curl http://localhost:8000/v1/audio/transcriptions \
-F "[email protected]" \
-F "model=Systran/faster-whisper-small"
Outras ferramentas que valem conhecer
| Ferramenta | Pra que serve |
|---|---|
| WhisperX | Timestamps precisos palavra a palavra e separação de quem falou o quê. É o que você quer pra transcrever reunião com várias pessoas. |
| subgen | Plugga no Plex, Jellyfin ou Emby e legenda automaticamente o que entra na biblioteca. |
| whisper.cpp | Implementação em C++, sem Python. Boa pra hardware muito fraco ou pra embarcar em outro programa. |
13
Deu errado? Comece por aqui
| Sintoma | Causa provável | O que fazer |
|---|---|---|
command not found: python3 |
Python não instalado | sudo apt update && sudo apt install python3 python3-venv |
No module named faster_whisper |
Você esqueceu de ativar o ambiente | Rode source ~/whisper-tests/.venv/bin/activate de novo. O prompt tem que mostrar (.venv). |
| Processo morre sem mensagem | Ficou sem memória | Troque pro small, ou crie swap. Confira o que sobra com free -m. |
| Demora muito mais que a tabela | Modelo grande demais pro hardware | Use small em int8. Em 2 vCPU ele faz 2,4× tempo real. |
| Texto sai em inglês | Detecção automática de idioma errou | Cravar language='pt', que já está na receita final. |
| Repete a mesma frase sem parar | Loop na emenda do áudio | condition_on_previous_text=False. Ver o Ajuste 2. |
| Aparece frase onde não tem ninguém falando | Alucinação em silêncio | vad_filter=True. Ver o Ajuste 3. |
| Erra sempre a mesma palavra técnica | Vocabulário desconhecido | Coloque o termo no initial_prompt. Ver o Ajuste 1. |
14
Próximos passos
Se você chegou até aqui com o script rodando, você tem uma central de transcrição própria, ilimitada e privada. O caminho natural daqui é ligar ela nas suas outras ferramentas pela API, e proteger o acesso com uma VPN em vez de abrir porta.
Tailscale: acesso remoto sem dor
O jeito certo de alcançar o seu servidor de transcrição de qualquer lugar sem expor a porta 8000 pra internet inteira.
Abrir Outro tutorialNextcloud em casa, do zero
Onde guardar os áudios e as transcrições sem depender de nuvem alheia. Fecha a stack com o que você montou aqui.
Abrir