Carlexxx
feat: ✨ aBINC 2.2
fb56537
raw
history blame
7.92 kB
# 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()