"""Revisão de frases: montar a tela de ênfases e salvar o que foi decidido. Extraído de models_api.py — a tabela de comandos segue lá. """ from __future__ import annotations import json from pathlib import Path from . import shared def cmd_build_phrase_review(args: dict) -> int: """Build the reviewable script (phrases + the AI's decisions) for the wizard. `voice_timeline` points at the _voice_timeline.json; `actions` carries the decision list the model returned (inline, in any of the shapes the skill emits). The review is always rebuilt from the current analysis, then the decisions saved on a previous visit are laid back over it — reopening the step must show the edits the user left there without freezing the acoustics as they were when they left. """ from fcpxml.phrase_review import ( build_phrase_review, load_phrase_review, merge_saved_decisions, ) timeline_path = str(args.get("voice_timeline", "")) if not timeline_path or not Path(timeline_path).exists(): shared.emit({"ok": False, "error": "Análise de voz (voice_timeline.json) não encontrada."}) return 1 try: with open(timeline_path, encoding="utf-8") as fh: timeline = json.load(fh) except (OSError, ValueError) as exc: shared.emit({"ok": False, "error": f"Erro ao ler a análise de voz: {exc}"}) return 1 extra = [d for d in (args.get("output_dir"), args.get("media_dir")) if d] review = build_phrase_review( timeline, args.get("actions"), voice_timeline_path=timeline_path, extra_dirs=extra, ) saved = None if args.get("fresh") else load_phrase_review(timeline_path) review = merge_saved_decisions(review, saved) shared.emit({"ok": True, "reused": saved is not None, **review}) return 0 def cmd_save_phrase_review(args: dict) -> int: """Persist the edited review and the actions derived from it.""" from fcpxml.phrase_review import save_phrase_review timeline_path = str(args.get("voice_timeline", "")) if not timeline_path: shared.emit({"ok": False, "error": "Caminho da análise de voz não informado."}) return 1 phrases = args.get("phrases") if not isinstance(phrases, list): shared.emit({"ok": False, "error": "Nenhuma frase para salvar."}) return 1 review = { "version": args.get("version", "1.0"), "source": args.get("source", ""), "duration": args.get("duration", 0.0), "speakers": args.get("speakers", []), "phrases": phrases, "zooms": args.get("zooms", []), } try: review_path, actions_path = save_phrase_review(timeline_path, review) except OSError as exc: shared.emit({"ok": False, "error": f"Erro ao salvar a revisão: {exc}"}) return 1 shared.emit({ "ok": True, "review_path": str(review_path), "actions_path": str(actions_path), "emphasis_count": sum(1 for p in phrases if int(p.get("emphasis", 0) or 0) >= 1), "removed_count": sum(1 for p in phrases if not p.get("active", True)), }) return 0