Intermediário 18 minÁudio

Whisper + Ollama localmente: transcrição 100% off-line ligne

Transcrever uma reunião de uma hora e depois gerar um relatório estruturado: é exatamente o que vendem Otter, Fireflies ou Tactiq — desde que você envie seu áudio para um terceiro. Whisper (OpenAI, mas de código aberto e executável offline) combinado com um LLM Ollama faz a mesma coisa na sua máquina, sem assinatura e sem vazamento. Este guia monta o pipeline whisper.cpp → Ollama de ponta a ponta: instalação, escolha do modelo, script bash, script Python e um caso prático de transcrição local de uma reunião de 1h.

Por Mohamed Meguedmi·Atualização 2026-08-27·Testado no Windows, macOS e Linux

#Por que um pipeline whisper + ollama de transcrição local?

Uma gravação de reunião contém nomes de clientes, números, decisões estratégicas e, às vezes, dados de RH. Os serviços SaaS de transcrição armazenam esses áudios em seus servidores e os usam (de acordo com os termos de uso) para treinar seus próprios modelos. Para uma equipe que leva a confidencialidade a sério, isso não é negociável.

O Whisper da OpenAI pode ser baixado livremente e funciona offline. O whisper.cpp (a versão em C++ de Georgi Gerganov) o executa de forma eficiente em CPU e GPU, sem exigir Python nem CUDA. O Ollama, por sua vez, expõe um LLM local em http://localhost:11434. Os dois funcionam em sequência: áudio → texto (Whisper) → resumo estruturado (Ollama). Tudo permanece no seu disco.

i
A divisão de tarefas
Whisper ≠ LLM. Whisper é um modelo de reconhecimento de fala (ASR): ele converte som em texto bruto. Resumir, formatar e extrair decisões são tarefas de um LLM que atua em seguida. Esses dois modelos não têm nada a ver um com o outro e não se substituem.

#Pré-requisitos

O kit IA Local

Seu ChatGPT privado e gratuito na sua máquina em 1 hora — LM Studio, Ollama, Open WebUI, seus documentos, sem nuvem.

  • Espaço online vitalício
  • PDF + arquivos
  • Atualizações vitalícias
macOS, Linux ou Windows (WSL2)
whisper.cpp compila em qualquer lugar. No Windows puro, use WSL2 — a compilação nativa funciona, mas exige mais configuração.
Ollama instalado e operacional
Ao executar ollama run qwen3.5:9b, você deve obter uma resposta. Caso contrário, volte ao guia de instalação para o seu sistema operacional.
Compilador C++ e CMake
build-essential cmake no Debian/Ubuntu, Xcode Command Line Tools no macOS.
ffmpeg
Para converter seus arquivos .m4a/.mp3/.mp4 em WAV de 16 kHz, o único formato que o whisper.cpp aceita como entrada.
No mínimo 8 GB de RAM
16 GB oferecem uma boa margem. O modelo large-v3 ocupa ~3 GB de RAM/VRAM ao ser carregado. Um pequeno LLM adicional, como Qwen 3.5 4B, ocupa ~3 GB.
GPU opcional
Uma RTX 3060 de 12 GB transcreve 1 hora de áudio em ~4 minutos com large-v3. Em Apple Silicon, o Metal é ativado automaticamente e a transcrição é igualmente rápida.

#1. Instalar whisper.cpp

Sem pacote oficial: clone o repositório e compile. Leva 2 minutos e dá um binário portátil que você pode mover onde quiser.

Clonagem + compilação para CPU
git clone https://github.com/ggerganov/whisper.cpp.git
cd whisper.cpp
cmake -B build
cmake --build build --config Release -j

O binário principal fica em build/bin/whisper-cli (antes chamado main, antes da reformulação do CMake). É ele que você executará para transcrever.

→
Aceleração com GPU
Para CUDA (NVIDIA), adicione -DGGML_CUDA=1 ao comando cmake -B build. Para Apple Silicon, o Metal é ativado por padrão — nada para configurar. Para AMD (ROCm): -DGGML_HIPBLAS=1. O binário então detecta a GPU ao iniciar.
Variante CUDA
cmake -B build -DGGML_CUDA=1
cmake --build build --config Release -j

Instale o ffmpeg separadamente, se ainda não tiver sido feito:

ffmpeg
# Debian / Ubuntu / WSL2
sudo apt install ffmpeg

# macOS
brew install ffmpeg

#2. Escolher o modelo Whisper adequado (tiny → large-v3)

Whisper existe em cinco tamanhos, cada um com duas variantes: multilíngue (padrão) e apenas inglês (sufixo .en). Para o francês, mantenha a versão multilíngue. A tabela abaixo resume o que realmente muda.

tiny (75 MB)
Rápido, mas ruim em francês. Restrito a testes rápidos ou ao Raspberry Pi. WER (taxa de erro) ~30% em francês espontâneo.
base (142 MB)
Aceitável para inglês claro, fraco em francês com ruído. Boa opção se você tiver pouquíssimos recursos computacionais.
small (466 MB)
O primeiro patamar sério. WER ~10–12% em áudio limpo em francês. Transcreve 1 hora de áudio em ~3 minutos em uma GPU modesta.
medium (1,5 GB)
Muito bom equilíbrio entre qualidade e velocidade para o francês falado em reuniões. WER ~7–8%. Reconhece bem a pontuação.
large-v3 (3,1 GB)
Estado da arte. Quase perfeito em francês claro, robusto diante de sotaques e ruído de fundo. Priorize quando tiver mais de 6 GB de RAM/VRAM livres.

Para transcrever uma reunião em francês, a recomendação prática é: medium por padrão, large-v3 se você tiver uma GPU capaz de executá-lo. small é uma boa alternativa para notebooks sem GPU dedicada.

Baixar um modelo
# Depuis le dossier whisper.cpp
./models/download-ggml-model.sh medium
# ou
./models/download-ggml-model.sh large-v3

Os modelos são baixados para models/ no formato ggml (equivalente ao gguf para LLMs). Você pode baixar modelos de vários tamanhos e alternar conforme a necessidade.

i
Versões quantizadas
Se a VRAM estiver escassa, o script aceita variantes quantizadas: large-v3-q5_0 (≈1,1 GB) ou medium-q5_0 (≈540 MB). A perda de qualidade é marginal em francês, e a economia de memória é real. Testar em seus próprios áudios.

#3. Transcrever um arquivo de áudio

O whisper.cpp lê apenas WAV mono de 16 kHz. Usamos o ffmpeg para preparar o áudio, depois o whisper-cli para transcrever.

Conversão para WAV 16 kHz
ffmpeg -i reunion.m4a -ar 16000 -ac 1 -c:a pcm_s16le reunion.wav
-ar 16000
Reamostragem a 16 kHz (a frequência de treinamento do Whisper).
-ac 1
Força o áudio mono. O Whisper ignora o áudio estéreo de qualquer forma.
-c:a pcm_s16le
PCM 16-bit little-endian, o formato WAV não comprimido esperado.
Transcrição
./build/bin/whisper-cli \
  -m models/ggml-medium.bin \
  -f reunion.wav \
  -l fr \
  -otxt \
  -of reunion

O resultado é salvo em reunion.txt com os segmentos marcados com timestamps. Alguns flags úteis para conhecer:

-l fr
Força o uso do francês. Sem esse flag, o Whisper detecta automaticamente o idioma — mas às vezes se engana em frases curtas.
-otxt / -osrt / -ovtt / -ojson
Formato de saída: texto simples, legendas SRT, VTT ou JSON estruturado com timestamps. Você pode combiná-los.
-of <prefixe>
Prefixo dos arquivos de saída (sem extensão).
-t 8
Número de threads do CPU. Por padrão, o whisper.cpp utiliza 4 — aumente para 8 ou 16 em um CPU recente.
--print-progress
Exibe uma barra de progresso. Útil para arquivos longos.
→
Formato JSON para o pipeline
Para continuar o processamento com um LLM, prefira -ojson: você obtém os segmentos com suas marcações de tempo de início e fim. Assim, pode citar uma marcação de tempo precisa no resumo final ("decisão tomada em 23:14").

#4. Resumir a transcrição com Ollama

Com a transcrição bruta em mãos, nós a enviamos ao Ollama pela API HTTP local dele. O endpoint /api/chat é o mais direto para uso one-shot.

Pré-requisitos do Ollama
ollama pull qwen3.5:9b
# Ou pour un résumé plus fin d'une longue réunion :
ollama pull mistral-small

Para uma reunião de 1 hora, a transcrição chega facilmente a 10.000 a 15.000 tokens. Qwen 3.5 9B aceita 256k de contexto nativo, o que é mais do que suficiente. Para um resumo ainda mais elaborado, Mistral Small 24B (excelente em francês) cabe em menos de 16 GB de VRAM.

Teste rápido via curl
curl -s http://localhost:11434/api/chat -d '{
  "model": "qwen3.5:9b",
  "stream": false,
  "options": {"temperature": 0.2, "num_ctx": 16384},
  "messages": [
    {"role": "system", "content": "Tu résumes une réunion de travail en français."},
    {"role": "user", "content": "<COLLE ICI LE CONTENU DE reunion.txt>"}
  ]
}' | jq -r '.message.content'
!
num_ctx, sem usar o valor padrão
O Ollama carrega seus modelos com um contexto de 2048 tokens por padrão, o que truncaria silenciosamente sua transcrição. Passe explicitamente num_ctx (8192, 16384, 32768…) em options a cada chamada — ou fixe esse valor por meio de um Modelfile.

#5. Pipeline completo: exemplo de relatório de reunião (1h)

Montamos tudo em um script Python que recebe um arquivo de áudio como entrada e gera um relatório em Markdown. Esse é o coração de um pipeline whisper ollama de transcrição local reutilizável.

Dependências do Python
pip install requests
pipeline_reunion.py
#!/usr/bin/env python3
"""Audio -> transcription Whisper -> compte-rendu via Ollama."""
import subprocess, sys, requests, pathlib, json

WHISPER_BIN = "./build/bin/whisper-cli"
WHISPER_MODEL = "models/ggml-medium.bin"
OLLAMA_URL = "http://localhost:11434/api/chat"
LLM_MODEL = "qwen3.5:9b"

SYSTEM_CR = """Tu es un assistant qui produit des comptes-rendus de
réunion en français à partir d'une transcription brute.

FORMAT DE SORTIE (Markdown) :
# Compte-rendu
## Participants identifiables
## Sujets abordés (1 paragraphe par sujet)
## Décisions prises
## Actions à mener (avec porteur si mentionné)
## Points en suspens

RÈGLES :
- N'invente AUCUN nom, AUCUNE décision, AUCUNE action.
- Si une info manque, écris \"Non précisé\".
- Sois concis : un compte-rendu se lit en 2 minutes.
"""

def to_wav(src: pathlib.Path) -> pathlib.Path:
    dst = src.with_suffix(".wav")
    subprocess.run([
        "ffmpeg", "-y", "-i", str(src),
        "-ar", "16000", "-ac", "1", "-c:a", "pcm_s16le",
        str(dst),
    ], check=True)
    return dst

def transcribe(wav: pathlib.Path) -> str:
    prefix = wav.with_suffix("")
    subprocess.run([
        WHISPER_BIN, "-m", WHISPER_MODEL, "-f", str(wav),
        "-l", "fr", "-otxt", "-of", str(prefix),
        "--print-progress",
    ], check=True)
    return prefix.with_suffix(".txt").read_text(encoding="utf-8")

def summarize(transcription: str) -> str:
    r = requests.post(OLLAMA_URL, json={
        "model": LLM_MODEL,
        "stream": False,
        "options": {"temperature": 0.2, "num_ctx": 16384},
        "messages": [
            {"role": "system", "content": SYSTEM_CR},
            {"role": "user",   "content": transcription},
        ],
    }, timeout=600)
    r.raise_for_status()
    return r.json()["message"]["content"]

if __name__ == "__main__":
    src = pathlib.Path(sys.argv[1])
    wav = to_wav(src)
    print(f"[1/3] Audio converti -> {wav}")
    texte = transcribe(wav)
    print(f"[2/3] Transcription : {len(texte)} caractères")
    cr = summarize(texte)
    out = src.with_name(src.stem + "_compte-rendu.md")
    out.write_text(cr, encoding="utf-8")
    print(f"[3/3] Compte-rendu : {out}")
Inicialização
python pipeline_reunion.py reunion.m4a

Em uma reunião de 1 hora com uma RTX 3060 de 12 GB e o modelo medium: cerca de 3 minutos para a transcrição, cerca de 30 segundos para o resumo Qwen 3.5 9B. Total: menos de 4 minutos, sem requisições de rede. Em um MacBook M2 de 16 GB com CPU + Metal: cerca de 6 minutos no total.

→
Reuniões muito longas
Acima de 90 minutos ou 30.000 tokens de transcrição, divida o texto em blocos de 10.000 tokens, resuma cada bloco e peça ao LLM para mesclar os resumos. Esse é o padrão clássico map-reduce. Caso contrário, a qualidade do resumo desmorona, mesmo que num_ctx aceite.

#Dicas e solução de problemas

Transcrição que alucina durante os silêncios
O Whisper às vezes inventa frases durante longos silêncios ("Legendas por...", "Obrigado por assistir"). Ative o VAD: --vad --vad-model models/ggml-silero-v5.1.2.bin (a baixar pelo mesmo script).
Nomes próprios distorcidos
Whisper não conhece os nomes dos seus colegas. Passe-os no prompt inicial via --prompt "Marie, Julien, Samir, ACME Corp, ProjetX". Eles serão escritos corretamente.
Áudio com compressão (Zoom, Teams)
As gravações MP4 do Zoom muitas vezes contêm áudio mono de baixa qualidade. Prefira a exportação de “somente áudio” (M4A) do Zoom ou grave em paralelo com o OBS se a qualidade for prioridade.
Erro ggml_metal_init no Mac
Você compilou sem Metal ou o whisper.cpp não encontra os recursos. Recompile do zero: rm -rf build && cmake -B build && cmake --build build --config Release -j.
Timeout do Ollama com contexto longo
O cliente HTTP interrompe a conexão antes do fim. Aumente o tempo limite para timeout=600 (10 min) na biblioteca requests. No servidor, OLLAMA_KEEP_ALIVE=30m mantém o modelo carregado.
Transcrição truncada
Se o resumo parecer omitir o restante do áudio a partir de certo ponto, é porque num_ctx está muito baixo. Verifique o número de tokens (wc -w no .txt × 1.3 ≈ tokens) e ajuste num_ctx para o dobro desse número.
Diarização (quem fala)
whisper.cpp não faz diarização. Para distinguir os falantes, adicione pyannote.audio no pipeline antes da transcrição, depois anote cada segmento. É uma camada adicional, fora do escopo aqui.
i
Custo concreto de hardware
Para uso diário — 2 a 3 reuniões transcritas por dia — um Mac mini M4 de 16 GB (~700 €) ou um mini-PC com RTX 3060 de 12 GB (~600 € de segunda mão) é mais que suficiente. Trata-se de um investimento único em comparação com ~15 €/mês/pessoa dos SaaS de transcrição, que se amortiza em menos de um ano para uma equipe de 5 pessoas.

#Para se aprofundar

Seu pipeline transcreve e resume localmente. Três direções lógicas de acordo com sua necessidade:

Relatório médico com faster-whisper
O guia de transcrição das consultas utiliza faster-whisper (port otimizado para Python) com foco no sigilo médico, na diarização com pyannote e na conformidade com o RGPD na área da saúde. Variante interessante do mesmo padrão.
Escolher o LLM adequado para resumo
O resumo é a etapa em que a qualidade mais varia. O guia para escolher a quantização compara Q4_K_M, Q5_K_M e Q8_0 — uma diferença audível em textos longos com nuances.
Automatizar o pipeline com n8n
Para ativar a sequência assim que um arquivo de áudio chegar (pasta monitorada, e-mail, Slack), o guia de automação n8n + Ollama mostra como construir o workflow sem código.
Este guia ajudou você?

Um comentário, um erro ou uma observação? Avise-nos; isso ajuda a melhorar o guia para todos.