chore: atualização geral
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# 03 — Camada MCP (`server.py`) — 62 ferramentas
|
||||
# 03 — Camada MCP (`server.py`) — 73 ferramentas
|
||||
|
||||
`server.py` (3824 linhas) é a camada de transporte. Não tem lógica de timeline —
|
||||
mapeia nome → handler e delega ao Engine. O dispatch é um dicionário
|
||||
@@ -20,7 +20,7 @@ mapeia nome → handler e delega ao Engine. O dispatch é um dicionário
|
||||
| `_parse_timestamp_parts()` | 433 | Parse de timestamps (min:seg, H:MM:SS, SMPTE) |
|
||||
| `_detect_flash_frames/gaps/duplicate_groups()` | 1667+ | Detectores de QC |
|
||||
|
||||
## As 62 ferramentas por categoria
|
||||
## As 73 ferramentas por categoria
|
||||
|
||||
### Timeline & análise (Projeto)
|
||||
`list_projects`, `analyze_timeline`, `list_clips`, `list_markers`, `list_connected_clips`,
|
||||
@@ -57,6 +57,72 @@ mapeia nome → handler e delega ao Engine. O dispatch é um dicionário
|
||||
### Reformat
|
||||
`reformat_timeline`.
|
||||
|
||||
### Voz (análise → decisão → aplicação)
|
||||
`analyze_voice_features`, `build_voice_timeline`, `refine_voice_timeline`,
|
||||
`remove_speakers`, `apply_voice_actions`, `get_voice_analysis_config`,
|
||||
`save_voice_analysis_config`.
|
||||
|
||||
O fluxo é sempre o mesmo: `build_voice_timeline` mede (caro, roda uma vez) →
|
||||
o modelo decide os cortes → **`refine_voice_timeline` renormaliza sobre o que
|
||||
sobrou** (barato, sem reabrir áudio) e propõe as janelas de zoom → o modelo
|
||||
corta a lista pelo ritmo → `apply_voice_actions` aplica. Pular a renormalização
|
||||
faz o ranking de ênfase apontar para as palavras erradas (ver
|
||||
`05_EXPERIENCIAS.md`).
|
||||
|
||||
### Legendas dinâmicas (geração → validação → aplicação)
|
||||
`generate_dynamic_subtitles`, `validate_subtitle_layout`, `transcript_markers`.
|
||||
|
||||
**Sempre gere e depois valide — nunca dê a geração como pronta sem
|
||||
`validate_subtitle_layout`.** A composição garante "sem sobreposição" só
|
||||
*por construção* dentro do que ela mesma sabe medir; um título editado à
|
||||
mão, uma palavra fora do alcance do que foi calibrado, ou conteúdo antigo
|
||||
no mesmo arquivo escapam dessa garantia. Fluxo:
|
||||
|
||||
```
|
||||
generate_dynamic_subtitles(filepath)
|
||||
↓
|
||||
validate_subtitle_layout(output_path) ← sempre, mesmo quando "parece certo"
|
||||
↓
|
||||
severidade none/warning → entregar
|
||||
severidade probable/severe → investigar CADA colisão pela fração exata do
|
||||
XML antes de mudar código (ver checklist abaixo)
|
||||
```
|
||||
|
||||
**Antes de atribuir uma colisão ao gerador, confirme que é o gerador.**
|
||||
Um `<title>` de nome estranho (`ref` diferente, params tipo `Auto-Shrink`/
|
||||
`Left Margin` que `_make_text_title_clip` nunca escreve) é conteúdo humano
|
||||
ou de outra ferramenta, não um bug — comparar contra o arquivo original
|
||||
(`grep` pelo texto) resolve em segundos. Caso real: uma colisão "severa"
|
||||
era um título manual feito no FCP que sobrou no arquivo reaproveitado como
|
||||
base de teste (`05_EXPERIENCIAS.md`, 2026-08-19).
|
||||
|
||||
**Antes de atribuir uma colisão a uma sobreposição real, confirme pela
|
||||
fração exata do FCPXML, não pelo float arredondado.** Dois títulos que só
|
||||
se tocam na borda (um bloco some exatamente quando o próximo começa, por
|
||||
design) podem imprimir tempos "iguais" e ainda assim colidir no relatório
|
||||
por ruído de ponto flutuante — `float(a+b) != float(c)` mesmo quando as
|
||||
frações `a+b` e `c` são idênticas. `temporal_overlap()` já tem uma
|
||||
tolerância (`_BOUNDARY_EPSILON = 1e-6`, muitas ordens abaixo de um frame)
|
||||
para absorver isso; se uma colisão nova parecer nascer do nada, comparar
|
||||
`m._parse_time(...)` dos dois títulos por igualdade exata antes de
|
||||
suspeitar de sobreposição de verdade.
|
||||
|
||||
**Constantes que resolvem os três bugs já encontrados nesta área** (todas
|
||||
em `fcpxml/text_layout.py`, exceto a última):
|
||||
|
||||
| Constante | O que resolve | Por quê |
|
||||
|---|---|---|
|
||||
| `TEXT_TEMPLATE_FONT_SCALE = 2.0` | Posição e tamanho de fonte dessincronizados | O template "Text" do FCP posiciona no espaço do **frame** (2160×3840), mas o layout mede em pontos de meia-escala (1080×1920). Escalar só o tamanho da fonte e não a posição espalha o texto errado — os dois têm que ser convertidos pelo mesmo fator na saída. |
|
||||
| `_EMPHASIS_ITALIC_CUSHION_RATIO = 0.06` | Linha de corpo lendo apertada sob a linha de ênfase | O itálico da Playfair inclina as hastes além da caixa de tinta que a métrica mede; ~14pt de respiro extra só nessa fronteira corrige sem tocar no `line_gap` do resto. |
|
||||
| `fit_emphasis()` (função, não constante) | Palavra de ênfase estourando o frame inteiro | Só linhas de corpo faziam wrap contra `box.width`; a linha de ênfase (sempre uma palavra só) nunca foi checada. Uma palavra longa ou toda maiúscula podia medir mais que o frame inteiro sozinha. Encolhe `font_size`+`kerning` pelo mesmo fator até caber — nunca abaixo do tamanho do corpo, senão ênfase deixa de ser ênfase. |
|
||||
| `_BOUNDARY_EPSILON = 1e-6` (`fcpxml/collision.py`) | Falso positivo de colisão em títulos que só se tocam | Ver parágrafo acima. |
|
||||
|
||||
Detalhe de implementação e efeito medido de cada um: `05_EXPERIENCIAS.md`,
|
||||
entradas de 2026-08-19 (#15 zoom, #16 colisão por float, #17 auto-fit da
|
||||
ênfase — a #15 é do módulo de voz, não de legendas, mas mesma causa-raiz
|
||||
de fundo: um mecanismo que lê a própria saída anterior precisa continuar
|
||||
sendo fonte de verdade legível, não só efeito colateral write-only).
|
||||
|
||||
### Live (macOS)
|
||||
`push_to_fcp`, `list_fcp_libraries`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user