Spaces:
Paused
Paused
| # aduc_framework/engineers/composer_2D.py | |
| # Versão 3.1.0 (Diálogo de Revisão Estruturado) | |
| # | |
| # - Implementa o fluxo de revisão em duas etapas (4.5 e 5) para | |
| # maior qualidade e consistência do storyboard. | |
| # - Etapa 4.5: A IA recebe o storyboard completo para uma análise global. | |
| # - Etapa 5: A IA itera cena a cena para fazer um polimento fino, | |
| # usando o contexto global absorvido na etapa anterior. | |
| # - Utiliza os métodos de serialização do Pydantic (`model_dump(mode='json')` e | |
| # `model_dump_json()`) para evitar TypeErrors com objetos datetime. | |
| import logging | |
| import json | |
| from typing import Generator, Dict, Any, List | |
| # --- Interface neural e tipos --- | |
| from .neura_link import neura_link_singleton as NeuraLink | |
| from ..types import GenerationState, CatalogoDeAtivos, Scene, Ato, AtivoCatalogado | |
| logger = logging.getLogger(__name__) | |
| class Composer2D: | |
| """ | |
| Orquestra um pipeline conversacional para gerar e refinar um storyboard, | |
| usando um sistema de identificação de ativos universal e um diálogo de | |
| revisão em várias etapas. | |
| """ | |
| def compose_storyboard(self, dna: GenerationState) -> Generator[GenerationState, None, None]: | |
| """ | |
| Executa o pipeline completo de pré-produção, incluindo a fase de revisão. | |
| """ | |
| params = getattr(dna.parametros_geracao, "pre_producao", None) | |
| if not params: | |
| raise ValueError("Parâmetros de pré-produção ausentes no DNA (parametros_geracao.pre_producao requerido).") | |
| num_scenes = params.num_scenes | |
| duration_per_fragment = params.duration_per_fragment | |
| global_prompt = params.prompt | |
| refs = list(getattr(dna, "midias_referencia", [])) | |
| image_paths = [r.caminho for r in refs if r.caminho] | |
| image_map_para_llm = [{"tag_referencia": r.tag} for r in refs] | |
| NeuraLink.reset_memory() | |
| dna.chat_history.append({"role": "Composer2D", "content": "Memória da IA reiniciada. Iniciando roteiro..."}) | |
| yield dna | |
| # --- ETAPAS 1-4: GERAÇÃO DO RASCUNHO INICIAL --- | |
| # ETAPA 1: NARRATIVA | |
| narrativa = NeuraLink.execute_task( | |
| task_id="TASK_01_CREATE_CINEMATIC_NARRATIVE", | |
| template_data={"global_prompt": global_prompt, "num_scenes": num_scenes}, | |
| image_paths=image_paths or None, expected_format="text", use_memory=True, | |
| ) | |
| dna.texto_global_historia = (narrativa or "").strip() | |
| dna.chat_history.append({"role": "Composer2D", "content": "Narrativa global criada."}) | |
| yield dna | |
| # ETAPA 2: CATÁLOGO DE ATIVOS | |
| asset_catalog_dict = NeuraLink.execute_task( | |
| task_id="TASK_02_SELECT_AND_CATALOG_ASSETS", | |
| template_data={"image_map": json.dumps(image_map_para_llm, ensure_ascii=False, indent=2)}, | |
| expected_format="json", use_memory=True, | |
| ) | |
| dna.ativos_catalogados = CatalogoDeAtivos(**(asset_catalog_dict or {})) | |
| dna.chat_history.append({"role": "Composer2D", "content": "Catálogo de ativos universais definido."}) | |
| yield dna | |
| all_assets_by_id: Dict[str, AtivoCatalogado] = {asset.id: asset for asset_list in [dna.ativos_catalogados.cenarios, dna.ativos_catalogados.personagens, dna.ativos_catalogados.objetos] for asset in asset_list} | |
| def upsert_asset_from_llm(llm_obj: Dict[str, Any], asset_type: str) -> AtivoCatalogado: | |
| asset_id = llm_obj.get("id") | |
| if not asset_id: raise ValueError(f"Ativo do tipo '{asset_type}' recebido do LLM sem 'id'.") | |
| if asset_id in all_assets_by_id: return all_assets_by_id[asset_id] | |
| logger.info(f"IA propôs um novo ativo dinamicamente: {asset_id} (Tipo: {asset_type})") | |
| novo_ativo = AtivoCatalogado(**llm_obj) | |
| getattr(dna.ativos_catalogados, f"{asset_type}s", []).append(novo_ativo) | |
| all_assets_by_id[novo_ativo.id] = novo_ativo | |
| return novo_ativo | |
| # ETAPA 3: STORYBOARD | |
| storyboard_dict = NeuraLink.execute_task( | |
| task_id="TASK_03_CREATE_DIRECTORS_STORYBOARD", | |
| template_data={"num_scenes": num_scenes}, expected_format="json", use_memory=True, | |
| ) | |
| scene_list = (storyboard_dict or {}).get("storyboard", []) | |
| normalized_scenes: List[Scene] = [] | |
| for idx, s_dict in enumerate(scene_list): | |
| if "id_cena" not in s_dict: s_dict["id_cena"] = idx + 1 | |
| canonical_cenario = upsert_asset_from_llm(s_dict.get("cenario_escolhido", {}), "cenario") | |
| s_dict["cenario_escolhido"] = canonical_cenario.model_dump() | |
| normalized_scenes.append(Scene(**s_dict)) | |
| dna.storyboard_producao = normalized_scenes | |
| dna.chat_history.append({"role": "Composer2D", "content": f"Rascunho do storyboard com {len(normalized_scenes)} cenas criado."}) | |
| yield dna | |
| # ETAPA 4: ATOS | |
| for scene in dna.storyboard_producao: | |
| acts_dict = NeuraLink.execute_task( | |
| task_id="TASK_04_DETAIL_SCENE_INTO_ACTS", | |
| template_data={"scene_directors_manual": scene.model_dump_json(indent=2), "max_duration_per_act_s": duration_per_fragment}, | |
| expected_format="json", use_memory=True, | |
| ) | |
| scene.atos = [Ato(**a) for a in (acts_dict or {}).get("atos", [])] | |
| dna.chat_history.append({"role": "Composer2D", "content": f"Cena {scene.id_cena}: atos detalhados."}) | |
| yield dna | |
| # --- ETAPA 4.5: PRÉ-REVISÃO (CARREGAMENTO DE CONTEXTO OTIMIZADO) --- | |
| dna.chat_history.append({"role": "Composer2D", "content": "Rascunho finalizado. Apresentando à IA para análise global antes do polimento..."}) | |
| yield dna | |
| full_storyboard_json = json.dumps( | |
| [s.model_dump(mode='json') for s in dna.storyboard_producao], | |
| indent=2, | |
| ensure_ascii=False | |
| ) | |
| confirmation_message = NeuraLink.execute_task( | |
| task_id="TASK_4_5_PRE_REVIEW_CONTEXT", | |
| template_data={"full_storyboard_json": full_storyboard_json}, | |
| expected_format="text", use_memory=True, | |
| ) | |
| dna.chat_history.append({"role": "Supervisor de Roteiro (IA)", "content": confirmation_message}) | |
| yield dna | |
| # --- ETAPA 5: REVISÃO DE CONTINUIDADE CENA A CENA (COM CONTEXTO IMPLÍCITO) --- | |
| dna.chat_history.append({"role": "Composer2D", "content": "Contexto carregado. Iniciando revisão detalhada cena a cena..."}) | |
| yield dna | |
| refined_storyboard = [] | |
| for scene_to_review in dna.storyboard_producao: | |
| dna.chat_history.append({"role": "Composer2D", "content": f"Polindo Cena {scene_to_review.id_cena}/{len(dna.storyboard_producao)}: '{scene_to_review.titulo_cena}'..."}) | |
| yield dna | |
| scene_json_for_prompt = scene_to_review.model_dump_json(indent=2) | |
| refined_scene_dict = NeuraLink.execute_task( | |
| task_id="TASK_05_SCENE_CONTINUITY_REVIEW", | |
| template_data={"scene_to_review_json": scene_json_for_prompt}, | |
| expected_format="json", use_memory=True, | |
| ) | |
| try: | |
| refined_scene = Scene(**refined_scene_dict) | |
| refined_storyboard.append(refined_scene) | |
| except Exception as e: | |
| logger.warning(f"Falha ao validar cena refinada {scene_to_review.id_cena}. Mantendo a versão original. Erro: {e}") | |
| refined_storyboard.append(scene_to_review) | |
| dna.storyboard_producao = refined_storyboard | |
| dna.chat_history.append({"role": "Composer2D", "content": "Revisão de continuidade concluída. Storyboard finalizado e polido."}) | |
| yield dna | |
| logger.info("Pipeline completo do Composer2D (Geração e Revisão) concluído com sucesso.") | |
| return | |
| # Singleton | |
| composer_2d_singleton = Composer2D() |