Carlexxx
feat: ✨ aBINC 2.2
fb56537
raw
history blame
6.41 kB
# aduc_framework/aduc_sdr.py
#
# Versão 16.0.0 (Maestro de Produção Integrado)
# - Implementa o método `task_produce_movie` para delegar a produção de vídeo
# ao especialista `Planner5D`, ativando o pipeline de produção iterativo.
# - Atua como a ponte final entre a interface do usuário (UI) e o complexo
# fluxo de trabalho de geração de vídeo cena a cena.
# - Utiliza o sistema de `yield from` para transmitir de forma eficiente as
# atualizações de estado do `Planner5D` de volta para a UI.
import logging
import os
from typing import Generator
# Importa os especialistas de alto nível (Engenheiros)
from .engineers.composer_2D import composer_2d_singleton as Composer2D
from .engineers.planner_5D import planner_5d_singleton as Planner5D
# Importa as estruturas de dados (o DNA Digital)
from .types import GenerationState, PreProductionParams, ProductionParams, MediaRef
from .director import AducDirector
logger = logging.getLogger(__name__)
class AducSdr:
"""
O Maestro do framework ADUC-SDR. Orquestra os especialistas (Engineers)
e gerencia o fluxo de dados através do Diretor (estado persistente).
"""
def __init__(self, workspace_root: str):
self.workspace_root = workspace_root
self.director: AducDirector | None = None
self.composer_2d = Composer2D
self.planner_5d = Planner5D
logger.info("ADUC-SDR Maestro (Arquitetura V2) inicializado e pronto.")
def load_project(self, project_name: str):
"""Carrega um projeto existente ou cria um novo."""
project_path = os.path.join(self.workspace_root, project_name)
self.director = AducDirector(project_path=project_path)
logger.info(f"Projeto '{project_name}' carregado no Diretor.")
def _ensure_project_loaded(self):
"""Garante que um projeto foi carregado antes de executar tarefas."""
if not self.director:
raise RuntimeError("Nenhum projeto foi carregado. Chame `aduc.load_project(project_name)` primeiro.")
def get_current_state(self) -> GenerationState:
"""Retorna o estado completo e atual do projeto."""
self._ensure_project_loaded()
return self.director.get_full_state()
def process_image_for_story(self, image_path: str, filename: str) -> str:
"""Processa uma imagem de referência para um formato padrão."""
self._ensure_project_loaded()
from PIL import Image
size = 480; quality = 40
img = Image.open(image_path).convert("RGB"); img.thumbnail((size, size), Image.Resampling.LANCZOS)
background = Image.new('RGB', (size, size), (0, 0, 0)); img_w, img_h = img.size; offset = ((size - img_w) // 2, (size - img_h) // 2)
background.paste(img, offset)
processed_path = os.path.join(self.director.project_path, filename)
background.save(processed_path, 'JPEG', quality=quality)
return processed_path
def _process_and_yield_updates(self, generator: Generator[GenerationState, None, None]):
"""
Loop genérico para processar atualizações de um especialista, salvar o estado
e repassar para a UI.
"""
for updated_dna in generator:
self.director.load_state_from_dict(updated_dna.model_dump())
if self.director.state.should_checkpoint():
checkpoint_dir = os.path.join(self.director.project_path, "checkpoints")
path = self.director.state.create_checkpoint(checkpoint_dir)
logger.info(f"Checkpoint do projeto salvo em: {path}")
self.director.save_state()
yield self.director.get_full_state()
def task_run_story_and_keyframes(self, params: PreProductionParams) -> Generator[GenerationState, None, None]:
"""
Orquestra a pré-produção (Fase 1), delegando ao Composer2D para criar o storyboard.
"""
self._ensure_project_loaded()
logger.info("Maestro: Iniciando Pré-Produção (Storyboard) com o Composer2D...")
initial_state = self.director.get_full_state()
initial_state.parametros_geracao.pre_producao = params
initial_state.midias_referencia = [
MediaRef(id=i, tag=f"<IMG{i}>", caminho=path)
for i, path in enumerate(params.ref_paths)
]
initial_state.texto_global_historia = None
initial_state.ativos_catalogados = None
initial_state.storyboard_producao = []
initial_state.chat_history.append({
"role": "Sistema",
"content": f"Iniciando pré-produção. {len(params.ref_paths)} imagens de referência foram tageadas para uso pela IA."
})
pre_production_generator = self.composer_2d.compose_storyboard(initial_state)
yield from self._process_and_yield_updates(pre_production_generator)
logger.info("Maestro: Pré-Produção (Fase 1) concluída.")
def task_produce_movie(self, params: ProductionParams) -> Generator[GenerationState, None, None]:
"""
Orquestra a produção completa do filme (Fase 2), delegando ao Planner5D.
"""
self._ensure_project_loaded()
logger.info("Maestro: Iniciando Produção de Vídeo com o Planner5D...")
# 1. Obter o estado atual, que já contém o storyboard da pré-produção.
current_state = self.director.get_full_state()
# 2. Atualizar o estado com os novos parâmetros de produção vindos da UI.
if current_state.parametros_geracao:
current_state.parametros_geracao.producao = params
current_state.chat_history.append({
"role": "Sistema",
"content": f"Parâmetros de produção recebidos. O Diretor de Produção (Planner5D) está assumindo o controle."
})
# Salva os parâmetros no dna.json antes de iniciar o processo longo.
self.director.save_state()
# 3. Chamar o especialista Planner5D com o estado atualizado.
# Ele agora irá controlar o loop de Deformes3D e Deformes4D.
production_generator = self.planner_5d.produce_movie_by_scene(current_state)
# 4. Processar as atualizações, salvar o estado e repassar para a UI em tempo real.
yield from self._process_and_yield_updates(production_generator)
logger.info("Maestro: Produção de vídeo (Fase 2) concluída.")