subtitles: corrigir legendas do Premiere Pro
Configuração única: veja INSTALL.md na raiz do kit. Com o plugin, a linha de configuração é
bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}"; com uma instalação manual (as quatro pastas skills/
copiadas lado a lado em ~/.claude/skills/), execute bash install.sh a partir da raiz do kit.
Os scripts estão na pasta scripts/ desta habilidade. Ela referencia a outra habilidade como ../rough-cut/....
O que a habilidade faz
O Premiere gera uma transcrição automática (um .json exportado) que geralmente está cheia de erros de digitação, principalmente
em nomes próprios (o nome de um fotógrafo vira duas palavras não relacionadas). O whisper.cpp transcreve muito melhor.
Esta habilidade transcreve o vídeo novamente localmente e recria um .json no formato exato do Premiere
(reimportável diretamente): nomes corrigidos com a ajuda de um roteiro de referência, pontuação e maiúsculas restauradas,
títulos de obras entre aspas. Por fim, realinha os tempos no áudio por alinhamento forçado (os timestamps do whisper têm deriva).
- SIM: transcrição local, correção de nomes, pontuação e maiúsculas, aspas ao redor de títulos, realinhamento temporal no áudio (alinhamento forçado), formato idêntico ao do Premiere, pronto para reimportar.
- NÃO: cortar o vídeo (isso é
rough-cut), traduzir, ressincronizar um arquivo de legenda já correto, legendas.srt/.vtt(o formato aqui é o JSON nativo do Premiere).
Entradas esperadas
- O vídeo exportado do Premiere (
.mp4/.mov): contém o áudio a ser transcrito. - O
.jsondas legendas exportado do Premiere: fornece o formato alvo (chaves, UUID dospeaker, idioma) a ser clonado. - O roteiro de referência do vídeo, em qualquer formato legível (texto simples, Markdown, um Google Doc, uma página do Notion, texto colado): a autoridade para a grafia dos nomes próprios (pessoas, obras, lugares, marcas). Se não houver, solicite-o, ou corrija apenas os erros óbvios e mantenha a grafia do whisper para qualquer nome incerto.
Idioma
Tipografia (espaçamento ao redor da pontuação), letras acentuadas, conjunto de pontuação, aspas e normalizações ortográficas estão em languages/<codigo>.json (fr e en já inclusos), nunca no código. O idioma é escolhido por --lang <codigo>, caso contrário o idioma do JSON do Premiere, senão o registrado na transcrição do whisper, senão en. Como os arquivos funcionam e como adicionar um idioma: ../rough-cut/references/languages.md (mesmo mecanismo; esta habilidade tem sua própria pasta languages/).
Requisitos (uma vez por máquina)
whisper-cli + ffmpeg + o modelo ~/Models/whisper/ggml-large-v3-turbo.bin. Veja ../rough-cut/references/whisper-setup.md (configuração compartilhada). Verifique: which whisper-cli ffmpeg && ls ~/Models/whisper/.
Alinhamento forçado (realinhamento dos tempos no áudio, etapa 6b):
pip3 install --break-system-packages ctc-forced-aligner torch torchaudio unidecode
Um modelo ONNX de cerca de 1,2 GB é baixado na primeira execução (cache ~/ctc_forced_aligner/). Verifique: python3 -c "import ctc_forced_aligner".
Fluxo de trabalho
Os comandos
scripts/...abaixo assumem que você está na pasta da habilidade. O diretório de trabalho pode ser redefinido entre duas chamadas de shell:cdpara a pasta da habilidade uma vez, ou prefixe cada script com seu caminho absoluto. Os arquivos de trabalho (áudio, transcrição, correções) vão para uma pasta temporária fora de qualquer pasta sincronizada.
1. Analisar o vídeo e o formato de entrada
PRIMEIRO: faça um snapshot do original. O Premiere pode REESCREVER o .json de entrada em uma reexportação, e ele é a única verdade de sincronia para verificar os tempos na etapa 7:
cp "<Reel.json>" /tmp/subs_original_premiere.json
ffprobe -v error -show_entries format=duration:stream=codec_type,r_frame_rate \
-of default=noprint_wrappers=1 "<video>"
Anote a duração (a última palavra deve estar dentro dela) e o fps. Em seguida, inspecione o JSON de entrada do Premiere para confirmar o formato:
python3 scripts/inspect_format.py "<Reel.json>"
Ele imprime as chaves (topo/segmento/palavra), o UUID do speaker, o idioma, o número de segmentos e o texto atual segmento por segmento (= a lista de erros de digitação a corrigir). O formato esperado está documentado em references/premiere-format.md: leia-o se a inspeção mostrar chaves incomuns.
2. Transcrever localmente (whisper.cpp)
python3 scripts/extract_audio.py "<video>" /tmp/subs_audio.wav
python3 scripts/transcribe.py /tmp/subs_audio.wav /tmp/subs_transcript.json --model large-v3-turbo --language <codigo>
Cerca de 8 s para 3 min no Apple Silicon. A transcrição tem segmentos com texto (pontuado, com maiúsculas) e palavras com timestamp.
2b. Se o whisper NÃO pontuou (entrega contínua): repontuar
Em monólogos rápidos, o whisper às vezes retorna um fluxo sem pontuação e sem maiúsculas (segmentos quebram no meio de uma frase, sem ./,). Sintoma claro: build_subs.py relata eos: 0. Sem pontuação, as legendas ficam ilegíveis. Verificação rápida: python3 scripts/words_of.py /tmp/subs_transcript.json 0 1 2 --plain.
Se for o caso, repontue você mesmo (é uma tarefa de LLM, não do whisper): reescreva o texto de cada segmento com pontuação e maiúsculas de frase, mantendo as palavras do whisper verbatim: adicione APENAS pontuação e maiúsculas; correções lexicais (nomes, siglas) ficam em corrections.json. A pontuação SEMPRE grudada na palavra (assim?, não assim ?): um sinal precedido por espaço vira um token isolado que o alinhamento descarta silenciosamente (114 ?/! foram perdidos de uma vez). build_subs.py insere o espaçamento do idioma sozinho (para francês, um espaço inseparável). Coloque o resultado em um JSON {índice: "texto pontuado"}, depois:
python3 scripts/repunctuate.py --transcript /tmp/subs_transcript.json --punct /tmp/punct.json --output /tmp/subs_transcript_punct.json
O script recusa se você adicionou, removeu ou alterou uma palavra (mostra o diff): é o que mantém o alinhamento palavra-tempo intacto. Cuide do fluxo entre segmentos: um segmento que continua uma frase começa com minúscula, um que abre uma frase começa com maiúscula. Use esta transcrição pontuada para o restante (--transcript na etapa 6).
Além disso, exclua qualquer alucinação de fim de clipe: no silêncio final, o whisper frequentemente inventa uma linha como um crédito de legenda ou "Obrigado por assistir" (as linhas típicas de cada idioma estão listadas em whisper_hallucinations em languages/<codigo>.json). Exclua-a com uma seq_rule N para 0. Outra alucinação: segmentos consecutivos com texto idêntico cujas palavras têm duração quase zero (início==fim), repetições inventadas sobre um silêncio ("lá vamos nós" x3). Detecção: segmentos i e i+1 com o mesmo texto e palavras de duração 0. Correção: remova-os da transcrição antes da construção (del segs[i:j]).
3. Ler a transcrição do whisper e o roteiro de referência
Imprima a transcrição segmento por segmento (texto) e compare com o texto de entrada do Premiere (etapa 1). O whisper já corrige muita coisa, mas mantém erros em nomes. Leia o roteiro de referência para obter a grafia canônica dos nomes próprios e dos títulos das obras que ele cita.
4. Construir corrections.json (o núcleo inteligente)
É aqui que a qualidade é decidida. Construa um arquivo de correções comparando o que o whisper ouviu com os nomes do roteiro. Inspecione a divisão palavra por palavra dos segmentos afetados para escrever regras exatas:
python3 scripts/words_of.py /tmp/subs_transcript.json 2 9 38 # tokens indexados dos segmentos a examinar
A saída indexa cada palavra (9:Smyth 10:Jones): é o que permite escrever regras exatas sem adivinhar a tokenização (quantos tokens um nome ocupa, hífens mantidos, etc.).
Formato de corrections.json (todas as chaves opcionais):
{
"quote_char": "\"",
"normalize_cotes": true,
"seq_rules": [
[["jon","smyth"], ["João","Silva"]],
[["train","park"], ["Trent","Parke"]],
[["arthus","bertrand"], ["Arthus-Bertrand"]]
],
"word_rules": {"macdum": "Magnum", "scholler": "Schoeller"},
"titles": [
{"match": ["the","decisive","moment"], "canonical": ["The","Decisive","Moment"]},
{"match": ["errance"], "canonical": ["Errance"], "sep_comma": true}
]
}
seq_rules: nomes com várias palavras, ou 1 para N / N para 1. A correspondência é feita nas palavras em minúsculas, sem pontuação. Use para qualquer nome com 2 ou mais palavras do whisper, ou quando o número de palavras muda. Maiúsculas: as palavras alvo são usadas VERBATIM: escreva a maiúscula final desejada, incluindo a posição na frase (["Hoje","nós",...]se a palavra abrir a frase, não["hoje",...]). Mesmo comprimento origem/destino: a pontuação (vírgulas internas) e os tempos são mantidos por índice; comprimentos diferentes: os tempos são redistribuídos e apenas a pontuação da primeira/última palavra sobrevive (as vírgulas internas das palavras substituídas são perdidas: releia esses segmentos na etapa 7). Exclusão: um destino vazio[["uh"], []]remove a palavra (reserve para ruídos isolados reais que o whisper dobrou; para uma palavra mal transcrita, corrija-a em vez de excluí-la, ou você perde parte da frase).word_rules: um nome de uma palavra, maiúscula forçada (chave minúscula para valor exato).titles: obras citadas (livros, séries, fotografias intituladas) recebem aspas automáticas (abertura na primeira palavra, fechamento na última) mais umcanonicalpara a maiúscula correta do título.sep_comma: trueadiciona uma vírgula após o título (útil quando vários títulos se sucedem). Coloque obras entre aspas, não nomes de pessoas ou marcas.normalize_cotes: aplica as normalizações ortográficas do arquivo de idioma (normalize_words), para variantes que o whisper escreve inconsistentemente. Desligado a menos que você o defina.french_typography: o interruptor para o espaçamento tipográfico do idioma (o nome é histórico; aplica-se a qualquer idioma em uso). Padrão tirado do arquivo de idioma: para francês, um espaço inseparável (U+00A0) antes dos sinais de pontuação dupla e da aspa de fechamento, e depois da aspa de abertura; para inglês, nenhum. Defina comofalseapenas se quiser pontuação grudada. Quando você repontua na etapa 2b, a pontuação DEVE estar grudada (Flop:);build_subs.pyinsere o espaçamento sozinho.
5. Resolver incertezas COM o usuário (nunca inventar)
O whisper às vezes produz uma palavra não-nome ambígua ou ininteligível. Não adivinhe silenciosamente. Liste esses pontos com seu timecode e pergunte ao usuário o que realmente foi dito, oferecendo uma hipótese se o contexto ou o roteiro sugerir uma. Distinga:
- Corrigir diretamente: nomes próprios confirmados pelo roteiro; erros de digitação óbvios e certos.
- Perguntar primeiro: palavras não-nome ambíguas, ou qualquer correção que mude o significado (por exemplo, whisper "quem sente" contra o roteiro "sem": uma inversão de significado, sinalize mesmo que o roteiro resolva).
Não reescreva o estilo falado (gíria, frases de preenchimento, repetições): as legendas devem seguir o áudio.
O que escrever no arquivo enquanto espera a resposta (você não precisa bloquear a geração): produza uma primeira versão que aplica todas as correções seguras mais sua melhor hipótese para as palavras ambíguas comuns (e sinalize-as), mas mantenha a grafia bruta do whisper para um nome INCERTO ausente do roteiro: nunca invente um nome próprio. Entregue essa versão com a lista de pontos a validar (timecodes) e, em seguida, regere após a resposta atualizando corrections.json. Esse é o fluxo normal: gerar, apresentar com as perguntas, refinar.
6. Gerar o arquivo corrigido
python3 scripts/build_subs.py \
--transcript /tmp/subs_transcript.json \
--original "<Reel.json>" \
--corrections /tmp/corrections.json \
--output "<pasta>/<nome>_corrigido.json" [--lang <codigo>]
O script clona o formato do original (UUID do speaker, idioma, chaves ordenadas, UTF-8 minificado), insere pontuação e maiúsculas, aplica as correções, adiciona as aspas, recalcula eos e imprime um relatório de validação.
Escreva <nome>_corrigido.json AO LADO do original, nunca sobrescreva a exportação original (é a fonte do usuário). O sufixo _corrigido é um nome de arquivo no qual os scripts confiam: mantenha-o.
6a. Verificar as 2 armadilhas recorrentes de build_subs.py (toda vez)
Dois bugs vistos em muitos vídeos, a verificar após CADA construção:
- Números decimais duplicados. O whisper divide
6,6em 2 tokens (6+,6; da mesma forma1,33, ou4 AMem4+AM); a reinjeção de pontuação os duplica na saída (1,4 ,4,6,6, ,6), eseq_rulescasam mal (a normalização não remove um./,interno). Detecção: grep na saída final pelos padrões\d[.,]?\s+[.,]\d. Correção: cirurgia na transcrição ANTES da construção: mescle os 2 tokens em um ({'text':'1,4','start':a.início,'end':b.fim,...}; esquema de palavra do whisper =texto/início/fim/confiança, NÃOduração), depois reconstrua. - Pontuação de fim de frase isolada descartada. Um
?/!/:presente notextodo segmento do whisper, mas sem um token de palavra próprio, desaparece (Como fizemos isso ?perde o?). Detecção: comparecount('?')(e!,:) entre o texto do whisper e a saída. Correção: edite o JSON de saída depois: reanexe?(com o espaçamento do idioma) ao token anterior.
Se a armadilha 1 for detectada, corrija a transcrição e reconstrua (etapa 6). Se a armadilha 2, corrija a saída diretamente.
6b. Realinhar os tempos no áudio: alinhamento forçado (SEMPRE)
Os tempos das palavras do whisper têm DERIVA (medida em até 7 s adiantada, não linear) com monólogos rápidos e múltiplas tomadas: o whisper achata os silêncios entre as tomadas, então a voz chega DEPOIS da legenda. Reclamação típica: "quando o 'Ah' aparece, já ouço a próxima frase". DTW (-dtw) não muda nada (mesmos deslocamentos), e uma distorção temporal em âncoras esparsas distorce as zonas que já estavam certas. O texto do whisper é bom, apenas seus tempos estão errados.
7. Verificação pós-construção
Compare as legendas corrigidas com a transcrição do whisper nos mesmos intervalos e com a linha do tempo do Premiere. Carregue o JSON corrigido no Premiere e verifique uma amostra das correções mais críticas (nomes, tempos nos primeiros 2 minutos).
Atalhos
vídeo curto: se o vídeo tiver < 3 min ou menos de 10 segmentos, pule a extração de áudio e use o áudio do próprio vídeo diretamente; ajuste os parâmetros do whisper conforme necessário.correções mínimas: se o roteiro de referência for muito curto ou inexistente e os erros do whisper forem raros, construacorrections.jsonmanualmente, verificando palavra por palavra apenas nos segmentos problemáticos.
Referências externas
- Formato de línguas – Como adicionar um idioma.
- Formato das legendas do Premiere – Documentação do formato alvo.
- Configuração do whisper – Guia de instalação do whisper.cpp + modelo.
- Kit para o Claude – Kit mais amplo (opcional) que fornece
install.she dados compartilhados.