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

77 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.