fix: troca except Exception genérico por exceções específicas nos scripts do Scanner

executar_scanner.py: nos dois pontos que processavam clipe-a-clipe (análise
visual e transcrição), o except genérico escondia bugs de programação junto
com falhas esperadas de mídia/dependência — foi assim que o bug do soundfile
ausente passou despercebido até um teste manual. Agora captura só
(OSError, RuntimeError, ValueError, json.JSONDecodeError) na visual e
(ImportError, OSError, RuntimeError, ValueError) na transcrição; erros de
programação propagam e aparecem de verdade.

executar_retakes.py e gerar_relatorio_de_analises.py: o except Exception no
main() é uma fronteira de processo legítima (traduz qualquer falha em JSON
pra tela), mantido, mas agora imprime o traceback completo no stderr antes
de reportar — hoje esse traceback se perdia, sobrando só str(erro).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
João Henrique
2026-09-09 23:38:52 -04:00
co-authored by Claude Sonnet 5
parent 88f9af28cf
commit 1156619937
3 changed files with 64 additions and 9 deletions
+27 -4
View File
@@ -33,6 +33,7 @@ from __future__ import annotations
import argparse
import json
import sys
import traceback
from dataclasses import asdict
from pathlib import Path
@@ -53,8 +54,12 @@ from engine.scanner.retakes import (
ClassificadorDeRetakes,
CoordenadorDeRetakes,
RegrasDeClassificacao,
RepositorioDeRetakes,
)
from engine.persistencia import RepositorioDeRetakesSQLite
# Os retakes são gravados no mesmo banco das demais análises do projeto. O
# caminho é absoluto porque o painel roda este script com cwd ``code``.
CAMINHO_DO_BANCO = Path(__file__).resolve().parent.parent.parent / ".jhonny" / "analises.db"
# Confiança mínima exibida por critério de confirmação da tela (§9 do guia).
LIMIARES_POR_CRITERIO = {
@@ -92,6 +97,23 @@ def _grupos_do_dict(grupos) -> list[dict]:
return [asdict(grupo) for grupo in grupos]
def _abrir_repositorio(pasta_do_caso: Path) -> RepositorioDeRetakesSQLite:
"""Abre o repositório de retakes no banco de análises do projeto.
Os retakes ficam no mesmo banco das falas e das evidências visuais, e não
num JSON por caso: é o que permite ao agente de edição ler, numa consulta
só, a fala e o fato de ela ser a terceira tentativa da mesma frase.
Parâmetros:
pasta_do_caso: Pasta do caso, mantida na assinatura porque o painel a
informa; o banco em si é o do projeto, não o da pasta.
Retorna:
O repositório SQLite pronto para uso.
"""
return RepositorioDeRetakesSQLite(CAMINHO_DO_BANCO)
def _analisar(pedido: dict, pasta_do_caso: Path) -> dict:
"""Executa a análise completa de retakes para o caso informado."""
configuracao = pedido.get("configuracao", {})
@@ -99,7 +121,7 @@ def _analisar(pedido: dict, pasta_do_caso: Path) -> dict:
video_id = str(pedido.get("video_id") or "video")
_emitir("Preparando análise", 5)
repositorio = RepositorioDeRetakes(diretoria_de_trabalho=pasta_do_caso / "retakes")
repositorio = _abrir_repositorio(pasta_do_caso)
if repositorio.ja_analisado(video_id):
_emitir("Reutilizando análise existente", 100)
return {"reutilizado": True,
@@ -134,7 +156,7 @@ def _revisar(pedido: dict, pasta_do_caso: Path) -> dict:
if acao not in STATUS_PADRAO_DO_PEDIDO:
validos = ", ".join(sorted(STATUS_PADRAO_DO_PEDIDO))
raise ValueError(f"Ação de revisão desconhecida: {acao!r}. Válidos: {validos}.")
repositorio = RepositorioDeRetakes(diretoria_de_trabalho=pasta_do_caso / "retakes")
repositorio = _abrir_repositorio(pasta_do_caso)
grupo = repositorio.atualizar_status_de_revisao(
video_id, grupo_id, STATUS_PADRAO_DO_PEDIDO[acao])
return {"grupos": _grupos_do_dict([grupo])}
@@ -158,7 +180,8 @@ def main() -> None:
args = parser.parse_args()
try:
resultado = executar(args.entrada, args.pasta_do_caso)
except Exception as erro: # repassa a causa para a tela decidir como exibir
except Exception as erro: # fronteira do processo: repassa a causa para a tela decidir como exibir
traceback.print_exc() # traceback completo no stderr, para não perder um bug real por trás do "erro"
print(json.dumps({"evento": "erro", "mensagem": str(erro)},
ensure_ascii=False), flush=True)
sys.exit(1)