Files
gart/.claude/skills/editar-por-voz/criterios/01-leitura-do-json.md
T
João HenriqueandClaude Sonnet 5 7b5aed79ee feat(voz): legenda por ênfase, forced align, IA local e correções de zoom/revisão
Trabalho da branch feat/revisao-enfases: pipeline de edição por voz ganha
alinhamento forçado (whisperx), roteirização por LLM local (Ollama), e a
etapa 5 (revisão de frases) passa a refletir de verdade o que é aplicado.

- generate_subtitles_by_emphasis: legenda comum cobre o clipe inteiro,
  legenda dinâmica só nas frases de ênfase, e a comum é desativada
  (enabled="0") onde a dinâmica cobre, em vez de nunca ser gerada ali.
- validate_subtitle_layout ignora títulos com enabled="0" — corrige falso
  positivo de colisão contra o que está desativado no lugar dele.
- Corrige zoom/marcador sendo descartado quando a borda encosta exatamente
  no início de um corte.
- Etapa 5 do Assistente: recarrega quando as decisões da IA mudam (com
  fresh=true, ignorando a revisão salva antiga) — resolve a dessincronia
  entre "ativa" na tela e o que já foi cortado no FCPXML.
- Etapa "Processar" reaplica as decisões da revisão (_phrase_actions.json)
  antes da cadeia de remoção de silêncio/legendas — antes, desativar uma
  frase na etapa 5 não tinha efeito nenhum no vídeo final.
- Etapa "Concluído" fundida em "Processar" — abrir no Final Cut/Finder
  aparece assim que termina, sem slide extra.
- Palavra clicável na etapa 5 agora funciona como toggle (clique de novo
  desfaz) e mostra a própria ênfase (sublinhado colorido + peso da fonte).
- fcpxml/forced_align.py, fcpxml/llm_local.py, ai_edit.py: alinhamento
  fonético via whisperx e roteirização local via Ollama/Gemma.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 18:26:04 -04:00

3.6 KiB
Raw Blame History

01 — Leitura do JSON

Escopo: Como ler o voice_timeline em camadas, sem recalcular o que já foi medido. Quando: Fase 1 — ver a ordem de trabalho em ../SKILL.md.

O arquivo <mídia>_voice_timeline.json é a entrada de todo o trabalho. Leia em camadas, de cima para baixo, e só desça quando precisar.

Camadas

Camada O que traz Para quê
layers o que de fato rodou na análise leia primeiro — ver 07-analise-incompleta.md
summary forma da peça, peak_moments, contagens visão geral em poucos números
speakers quem fala, % do tempo, frases de exemplo identificar papéis
segments cada fala com seus agregados onde você mais trabalha
segments[].words detalhe por palavra achar o instante exato de um destaque
scales o que cada número significa documentação dentro do próprio arquivo

Campos que decidem quase tudo

gap_before — silêncio antes da fala, em segundos. É o mapa estrutural da gravação: acima de ~3s (take_boundary: true) a câmera parou ou a tomada recomeçou. Num material real de 3min17s isso identificou 6 fronteiras, todas exatamente onde a pessoa recomeçava o roteiro.

take_boundary — booleano derivado do gap_before. Use para agrupar tomadas.

emphasis (0–1) — índice combinado de energia, variação de tom, variação de ritmo, pausa anterior e duração. É relativo ao material analisado, nunca uma medida absoluta. Ver 02-enfase-e-reanalise.md.

energy (0–1) — intensidade relativa ao trecho mais alto da gravação.

pitch_delta (0–1) — quanto o tom se afasta da média do falante.

peak_emphasis e avg_energy (por segmento) — permitem julgar uma frase inteira sem ler palavra por palavra. É por aqui que você avalia o arco narrativo.

energy_raw e pitch_hz — valores brutos, sem normalização. Não use para decidir; existem para permitir a reanálise da Fase 2.

O que NÃO fazer

  • Não recalcule energia, tom ou ênfase. O sistema mede melhor e de forma reprodutível.
  • Não reestime tempos "no olho". Use os timestamps do JSON.
  • Não trate emphasis como valor absoluto. Um 0,35 pode ser o pico de uma gravação e ruído em outra.

O timestamp por palavra tem um viés conhecido

O início de cada palavra vem sistematicamente adiantado em ~0,3-0,5s em relação ao ataque real da fala — medido em material real com ffmpeg (astats), consistente em 6 pontos do mesmo vídeo. O fim da palavra não tem esse problema (erro de poucos centésimos). Causa: word_timestamps do faster-whisper deriva por atenção cruzada, sem alinhamento forçado — ver 05_EXPERIENCIAS.md, entrada de 2026-08-19.

Quando o pipeline já corrigiu isso: se layers.alignment for true (transcript gerado com alinhamento forçado fonético via whisperx, implementado depois desse aviso), o viés foi removido na origem — não aplique o offset manual abaixo. O aviso vale só para transcripts antigos sem layers.alignment.

Isso não é "reestimar no olho" — é um bug de medição na fonte, não um julgamento seu. Na prática (somente sem layers.alignment):

  • Ao posicionar um zoom cujo start precisa cair exatamente na palavra (não uma frase inteira), some +0,3 a +0,4s ao timestamp do JSON antes de decidir, ou confira com ffmpeg -af astats se a precisão importar para o frame.
  • Não aplique essa correção a gap_before para decidir corte — a régua de silêncio (06-texto-corte-marcador.md) já é conservadora o bastante para absorver esse erro; corrigir os dois ao mesmo tempo é redundante.