# aduc_framework/engineers/deformes3D_thinker.py # # Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos # # Versão 1.2.0 (Enhanced Logging & Robust Parsing) # # Adiciona logging detalhado da resposta bruta do LLM antes do parseamento # para facilitar a depuração de erros de formato JSON. import logging from pathlib import Path from PIL import Image import gradio as gr from typing import List, Dict, Any import json import re # Importa o nosso manager testado e aprovado from ..managers.llama_scout_manager import llama_scout_manager_singleton logger = logging.getLogger(__name__) def robust_json_parser(raw_text: str) -> dict: """ Tenta extrair e parsear um objeto JSON de uma string que pode conter texto adicional ou blocos de código markdown. """ # Tenta encontrar um bloco de código JSON match = re.search(r'```json\s*(\{.*?\})\s*```', raw_text, re.DOTALL) if match: json_str = match.group(1) return json.loads(json_str) # Se não encontrar, tenta encontrar o primeiro '{' e o último '}' try: start_index = raw_text.find('{') end_index = raw_text.rfind('}') if start_index != -1 and end_index != -1 and end_index > start_index: json_str = raw_text[start_index : end_index + 1] return json.loads(json_str) except json.JSONDecodeError: pass # Se todas as tentativas falharem, tenta parsear o texto original # para levantar o erro original e informativo. return json.loads(raw_text) class Deformes3DThinker: """ O especialista cognitivo 3D, responsável pelas tarefas de maior complexidade criativa, começando pela criação do storyboard. """ def _read_prompt_template(self, filename: str) -> str: """Lê um arquivo de template de prompt do diretório 'prompts'.""" try: prompts_dir = Path(__file__).resolve().parent.parent / "prompts" with open(prompts_dir / filename, "r", encoding="utf-8") as f: return f.read() except FileNotFoundError: raise gr.Error(f"Arquivo de template de prompt não encontrado: {filename}") def generate_storyboard(self, prompt: str, num_keyframes: int, ref_image_paths: List[str]) -> List[str]: """ Atua como Roteirista para criar o roteiro inicial (lista de atos) usando o Llama Scout Manager. """ response_str = "" # Inicializa para o bloco de exceção try: template = self._read_prompt_template("unified_storyboard_prompt.txt") storyboard_prompt = template.format(user_prompt=prompt, num_fragments=num_keyframes) images = [Image.open(p) for p in ref_image_paths] response_str = llama_scout_manager_singleton.analyze_sequence( image_list=images, question=storyboard_prompt ) # --- LOG ADICIONADO --- # Exibe a resposta EXATA que será enviada para o parser de JSON. logger.info(f"Deformes3D Thinker: Recebida resposta bruta do LlamaScoutManager. Tentando parsear:\n---\n{response_str}\n---") # ---------------------- storyboard_data = robust_json_parser(response_str) storyboard = storyboard_data.get("scene_storyboard", []) if not storyboard or len(storyboard) != num_keyframes: logger.warning(f"Número de cenas gerado ({len(storyboard)}) é diferente do solicitado ({num_keyframes}). Ajustando.") default_scene = storyboard[-1] if storyboard else "Cena de continuação cinematográfica." storyboard = (storyboard + [default_scene] * num_keyframes)[:num_keyframes] return storyboard except Exception as e: # O log da resposta bruta já foi feito acima, então a exceção aqui será mais informativa. logger.error(f"O Roteirista (Deformes3D Thinker) falhou durante o parseamento ou processamento. Erro: {e}", exc_info=True) raise gr.Error(f"O Roteirista (Deformes3D Thinker) falhou ao criar o storyboard: {e}") # --- Instância Singleton --- deformes3d_thinker_singleton = Deformes3DThinker()