euiia commited on
Commit
8ec79b2
·
verified ·
1 Parent(s): f5c517f

Update aduc_orchestrator.py

Browse files
Files changed (1) hide show
  1. aduc_orchestrator.py +149 -100
aduc_orchestrator.py CHANGED
@@ -1,29 +1,15 @@
1
- #Uma implementação aberta e funcional da arquitetura ADUC-SDR para geração de vídeo coerente.
2
- # Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
3
  #
4
- # Contato:
5
- # Carlos Rodrigues dos Santos
6
- # carlex22@gmail.com
7
  #
8
- # Repositórios e Projetos Relacionados:
9
- # GitHub: https://github.com/carlex22/Aduc-sdr
10
- # YouTube (Resultados): https://m.youtube.com/channel/UC3EgoJi_Fv7yuDpvfYNtoIQ
11
  #
12
- # Este programa é software livre: você pode redistribuí-lo e/ou modificá-lo
13
- # sob os termos da Licença Pública Geral Affero da GNU como publicada pela
14
- # Free Software Foundation, seja a versão 3 da Licença, ou
15
- # (a seu critério) qualquer versão posterior.
16
- #
17
- # Este programa é distribuído na esperança de que seja útil,
18
- # mas SEM QUALQUER GARANTIA; sem mesmo a garantia implícita de
19
- # COMERCIALIZAÇÃO ou ADEQUAÇÃO A UM DETERMINADO FIM. Consulte a
20
- # Licença Pública Geral Affero da GNU para mais detalhes.
21
- #
22
- # Você deve ter recebido uma cópia da Licença Pública Geral Affero da GNU
23
- # junto com este programa. Se não, veja <https://www.gnu.org/licenses/>.
24
- #
25
- # AVISO DE PATENTE PENDENTE: O método e sistema ADUC implementado neste
26
- # software está em processo de patenteamento. Consulte NOTICE.md.
27
 
28
  import os
29
  import time
@@ -38,131 +24,133 @@ from ltx_manager_helpers import ltx_manager_singleton
38
  from gemini_helpers import gemini_singleton
39
  from image_specialist import image_specialist_singleton
40
 
41
- # O logger é configurado no app.py, aqui apenas obtemos a instância.
42
  logger = logging.getLogger(__name__)
43
 
44
  class AducDirector:
45
  """
46
- Representa o Diretor de Cena, responsável pelo gerenciamento do estado da produção.
47
- Atua como a "partitura" da orquestra, mantendo o controle de todos os artefatos
48
- gerados (roteiro, keyframes, etc.) durante o processo criativo.
49
  """
50
  def __init__(self, workspace_dir: str):
51
  """
52
- Inicializa o Diretor, criando o diretório de trabalho.
53
 
54
  Args:
55
- workspace_dir (str): O caminho para o diretório onde todos os artefatos
56
- de geração serão armazenados.
57
  """
58
  self.workspace_dir = workspace_dir
59
  os.makedirs(self.workspace_dir, exist_ok=True)
60
  self.state: Dict[str, Any] = {}
61
- logger.info(f"O palco está pronto. Workspace em '{self.workspace_dir}'.")
62
 
63
  def update_state(self, key: str, value: Any) -> None:
64
  """
65
- Anota uma nova informação na "partitura", atualizando o estado da produção.
66
 
67
  Args:
68
- key (str): A chave para o estado a ser salvo (ex: "storyboard").
69
- value (Any): O valor do estado (ex: a lista de cenas do roteiro).
70
  """
71
- logger.info(f"Anotando na partitura: Estado '{key}' atualizado.")
72
  self.state[key] = value
73
 
74
  def get_state(self, key: str, default: Any = None) -> Any:
75
  """
76
- Consulta uma informação da "partitura", recuperando um estado salvo.
77
 
78
  Args:
79
- key (str): A chave do estado a ser recuperado.
80
- default (Any, optional): O valor a ser retornado se a chave não existir.
81
 
82
  Returns:
83
- Any: O valor do estado salvo ou o valor padrão.
84
  """
85
  return self.state.get(key, default)
86
 
87
  class AducOrchestrator:
88
  """
89
- Implementa o Maestro (Γ), a camada central de orquestração da arquitetura ADUC.
90
- Ele não executa as tarefas de IA diretamente, mas delega cada etapa do processo
91
- criativo (roteiro, arte, cinematografia) aos Especialistas apropriados.
92
  """
93
  def __init__(self, workspace_dir: str):
94
  """
95
- Inicializa o Maestro e seus músicos (os especialistas de IA).
96
 
97
  Args:
98
- workspace_dir (str): O caminho para o diretório de trabalho, que será
99
- gerenciado pelo AducDirector.
100
  """
101
  self.director = AducDirector(workspace_dir)
102
  self.editor = Deformes4DEngine(ltx_manager_singleton, workspace_dir)
103
  self.painter = image_specialist_singleton
104
- logger.info("Maestro ADUC está no pódio. Músicos (especialistas) prontos.")
105
 
106
  def process_image_for_story(self, image_path: str, size: int, filename: str) -> str:
107
  """
108
- Pré-processa uma imagem de referência, padronizando-a para uso pelos Especialistas.
109
- Converte para RGB, redimensiona para um formato quadrado e salva no workspace.
110
 
111
  Args:
112
- image_path (str): Caminho da imagem original.
113
- size (int): Tamanho (largura e altura) da imagem final.
114
- filename (str): Nome do arquivo para salvar a imagem processada.
115
 
116
  Returns:
117
- str: O caminho para a imagem processada e salva.
118
  """
119
  img = Image.open(image_path).convert("RGB")
120
  img_square = ImageOps.fit(img, (size, size), Image.Resampling.LANCZOS)
121
  processed_path = os.path.join(self.director.workspace_dir, filename)
122
  img_square.save(processed_path)
123
- logger.info(f"Imagem de referência processada e salva em: {processed_path}")
124
  return processed_path
125
 
126
- def task_generate_storyboard(self, prompt: str, num_keyframes: int, ref_image_paths: List[str],
 
 
127
  progress: gr.Progress) -> Tuple[List[str], str, Any]:
128
  """
129
- Delega ao Roteirista (Gemini) a tarefa de criar o roteiro (storyboard).
130
  """
131
- logger.info(f"Ato 1, Cena 1: Roteiro. Instruindo o Roteirista (Gemini) a criar {num_keyframes} cenas a partir de: '{prompt}'")
132
- progress(0.2, desc="Consultando Roteirista IA (Gemini)...")
133
-
134
  storyboard = gemini_singleton.generate_storyboard(prompt, num_keyframes, ref_image_paths)
135
-
136
- logger.info(f"Roteirista retornou a partitura: {storyboard}")
137
  self.director.update_state("storyboard", storyboard)
138
  self.director.update_state("processed_ref_paths", ref_image_paths)
139
-
140
  return storyboard, ref_image_paths[0], gr.update(visible=True, open=True)
141
 
142
- def task_select_keyframes(self, storyboard: List[str], base_ref_paths: List[str],
143
  pool_ref_paths: List[str]) -> List[str]:
144
  """
145
- Delega ao Editor/Fotógrafo (Gemini) a tarefa de selecionar as melhores imagens
146
- de um "banco de cenas" para corresponder ao roteiro (Modo Fotógrafo).
147
  """
148
- logger.info(f"Ato 1, Cena 2 (Modo Fotógrafo): Instruindo o Editor (Gemini) a selecionar {len(storyboard)} keyframes.")
149
-
150
  selected_paths = gemini_singleton.select_keyframes_from_pool(storyboard, base_ref_paths, pool_ref_paths)
151
-
152
- logger.info(f"Editor selecionou as seguintes cenas: {[os.path.basename(p) for p in selected_paths]}")
153
  self.director.update_state("keyframes", selected_paths)
154
  return selected_paths
155
 
156
- def task_generate_keyframes(self, storyboard: List[str], initial_ref_path: str, global_prompt: str,
157
  keyframe_resolution: int, progress_callback_factory=None) -> List[str]:
158
  """
159
- Delega ao Diretor de Arte (ImageSpecialist) a tarefa de gerar os keyframes
160
- visuais a partir do roteiro (Modo Diretor de Arte).
161
  """
162
- logger.info("Ato 1, Cena 2 (Modo Diretor de Arte): Delegando ao Especialista de Imagem.")
163
-
164
  general_ref_paths = self.director.get_state("processed_ref_paths", [])
165
-
166
  final_keyframes = self.painter.generate_keyframes_from_storyboard(
167
  storyboard=storyboard,
168
  initial_ref_path=initial_ref_path,
@@ -171,43 +159,104 @@ class AducOrchestrator:
171
  general_ref_paths=general_ref_paths,
172
  progress_callback_factory=progress_callback_factory
173
  )
174
-
175
  self.director.update_state("keyframes", final_keyframes)
176
- logger.info("Maestro: Especialista de Imagem concluiu a geração dos keyframes.")
177
  return final_keyframes
178
-
179
- def task_produce_final_movie_with_feedback(self, keyframes: List[str], global_prompt: str, seconds_per_fragment: float,
180
- trim_percent: int, handler_strength: float,
181
- destination_convergence_strength: float,
182
- use_upscaler: bool, use_refiner: bool, use_hd: bool, use_audio: bool,
183
- video_resolution: int, use_continuity_director: bool,
184
- progress: gr.Progress) -> Generator[Dict[str, Any], None, None]:
 
 
185
  """
186
- Delega ao Editor/Cineasta (Deformes4DEngine) a produção final do filme.
 
187
  """
188
- logger.info("Maestro: Delegando a produção do filme completo ao Deformes4DEngine.")
189
  storyboard = self.director.get_state("storyboard", [])
190
 
191
- for update in self.editor.generate_full_movie(
192
- keyframes=keyframes,
193
- global_prompt=global_prompt,
 
194
  storyboard=storyboard,
195
- seconds_per_fragment=seconds_per_fragment,
196
  trim_percent=trim_percent,
197
- handler_strength=handler_strength,
198
  destination_convergence_strength=destination_convergence_strength,
199
- use_upscaler=use_upscaler,
200
- use_refiner=use_refiner,
201
- use_hd=use_hd,
202
- use_audio=use_audio,
203
- video_resolution=video_resolution,
204
- use_continuity_director=use_continuity_director,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  progress=progress
206
  ):
207
  if "final_path" in update and update["final_path"]:
208
- final_movie_path = update["final_path"]
209
- self.director.update_state("final_video_path", final_movie_path)
210
- yield {"final_path": final_movie_path}
211
  break
 
 
212
 
213
- logger.info("Maestro: Produção do filme concluída e estado do diretor atualizado.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # aduc_orchestrator.py
 
2
  #
3
+ # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
 
 
4
  #
5
+ # Version: 2.0.0
 
 
6
  #
7
+ # This file contains the core ADUC (Automated Discovery and Orchestration of Complex tasks)
8
+ # orchestrator, known as the "Maestro" (Γ). Its responsibility is to manage the high-level
9
+ # creative workflow of film production. It receives user intent from the UI, delegates
10
+ # specific tasks (like storyboarding, keyframe generation, video rendering, and post-production)
11
+ # to the appropriate AI "Specialists," and manages the state of the production via the
12
+ # "Director" component. It does not perform AI inference itself but acts as the central conductor.
 
 
 
 
 
 
 
 
 
13
 
14
  import os
15
  import time
 
24
  from gemini_helpers import gemini_singleton
25
  from image_specialist import image_specialist_singleton
26
 
27
+ # The logger is configured in app.py; here we just get the instance.
28
  logger = logging.getLogger(__name__)
29
 
30
  class AducDirector:
31
  """
32
+ Represents the Scene Director, responsible for managing the production state.
33
+ Acts as the "score" for the orchestra, keeping track of all generated artifacts
34
+ (script, keyframes, etc.) during the creative process.
35
  """
36
  def __init__(self, workspace_dir: str):
37
  """
38
+ Initializes the Director, creating the workspace directory.
39
 
40
  Args:
41
+ workspace_dir (str): The path to the directory where all generation
42
+ artifacts will be stored.
43
  """
44
  self.workspace_dir = workspace_dir
45
  os.makedirs(self.workspace_dir, exist_ok=True)
46
  self.state: Dict[str, Any] = {}
47
+ logger.info(f"The stage is set. Workspace at '{self.workspace_dir}'.")
48
 
49
  def update_state(self, key: str, value: Any) -> None:
50
  """
51
+ Notes new information on the "score," updating the production state.
52
 
53
  Args:
54
+ key (str): The key for the state to be saved (e.g., "storyboard").
55
+ value (Any): The value of the state (e.g., the list of storyboard scenes).
56
  """
57
+ logger.info(f"Notating on the score: State '{key}' updated.")
58
  self.state[key] = value
59
 
60
  def get_state(self, key: str, default: Any = None) -> Any:
61
  """
62
+ Consults information from the "score," retrieving a saved state.
63
 
64
  Args:
65
+ key (str): The key of the state to be retrieved.
66
+ default (Any, optional): The value to return if the key does not exist.
67
 
68
  Returns:
69
+ Any: The value of the saved state or the default value.
70
  """
71
  return self.state.get(key, default)
72
 
73
  class AducOrchestrator:
74
  """
75
+ Implements the Maestro (Γ), the central orchestration layer of the ADUC architecture.
76
+ It does not execute AI tasks directly but delegates each step of the creative
77
+ process (scriptwriting, art direction, cinematography) to the appropriate Specialists.
78
  """
79
  def __init__(self, workspace_dir: str):
80
  """
81
+ Initializes the Maestro and its musicians (the AI specialists).
82
 
83
  Args:
84
+ workspace_dir (str): The path to the workspace, which will be managed
85
+ by the AducDirector.
86
  """
87
  self.director = AducDirector(workspace_dir)
88
  self.editor = Deformes4DEngine(ltx_manager_singleton, workspace_dir)
89
  self.painter = image_specialist_singleton
90
+ logger.info("ADUC Maestro is on the podium. Musicians (specialists) are ready.")
91
 
92
  def process_image_for_story(self, image_path: str, size: int, filename: str) -> str:
93
  """
94
+ Pre-processes a reference image, standardizing it for use by the Specialists.
95
+ Converts to RGB, resizes to a square format, and saves to the workspace.
96
 
97
  Args:
98
+ image_path (str): Path of the original image.
99
+ size (int): Width and height of the final image.
100
+ filename (str): Filename for the processed image.
101
 
102
  Returns:
103
+ str: The path to the processed and saved image.
104
  """
105
  img = Image.open(image_path).convert("RGB")
106
  img_square = ImageOps.fit(img, (size, size), Image.Resampling.LANCZOS)
107
  processed_path = os.path.join(self.director.workspace_dir, filename)
108
  img_square.save(processed_path)
109
+ logger.info(f"Reference image processed and saved to: {processed_path}")
110
  return processed_path
111
 
112
+ # --- PRE-PRODUCTION TASKS ---
113
+
114
+ def task_generate_storyboard(self, prompt: str, num_keyframes: int, ref_image_paths: List[str],
115
  progress: gr.Progress) -> Tuple[List[str], str, Any]:
116
  """
117
+ Delegates the task of creating the storyboard to the Scriptwriter (Gemini).
118
  """
119
+ logger.info(f"Act 1, Scene 1: Script. Instructing Scriptwriter (Gemini) to create {num_keyframes} scenes from: '{prompt}'")
120
+ progress(0.2, desc="Consulting AI Scriptwriter (Gemini)...")
121
+
122
  storyboard = gemini_singleton.generate_storyboard(prompt, num_keyframes, ref_image_paths)
123
+
124
+ logger.info(f"Scriptwriter returned the score: {storyboard}")
125
  self.director.update_state("storyboard", storyboard)
126
  self.director.update_state("processed_ref_paths", ref_image_paths)
127
+
128
  return storyboard, ref_image_paths[0], gr.update(visible=True, open=True)
129
 
130
+ def task_select_keyframes(self, storyboard: List[str], base_ref_paths: List[str],
131
  pool_ref_paths: List[str]) -> List[str]:
132
  """
133
+ Delegates to the Editor/Photographer (Gemini) the task of selecting the best images
134
+ from a "scene bank" to match the script (Photographer Mode).
135
  """
136
+ logger.info(f"Act 1, Scene 2 (Photographer Mode): Instructing Editor (Gemini) to select {len(storyboard)} keyframes.")
137
+
138
  selected_paths = gemini_singleton.select_keyframes_from_pool(storyboard, base_ref_paths, pool_ref_paths)
139
+
140
+ logger.info(f"Editor selected the following scenes: {[os.path.basename(p) for p in selected_paths]}")
141
  self.director.update_state("keyframes", selected_paths)
142
  return selected_paths
143
 
144
+ def task_generate_keyframes(self, storyboard: List[str], initial_ref_path: str, global_prompt: str,
145
  keyframe_resolution: int, progress_callback_factory=None) -> List[str]:
146
  """
147
+ Delegates to the Art Director (ImageSpecialist) the task of generating the visual
148
+ keyframes from the script (Art Director Mode).
149
  """
150
+ logger.info("Act 1, Scene 2 (Art Director Mode): Delegating to Image Specialist.")
151
+
152
  general_ref_paths = self.director.get_state("processed_ref_paths", [])
153
+
154
  final_keyframes = self.painter.generate_keyframes_from_storyboard(
155
  storyboard=storyboard,
156
  initial_ref_path=initial_ref_path,
 
159
  general_ref_paths=general_ref_paths,
160
  progress_callback_factory=progress_callback_factory
161
  )
162
+
163
  self.director.update_state("keyframes", final_keyframes)
164
+ logger.info("Maestro: Image Specialist has completed keyframe generation.")
165
  return final_keyframes
166
+
167
+ # --- PRODUCTION & POST-PRODUCTION TASKS ---
168
+
169
+ def task_produce_original_movie(self, keyframes: List[str], global_prompt: str, seconds_per_fragment: float,
170
+ trim_percent: int, handler_strength: float,
171
+ destination_convergence_strength: float,
172
+ guidance_scale: float, stg_scale: float, inference_steps: int,
173
+ video_resolution: int, use_continuity_director: bool,
174
+ progress: gr.Progress) -> Dict[str, Any]:
175
  """
176
+ Delegates the production of the original master video to the Deformes4DEngine.
177
+ This is the core video generation step.
178
  """
179
+ logger.info("Maestro: Delegating production of the original movie to Deformes4DEngine.")
180
  storyboard = self.director.get_state("storyboard", [])
181
 
182
+ # The engine will now handle the full generation and return the final paths
183
+ result = self.editor.generate_original_movie(
184
+ keyframes=keyframes,
185
+ global_prompt=global_prompt,
186
  storyboard=storyboard,
187
+ seconds_per_fragment=seconds_per_fragment,
188
  trim_percent=trim_percent,
189
+ handler_strength=handler_strength,
190
  destination_convergence_strength=destination_convergence_strength,
191
+ video_resolution=video_resolution,
192
+ use_continuity_director=use_continuity_director,
193
+ # New LTX pipeline parameters
194
+ guidance_scale=guidance_scale,
195
+ stg_scale=stg_scale,
196
+ num_inference_steps=inference_steps,
197
+ progress=progress
198
+ )
199
+
200
+ self.director.update_state("final_video_path", result["final_path"])
201
+ self.director.update_state("latent_paths", result["latent_paths"])
202
+ logger.info("Maestro: Original movie production complete.")
203
+ return result
204
+
205
+ def task_run_latent_upscaler(self, latent_paths: List[str], chunk_size: int, progress: gr.Progress) -> Generator[Dict[str, Any], None, None]:
206
+ """
207
+ Orchestrates the latent upscaling task.
208
+ """
209
+ logger.info(f"Maestro: Delegating latent upscaling task for {len(latent_paths)} fragments.")
210
+
211
+ # This is a generator function to allow for UI updates
212
+ for update in self.editor.upscale_latents_and_create_video(
213
+ latent_paths=latent_paths,
214
+ chunk_size=chunk_size,
215
+ progress=progress
216
+ ):
217
+ if "final_path" in update and update["final_path"]:
218
+ self.director.update_state("final_video_path", update["final_path"])
219
+ yield update["final_path"]
220
+ break
221
+
222
+ logger.info("Maestro: Latent upscaling complete.")
223
+
224
+ def task_run_hd_mastering(self, source_video_path: str, model_version: str, steps: int, progress: gr.Progress) -> Generator[Dict[str, Any], None, None]:
225
+ """
226
+ Orchestrates the HD mastering task.
227
+ """
228
+ logger.info(f"Maestro: Delegating HD mastering task using SeedVR {model_version}.")
229
+
230
+ # We'll need a new method in the editor to handle this
231
+ for update in self.editor.master_video_hd(
232
+ source_video_path=source_video_path,
233
+ model_version=model_version,
234
+ steps=steps,
235
+ prompt=self.director.get_state("storyboard", ["A cinematic high-quality movie."])[0],
236
  progress=progress
237
  ):
238
  if "final_path" in update and update["final_path"]:
239
+ self.director.update_state("final_video_path", update["final_path"])
240
+ yield update["final_path"]
 
241
  break
242
+
243
+ logger.info("Maestro: HD mastering complete.")
244
 
245
+ def task_run_audio_generation(self, source_video_path: str, audio_prompt: str, progress: gr.Progress) -> Generator[Dict[str, Any], None, None]:
246
+ """
247
+ Orchestrates the audio generation task.
248
+ """
249
+ logger.info(f"Maestro: Delegating audio generation task.")
250
+
251
+ # Another new method in the editor
252
+ for update in self.editor.generate_audio_for_final_video(
253
+ source_video_path=source_video_path,
254
+ audio_prompt=audio_prompt,
255
+ progress=progress
256
+ ):
257
+ if "final_path" in update and update["final_path"]:
258
+ self.director.update_state("final_video_path", update["final_path"])
259
+ yield update["final_path"]
260
+ break
261
+
262
+ logger.info("Maestro: Audio generation complete.")