aducsdr commited on
Commit
8f84363
·
verified ·
1 Parent(s): 6fb6534

Update aduc_framework/orchestrator.py

Browse files
Files changed (1) hide show
  1. aduc_framework/orchestrator.py +118 -88
aduc_framework/orchestrator.py CHANGED
@@ -2,30 +2,33 @@
2
  #
3
  # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
4
  #
5
- # Versão 3.1.0 (Framework Core com Inicialização Centralizada)
6
- #
7
- # Esta versão representa a camada de orquestração do Aduc Framework.
8
- # Ela é agnóstica a qualquer interface (UI ou API) e opera com
9
- # tipos de dados bem definidos (Pydantic) e um estado de geração central.
10
- # Agora, é responsável por inicializar os singletons dos engenheiros.
11
 
12
  import logging
13
- from typing import List, Dict, Any, Tuple, Callable, Optional
14
  from PIL import Image, ImageOps
15
  import os
 
 
 
 
 
 
16
 
17
  # Importa componentes internos do framework
18
  from .director import AducDirector
19
  from .types import GenerationState, PreProductionParams, ProductionParams
20
- from .engineers import (
21
- deformes2d_thinker_singleton,
22
- deformes3d_engine_singleton,
23
- Deformes4DEngine
24
- )
 
 
 
25
 
26
  logger = logging.getLogger(__name__)
27
 
28
- # Define um tipo para o callback de progresso para clareza
29
  ProgressCallback = Optional[Callable[[float, str], None]]
30
 
31
  class AducOrchestrator:
@@ -35,38 +38,18 @@ class AducOrchestrator:
35
  engenheiros especialistas e retorna o estado atualizado.
36
  """
37
  def __init__(self, workspace_dir: str):
38
- """
39
- Inicializa o Maestro e seus componentes principais.
40
-
41
- Args:
42
- workspace_dir (str): O diretório raiz para salvar todos os artefatos gerados.
43
- """
44
  self.director = AducDirector(workspace_dir)
45
- self.editor = Deformes4DEngine() # Instancia o editor
46
- self.editor.initialize(workspace_dir) # E o inicializa
47
-
48
- # Inicializa os singletons globais com a configuração necessária
49
  self.painter = deformes3d_engine_singleton
50
  self.painter.initialize(workspace_dir)
51
-
52
-
53
-
54
  logger.info("ADUC Maestro (Framework Core) está no pódio. Engenheiros especialistas prontos.")
55
 
56
  def get_current_state(self) -> GenerationState:
57
- """
58
- Retorna o objeto de estado Pydantic completo e atual.
59
-
60
- Returns:
61
- GenerationState: O modelo Pydantic representando o estado completo.
62
- """
63
  return self.director.get_full_state()
64
 
65
  def process_image_for_story(self, image_path: str, size: int, filename: str) -> str:
66
- """
67
- Pré-processa uma imagem de referência, padronizando-a para uso pelos Especialistas.
68
- Este é um método utilitário exposto pelo framework.
69
- """
70
  img = Image.open(image_path).convert("RGB")
71
  img_square = ImageOps.fit(img, (size, size), Image.Resampling.LANCZOS)
72
  processed_path = os.path.join(self.director.workspace_dir, filename)
@@ -74,78 +57,125 @@ class AducOrchestrator:
74
  logger.info(f"Imagem de referência processada e salva em: {processed_path}")
75
  return processed_path
76
 
77
- # --- TAREFAS PRINCIPAIS DO FRAMEWORK ---
78
-
79
  def task_pre_production(self, params: PreProductionParams, progress_callback: ProgressCallback = None) -> Tuple[List[str], List[str], GenerationState]:
80
- """
81
- Executa o fluxo completo de pré-produção: storyboard e geração de keyframes.
82
- """
83
  logger.info("Maestro: Iniciando tarefa de Pré-Produção.")
84
-
85
  self.director.update_parameters("pre_producao", params)
86
-
87
  if progress_callback: progress_callback(0.1, "Gerando storyboard...")
88
-
89
- storyboard_list = deformes2d_thinker_singleton.generate_storyboard(
90
- prompt=params.prompt,
91
- num_keyframes=params.num_keyframes,
92
- ref_image_paths=params.ref_paths
93
- )
94
  self.director.update_pre_production_state(params.prompt, params.ref_paths, storyboard_list)
95
-
96
  if progress_callback: progress_callback(0.2, "Iniciando geração de keyframes...")
97
-
98
- keyframes_detailed_data = self.painter.generate_keyframes_from_storyboard(
99
- generation_state=self.director.get_full_state_as_dict(),
100
- progress_callback=progress_callback
101
- )
102
  self.director.update_keyframes_state(keyframes_detailed_data)
103
-
104
  final_keyframe_paths = [kf["caminho_pixel"] for kf in keyframes_detailed_data]
105
  final_state = self.director.get_full_state()
106
-
107
  logger.info("Maestro: Tarefa de Pré-Produção concluída.")
108
  return storyboard_list, final_keyframe_paths, final_state
109
 
110
-
111
  def task_produce_original_movie(self, params: ProductionParams, progress_callback: ProgressCallback = None) -> Tuple[str, List[str], GenerationState]:
112
- """
113
- Executa o fluxo de produção do vídeo principal.
114
- """
115
  logger.info("Maestro: Iniciando tarefa de Produção do Filme Original.")
116
-
117
  self.director.update_parameters("producao", params)
118
-
119
- result_data = self.editor.generate_original_movie(
120
- full_generation_state=self.director.get_full_state_as_dict(),
121
- progress_callback=progress_callback
122
- )
123
-
124
  self.director.update_video_state(result_data["video_data"])
125
-
126
  final_video_path = result_data["final_path"]
127
  latent_paths = result_data["latent_paths"]
128
  final_state = self.director.get_full_state()
129
-
130
  logger.info("Maestro: Tarefa de Produção do Filme Original concluída.")
131
  return final_video_path, latent_paths, final_state
132
 
133
- # --- TAREFAS DE PÓS-PRODUÇÃO (Exemplos para futura refatoração) ---
134
-
135
- def task_run_hd_mastering(self, source_video_path: str, hd_params: Dict[str, Any], progress_callback: ProgressCallback = None) -> str:
136
- logger.info(f"Maestro: Delegando tarefa de masterização HD.")
137
- # Lógica futura:
138
- # self.director.update_parameters("pos_producao", {"hd_mastering": hd_params})
139
- # final_path = self.editor.master_video_hd(...)
140
- # self.director.update_pos_production_results(...)
141
- # return final_path
142
- return "" # Placeholder
 
 
 
 
143
 
144
- def task_run_audio_generation(self, source_video_path: str, audio_params: Dict[str, Any], progress_callback: ProgressCallback = None) -> str:
145
- logger.info(f"Maestro: Delegando tarefa de geração de áudio.")
146
- # Lógica futura:
147
- # self.director.update_parameters("pos_producao", {"audio_generation": audio_params})
148
- # final_path = self.editor.generate_audio_for_final_video(...)
149
- # self.director.update_pos_production_results(...)
150
- # return final_path
151
- return "" # Placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  #
3
  # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
4
  #
5
+ # Versão 3.2.0 (Com Orquestração de Pós-Produção)
 
 
 
 
 
6
 
7
  import logging
8
+ from typing import List, Dict, Any, Tuple, Callable, Optional, Generator
9
  from PIL import Image, ImageOps
10
  import os
11
+ import subprocess
12
+ import shutil
13
+ from pathlib import Path
14
+ import time
15
+ import gc
16
+ import torch # Necessário para torch.load
17
 
18
  # Importa componentes internos do framework
19
  from .director import AducDirector
20
  from .types import GenerationState, PreProductionParams, ProductionParams
21
+ from .engineers import deformes2d_thinker_singleton, deformes3d_engine_singleton, Deformes4DEngine
22
+ # Importa managers diretamente para as tarefas de pós-produção
23
+ from .managers.latent_enhancer_manager import latent_enhancer_specialist_singleton
24
+ from .managers.seedvr_manager import seedvr_manager_singleton
25
+ from .managers.mmaudio_manager import mmaudio_manager_singleton
26
+ from .managers.vae_manager import vae_manager_singleton
27
+ from .tools.video_encode_tool import video_encode_tool_singleton
28
+
29
 
30
  logger = logging.getLogger(__name__)
31
 
 
32
  ProgressCallback = Optional[Callable[[float, str], None]]
33
 
34
  class AducOrchestrator:
 
38
  engenheiros especialistas e retorna o estado atualizado.
39
  """
40
  def __init__(self, workspace_dir: str):
 
 
 
 
 
 
41
  self.director = AducDirector(workspace_dir)
42
+ self.editor = Deformes4DEngine()
43
+ self.editor.initialize(workspace_dir)
 
 
44
  self.painter = deformes3d_engine_singleton
45
  self.painter.initialize(workspace_dir)
46
+ self.device = 'cuda' if torch.cuda.is_available() else 'cpu' # Para operações com tensores
 
 
47
  logger.info("ADUC Maestro (Framework Core) está no pódio. Engenheiros especialistas prontos.")
48
 
49
  def get_current_state(self) -> GenerationState:
 
 
 
 
 
 
50
  return self.director.get_full_state()
51
 
52
  def process_image_for_story(self, image_path: str, size: int, filename: str) -> str:
 
 
 
 
53
  img = Image.open(image_path).convert("RGB")
54
  img_square = ImageOps.fit(img, (size, size), Image.Resampling.LANCZOS)
55
  processed_path = os.path.join(self.director.workspace_dir, filename)
 
57
  logger.info(f"Imagem de referência processada e salva em: {processed_path}")
58
  return processed_path
59
 
60
+ # --- TAREFAS DE PRÉ-PRODUÇÃO E PRODUÇÃO (sem alterações lógicas) ---
 
61
  def task_pre_production(self, params: PreProductionParams, progress_callback: ProgressCallback = None) -> Tuple[List[str], List[str], GenerationState]:
 
 
 
62
  logger.info("Maestro: Iniciando tarefa de Pré-Produção.")
 
63
  self.director.update_parameters("pre_producao", params)
 
64
  if progress_callback: progress_callback(0.1, "Gerando storyboard...")
65
+ storyboard_list = deformes2d_thinker_singleton.generate_storyboard(prompt=params.prompt, num_keyframes=params.num_keyframes, ref_image_paths=params.ref_paths)
 
 
 
 
 
66
  self.director.update_pre_production_state(params.prompt, params.ref_paths, storyboard_list)
 
67
  if progress_callback: progress_callback(0.2, "Iniciando geração de keyframes...")
68
+ keyframes_detailed_data = self.painter.generate_keyframes_from_storyboard(generation_state=self.director.get_full_state_as_dict(), progress_callback=progress_callback)
 
 
 
 
69
  self.director.update_keyframes_state(keyframes_detailed_data)
 
70
  final_keyframe_paths = [kf["caminho_pixel"] for kf in keyframes_detailed_data]
71
  final_state = self.director.get_full_state()
 
72
  logger.info("Maestro: Tarefa de Pré-Produção concluída.")
73
  return storyboard_list, final_keyframe_paths, final_state
74
 
 
75
  def task_produce_original_movie(self, params: ProductionParams, progress_callback: ProgressCallback = None) -> Tuple[str, List[str], GenerationState]:
 
 
 
76
  logger.info("Maestro: Iniciando tarefa de Produção do Filme Original.")
 
77
  self.director.update_parameters("producao", params)
78
+ result_data = self.editor.generate_original_movie(full_generation_state=self.director.get_full_state_as_dict(), progress_callback=progress_callback)
 
 
 
 
 
79
  self.director.update_video_state(result_data["video_data"])
 
80
  final_video_path = result_data["final_path"]
81
  latent_paths = result_data["latent_paths"]
82
  final_state = self.director.get_full_state()
 
83
  logger.info("Maestro: Tarefa de Produção do Filme Original concluída.")
84
  return final_video_path, latent_paths, final_state
85
 
86
+ # --- TAREFAS DE PÓS-PRODUÇÃO (MOVIDAS PARA ) ---
87
+
88
+ def task_run_latent_upscaler(self, latent_paths: List[str], chunk_size: int, progress_callback: ProgressCallback = None) -> Generator[Dict[str, Any], None, None]:
89
+ if not self.director.workspace_dir: raise RuntimeError("Orchestrator não inicializado corretamente.")
90
+ if not latent_paths:
91
+ raise ValueError("Não é possível fazer o upscale: nenhum caminho de latente foi fornecido.")
92
+
93
+ logger.info("--- ORQUESTRADOR: Tarefa de Upscaling de Latentes ---")
94
+ run_timestamp = int(time.time())
95
+ temp_dir = os.path.join(self.director.workspace_dir, f"temp_upscaled_clips_{run_timestamp}")
96
+ os.makedirs(temp_dir, exist_ok=True)
97
+
98
+ final_upscaled_clip_paths = []
99
+ num_chunks = -(-len(latent_paths) // chunk_size) if chunk_size > 0 else 0
100
 
101
+ for i in range(num_chunks):
102
+ chunk_start_index = i * chunk_size
103
+ chunk_end_index = chunk_start_index + chunk_size
104
+ chunk_paths = latent_paths[chunk_start_index:chunk_end_index]
105
+
106
+ if progress_callback: progress_callback(i / num_chunks, f"Upscalando & Decodificando Lote {i+1}/{num_chunks}")
107
+
108
+ tensors_in_chunk = [torch.load(p, map_location=self.device) for p in chunk_paths]
109
+ sub_group_latent = torch.cat(tensors_in_chunk, dim=2)
110
+ del tensors_in_chunk; gc.collect(); torch.cuda.empty_cache()
111
+
112
+ upscaled_latent_chunk = latent_enhancer_specialist_singleton.upscale(sub_group_latent)
113
+ del sub_group_latent; gc.collect(); torch.cuda.empty_cache()
114
+
115
+ pixel_tensor = vae_manager_singleton.decode(upscaled_latent_chunk)
116
+ del upscaled_latent_chunk; gc.collect(); torch.cuda.empty_cache()
117
+
118
+ base_name = f"upscaled_clip_{i:04d}_{run_timestamp}"
119
+ current_clip_path = os.path.join(temp_dir, f"{base_name}.mp4")
120
+ self.editor.save_video_from_tensor(pixel_tensor, current_clip_path, fps=24) # Reutiliza o helper do editor
121
+ final_upscaled_clip_paths.append(current_clip_path)
122
+ del pixel_tensor; gc.collect(); torch.cuda.empty_cache()
123
+
124
+ yield {"progress": (i + 1) / num_chunks, "desc": f"Lote {i+1}/{num_chunks} completo."}
125
+
126
+ if progress_callback: progress_callback(0.98, "Montando vídeo com upscale...")
127
+ final_video_path = os.path.join(self.director.workspace_dir, f"upscaled_movie_{run_timestamp}.mp4")
128
+ video_encode_tool_singleton.concatenate_videos(final_upscaled_clip_paths, final_video_path, self.director.workspace_dir)
129
+
130
+ shutil.rmtree(temp_dir)
131
+ logger.info(f"Upscaling de latentes completo! Vídeo final em: {final_video_path}")
132
+ yield {"final_path": final_video_path}
133
+
134
+ def task_run_hd_mastering(self, source_video_path: str, model_version: str, steps: int, prompt: str, progress_callback: ProgressCallback = None) -> Generator[Dict[str, Any], None, None]:
135
+ if not self.director.workspace_dir: raise RuntimeError("Orchestrator não inicializado corretamente.")
136
+ logger.info(f"--- ORQUESTRADOR: Tarefa de Masterização HD com SeedVR {model_version} ---")
137
+
138
+ run_timestamp = int(time.time())
139
+ output_path = os.path.join(self.director.workspace_dir, f"hd_mastered_movie_{model_version}_{run_timestamp}.mp4")
140
+
141
+ final_path = seedvr_manager_singleton.process_video(
142
+ input_video_path=source_video_path,
143
+ output_video_path=output_path,
144
+ prompt=prompt,
145
+ model_version=model_version,
146
+ steps=steps,
147
+ progress=progress_callback
148
+ )
149
+ logger.info(f"Masterização HD completa! Vídeo final em: {final_path}")
150
+ yield {"final_path": final_path}
151
+
152
+ def task_run_audio_generation(self, source_video_path: str, audio_prompt: str, progress_callback: ProgressCallback = None) -> Generator[Dict[str, Any], None, None]:
153
+ if not self.director.workspace_dir: raise RuntimeError("Orchestrator não inicializado corretamente.")
154
+ logger.info(f"--- ORQUESTRADOR: Tarefa de Geração de Áudio ---")
155
+
156
+ if progress_callback: progress_callback(0.1, "Preparando para geração de áudio...")
157
+
158
+ run_timestamp = int(time.time())
159
+ source_name = Path(source_video_path).stem
160
+ output_path = os.path.join(self.director.workspace_dir, f"{source_name}_with_audio_{run_timestamp}.mp4")
161
+
162
+ result = subprocess.run(
163
+ ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", source_video_path],
164
+ capture_output=True, text=True, check=True
165
+ )
166
+ duration = float(result.stdout.strip())
167
+
168
+ if progress_callback: progress_callback(0.5, "Gerando trilha de áudio...")
169
+
170
+ final_path = mmaudio_manager_singleton.generate_audio_for_video(
171
+ video_path=source_video_path,
172
+ prompt=audio_prompt,
173
+ duration_seconds=duration,
174
+ output_path_override=output_path
175
+ )
176
+
177
+ logger.info(f"Geração de áudio completa! Vídeo com áudio em: {final_path}")
178
+ if progress_callback: progress_callback(1.0, "Geração de áudio completa!")
179
+ yield {"final_path": final_path}```
180
+
181
+ Quando estiver pronto, podemos prosseguir para a próxima classe alterada: `Deformes4DEngine`.