LiveCaption

Legendas ao vivo com tradução em tempo real, 100% local, para Mac (Apple Silicon). Microfone → Whisper (WhisperKit/CoreML) → modelo de tradução aberto (Hy-MT2-1.8B, via Ollama) → janela flutuante só com o texto traduzido, que aparece palavra por palavra.

EN — Live captions with real-time translation for macOS (Apple Silicon), fully on-device. Microphone → Whisper (WhisperKit/CoreML) → open translation model (Hy-MT2-1.8B through Ollama) → a floating window showing the translation as it is generated. Default pair is Portuguese → Spanish; the translator is any Ollama-compatible chat API, so you can swap the model. Nothing leaves your Mac. Quickstart below; commands are the same in both languages. This repository ships source code only: the open models are downloaded from their official repositories by a script.

Projeto pessoal, usado numa aula real de 2h44. Não é um produto: foi medido em um Mac (MacBook Air M2, 16 GB) e a qualidade depende dos modelos (veja "Limites").

Por que é local

  • O áudio do microfone é processado em memória, no seu Mac. Não há telemetria nem contas.
  • Em execução normal a única rede usada é localhost (o servidor do Ollama). Os modelos são baixados uma vez pelo fetch_models.sh. Exceção: se faltar o tokenizer do Whisper na pasta de dados (por exemplo, ao apontar LC_WHISPER_DIR para outro modelo), o WhisperKit o baixa do Hugging Face uma vez; nenhum áudio nem texto sai.
  • Por padrão nada do que é dito é gravado em disco. LC_LOG=1 liga um histórico (frases PT/ES e métricas em logs/); LC_SAVE_AUDIO=1 grava o áudio do microfone. Ambos são opcionais e ficam na sua pasta de dados.
  • O tradutor é substituível sem recompilar: qualquer API de chat compatível com a do Ollama (LC_MT_URL, LC_MT_MODEL).

Requisitos

  • Mac com Apple Silicon, macOS 14 ou superior (WhisperKit/CoreML não roda em Intel).
  • Só para os testes opcionais: ffmpeg e a voz Luciana (pt-BR) do macOS (Ajustes → Acessibilidade → Conteúdo falado), usadas por gen_test_audio.sh.
  • Swift 5.9+ (Xcode Command Line Tools: xcode-select --install).
  • Ollama instalado e em execução (só serve o modelo de tradução localmente).
  • hf para baixar os modelos: pipx install huggingface_hub (ou pip install -U huggingface_hub; com o Python do Homebrew prefira pipx).

Início rápido

hf download Veronyka/livecaption --local-dir livecaption && cd livecaption   # ou: git clone https://huggingface.co/Veronyka/livecaption
zsh scripts/fetch_models.sh        # baixa Whisper small + Hy-MT2 1.8B (~1,6 GB) e importa o tradutor no Ollama
zsh scripts/build_app.sh --install # compila e copia LiveCaption.app para /Applications
open /Applications/LiveCaption.app # aceite a permissão de microfone

A primeira abertura leva cerca de 1 minuto (o macOS compila o modelo para o Neural Engine); depois abre em segundos. O app é assinado só localmente (ad hoc): por ser compilado por você, o Gatekeeper não bloqueia.

Os modelos ficam em ~/Library/Application Support/LiveCaption/ (mude com LC_PROJECT). Os scripts são chamados com zsh scripts/… para não depender do bit de execução dos arquivos.

Uso

Janela escura arrastável e redimensionável com o espanhol (frase mais recente em destaque). Botões Pausar (desliga o microfone de verdade) e Sair. De fora do app:

zsh scripts/livecaption.sh start | stop | pause | status   # `pause` alterna pausar/retomar (SIGUSR1)

O rodapé mostra: tempo do Whisper, 1ª palavra da tradução, tradução completa, fim da frase→legenda e fila.

Configuração (variáveis de ambiente)

Variável Padrão Para quê
LC_SRC / LC_DST pt / Spanish idioma falado (código do Whisper) e idioma de destino (nome em inglês, vai no prompt do tradutor)
LC_MT_URL / LC_MT_MODEL http://localhost:11434/api/chat / hymt2-1.8b tradutor
LC_PROJECT ~/Library/Application Support/LiveCaption pasta de dados (modelos, glossary.json, logs)
LC_WHISPER_DIR <dados>/models/whisper/openai_whisper-small outro modelo do Whisper
LC_LOG=1 desligado grava histórico e métricas em <dados>/logs/
LC_SAVE_AUDIO=1 desligado grava o microfone em <dados>/logs/audio-*.f32
LC_WAV / LC_DURATION — teste: alimenta o app com um arquivo f32le 16 kHz mono em tempo real
LC_SNAPSHOT=<arquivo.png> — depuração: desenha a janela num PNG

Variáveis só valem ao iniciar pelo terminal: LC_LOG=1 /Applications/LiveCaption.app/Contents/MacOS/LiveCaption.

glossary.json (opcional, na pasta de dados; modelo em glossary.example.json): pre_substitutions (regex no texto falado antes de traduzir), post_corrections (regex no que o Whisper ouviu), keep_terms (nomes que o tradutor mantém). Não preencha whisper_vocab: medido, deixa o Whisper ~2x mais lento.

Como evita o "atraso que só cresce"

  • Janela de áudio limitada (nunca reenvia a sessão inteira ao Whisper); cada frase confirmada sai da janela.
  • Só se traduz o que o Whisper já confirmou; fila "mais recente ganha" (o atraso acumulado vira um único pedido, nunca uma fila).
  • Tradução em streaming: o espanhol só acrescenta palavras, não reescreve.
  • Decodificações em loop são cortadas por limite de tokens e descartadas se o Whisper devolver segmentos demais para a duração.

Medições (MacBook Air M2, 16 GB, macOS 26)

Uma aula real de 2h44 com voz ao vivo (pt→es), sem OBS, app em segundo plano:

  • 1ª palavra do espanhol: mediana 0,17 s; tradução completa da frase: mediana 0,60 s (p95 3,8 s; um pico isolado de 22,6 s).
  • Whisper small: 0,31 s → 0,30 s de média entre o 1º e o último quarto da aula (sem degradação).
  • App: ~90–134 MB de RAM, ~19% de um núcleo; estado térmico nominal/fair. Mais ~1,2 GB do modelo no Ollama.

Alternativas testadas e descartadas neste Mac: Hy-MT2 7B (~19 vs 42 caracteres/s, perto demais da velocidade da fala); Whisper medium (2,16 s vs 0,38 s por decodificação, não acompanha a fala). Reproduzir: zsh scripts/gen_test_audio.sh (voz sintética pt-BR do macOS) e zsh scripts/soak.sh 600 (usa LC_LOG=1; saída em <dados>/logs/). Os números acima não foram medidos em outros Macs, e os logs da aula não estão neste repositório (contêm conversas de terceiros), então não são verificáveis aqui; soak.sh reproduz o método com áudio sintético.

Modelos e licenças

Este repositório não redistribui pesos. O script baixa dos repositórios oficiais:

Componente Origem Licença (conforme o repositório de origem)
Whisper small (conversão CoreML) argmaxinc/whisperkit-coreml (pesos originais: openai/whisper-small) conversão: MIT; pesos originais: Apache-2.0
Tokenizer do Whisper openai/whisper-small Apache-2.0
Hy-MT2-1.8B (GGUF Q4_K_M) tencent/Hy-MT2-1.8B-GGUF Apache-2.0 (LICENSE.txt oficial, sem restrição territorial, conferido em 2026-11-09)
WhisperKit (biblioteca) argmaxinc/WhisperKit MIT
Ollama ollama/ollama MIT

Atenção: relatos indicam que cópias do Hy-MT2 no catálogo do Ollama (por exemplo kaelri/hy-mt2) trazem a licença antiga da Tencent, que excluía a União Europeia (não verifiquei essas cópias diretamente). Por segurança, use o GGUF oficial: o script confere o SHA-256 dc5f44fcf1fa496ee7ad725982c0c8c553a4de00259b53af84c4b89fb0c06699 (revisão a0c709d9). Isto é uma leitura técnica das licenças, não parecer jurídico.

Limites

  • Qualidade: o Whisper small erra nomes próprios e termos técnicos; o Hy-MT2 1.8B às vezes acrescenta palavras que não foram ditas e traduz expressões coloquiais de forma literal (o glossário ajuda nos casos conhecidos). Revise antes de usar em contexto formal ou legal.
  • Só Apple Silicon. Testado apenas com pt→es (o Whisper cobre outros idiomas de origem; o destino depende do que o tradutor suporta, e isso não foi testado aqui).
  • Sem separação de falantes. Áudio só do microfone (não captura o áudio do sistema).
  • Não foi testado com leitor de tela nem em outros Macs.

Estrutura

  • Sources/LiveCaption/main.swift — app (captura, laço do Whisper, fila de tradução, janela).
  • scripts/ — fetch_models.sh, build_app.sh, livecaption.sh, soak.sh, gen_test_audio.sh, test_mt.py.
  • assets/hymt2.Modelfile — template de chat e token de parada corretos do Hy-MT2 para o Ollama (sem eles o modelo não termina a frase).
  • glossary.example.json, tests/live_pt.txt (texto do áudio de teste).

Licença

Código: MIT (ver LICENSE). Os modelos mantêm as próprias licenças, listadas acima.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support