"""Perfil declarativo que liga a configuração do painel à leitura visual.""" from dataclasses import dataclass from typing import Any RECURSOS_VISION = frozenset(( "faces", "qualidade_facial", "pessoas", "pose", "maos", "ocr", "categorias", "estetica", "codigos", "horizonte", "retangulos", "contornos", "segmentacao_de_pessoas", )) @dataclass(frozen=True) class ConfiguracaoVisualDoScanner: """Interface curta para uma execução de leitura visual da timeline.""" intervalo_em_segundos: float = 1.0 faixas_de_video: tuple[int, ...] = () faixas_de_audio: tuple[int, ...] = () recursos_vision: frozenset[str] = RECURSOS_VISION detectar_cenas: bool = True analisar_continuidade: bool = True preparar_reenquadramento: bool = False interpretar_cena: bool = True def __post_init__(self) -> None: if not 0.04 <= self.intervalo_em_segundos <= 60: raise ValueError("intervalo_em_segundos deve estar entre 0,04 e 60.") desconhecidos = self.recursos_vision - RECURSOS_VISION if desconhecidos: raise ValueError(f"Recursos Vision desconhecidos: {', '.join(sorted(desconhecidos))}") if any(indice < 0 for indice in self.faixas_de_video + self.faixas_de_audio): raise ValueError("Índices de faixa não podem ser negativos.") @classmethod def de_dict(cls, dados: dict[str, Any]) -> "ConfiguracaoVisualDoScanner": """Lê o mesmo JSON produzido pelo painel, sem vazar detalhes de adapters.""" return cls( intervalo_em_segundos=float(dados.get("intervalo_em_segundos", 1)), faixas_de_video=tuple(sorted(set(int(item) for item in dados.get("faixas_de_video", ())))), faixas_de_audio=tuple(sorted(set(int(item) for item in dados.get("faixas_de_audio", ())))), recursos_vision=frozenset(dados.get("recursos_vision", RECURSOS_VISION)), detectar_cenas=bool(dados.get("detectar_cenas", True)), analisar_continuidade=bool(dados.get("analisar_continuidade", True)), preparar_reenquadramento=bool(dados.get("preparar_reenquadramento", False)), interpretar_cena=bool(dados.get("interpretar_cena", True)), ) def para_dict(self) -> dict[str, Any]: return { "versao": 1, "intervalo_em_segundos": self.intervalo_em_segundos, "faixas_de_video": list(self.faixas_de_video), "faixas_de_audio": list(self.faixas_de_audio), "recursos_vision": sorted(self.recursos_vision), "detectar_cenas": self.detectar_cenas, "analisar_continuidade": self.analisar_continuidade, "preparar_reenquadramento": self.preparar_reenquadramento, "interpretar_cena": self.interpretar_cena, }