feat: corrigido o KeyError 'totalTracks' no cliente MCP: extração

- corrigido o KeyError 'totalTracks' no cliente MCP: extração de structuredContent.data na resposta do servidor (SDK 2.0+)
- sincronizado cortes de vídeo e áudio usando razor_all_tracks em vez de split_clip por faixa, eliminando drift entre cortes
- atualizado hook para usar razor_all_tracks, isolando vídeo e áudio no mesmo instante
- adicionado simulador razor_all_tracks no dublê de teste

Resumo:
- 5 arquivos alterados
- 0 novos
- 5 modificados
- 0 removidos

 5 files changed, 264 insertions(+), 12 deletions(-)

Arquivos:
  - .jhonny/analises.db
  - code/engine/editor/aplicador_de_plano_de_edicao.py
  - code/engine/editor/escrita/escrita_no_editor.py
  - code/engine/integracoes/visual/apple_vision_runner.swift
  - code/engine/testes/duplos_de_premiere.py
This commit is contained in:
João Henrique
2026-09-10 17:31:10 -04:00
parent fc7310be39
commit 2c11ba8dda
5 changed files with 264 additions and 12 deletions
+41
View File
@@ -111,6 +111,7 @@ class ClienteMCPFalso(ClienteMCP):
"add_track": self._simular_add_track,
"set_playhead_position": self._simular_set_playhead_position,
"add_adjustment_layer": self._simular_add_adjustment_layer,
"razor_all_tracks": self._simular_razor_all_tracks,
"get_clip_at_position": self._simular_get_clip_at_position,
"trim_clip": self._simular_trim_clip,
"move_clip": self._simular_move_clip,
@@ -223,6 +224,46 @@ class ClienteMCPFalso(ClienteMCP):
f"No clip strictly spans {instante}s on track {identificador_da_faixa}."
)
def _simular_razor_all_tracks(self, argumentos: dict[str, Any]) -> dict[str, Any]:
"""Divide todos os clipes de todas as faixas no instante informado.
Reproduz o ``razor_all_tracks`` do bridge real: corta todas as faixas
de vídeo e/ou áudio no mesmo ponto de tempo, garantindo
sincronização entre elas.
"""
instante_pedido = float(argumentos["time_seconds"])
track_type = argumentos.get("track_type", "both")
cortados = 0
self._salvar_estado()
for identificador_da_faixa, faixa in self._faixas.items():
if track_type == "video" and not identificador_da_faixa.startswith("video_"):
continue
if track_type == "audio" and not identificador_da_faixa.startswith("audio_"):
continue
for posicao, clipe in enumerate(faixa):
if clipe.inicio_na_timeline < instante_pedido < clipe.fim_na_timeline:
instante = min(
max(instante_pedido + self.desvio_do_split, clipe.inicio_na_timeline + 0.001),
clipe.fim_na_timeline - 0.001,
)
deslocamento = instante - clipe.inicio_na_timeline
self._proximo_id += 1
parte_esquerda = _ClipeFalso(
f"{clipe.identificador}_esq{self._proximo_id}", clipe.nome,
clipe.inicio_na_timeline, instante,
clipe.inicio_na_origem, clipe.inicio_na_origem + deslocamento,
)
self._proximo_id += 1
parte_direita = _ClipeFalso(
f"{clipe.identificador}_dir{self._proximo_id}", clipe.nome,
instante, clipe.fim_na_timeline,
clipe.inicio_na_origem + deslocamento, clipe.fim_na_origem,
)
faixa[posicao:posicao + 1] = [parte_esquerda, parte_direita]
cortados += 1
break
return {"razored": cortados, "verified": True}
def _simular_ripple_delete(self, argumentos: dict[str, Any]) -> dict[str, Any]:
"""Remove o clipe pedido e fecha o espaço deixado na mesma faixa."""
identificador_do_clipe = argumentos["node_id"]