Aduc-sdr commited on
Commit
eac9355
verified
1 Parent(s): b530c31

Update engineers/deformes3D.py

Browse files
Files changed (1) hide show
  1. engineers/deformes3D.py +95 -45
engineers/deformes3D.py CHANGED
@@ -1,33 +1,17 @@
1
  # engineers/deformes3D.py
2
- # AducSdr: Uma implementa莽茫o aberta e funcional da arquitetura ADUC-SDR
3
- # Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
4
  #
5
- # Contato:
6
- # Carlos Rodrigues dos Santos
7
8
- # Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
9
  #
10
- # Reposit贸rios e Projetos Relacionados:
11
- # GitHub: https://github.com/carlex22/Aduc-sdr
12
- #
13
- # This program is free software: you can redistribute it and/or modify
14
- # it under the terms of the GNU Affero General Public License as published by
15
- # the Free Software Foundation, either version 3 of the License, or
16
- # (at your option) any later version.
17
- #
18
- # This program is distributed in the hope that it will be useful,
19
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
- # GNU Affero General Public License for more details.
22
- #
23
- # You should have received a copy of the GNU Affero General Public License
24
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
25
  #
26
  # This program is free software: you can redistribute it and/or modify
27
  # it under the terms of the GNU Affero General Public License...
28
  # PENDING PATENT NOTICE: Please see NOTICE.md.
29
  #
30
- # Version 1.4.5
 
 
 
31
 
32
  from PIL import Image
33
  import os
@@ -35,16 +19,21 @@ import time
35
  import logging
36
  import gradio as gr
37
  import yaml
 
 
38
 
39
  from managers.flux_kontext_manager import flux_kontext_singleton
40
  from engineers.deformes2D_thinker import deformes2d_thinker_singleton
 
 
 
 
41
 
42
  logger = logging.getLogger(__name__)
43
 
44
  class Deformes3DEngine:
45
  """
46
  ADUC Specialist for static image (keyframe) generation.
47
- This is responsible for the entire process of turning a script into a gallery of keyframes.
48
  """
49
  def __init__(self, workspace_dir):
50
  self.workspace_dir = workspace_dir
@@ -53,7 +42,7 @@ class Deformes3DEngine:
53
 
54
  def _generate_single_keyframe(self, prompt: str, reference_images: list[Image.Image], output_filename: str, width: int, height: int, callback: callable = None) -> str:
55
  """
56
- Low-level function that generates a single image.
57
  """
58
  logger.info(f"Generating keyframe '{output_filename}' with prompt: '{prompt}'")
59
  generated_image = self.image_generation_helper.generate_image(
@@ -67,55 +56,116 @@ class Deformes3DEngine:
67
 
68
  def generate_keyframes_from_storyboard(self, storyboard: list, initial_ref_path: str, global_prompt: str, keyframe_resolution: int, general_ref_paths: list, progress_callback_factory: callable = None):
69
  """
70
- Orchestrates the generation of all keyframes from a storyboard.
 
 
71
  """
72
  current_base_image_path = initial_ref_path
73
  previous_prompt = "N/A (initial reference image)"
74
- final_keyframes = [current_base_image_path]
75
  width, height = keyframe_resolution, keyframe_resolution
 
76
 
77
  num_keyframes_to_generate = len(storyboard) - 1
78
-
79
- logger.info(f"IMAGE SPECIALIST: Received order to generate {num_keyframes_to_generate} keyframes.")
80
 
81
  for i in range(num_keyframes_to_generate):
 
82
  current_scene = storyboard[i]
83
  future_scene = storyboard[i+1]
84
- progress_callback = progress_callback_factory(i + 1, num_keyframes_to_generate) if progress_callback_factory else None
85
 
86
- logger.info(f"--> Generating Keyframe {i+1}/{num_keyframes_to_generate}...")
 
 
 
87
 
88
- new_flux_prompt = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
89
  global_prompt=global_prompt, scene_history=previous_prompt,
90
  current_scene_desc=current_scene, future_scene_desc=future_scene,
91
  last_image_path=current_base_image_path, fixed_ref_paths=general_ref_paths
92
  )
93
 
94
- images_for_flux_paths = list(set([current_base_image_path] + general_ref_paths))
95
- images_for_flux = [Image.open(p) for p in images_for_flux_paths]
96
 
97
- new_keyframe_path = self._generate_single_keyframe(
98
- prompt=new_flux_prompt, reference_images=images_for_flux,
99
- output_filename=f"keyframe_{i+1}.png", width=width, height=height,
100
- callback=progress_callback
101
  )
 
 
 
 
102
 
103
- final_keyframes.append(new_keyframe_path)
104
- current_base_image_path = new_keyframe_path
105
- previous_prompt = new_flux_prompt
106
 
107
- logger.info(f"IMAGE SPECIALIST: Keyframe generation complete.")
108
- return final_keyframes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  # --- Singleton Instantiation ---
111
  try:
112
  with open("config.yaml", 'r') as f:
113
  config = yaml.safe_load(f)
114
  WORKSPACE_DIR = config['application']['workspace_dir']
115
-
116
- # Correctly instantiate the Deformes3DEngine class
117
  deformes3d_engine_singleton = Deformes3DEngine(workspace_dir=WORKSPACE_DIR)
118
-
119
  except Exception as e:
120
  logger.error(f"Could not initialize Deformes3DEngine: {e}", exc_info=True)
121
  deformes3d_engine_singleton = None
 
1
  # engineers/deformes3D.py
 
 
2
  #
3
+ # Copyright (C) 2025 Carlos Rodrigues dos Santos
 
 
 
4
  #
5
+ # Version: 1.5.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  #
7
  # This program is free software: you can redistribute it and/or modify
8
  # it under the terms of the GNU Affero General Public License...
9
  # PENDING PATENT NOTICE: Please see NOTICE.md.
10
  #
11
+ # This version implements an experimental dual-generation workflow. For each
12
+ # keyframe, it first generates a version using the FLUX specialist, then
13
+ # generates a second, "enriched" version using the LTX video engine to
14
+ # allow for direct comparison of the models' visual languages.
15
 
16
  from PIL import Image
17
  import os
 
19
  import logging
20
  import gradio as gr
21
  import yaml
22
+ import torch
23
+ import numpy as np
24
 
25
  from managers.flux_kontext_manager import flux_kontext_singleton
26
  from engineers.deformes2D_thinker import deformes2d_thinker_singleton
27
+ from aduc_types import LatentConditioningItem
28
+ from managers.ltx_manager import ltx_manager_singleton
29
+ from managers.vae_manager import vae_manager_singleton
30
+ from managers.latent_enhancer_manager import latent_enhancer_specialist_singleton
31
 
32
  logger = logging.getLogger(__name__)
33
 
34
  class Deformes3DEngine:
35
  """
36
  ADUC Specialist for static image (keyframe) generation.
 
37
  """
38
  def __init__(self, workspace_dir):
39
  self.workspace_dir = workspace_dir
 
42
 
43
  def _generate_single_keyframe(self, prompt: str, reference_images: list[Image.Image], output_filename: str, width: int, height: int, callback: callable = None) -> str:
44
  """
45
+ Low-level function that generates a single image using the FLUX helper.
46
  """
47
  logger.info(f"Generating keyframe '{output_filename}' with prompt: '{prompt}'")
48
  generated_image = self.image_generation_helper.generate_image(
 
56
 
57
  def generate_keyframes_from_storyboard(self, storyboard: list, initial_ref_path: str, global_prompt: str, keyframe_resolution: int, general_ref_paths: list, progress_callback_factory: callable = None):
58
  """
59
+ Orchestrates the generation of all keyframes. For each keyframe, first
60
+ generates a version with FLUX, and then an "enriched" version with LTX
61
+ for direct comparison.
62
  """
63
  current_base_image_path = initial_ref_path
64
  previous_prompt = "N/A (initial reference image)"
65
+ final_keyframes_gallery = [current_base_image_path]
66
  width, height = keyframe_resolution, keyframe_resolution
67
+ target_resolution_tuple = (width, height)
68
 
69
  num_keyframes_to_generate = len(storyboard) - 1
70
+ logger.info(f"IMAGE SPECIALIST: Received order to generate {num_keyframes_to_generate} keyframes (FLUX + LTX versions).")
 
71
 
72
  for i in range(num_keyframes_to_generate):
73
+ scene_index = i + 1
74
  current_scene = storyboard[i]
75
  future_scene = storyboard[i+1]
76
+ progress_callback_flux = progress_callback_factory(scene_index, num_keyframes_to_generate) if progress_callback_factory else None
77
 
78
+ logger.info(f"--> Generating Keyframe {scene_index}/{num_keyframes_to_generate}...")
79
+
80
+ # --- STEP A: Generate with FLUX ---
81
+ logger.info(f" - Step A: Generating with FLUX...")
82
 
83
+ flux_prompt = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
84
  global_prompt=global_prompt, scene_history=previous_prompt,
85
  current_scene_desc=current_scene, future_scene_desc=future_scene,
86
  last_image_path=current_base_image_path, fixed_ref_paths=general_ref_paths
87
  )
88
 
89
+ flux_ref_paths = list(set([current_base_image_path] + general_ref_paths))
90
+ flux_ref_images = [Image.open(p) for p in flux_ref_paths]
91
 
92
+ flux_keyframe_path = self._generate_single_keyframe(
93
+ prompt=flux_prompt, reference_images=flux_ref_images,
94
+ output_filename=f"keyframe_{scene_index}_flux.png", width=width, height=height,
95
+ callback=progress_callback_flux
96
  )
97
+ final_keyframes_gallery.append(flux_keyframe_path)
98
+
99
+ # --- STEP B: LTX Enrichment Experiment ---
100
+ logger.info(f" - Step B: Generating enrichment with LTX...")
101
 
102
+ ltx_conditioning_items = []
103
+ context_paths = [current_base_image_path] + [p for p in general_ref_paths if p != current_base_image_path][:3]
 
104
 
105
+ weight = 1.0
106
+ for idx, path in enumerate(context_paths):
107
+ img_pil = Image.open(path).convert("RGB")
108
+ img_processed = self._preprocess_image_for_latent_conversion(img_pil, target_resolution_tuple)
109
+ pixel_tensor = self._pil_to_pixel_tensor(img_processed)
110
+ latent_tensor = vae_manager_singleton.encode(pixel_tensor)
111
+
112
+ ltx_conditioning_items.append(LatentConditioningItem(latent_tensor, 0, weight))
113
+
114
+ if idx >= 0:
115
+ weight -= 0.2
116
+
117
+ ltx_base_params = {"guidance_scale": 3.0, "stg_scale": 0.1, "num_inference_steps": 25}
118
+ generated_latents, _ = ltx_manager_singleton.generate_latent_fragment(
119
+ height=height, width=width,
120
+ conditioning_items_data=ltx_conditioning_items,
121
+ motion_prompt=flux_prompt,
122
+ video_total_frames=16,
123
+ video_fps=24,
124
+ **ltx_base_params
125
+ )
126
+
127
+ final_latent = generated_latents[:, :, -1:, :, :]
128
+ upscaled_latent = latent_enhancer_specialist_singleton.upscale(final_latent)
129
+ enriched_pixel_tensor = vae_manager_singleton.decode(upscaled_latent)
130
+
131
+ ltx_keyframe_path = os.path.join(self.workspace_dir, f"keyframe_{scene_index}_ltx.png")
132
+ self.save_image_from_tensor(enriched_pixel_tensor, ltx_keyframe_path)
133
+ final_keyframes_gallery.append(ltx_keyframe_path)
134
+
135
+ current_base_image_path = flux_keyframe_path
136
+ previous_prompt = flux_prompt
137
+
138
+ logger.info(f"IMAGE SPECIALIST: Generation of all keyframe versions (FLUX + LTX) complete.")
139
+ return final_keyframes_gallery
140
+
141
+ # --- HELPER FUNCTIONS ---
142
+
143
+ def _preprocess_image_for_latent_conversion(self, image: Image.Image, target_resolution: tuple) -> Image.Image:
144
+ """Resizes and fits an image to the target resolution for VAE encoding."""
145
+ if image.size != target_resolution:
146
+ return ImageOps.fit(image, target_resolution, Image.Resampling.LANCZOS)
147
+ return image
148
+
149
+ def _pil_to_pixel_tensor(self, pil_image: Image.Image) -> torch.Tensor:
150
+ """Helper to convert PIL to the 5D pixel tensor the VAE expects."""
151
+ image_np = np.array(pil_image).astype(np.float32) / 255.0
152
+ tensor = torch.from_numpy(image_np).permute(2, 0, 1).unsqueeze(0).unsqueeze(2)
153
+ return (tensor * 2.0) - 1.0
154
+
155
+ def save_image_from_tensor(self, pixel_tensor: torch.Tensor, path: str):
156
+ """Helper to save a 1-frame pixel tensor as an image."""
157
+ tensor_chw = pixel_tensor.squeeze(0).squeeze(1)
158
+ tensor_hwc = tensor_chw.permute(1, 2, 0)
159
+ tensor_hwc = (tensor_hwc.clamp(-1, 1) + 1) / 2.0
160
+ image_np = (tensor_hwc.cpu().float().numpy() * 255).astype(np.uint8)
161
+ Image.fromarray(image_np).save(path)
162
 
163
  # --- Singleton Instantiation ---
164
  try:
165
  with open("config.yaml", 'r') as f:
166
  config = yaml.safe_load(f)
167
  WORKSPACE_DIR = config['application']['workspace_dir']
 
 
168
  deformes3d_engine_singleton = Deformes3DEngine(workspace_dir=WORKSPACE_DIR)
 
169
  except Exception as e:
170
  logger.error(f"Could not initialize Deformes3DEngine: {e}", exc_info=True)
171
  deformes3d_engine_singleton = None