Communitygithub.com

kevin-burns/transcribe-summarize

Habilidade para Claude Code/Codex de transcrição de reuniões local-first. Executa Whisper na sua própria máquina (macOS, Windows e Linux), filtra segmentos inventados por Whisper durante silêncios e gera atas factuais da reunião e um PDF. APIs hospedadas são opcionais e informam o que enviarão e o custo antes do envio.

O que é transcribe-summarize?

Esta habilidade para agentes de IA (Claude Code, Codex) realiza transcrição de áudio de forma local-first, utilizando Whisper na máquina do usuário (macOS arm64, Windows, Linux) para garantir privacidade e zero custos de API. Ela se diferencia por automaticamente filtrar segmentos de fala inventados por Whisper durante períodos de silêncio (um problema comum, mesmo com modelos grandes), mantendo um registro auditável no JSON. Além da transcrição pura, a ferramenta pode gerar atas factuais da reunião e um PDF formatado, seguindo regras rigorosas de privacidade e precisão: nomes de palestrantes e datas devem ser confirmados com o usuário, e nenhuma análise ou 'próximos passos' são inventados. O workflow é transcrever, revisar (o usuário verifica nomes, números e datas), e então gerar as notas, garantindo que o output final seja um registro confiável e não uma interpretação. Também suporta transcrições de plataformas (Teams, Zoom) a partir de arquivos .vtt, apenas normalizando o formato sem re-transcrever.

Funciona com✓Claude Code✓Codex CLI~Cursor✓Gemini CLI
npx skills add kevin-burns/transcribe-summarize

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que transcribe-summarize faz?

Áudio de entrada, uma transcrição de saída e, opcionalmente, um conjunto de atas de reunião. O caminho padrão executa inteiramente na máquina do usuário.

Duas coisas tornam isso diferente de chamar o Whisper você mesmo, e ambas surgiram de um dia de medição, não de design:

  1. O Whisper inventa fala sobre silêncio, e um modelo maior não ajuda. Em uma chamada real com 40 s de silêncio de entrada, o large-v3 produziu um segmento de 18 segundos de uma palavra repetida 55 vezes. Esta habilidade filtra esses segmentos e os mantém, com as métricas que os rejeitaram, em um arquivo auxiliar para que a decisão seja auditável.
  2. Limpar o áudio supera a escolha do modelo. Normalizar e cortar silêncio reduziu os segmentos inventados de 2 para 0 e corrigiu uma palavra que tanto large-v3 quanto turbo erraram. Está ativado por padrão.

Configuração

ffmpeg e ffprobe devem estar no PATH — no macOS brew install ffmpeg, no Windows winget install Gyan.FFmpeg, no Linux apt install ffmpeg.

Todo o resto é stdlib. O backend traz sua própria biblioteca, e apenas a selecionada, então escolha com uv run --with:

backendplataformaespecificação --with
mlx-whisper — padrão no Apple SiliconmacOS arm64 apenas'mlx-whisper>=0.4.2'
faster-whisper — padrão em outros lugaresmac / Windows / Linux'faster-whisper>=1.2'
parakeet — opcionalApple Silicon verificado'parakeet-mlx'
groq, openai, elevenlabs, gemini — opcionais, redequalquernada para instalar

Se a biblioteca estiver faltando, o erro exibe o comando exato. Não adivinhe.

Executando

Declare o helper no topo de todo bloco de comando — o estado do shell não persiste entre chamadas de ferramenta:

ts() {
  UV="$(command -v uv || ls "$HOME/.local/bin/uv" "$HOME/.cargo/bin/uv" \
        /opt/homebrew/bin/uv /usr/local/bin/uv 2>/dev/null | head -1)"
  "$UV" run --with "$1" --script "$HOME/.claude/skills/transcribe-summarize/scripts/transcribe.py" "${@:2}"
}

# Apple Silicon
ts 'mlx-whisper>=0.4.2' meeting.m4a

# Windows / Linux
ts 'faster-whisper>=1.2' meeting.m4a --backend faster-whisper

# Viés do decodificador para jargões conhecidos e corrige um nome que ele sempre erra
ts 'mlx-whisper>=0.4.2' meeting.m4a --prompt 'Terragrunt, EKS' --replace 'north wind=Northwind'

Use o caminho absoluto. Um caminho relativo só resolve se o diretório de trabalho atual for o diretório da habilidade.

Contrato de saída

<dir_saida>/
  <stem>.md                    a transcrição, com âncoras [hh:mm:ss]
  <stem>-artifacts/
      <stem>.srt               legendas
      <stem>.json              cada segmento, incluindo os suprimidos
      <stem>.run.json          backend, modelo, deslocamentos de corte, contagem da guarda

--json imprime esses caminhos para stdout como JSON. Relate caminhos absolutos ao usuário; um arquivo que ele tenha que caçar não é uma entrega.

Os carimbos de data/hora seguem o relógio da gravação original. O corte encurta o áudio durante a decodificação, e os deslocamentos são mapeados de volta antes que qualquer coisa seja escrita, para que o .srt se alinhe com o próprio arquivo do usuário.

A regra de rede — declare-a, depois obedeça-a

Um backend de rede é acessível apenas quando o usuário o solicita naquela invocação. Nunca como fallback, nunca após um backend local falhar, nunca porque seria mais rápido. --backend auto não pode alcançar um; não há caminho de código.

Antes de qualquer coisa ser enviada, a ferramenta imprime provedor, endpoint, tamanho do arquivo, duração e custo estimado, então aguarda. Use --dry-run para mostrar ao usuário esse bloco antes de confirmar. Em uma sessão não interativa, um upload não confirmado é recusado.

As chaves vêm do ambiente, uma variável por backend, e de nenhum outro lugar. Nunca aceite uma como flag, nunca ecoe uma, nunca escreva uma em um arquivo.

backendchavemodelo$/horadiariza
groqGROQ_API_KEYwhisper-large-v3-turbo0.04não
groqGROQ_API_KEYwhisper-large-v3 (padrão)0.111não
elevenlabsELEVENLABS_API_KEYscribe_v20.22até 32
geminiGEMINI_API_KEYgemini-3.5-transcribe0.306até 3
openaiOPENAI_API_KEYwhisper-10.36não

--backend gemini — as duas coisas a dizer antes de executá-lo

ts '' /caminho/para/audio.m4a --backend gemini --dry-run     # mostra o bloco, não envia nada
ts '' /caminho/para/audio.m4a --backend gemini               # então executa

Nada para instalar — é stdlib http.client, então o argumento --with é vazio. Dois fatos pertencem à frase que você diz ao usuário antes de executá-lo, porque nenhum é visível na linha de comando:

  • O áudio é enviado duas vezes. O Gemini não tem endpoint de etapa única: o arquivo vai primeiro para a API de Arquivos do Google, e a solicitação de transcrição então carrega apenas o URI que retornou. O Google mantém esse upload por 48 horas. O bloco de divulgação imprime isso; não pule por cima dele.
  • 30 minutos é o limite máximo, não a hora que a própria página do Google anuncia. A hora se aplica apenas sem carimbos de data/hora de palavras ou diarização, e este backend sempre solicita ambos — sem deslocamentos de palavras não há relógio para mapear de volta ao arquivo do usuário. Uma gravação mais longa é recusada antes do upload começar.

Não ofereça o modo smart do Gemini. Não está conectado, de propósito. Se o usuário perguntar por ele — é o recurso principal do modelo, e ele remove palavras de enchimento e reescreve autocorreções faladas — a resposta é que a API do Google recusa carimbos de data/hora de palavras e rótulos de orador junto com ele, então não produziria nenhum .srt e nenhum orador, e ele muda as palavras. A remoção de enchimento acontece na etapa de notas, onde é rotulada como um resumo e verificada. Veja references/backends.md.

A guarda de qualidade

Ativada por padrão. Segmentos suprimidos permanecem no .json com o motivo e as métricas; eles são removidos do .md e .srt. --guard mark os mantém inline sinalizados, --guard off o desabilita.

Não se transfere para todos os backends. As regras fortes leem as métricas do decodificador do Whisper. faster-whisper, Groq e OpenAI retornam todos os três, então a guarda é o mesmo código. Parakeet, ElevenLabs e Gemini não retornam nenhum deles e caem apenas para as regras independentes de backend — a ferramenta informa isso em tempo de execução. Veja references/backends.md.

Se o usuário perguntar por que um trecho da transcrição está faltando, leia o .json: a resposta está lá com os números que o causaram.

Começando a partir de uma transcrição que você já possui

A maioria das reuniões já é transcrita pela plataforma, e muitas vezes não há áudio nenhum. Teams e Zoom fornecem um .vtt (às vezes .srt), e ele é ilegível como prosa: uma legenda a cada poucos segundos, frases cortadas entre legendas, o nome do orador repetido em cada linha, códigos de tempo por toda parte.

Esse é um ponto de entrada suportado. Nada é re-transcrito — o caminho do áudio é pulado completamente:

"$HOME/.claude/skills/transcribe-summarize/scripts/normalise_transcript.py" meeting.vtt
# -> meeting.md, legendas reagrupadas em parágrafos, oradores atribuídos, uma âncora por parágrafo

Em seguida, prossiga exatamente como se a transcrição tivesse sido decodificada aqui: leia-a, peça os fatos da reunião e escreva as notas em references/notes-register.md.

--no-speakers remove a atribuição se os rótulos de origem estiverem errados ou indesejados.

É uma conversão de formato e nada mais. Nenhuma palavra é alterada, nenhum enchimento removido, nenhuma gramática corrigida. Decidir o que foi dito é a etapa de sumarização e ela tem suas próprias regras. Se um usuário lhe entregar uma transcrição bagunçada e pedir para "arrumá-la", normalize o formato aqui e faça o julgamento nas notas — não reescreva silenciosamente as palavras de alguém em um documento que deveria registrá-las.

Os oradores são mantidos na transcrição e proibidos nas notas, o que não é uma contradição: uma transcrição é um artefato de trabalho e pode carregar proveniência; as notas são um registro e não podem. notes_check.py ainda rejeitará um rótulo Speaker 2 bruto nas notas.

Se alguém passar um .vtt para transcribe.py, ele para e aponta para aqui em vez de tentar decodificá-lo.

Arquivos de vídeo

.mp4 é o que um download do Teams ou Zoom realmente é, e funciona diretamente — não há necessidade de extrair o áudio primeiro. Verificado como funcionando: .mp4, .mov, .mkv, .webm, além de todos os contêineres de áudio (.m4a, .mp3, .wav, .flac, .opus). o ffmpeg extrai a faixa de áudio; o vídeo é ignorado e nunca enviado.

Um arquivo sem faixa de áudio — uma gravação de tela silenciada — é recusado de imediato, antes que qualquer backend de rede o receba. Essa verificação é executada antes da porta de saída especificamente para que um vídeo silencioso nunca seja enviado e faturado.

Revisão é uma etapa, não um extra opcional

A saída da transcrição é um rascunho. Diga isso e faça o usuário verificá-la.

A transcrição automática erra com confiança de maneiras que nenhum limite detecta. Medido em áudio real neste projeto: o large-v3 silenciosamente descartou a correção falada de um número por um orador, e todo backend ouviu "board pack" como "board packs up". Ambas leem perfeitamente fluentes. A guarda de qualidade captura invenções sobre silêncio; ela não pode capturar um erro de audição plausível, e você também não pode lendo a saída.

Portanto, o fluxo de trabalho é transcrever → o usuário verifica → então notas:

  1. O .md da transcrição termina com uma seção "Vale a pena verificar" — carimbos de data/hora classificados onde uma escuta provavelmente mais compensará (segmentos de menor confiança, qualquer coisa contendo números). Aponte o usuário para ela explicitamente.
  2. Nomes, números e datas são o que verificar. Eles são a primeira coisa a se degradar e os mais caros de errar em um registro.
  3. As correções vão para o .md, manualmente ou com --replace em uma nova execução. Em seguida, regere qualquer coisa construída a partir dele.

Nunca apresente uma transcrição ou um conjunto de notas como verificado. Você não ouviu o áudio; o usuário ouviu. Diga o que foi decodificado, diga onde é menos certo e deixe-o confirmar.

Editando e regenerando

O .md é a fonte. Edite-o e reconstrua o PDF — sem re-transcrição:

"$HOME/.claude/skills/transcribe-summarize/scripts/notes_check.py" notes.md
"$HOME/.claude/skills/transcribe-summarize/scripts/render_pdf.py"  notes.md

Execute o verificador novamente após qualquer edição. A edição manual é exatamente quando um vazamento de proveniência ou uma linha inferida de "próximos passos" é introduzida.

Escrevendo as notas

Quando o usuário quiser atas de reunião em vez de uma transcrição, você as escreve — leia a transcrição e produza o documento você mesmo. Existe um fallback scripts/summarize.py que chama um modelo de rede, mas é para executar este pipeline fora de uma sessão do Claude Code; dentro de uma, é um upload inútil.

Pergunte primeiro — três coisas que o áudio não pode lhe dizer

Quase nenhum backend aqui identifica oradores. Todo mecanismo Whisper e o Parakeet não retornam nenhum campo de orador. Duas exceções: --backend elevenlabs (Scribe) diariza até 32 oradores, e --backend gemini até 3. Ambos retornam rótulos posicionais em vez de nomes — speaker_0 e spk:0 respectivamente, os formatos medidos a partir de respostas ao vivo em 2026-09-04 e 2026-09-06 — e o registro proíbe um rótulo bruto em um documento de notas, em qualquer formato. Então eles lhe dizem quantas pessoas falaram e quais linhas pertencem juntas; eles ainda não podem lhe dizer quem. A atribuição vem do usuário de qualquer maneira; a diarização apenas torna o mapeamento possível a partir da transcrição em vez da memória.

Antes de escrever notas, pergunte:

  1. Quem estava presente. Sem nomes, escreva as notas sem nenhuma atribuição — impessoal, "foi afirmado que…". Nunca invente um nome, um cargo ou um rótulo posicional. Se a transcrição tornar óbvio quem falou (alguém é chamado pelo nome), você pode atribuir isso; ambiguidade significa sem nome.
  2. A data da reunião. A data de hoje é um padrão, não um fato. O áudio é frequentemente redigido dias após a conversa, e uma data errada em um registro factual é pior do que nenhuma data. Confirme-a.
  3. O que foi a reunião — um título nos termos dos próprios participantes.

Pergunte todos os três em uma única mensagem, não um de cada vez, e ofereça a data de hoje como padrão para que o usuário só tenha que corrigi-la. Se o usuário se recusar a fornecer participantes, prossiga sem atribuição e diga que foi isso que você fez.

Antes de escrever uma única linha, leia references/notes-register.md. É curto e é toda a especificação. Não é um conselho de estilo; as regras nele foram aprendidas ao ter seções deletadas manualmente de um documento real, e as razões são legais em vez de estéticas.

As duas regras que ele ativa:

  • Apenas resumo factual. O que foi dito. Sem análise, sem implicações, sem "próximos passos", sem "o que não foi coberto", sem preencher uma lacuna.
  • Lê-se como um relato de protocolo por alguém que estava lá. Nunca menciona uma gravação, uma transcrição, áudio, um modelo ou qualquer artefato de decodificador — sem códigos de tempo, sem rótulos Speaker 2.

Em seguida, verifique-o, toda vez — o registro não é autoaplicável e um modelo solicitado a resumir adicionará análise sem ser solicitado:

"$HOME/.claude/skills/transcribe-summarize/scripts/notes_check.py" notes.md

Saída 0 está limpo; saída 1 lista arquivo:linha para cada violação. Corrija-as antes de entregar o documento. Execute-o também no PDF — um vazamento que só existe no arquivo renderizado ainda conta.

Orientação é bem-vinda, mas após as notas e fora do documento. Ofereça sua leitura em conversa, ou escreva-a em um arquivo separado. Nunca a anexe.

O PDF

"$HOME/.claude/skills/transcribe-summarize/scripts/render_pdf.py" notes.md

Chrome headless, Chromium ou Edge, descobertos automaticamente. Se nenhum estiver instalado, ele escreve o HTML, informa e sai com 0 — o HTML ainda é uma entrega.

Proveniência

A decodificação local é mlx-whisper (MLX) ou faster-whisper (CTranslate2); a preparação de áudio é ffmpeg. Os backends de rede chamam os endpoints de transcrição do Groq e da OpenAI diretamente sobre stdlib urllib — sem SDK de fornecedor.

Manter a proveniência fora de um documento de notas muda o que o documento diz, não o que aconteceu. Gravar uma chamada sem consentimento é uma ofensa criminal em muitas jurisdições. Se o usuário pedir garantias que você não pode dar, não as invente.

Referências

  • references/backends.md — especificação completa do backend, formato de resposta, métricas disponíveis
  • references/notes-register.md — regras para escrever atas de reunião factuais
  • references/privacy.md — modelo de privacidade e perguntas frequentes

Histórico de versões

  • 2026-09-04 — suporte ao backend Gemini adicionado; modo smart bloqueado de propósito
  • 2026-08-20 — normalizador de transcrição .vtt
  • 2026-08-13 — guarda de qualidade, pipeline de revisão

Habilidades Relacionadas