chore: atualização geral
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: editar-por-voz
|
||||
description: Edita um vídeo a partir da análise de voz — lê a timeline de voz (JSON) de uma gravação, separa o roteiro da conversa de bastidor, escolhe a melhor tomada de cada frase, decide cortes/zooms/textos e devolve a lista de decisões em JSON. Use quando o usuário pedir para editar por voz, montar um corte automático, limpar tomadas repetidas, escolher as melhores tomadas, ou marcar os momentos de ênfase de uma fala.
|
||||
---
|
||||
|
||||
# Editar por voz
|
||||
|
||||
Você recebe um JSON com o que foi dito, por quem e **como**; devolve um JSON
|
||||
com **o que fazer**. Quem aplica é o programa — você nunca escreve XML.
|
||||
|
||||
## Princípio
|
||||
|
||||
O sistema já mede *como* a pessoa falou, de forma reprodutível. Não
|
||||
recalcule nada disso nem reestime tempos "no olho".
|
||||
|
||||
Seu trabalho é o que nenhum limiar resolve: **o que aquilo significa.** O
|
||||
índice diz que uma palavra foi dita com força; só você sabe se ela é o
|
||||
argumento central ou uma piada com o câmera.
|
||||
|
||||
## Entrada e saída
|
||||
|
||||
**Entrada:** `<mídia>_voice_timeline.json` (de `build_voice_timeline`). Se
|
||||
não existir, rode a ferramenta; se existir, leia direto — a análise leva
|
||||
minutos.
|
||||
|
||||
**Saída:** JSON com a lista de ações → `criterios/08-formato-de-saida.md`
|
||||
|
||||
`apply_voice_actions` aplica direto, mas é para **teste**. O produto do seu
|
||||
trabalho é a lista de decisões.
|
||||
|
||||
## Ordem de trabalho
|
||||
|
||||
Siga nesta ordem. Pular a Fase 2 ou a 3 leva a decisões erradas.
|
||||
|
||||
| Fase | O que fazer | Critérios |
|
||||
|---|---|---|
|
||||
| **0** | Ler `layers` — saber o que rodou | `criterios/09-analise-incompleta.md` |
|
||||
| **1** | Ler o JSON em camadas | `criterios/01-leitura-do-json.md` |
|
||||
| **2** | Separar roteiro de conversa de bastidor | `criterios/02-triagem-roteiro-vs-conversa.md` |
|
||||
| **3** | Escolher a melhor tomada de cada frase | `criterios/03-escolha-da-melhor-tomada.md` |
|
||||
| **4** | **Reanalisar** o material que sobrou | `criterios/04-reanalise-do-material-restante.md` |
|
||||
| **5** | Decidir zooms | `criterios/05-zoom.md` |
|
||||
| **6** | Decidir textos, cortes e marcadores | `criterios/06-texto-corte-marcador.md` |
|
||||
| **7** | Cortar a lista pelo ritmo | `criterios/07-ritmo.md` |
|
||||
| **8** | Montar o JSON de saída | `criterios/08-formato-de-saida.md` |
|
||||
|
||||
## As três armadilhas
|
||||
|
||||
Cada uma já causou erro silencioso em material real:
|
||||
|
||||
1. **A conversa de bastidor tem a maior ênfase do vídeo.** O índice acústico
|
||||
favorece a fala solta sobre o texto decorado. Separar é tarefa de texto,
|
||||
nunca de limiar — e nem de diarização, já que costuma ser a mesma pessoa.
|
||||
|
||||
2. **Ênfase é relativa ao conjunto analisado.** Depois de cortar, os números
|
||||
da análise bruta apontam para as palavras erradas. Sempre reanalise
|
||||
(Fase 4) antes de escolher zooms.
|
||||
|
||||
3. **Tempos sempre na mídia original.** Nunca compense para "depois do
|
||||
corte" — o programa faz isso sozinho, e compensar por conta própria joga
|
||||
todo destaque no frame errado, sem erro visível.
|
||||
|
||||
## Ordem no sistema
|
||||
|
||||
Sua edição roda **primeiro, na timeline intacta**. Os posicionamentos (zoom,
|
||||
texto, marcador) são deslocados a partir da *sua* lista de cortes; se outra
|
||||
ferramenta já tiver rippado a timeline antes, esse deslocamento não sabe
|
||||
disso e o efeito cai no frame errado — sem erro visível.
|
||||
|
||||
```
|
||||
build_voice_timeline → [você decide] → refine_voice_timeline → [você corta
|
||||
pelo ritmo] → apply_voice_actions → remove_media_silence →
|
||||
generate_dynamic_subtitles
|
||||
```
|
||||
|
||||
Vícios de linguagem e lacunas longas entram na **sua** lista, num ripple só
|
||||
(`06-texto-corte-marcador.md`). Silêncio fino e legendas vêm depois.
|
||||
|
||||
`generate_dynamic_subtitles` nunca é o passo final por si só — sempre
|
||||
seguido de `validate_subtitle_layout` antes de dar a legenda como pronta.
|
||||
Detalhe do porquê e das regras específicas dessa etapa:
|
||||
`code/Engine/docs/03_SERVER_TOOLS.md`, seção "Legendas dinâmicas".
|
||||
|
||||
## Ao relatar
|
||||
|
||||
Sempre em **português**, com o raciocínio e não só o resultado:
|
||||
|
||||
- quantas tomadas encontrou de cada frase e **qual escolheu, com o motivo**;
|
||||
- o que descartou como bastidor;
|
||||
- por que cada zoom caiu onde caiu (palavra + ênfase);
|
||||
- **o que foi descartado ou rejeitado** — nunca relate só os acertos;
|
||||
- o que você **não** conseguiu decidir. Em dúvida entre duas tomadas,
|
||||
marque as duas e deixe para o editor.
|
||||
@@ -0,0 +1,71 @@
|
||||
# 01 — Leitura do JSON
|
||||
|
||||
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.
|
||||
|
||||
Isso não é "reestimar no olho" — é um bug de medição na fonte, não um
|
||||
julgamento seu. Na prática:
|
||||
|
||||
- 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.
|
||||
- Se um dia o pipeline ganhar alinhamento forçado (WhisperX), este aviso
|
||||
perde a razão de existir — confira se `layers` ou a versão do documento
|
||||
já indicam isso antes de aplicar o offset manualmente.
|
||||
@@ -0,0 +1,51 @@
|
||||
# 02 — Triagem: roteiro vs. conversa de bastidor
|
||||
|
||||
**Primeira coisa a fazer, antes de qualquer decisão de efeito.**
|
||||
|
||||
Material bruto de gravação quase nunca é uma tomada só. A pessoa lê o
|
||||
roteiro, erra, conversa com a equipe e recomeça.
|
||||
|
||||
## Por que isso é tarefa sua, e não do sistema
|
||||
|
||||
No áudio essa separação é **invisível** — e pior: o índice de ênfase
|
||||
*favorece* a conversa, que é mais solta e mais alta que o texto decorado.
|
||||
|
||||
Caso real: a fala mais enfática de um vídeo inteiro (energia **1,00**, o
|
||||
topo absoluto da gravação) era *"Amor, eu tô intacto!"*, dita para o marido
|
||||
fora de quadro. Três das sete palavras de maior ênfase do vídeo vinham
|
||||
dessa única frase de bastidor.
|
||||
|
||||
Nenhum limiar acústico separa isso. O **texto** separa sem erro.
|
||||
|
||||
> Atenção: isso também **não é diarização**. Num caso real, a pessoa da
|
||||
> equipe estava fora do microfone — a diarização a ouvia, mas o Whisper não
|
||||
> a transcrevia. As falas a descartar eram da **própria protagonista**:
|
||||
> mesma voz, contexto diferente. "Quem fala" e "isso é tomada válida" são
|
||||
> perguntas diferentes.
|
||||
|
||||
## Descartar — conversa com a equipe
|
||||
|
||||
Reconhece-se pelo **conteúdo**:
|
||||
|
||||
- **vocativo para alguém da sala** — *"Amor, eu tô intacto!"*
|
||||
- **pergunta operacional** — *"Posso começar da mastopexia?"*,
|
||||
*"E aí, continua?"*, *"Mas eu vou ter que falar tudo de novo?"*
|
||||
- **instrução técnica** — *"Só clica aí agora na tela."*, *"Aumenta."*
|
||||
- **comentário sobre a própria gravação** — *"Vou falar só a última frase,
|
||||
só um pouquinho, não pegou?"*
|
||||
|
||||
## Descartar — frases interrompidas
|
||||
|
||||
Texto que morre no meio, tipicamente em reticências ou emendando numa
|
||||
pergunta:
|
||||
|
||||
- *"E tudo isso associado à medida..."*
|
||||
- *"Aquela mama com um formato mais estruturado, com o colo que..."*
|
||||
- *"de pele..."*
|
||||
|
||||
## Sinais estruturais que ajudam
|
||||
|
||||
Use `take_boundary` para achar onde cada tomada recomeça. Num material
|
||||
real, as fronteiras (gaps de 3,6s a 19,8s) caíam exatamente nos pontos onde
|
||||
a médica reiniciava o roteiro — inclusive nas duas retomadas da frase de
|
||||
abertura.
|
||||
@@ -0,0 +1,60 @@
|
||||
# 03 — Escolha da melhor tomada
|
||||
|
||||
A mesma frase costuma aparecer 2, 3, 4 vezes. Seu trabalho é ficar com
|
||||
**uma**.
|
||||
|
||||
## Como agrupar
|
||||
|
||||
1. Use `take_boundary` para localizar onde cada tomada recomeça.
|
||||
2. Agrupe as repetições **pelo texto**, não pelo tempo — a mesma frase
|
||||
reaparece em pontos distantes da gravação. Num caso real, a abertura
|
||||
*"Aquela mama com um formato mais estruturado"* apareceu aos 2,0s, 64,9s
|
||||
e 86,4s.
|
||||
|
||||
## Critérios, nesta ordem
|
||||
|
||||
### 1. Completa
|
||||
Não morre no meio, não emenda numa pergunta. Uma tomada incompleta está
|
||||
descartada por definição, mesmo que a dicção seja ótima.
|
||||
|
||||
### 2. Dicção limpa
|
||||
Sem tropeço, sem repetição de palavra, sem vício de linguagem. **Compare os
|
||||
textos lado a lado:**
|
||||
|
||||
| Tomada 1 | Tomada 3 | Escolha |
|
||||
|---|---|---|
|
||||
| *"isso é desejo de muitas mulheres"* | *"**aí** isso é desejo de muitas mulheres"* | Tomada 1 |
|
||||
|
||||
### 3. Formulação melhor
|
||||
Quando as duas estão limpas, prefira a mais direta — normalmente a última,
|
||||
porque é onde a pessoa já se ajustou:
|
||||
|
||||
| Antes | Depois | Escolha |
|
||||
|---|---|---|
|
||||
| *"a gente **faz a inserção de** próteses"* | *"a gente **insere** próteses"* | a segunda |
|
||||
| *"reestrutura a mama"* | *"reestrutura a **sua** mama"* | a segunda |
|
||||
|
||||
### 4. Entrega
|
||||
**Só então** desempate por `avg_energy` / `peak_emphasis`.
|
||||
|
||||
Quando duas tomadas têm texto **idêntico palavra por palavra**, aí a
|
||||
energia decide sozinha — é o único sinal disponível. Caso real: o fecho
|
||||
tinha duas tomadas iguais, energia **0,38** e **0,19**. A de 0,38 é a boa,
|
||||
e o texto sozinho jamais diria isso.
|
||||
|
||||
## Regra de ouro
|
||||
|
||||
A **última** tomada costuma ser a melhor — é onde a pessoa acertou. Mas
|
||||
**confirme lendo o texto**; nunca assuma.
|
||||
|
||||
## Quando estiver em dúvida
|
||||
|
||||
Não decida no escuro. Coloque um `marker` nas duas candidatas, explique a
|
||||
dúvida no `reason`, e deixe a escolha para o editor humano.
|
||||
|
||||
## Continuidade
|
||||
|
||||
Ao montar o corte final você pode misturar blocos de tomadas diferentes —
|
||||
abertura da tomada 1, corpo da tomada 3. Isso é normal. Mas **avise nas
|
||||
emendas**: coloque um `marker` em cada junção para o editor conferir se o
|
||||
enquadramento e a posição da pessoa combinam.
|
||||
@@ -0,0 +1,70 @@
|
||||
# 04 — Reanálise do material que sobrou
|
||||
|
||||
**Não escolha zooms com os números da análise bruta.**
|
||||
|
||||
## O problema
|
||||
|
||||
Ênfase e energia são **relativas ao conjunto analisado**. Energia é
|
||||
normalizada contra o momento mais alto da gravação; ênfase deriva dela.
|
||||
|
||||
Se esse momento mais alto foi cortado — uma piada, um grito, uma conversa
|
||||
de bastidor — tudo que sobrou continua pontuado contra uma referência que o
|
||||
espectador **nunca verá**. As notas do corte final ficam artificialmente
|
||||
comprimidas, e o ranking aponta para as palavras erradas.
|
||||
|
||||
Caso real: o pico do vídeo era *"Amor, eu tô intacto!"* (energia 1,00),
|
||||
descartado na triagem. Todo o material restante estava sendo medido contra
|
||||
ele.
|
||||
|
||||
## A solução
|
||||
|
||||
Depois de definir os cortes, renormalize sobre os sobreviventes. Chame a
|
||||
ferramenta **`refine_voice_timeline`**, passando a mídia e a lista de
|
||||
cortes que você já decidiu:
|
||||
|
||||
```
|
||||
refine_voice_timeline(media_path, cuts=[{start, end}, ...], min_gap=8.0)
|
||||
```
|
||||
|
||||
Ela devolve, numa chamada só, a comparação bruto × sobreviventes, os picos
|
||||
re-ranqueados e os candidatos a zoom. É barata: renormaliza os números já
|
||||
medidos, sem reabrir o áudio.
|
||||
|
||||
Efeito medido no mesmo material:
|
||||
|
||||
| | Bruto | Só o que sobrou |
|
||||
|---|---|---|
|
||||
| Ênfase média | 0,179 | **0,197** |
|
||||
| *"Aquela"* | 0,39 | **0,42** |
|
||||
| *"mastopexia"* | 0,26 | **0,34** |
|
||||
| *"devolver"* | — | **0,35** |
|
||||
|
||||
*"mastopexia"* só virou candidata legítima depois da reanálise.
|
||||
|
||||
## As janelas que ela propõe
|
||||
|
||||
A seção **Zoom Candidates** da resposta já vem com três coisas resolvidas:
|
||||
|
||||
1. **Pega a palavra de conteúdo mais enfática de cada frase.** Artigos e
|
||||
conectivos são filtrados — um *"a"* falado alto continua sendo um artigo.
|
||||
Sem esse filtro, o ranking bruto apontava para "o", "a", "eu": picos de
|
||||
*entrega*, não de *sentido*.
|
||||
2. **Estende a janela até o fim da frase**, não do segmento (ver
|
||||
`05-zoom.md`).
|
||||
3. **Mantém distância mínima** entre zooms.
|
||||
|
||||
São **candidatos, não obrigações.** Corte a lista pelo ritmo
|
||||
(`07-ritmo.md`). Os tempos continuam na mídia original — vão direto para
|
||||
`apply_voice_actions`.
|
||||
|
||||
`max_zooms` limita a lista, mas prefira cortá-la você mesmo: o corte por
|
||||
ritmo é decisão editorial, não um teto numérico.
|
||||
|
||||
## Princípio geral
|
||||
|
||||
> "Qual o momento mais forte da **gravação**?" e "qual o momento mais forte
|
||||
> do **vídeo final**?" são perguntas diferentes sempre que a métrica for
|
||||
> relativa.
|
||||
|
||||
Toda métrica normalizada precisa ser recalculada quando o conjunto muda —
|
||||
senão ela responde a pergunta errada, silenciosamente.
|
||||
@@ -0,0 +1,71 @@
|
||||
# 05 — Zoom (punch-in)
|
||||
|
||||
## Quando usar
|
||||
|
||||
No momento em que o argumento vira. Um pico acústico só merece zoom se for
|
||||
também um pico **de sentido**.
|
||||
|
||||
Palavra gritada sem peso narrativo não ganha nada — e isso inclui os picos
|
||||
que caem em artigos e conectivos, que são picos de entrega, não de conteúdo.
|
||||
|
||||
## A janela
|
||||
|
||||
**`start`** — na palavra de ênfase.
|
||||
|
||||
**`end`** — no **fim da frase**. A frase inteira, não o fim do segmento da
|
||||
transcrição.
|
||||
|
||||
O Whisper corta frases no meio, por respiração e não por gramática:
|
||||
|
||||
> *"Aquela mama com um formato mais estruturado, que valoriza o seu colo,
|
||||
> que dá aquele ar"* **|** *"de elegância, isso é desejo de muitas mulheres,
|
||||
> né?"*
|
||||
|
||||
Soltar o zoom no fim do primeiro segmento libera **no meio do pensamento** —
|
||||
é o que faz um punch-in parecer arbitrário. `suggest_zoom_windows` já
|
||||
estende até a pontuação final (`.` `!` `?` `…`), e nunca atravessa uma
|
||||
fronteira de tomada.
|
||||
|
||||
## A forma — o programa decide sozinho
|
||||
|
||||
Você escolhe `start` e `end`; a forma sai da posição da janela dentro do
|
||||
trecho:
|
||||
|
||||
| Situação | Comportamento | Por quê |
|
||||
|---|---|---|
|
||||
| Começa a **>0,5s** do início do trecho | entrada rápida (~0,25s) | o movimento chega junto com a palavra |
|
||||
| Começa a **≤0,5s** do início | **entra já ampliado, sem transição** | o corte já foi a transição; uma rampa ali lê como a imagem se acomodando |
|
||||
| Frase termina no meio do trecho | **saída seca**, 1 frame | volta ao enquadramento sem chamar atenção |
|
||||
| Frase termina a **≤1s** do corte | **não volta** — segura até o corte | o próximo trecho já abre no enquadramento dele; voltar antes é movimento desperdiçado |
|
||||
|
||||
Os limiares são diferentes de propósito: no fim o corte esconde um retorno
|
||||
inacabado, mas no início a rampa é visível desde o primeiro frame.
|
||||
|
||||
Para forçar manualmente, existem `start_at_peak` e `hold_at_end` — mas o
|
||||
automático acerta na quase totalidade dos casos.
|
||||
|
||||
## Escala
|
||||
|
||||
| Valor | Uso |
|
||||
|---|---|
|
||||
| 1,15 | sutil |
|
||||
| 1,18 – 1,3 | padrão |
|
||||
| 1,5 | forte |
|
||||
|
||||
Em vídeo institucional, fique na faixa baixa. Acima de 3,0 é rejeitado.
|
||||
|
||||
O zoom é **relativo ao enquadramento existente**: se o clipe já tem escala
|
||||
1,77 (material gravado de lado e reenquadrado), um zoom 1,18 anima de 1,77
|
||||
para 2,09 e preserva rotação e posição.
|
||||
|
||||
## Dois zooms no mesmo clipe
|
||||
|
||||
Depois do corte, dois picos que você escolheu podem cair no **mesmo**
|
||||
trecho sobrevivente (nenhum corte os separou em clipes distintos) — é
|
||||
comum quando a corrida limpa de uma tomada é longa. O sistema resolve isso
|
||||
sozinho, e a regra é a mesma que rege o resto: janelas **distantes**
|
||||
empilham (os dois zooms convivem, cada um voltando ao enquadramento real
|
||||
entre um e outro); janelas que **se sobrepõem** substituem (é o mesmo
|
||||
evento sendo reajustado, não dois). Você não precisa calcular isso na
|
||||
hora de decidir — só respeitar o `min_gap` de `07-ritmo.md`, que já
|
||||
garante que dois zooms escolhidos por você nunca se sobrepõem.
|
||||
@@ -0,0 +1,88 @@
|
||||
# 06 — Texto, corte e marcador
|
||||
|
||||
## Texto
|
||||
|
||||
Para fixar um **conceito, número ou nome** que o espectador precisa reter.
|
||||
|
||||
- Use a palavra **dita**, não uma paráfrase.
|
||||
- Curta, em caixa alta. Até 120 caracteres (é truncado além disso).
|
||||
- Uma por frase, no máximo.
|
||||
|
||||
**Não legende a frase inteira.** Para isso existe
|
||||
`generate_dynamic_subtitles`, que é outra ferramenta e outro propósito.
|
||||
|
||||
Boas candidatas são as palavras-chave que sobram depois de filtrar as
|
||||
funcionais — num caso real: *mastopexia*, *flacidez*, *próteses*,
|
||||
*devolver*, *desejo*.
|
||||
|
||||
## Corte
|
||||
|
||||
Digressão, repetição, frase abandonada, conversa de bastidor, tomada pior —
|
||||
e mais duas coisas que **são** seu trabalho, ao contrário do que parece.
|
||||
|
||||
### Vícios de linguagem entram na sua lista
|
||||
|
||||
Não delegue para `remove_filler_words`. Você já está percorrendo palavra por
|
||||
palavra na triagem; marcar as muletas é uma linha a mais, sem custo. E você
|
||||
tem o que a lista fixa não tem: **contexto**.
|
||||
|
||||
Um *"tipo"* em *"tipo assim, sabe"* é muleta. Em *"esse tipo de cirurgia"*
|
||||
é a palavra principal. Um *"não não não"* pode ser gagueira ou ênfase. A
|
||||
lista fixa não distingue; você distingue.
|
||||
|
||||
### Lacunas longas entram na sua lista — curtas, nunca
|
||||
|
||||
**O tamanho da lacuna muda o que ela é.** A régua está medida em material
|
||||
real (`pause_weight()` em `emphasis.py`, `TAKE_BOUNDARY_GAP` em
|
||||
`voice_timeline.py`):
|
||||
|
||||
| `pause_before` | O que é | O que fazer |
|
||||
|---|---|---|
|
||||
| até ~1,5s | o falante montando a frase — **isso É a ênfase** | **nunca cortar** |
|
||||
| 1,5–3s | zona cinza | julgue pela frase |
|
||||
| acima de 3s | troca de tomada, ar morto, outra pessoa falando | **cortar** |
|
||||
|
||||
Cortar a pausa curta é o erro grave: ela é uma das cinco entradas do índice
|
||||
de ênfase, então você estaria apagando justamente a batida que faz a palavra
|
||||
seguinte pontuar alto. Uma frase fluida não se aperta.
|
||||
|
||||
Acima de 3s a pausa deixa de contar como ênfase por construção — medido em
|
||||
material real, lacunas de 6–9s rankeavam como os momentos mais enfáticos da
|
||||
gravação só porque a escala saturava.
|
||||
|
||||
### O que continua NÃO sendo seu trabalho
|
||||
|
||||
| Tarefa | Ferramenta | Por quê |
|
||||
|---|---|---|
|
||||
| Apertar o ar **dentro** da fala | `remove_media_silence` | Lê o áudio real com ffmpeg; você só tem os intervalos entre palavras transcritas |
|
||||
|
||||
E cuidado: **ausência de fala não é ausência de som.** Respiração, riso,
|
||||
suspiro, a reação depois da frase — nada disso vira palavra, então aparece
|
||||
como lacuna, e às vezes é o melhor frame do vídeo. Lacuna longa é candidata
|
||||
a corte, não corte automático.
|
||||
|
||||
`remove_media_silence` roda **depois** de `apply_voice_actions`, como
|
||||
acabamento opcional, sobre o material que sobrou.
|
||||
|
||||
**Antes de rodar `remove_media_silence` sobre o corte final, sempre rode a
|
||||
detecção primeiro** (sem aplicar) e leia os spans um a um contra a régua
|
||||
acima. O detector corta por limiar de dB — ele não sabe distinguir "batida
|
||||
de 0,8s entre duas frases", que a régua protege, de "ar morto de emenda",
|
||||
que deveria ser apertado. Aplicar direto, sem essa checagem, é o mesmo erro
|
||||
de cortar pausa curta, só que por outra ferramenta.
|
||||
|
||||
## Marcador
|
||||
|
||||
Quando você quer **sinalizar para o editor humano decidir**, em vez de
|
||||
decidir por ele.
|
||||
|
||||
Use em:
|
||||
|
||||
- **Emendas entre tomadas** — sempre. O editor precisa conferir se o
|
||||
enquadramento e a posição da pessoa combinam na junção.
|
||||
- **Dúvida entre duas tomadas** — marque as duas, explique no `reason`.
|
||||
- **Momentos que talvez mereçam efeito** mas que você não tem confiança
|
||||
para decidir.
|
||||
|
||||
Marcador é um **ponto**, não um trecho: sobrevive mesmo encostado na borda
|
||||
de um corte, o que é justamente o caso das emendas.
|
||||
@@ -0,0 +1,37 @@
|
||||
# 07 — Ritmo
|
||||
|
||||
**O erro mais comum é efeito demais.** Cansa mais que efeito de menos, e
|
||||
denuncia edição automática.
|
||||
|
||||
## Limites
|
||||
|
||||
| Regra | Valor |
|
||||
|---|---|
|
||||
| Distância mínima entre dois zooms | **8–10 segundos** |
|
||||
| Zooms por minuto de vídeo | **2 a 4** (teto) |
|
||||
| Zoom + texto no mesmo instante | só com motivo claro |
|
||||
|
||||
Se dois picos estiverem colados, **escolha o mais forte e abra mão do
|
||||
outro**. Não tente encaixar os dois.
|
||||
|
||||
## Candidatos ≠ obrigações
|
||||
|
||||
`suggest_zoom_windows` devolve uma lista de candidatos. Normalmente você usa
|
||||
uma **fração** dela.
|
||||
|
||||
Caso real: num corte de 47,6s a ferramenta sugeriu **5** janelas. O certo
|
||||
foram **3** — 5 violaria o teto de 2–4 por minuto. Ficaram a abertura, o
|
||||
termo central e o fecho; as duas descartadas eram frases de apoio.
|
||||
|
||||
O mesmo vale para `peak_moments` no `summary`: é lista de candidatos.
|
||||
|
||||
## Como escolher quais manter
|
||||
|
||||
Quando precisar cortar a lista, priorize por **função narrativa**, não por
|
||||
nota:
|
||||
|
||||
1. **A abertura** — prende o espectador.
|
||||
2. **O conceito central** — o termo que o vídeo existe para explicar.
|
||||
3. **O fecho** — a frase que fica.
|
||||
|
||||
Só depois disso, as frases de apoio, por ordem de ênfase.
|
||||
@@ -0,0 +1,65 @@
|
||||
# 08 — Formato de saída
|
||||
|
||||
O produto do seu trabalho é **este JSON**. É ele que vai para o programa
|
||||
gerar o FCPXML. Você nunca escreve XML.
|
||||
|
||||
## Estrutura
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "0E6A8290.mp4",
|
||||
"actions": [
|
||||
{"kind": "cut", "start": 21.9, "end": 127.6,
|
||||
"reason": "tomadas descartadas, frases interrompidas e conversa com a equipe"},
|
||||
{"kind": "zoom", "start": 2.0, "end": 10.7,
|
||||
"params": {"scale": 1.15}, "reason": "abertura: \"Aquela mama\" (ênfase 0.42)"},
|
||||
{"kind": "text", "start": 127.7, "end": 129.0,
|
||||
"params": {"content": "MASTOPEXIA"}, "reason": "fixa o termo central"},
|
||||
{"kind": "marker", "start": 21.85, "end": 22.0,
|
||||
"reason": "EMENDA 1 — conferir junção entre tomadas"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Regras
|
||||
|
||||
### 1. Tempos em segundos da mídia ORIGINAL
|
||||
Exatamente como aparecem no `voice_timeline.json`.
|
||||
|
||||
**Nunca compense para "depois do corte".** O programa faz esse deslocamento
|
||||
sozinho: ele resolve os cortes primeiro e reposiciona todo o resto. Se você
|
||||
compensar por conta própria, **todo destaque cai no frame errado** — e o
|
||||
erro é silencioso.
|
||||
|
||||
### 2. `end` sempre maior que `start`
|
||||
Ambos ≥ 0. Um `end <= start` é rejeitado.
|
||||
|
||||
### 3. Tipos
|
||||
`cut` · `zoom` · `text` · `marker`
|
||||
|
||||
### 4. Parâmetros por tipo
|
||||
|
||||
| Tipo | `params` |
|
||||
|---|---|
|
||||
| `cut` | nenhum |
|
||||
| `zoom` | `scale` entre 1.0 e 3.0 (padrão 1.3 se omitido) |
|
||||
| `text` | `content` **obrigatório**, até 120 caracteres |
|
||||
| `marker` | opcional: `content` vira o nome do marcador |
|
||||
|
||||
### 5. `reason` — sempre preencha
|
||||
É o que o usuário lê para revisar sua decisão, e o que te obriga a **ter**
|
||||
uma. Um `reason` vazio é sinal de decisão sem critério.
|
||||
|
||||
Inclua o dado que embasou: *"abertura: 'Aquela mama' (ênfase 0.42)"* é útil;
|
||||
*"zoom"* não é.
|
||||
|
||||
## Como o programa trata erros
|
||||
|
||||
- **Ação inválida** → rejeitada e reportada **individualmente**. Uma linha
|
||||
malformada nunca derruba as outras.
|
||||
- **Ação apontando para material cortado** → descartada e reportada, nunca
|
||||
deslizada para o conteúdo vizinho.
|
||||
- **Ação fora da mídia** → reportada como não colocada.
|
||||
|
||||
Você recebe o relatório dos três casos. **Repasse ao usuário** — nunca
|
||||
relate só os acertos.
|
||||
@@ -0,0 +1,48 @@
|
||||
# 09 — Quando a análise veio incompleta
|
||||
|
||||
O bloco `layers` no topo do JSON diz **o que de fato rodou**. Leia antes de
|
||||
qualquer outra coisa.
|
||||
|
||||
```json
|
||||
"layers": {"transcript": true, "acoustics": false, "speakers": false}
|
||||
```
|
||||
|
||||
## Por que esse bloco existe
|
||||
|
||||
Fala monótona e acústica que não carregou deixam **os mesmos zeros** nos
|
||||
dados. Sem o `layers`, é impossível distinguir "esta pessoa fala de forma
|
||||
uniforme" de "a análise acústica falhou".
|
||||
|
||||
## Os casos
|
||||
|
||||
### `acoustics: false`
|
||||
Todos os valores acústicos são 0. **Você não tem ênfase real.**
|
||||
|
||||
- Decida só pelo texto.
|
||||
- **Avise o usuário** explicitamente.
|
||||
- Prefira `marker` a `zoom` — sinalize em vez de decidir.
|
||||
|
||||
Causa comum: o componente librosa não está instalado, ou o ffmpeg não
|
||||
conseguiu extrair o áudio do container.
|
||||
|
||||
### `speakers: false` num vídeo com várias pessoas
|
||||
A diarização não rodou — falta o token do HuggingFace (aba Modelos do app).
|
||||
|
||||
- Avise antes de tratar tudo como uma voz só.
|
||||
- Lembre que isso **não impede** a triagem roteiro/conversa, que é feita
|
||||
pelo texto (ver `02-triagem-roteiro-vs-conversa.md`).
|
||||
|
||||
### `peak_count: 0`
|
||||
Nada cruzou o piso de ênfase. Duas causas possíveis:
|
||||
|
||||
1. A fala é uniforme mesmo — material sem picos.
|
||||
2. O limiar está alto para esse material.
|
||||
|
||||
Sugira ajustar em **Análise de Voz** no app. **Não force destaques
|
||||
inexistentes** só para entregar alguma coisa.
|
||||
|
||||
## Regra geral
|
||||
|
||||
Não finja precisão que você não tem. Uma edição entregue com a ressalva
|
||||
certa é útil; uma entregue como se estivesse completa, quando metade dos
|
||||
dados faltou, custa a confiança do usuário no sistema inteiro.
|
||||
Reference in New Issue
Block a user