Spaces:
Paused
Paused
File size: 7,916 Bytes
fb56537 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# 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() |