chore(fase0): higiene do repositório + corrige gitignore que escondia fcpxml/models/

Fase 0 do roteiro de reestruturação (Engine/docs/10_MAPA_REESTRUTURACAO.md):
move code/WHISPERX (2,6 GB de backups órfãos, sem uso ativo, sem
.gitmodules) para ~/Archives/G-ART-WHISPERX-backup fora do workspace git;
traz admin/ para o gate de lint de run_after_fix.sh; corrige
fcpxml/writer/adjustment.py, que gerava um wrapper <adjustment> inexistente
no DTD 1.13 (filtros agora vão direto no <clip>, na ordem exigida), com
teste de regressão novo.

Achado à parte: .gitignore tinha uma regra solta "models/" (pensada só
para o cache do Whisper em code/models/) que também escondia do git todo o
pacote fcpxml/models/ — nunca commitado, sem proteção nenhuma. Corrigida
para /code/models/, ancorada na raiz.

Docs atualizados no mesmo commit (02_MODULES, 09_MANUTENCAO,
10_MAPA_REESTRUTURACAO, 05_EXPERIENCIAS #34 e #36), conforme a regra do
CLAUDE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
João Henrique
2026-09-23 08:28:44 -04:00
co-authored by Claude Sonnet 5
parent 0fdfe33613
commit d13f643ebc
19 changed files with 2013 additions and 29 deletions
+80 -5
View File
@@ -68,6 +68,39 @@ Commands:
-> {"ok": true, "review_path", "actions_path", "emphasis_count",
"removed_count"}
build_speaker_review {"voice_timeline": "..._voice_timeline.json", "fresh": false}
Runs right after `analyze_voice` (wizard step 3): who was detected
(with speaking share and sample lines, default active/kept) plus one
row per transcript segment, for a naming + mute + strike-line screen
before anything reaches the AI. A review saved earlier is merged
back on top unless `fresh` is true.
-> {"ok": true, "reused": bool, "source", "duration", "video_type",
"speakers": [{id, name, display_name, speaking_seconds, share,
segment_count, avg_segment, word_count, samples,
active}],
"segments": [{id, start, end, speaker, text, excluded, words}]}
recalc_speaker_review {"voice_timeline": "...", "speakers": [...],
"segments": [...], "video_type": ""}
Reruns the same filter+recompute `save_speaker_review` persists to
_voice_timeline_clean.json, but writes nothing — a live preview for
the "Recalcular" button so muting a speaker or striking a line
updates the emphasis/peak numbers shown (pure math over the words
that survived; no new audio pass).
-> {"ok": true, "duration", "peak_count",
"segments": [{start, end, speaker, text, words, ...}]}
save_speaker_review {"voice_timeline": "...", "speakers": [...],
"segments": [...], "video_type": "", "source": "...",
"duration": 0.0}
Writes _speaker_review.json (the decisions) and
_voice_timeline_clean.json (inactive speakers + struck lines
removed) — the raw _voice_timeline.json is never touched. From here
on, `copyForChat` and `generate_voice_script` should prefer the
_clean file when it exists.
-> {"ok": true, "review_path", "clean_path", "active_speakers",
"muted_speakers", "excluded_segments"}
generate_voice_script {"media_path": "...", "voice_timeline": "...", "filepath": "...",
"model": "gemma3:12b", "base_url": "http://localhost:11434",
"model_size": "base", "language": "pt"|"auto"|null,
@@ -90,15 +123,46 @@ Commands:
-> {"ok": true, "models": ["gemma3:12b", ...]}
dynamic_subtitle_config {}
Compat: style of the FIRST ACTIVE registered layout (no id/name/
active). Prefer list_dynamic_subtitle_layouts for the app's UI.
-> {"ok": true, "band_height", "block_center_y", "line_gap", "font",
"font_size", "emphasis_font", "emphasis_face", "emphasis_size",
"active_color", "emphasis_color", "text_scale"}
set_dynamic_subtitle_config {<any of the fields above>}
Persists only the given fields to ~/.fcp-mcp-server/config.json.
generate_dynamic_subtitles reads this as its own fallback default.
Compat: persists style fields onto the first active layout. Prefer
update_dynamic_subtitle_layout for the app's UI.
-> {"ok": true, <same shape as dynamic_subtitle_config>}
list_dynamic_subtitle_layouts {}
All registered "Legendas Dinâmicas" layouts. A single global config
used to hold ONE style; it's now a list of named, independently
toggleable layouts. With 2+ marked `active`, generate_dynamic_subtitles
randomly samples one per subtitle block, alternating styles through
the video. With 0 active, the first registered layout is used.
-> {"ok": true, "layouts": [{"id", "name", "active", "band_height",
"block_center_y", "line_gap", "font", "font_size",
"emphasis_font", "emphasis_face", "emphasis_size",
"active_color", "emphasis_color", "text_scale", "role"}, ...]}
create_dynamic_subtitle_layout {"name": "...", <any style field above>}
Registers a new layout, active by default. Omitted style fields fall
back to the same defaults as the very first layout.
-> {"ok": true, "layout": {...}}
update_dynamic_subtitle_layout {"id": "...", <name/active/style fields>}
Updates only the given fields of one registered layout.
-> {"ok": true, "layout": {...}} or {"ok": false, "error": "..."}
delete_dynamic_subtitle_layout {"id": "..."}
Removes a layout. If it was the last one, a "Padrão" layout is
recreated automatically so there is always at least one registered.
-> {"ok": true, "layouts": [...]}
set_dynamic_subtitle_layout_active {"id": "...", "active": true}
Toggles one layout's active flag.
-> {"ok": true, "layout": {...}}
silence_config {}
-> {"ok": true, "noise_db": -30.0, "min_silence": 0.5, "padding": 0.05}
@@ -108,7 +172,10 @@ Commands:
-> {"ok": true, <same shape as silence_config>}
transcribe {"path": "...", "model": "small", "language": "pt"|null,
"hf_token": "..."|null, "num_speakers": ""|null}
"hf_token": "..."|null, "num_speakers": ""|null,
"force": true|false}
`force: true` ignores the existing transcript cache and overwrites it
with a fresh transcription. The default is false.
-> JSON-lines:
{"type":"progress","fraction":0.5,"stage":"Transcrevendo..."}
{"type":"result","transcripts":[{"media","language","words",
@@ -184,7 +251,7 @@ _REPO_ROOT = str(Path(__file__).resolve().parent.parent)
if _REPO_ROOT not in sys.path:
sys.path.insert(0, _REPO_ROOT)
from admin.api import (
from admin.api import ( # noqa: E402
editing,
models,
project,
@@ -194,7 +261,7 @@ from admin.api import (
voice,
zoom,
)
from admin.api.shared import emit # noqa: F401
from admin.api.shared import emit # noqa: E402,F401
def main() -> int:
@@ -238,6 +305,11 @@ def main() -> int:
"analyze_voice": voice.cmd_analyze_voice,
"dynamic_subtitle_config": subtitles.cmd_dynamic_subtitle_config,
"set_dynamic_subtitle_config": subtitles.cmd_set_dynamic_subtitle_config,
"list_dynamic_subtitle_layouts": subtitles.cmd_list_dynamic_subtitle_layouts,
"create_dynamic_subtitle_layout": subtitles.cmd_create_dynamic_subtitle_layout,
"update_dynamic_subtitle_layout": subtitles.cmd_update_dynamic_subtitle_layout,
"delete_dynamic_subtitle_layout": subtitles.cmd_delete_dynamic_subtitle_layout,
"set_dynamic_subtitle_layout_active": subtitles.cmd_set_dynamic_subtitle_layout_active,
"plain_subtitle_config": subtitles.cmd_plain_subtitle_config,
"set_plain_subtitle_config": subtitles.cmd_set_plain_subtitle_config,
"apply_voice_actions": voice.cmd_apply_voice_actions,
@@ -245,6 +317,9 @@ def main() -> int:
"list_ollama_models": voice.cmd_list_ollama_models,
"build_phrase_review": review.cmd_build_phrase_review,
"save_phrase_review": review.cmd_save_phrase_review,
"build_speaker_review": review.cmd_build_speaker_review,
"recalc_speaker_review": review.cmd_recalc_speaker_review,
"save_speaker_review": review.cmd_save_speaker_review,
"project_config": project.cmd_project_config,
"set_project_config": project.cmd_set_project_config,
"silence_config": editing.cmd_silence_config,