Aduc-sdr commited on
Commit
f16b044
·
verified ·
1 Parent(s): 634939c

Update engineers/deformes3D.py

Browse files
Files changed (1) hide show
  1. engineers/deformes3D.py +28 -97
engineers/deformes3D.py CHANGED
@@ -2,39 +2,28 @@
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
 
17
- from PIL import Image, ImageOps
18
  import os
19
  import time
20
  import logging
21
  import gradio as gr
22
  import yaml
23
- import torch
24
- import numpy as np
25
 
26
  from managers.flux_kontext_manager import flux_kontext_singleton
27
  from engineers.deformes2D_thinker import deformes2d_thinker_singleton
28
- from aduc_types import LatentConditioningItem
29
- from managers.ltx_manager import ltx_manager_singleton
30
- from managers.vae_manager import vae_manager_singleton
31
- from managers.latent_enhancer_manager import latent_enhancer_specialist_singleton
32
 
33
  logger = logging.getLogger(__name__)
34
 
35
  class Deformes3DEngine:
36
  """
37
  ADUC Specialist for static image (keyframe) generation.
 
38
  """
39
  def __init__(self, workspace_dir):
40
  self.workspace_dir = workspace_dir
@@ -57,116 +46,58 @@ class Deformes3DEngine:
57
 
58
  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):
59
  """
60
- Orchestrates the generation of all keyframes. For each keyframe, first
61
- generates a version with FLUX, and then an "enriched" version with LTX
62
- for direct comparison.
63
  """
64
  current_base_image_path = initial_ref_path
65
  previous_prompt = "N/A (initial reference image)"
66
- final_keyframes_gallery = [current_base_image_path]
67
  width, height = keyframe_resolution, keyframe_resolution
68
- target_resolution_tuple = (width, height)
69
 
70
  num_keyframes_to_generate = len(storyboard) - 1
71
- logger.info(f"IMAGE SPECIALIST: Received order to generate {num_keyframes_to_generate} keyframes (FLUX + LTX versions).")
 
72
 
73
  for i in range(num_keyframes_to_generate):
74
  scene_index = i + 1
75
  current_scene = storyboard[i]
76
  future_scene = storyboard[i+1]
77
- progress_callback_flux = progress_callback_factory(scene_index, num_keyframes_to_generate) if progress_callback_factory else None
78
 
79
  logger.info(f"--> Generating Keyframe {scene_index}/{num_keyframes_to_generate}...")
80
-
81
- # --- STEP A: Generate with FLUX ---
82
- logger.info(f" - Step A: Generating with FLUX...")
83
 
84
- flux_prompt = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
 
85
  global_prompt=global_prompt, scene_history=previous_prompt,
86
  current_scene_desc=current_scene, future_scene_desc=future_scene,
87
  last_image_path=current_base_image_path, fixed_ref_paths=general_ref_paths
88
  )
89
 
90
- flux_ref_paths = list(set([current_base_image_path] + general_ref_paths))
91
- flux_ref_images = [Image.open(p) for p in flux_ref_paths]
92
 
93
- flux_keyframe_path = self._generate_single_keyframe(
94
- prompt=flux_prompt, reference_images=flux_ref_images,
95
- output_filename=f"keyframe_{scene_index}_flux.png", width=width, height=height,
96
- callback=progress_callback_flux
 
97
  )
98
- final_keyframes_gallery.append(flux_keyframe_path)
99
-
100
- # --- STEP B: LTX Enrichment Experiment ---
101
- logger.info(f" - Step B: Generating enrichment with LTX...")
102
 
103
- ltx_conditioning_items = []
104
- context_paths = [current_base_image_path] + [p for p in general_ref_paths if p != current_base_image_path][:3]
105
-
106
- weight = 1.0
107
- for idx, path in enumerate(context_paths):
108
- img_pil = Image.open(path).convert("RGB")
109
- img_processed = self._preprocess_image_for_latent_conversion(img_pil, target_resolution_tuple)
110
- pixel_tensor = self._pil_to_pixel_tensor(img_processed)
111
- latent_tensor = vae_manager_singleton.encode(pixel_tensor)
112
-
113
- ltx_conditioning_items.append(LatentConditioningItem(latent_tensor, 0, weight))
114
-
115
- if idx >= 0:
116
- weight -= 0.2
117
 
118
- ltx_base_params = {"guidance_scale": 3.0, "stg_scale": 0.1, "num_inference_steps": 25}
119
- generated_latents, _ = ltx_manager_singleton.generate_latent_fragment(
120
- height=height, width=width,
121
- conditioning_items_data=ltx_conditioning_items,
122
- motion_prompt=flux_prompt,
123
- video_total_frames=16,
124
- video_fps=24,
125
- **ltx_base_params
126
- )
127
-
128
- final_latent = generated_latents[:, :, -1:, :, :]
129
- upscaled_latent = latent_enhancer_specialist_singleton.upscale(final_latent)
130
- enriched_pixel_tensor = vae_manager_singleton.decode(upscaled_latent)
131
-
132
- ltx_keyframe_path = os.path.join(self.workspace_dir, f"keyframe_{scene_index}_ltx.png")
133
- self.save_image_from_tensor(enriched_pixel_tensor, ltx_keyframe_path)
134
- final_keyframes_gallery.append(ltx_keyframe_path)
135
-
136
- current_base_image_path = flux_keyframe_path
137
- previous_prompt = flux_prompt
138
-
139
- logger.info(f"IMAGE SPECIALIST: Generation of all keyframe versions (FLUX + LTX) complete.")
140
- return final_keyframes_gallery
141
-
142
- # --- HELPER FUNCTIONS ---
143
-
144
- def _preprocess_image_for_latent_conversion(self, image: Image.Image, target_resolution: tuple) -> Image.Image:
145
- """Resizes and fits an image to the target resolution for VAE encoding."""
146
- if image.size != target_resolution:
147
- return ImageOps.fit(image, target_resolution, Image.Resampling.LANCZOS)
148
- return image
149
-
150
- def _pil_to_pixel_tensor(self, pil_image: Image.Image) -> torch.Tensor:
151
- """Helper to convert PIL to the 5D pixel tensor the VAE expects."""
152
- image_np = np.array(pil_image).astype(np.float32) / 255.0
153
- tensor = torch.from_numpy(image_np).permute(2, 0, 1).unsqueeze(0).unsqueeze(2)
154
- return (tensor * 2.0) - 1.0
155
-
156
- def save_image_from_tensor(self, pixel_tensor: torch.Tensor, path: str):
157
- """Helper to save a 1-frame pixel tensor as an image."""
158
- tensor_chw = pixel_tensor.squeeze(0).squeeze(1)
159
- tensor_hwc = tensor_chw.permute(1, 2, 0)
160
- tensor_hwc = (tensor_hwc.clamp(-1, 1) + 1) / 2.0
161
- image_np = (tensor_hwc.cpu().float().numpy() * 255).astype(np.uint8)
162
- Image.fromarray(image_np).save(path)
163
 
164
  # --- Singleton Instantiation ---
165
  try:
166
  with open("config.yaml", 'r') as f:
167
  config = yaml.safe_load(f)
168
  WORKSPACE_DIR = config['application']['workspace_dir']
 
 
169
  deformes3d_engine_singleton = Deformes3DEngine(workspace_dir=WORKSPACE_DIR)
 
170
  except Exception as e:
171
  logger.error(f"Could not initialize Deformes3DEngine: {e}", exc_info=True)
172
  deformes3d_engine_singleton = None
 
2
  #
3
  # Copyright (C) 2025 Carlos Rodrigues dos Santos
4
  #
5
+ # Version: 1.1.1
6
  #
7
+ # This file defines the Deformes3DEngine, the specialist responsible for
8
+ # generating the key visual anchors (keyframes) of the story. It acts as the
9
+ # "Art Director," translating narrative scenes into static images.
 
 
 
 
 
 
10
 
11
+ from PIL import Image
12
  import os
13
  import time
14
  import logging
15
  import gradio as gr
16
  import yaml
 
 
17
 
18
  from managers.flux_kontext_manager import flux_kontext_singleton
19
  from engineers.deformes2D_thinker import deformes2d_thinker_singleton
 
 
 
 
20
 
21
  logger = logging.getLogger(__name__)
22
 
23
  class Deformes3DEngine:
24
  """
25
  ADUC Specialist for static image (keyframe) generation.
26
+ This is responsible for the entire process of turning a script into a gallery of keyframes.
27
  """
28
  def __init__(self, workspace_dir):
29
  self.workspace_dir = workspace_dir
 
46
 
47
  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):
48
  """
49
+ Orchestrates the generation of all keyframes from a storyboard.
 
 
50
  """
51
  current_base_image_path = initial_ref_path
52
  previous_prompt = "N/A (initial reference image)"
53
+ final_keyframes = [current_base_image_path]
54
  width, height = keyframe_resolution, keyframe_resolution
 
55
 
56
  num_keyframes_to_generate = len(storyboard) - 1
57
+
58
+ logger.info(f"IMAGE SPECIALIST: Received order to generate {num_keyframes_to_generate} keyframes.")
59
 
60
  for i in range(num_keyframes_to_generate):
61
  scene_index = i + 1
62
  current_scene = storyboard[i]
63
  future_scene = storyboard[i+1]
64
+ progress_callback = progress_callback_factory(scene_index, num_keyframes_to_generate) if progress_callback_factory else None
65
 
66
  logger.info(f"--> Generating Keyframe {scene_index}/{num_keyframes_to_generate}...")
 
 
 
67
 
68
+ # Delegate the "thinking" part to the Deformes2DThinker
69
+ new_flux_prompt = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
70
  global_prompt=global_prompt, scene_history=previous_prompt,
71
  current_scene_desc=current_scene, future_scene_desc=future_scene,
72
  last_image_path=current_base_image_path, fixed_ref_paths=general_ref_paths
73
  )
74
 
75
+ images_for_flux_paths = list(set([current_base_image_path] + general_ref_paths))
76
+ images_for_flux = [Image.open(p) for p in images_for_flux_paths]
77
 
78
+ # Execute the image generation
79
+ new_keyframe_path = self._generate_single_keyframe(
80
+ prompt=new_flux_prompt, reference_images=images_for_flux,
81
+ output_filename=f"keyframe_{scene_index}.png", width=width, height=height,
82
+ callback=progress_callback
83
  )
 
 
 
 
84
 
85
+ final_keyframes.append(new_keyframe_path)
86
+ current_base_image_path = new_keyframe_path
87
+ previous_prompt = new_flux_prompt
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ logger.info("IMAGE SPECIALIST: Keyframe generation complete.")
90
+ return final_keyframes
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  # --- Singleton Instantiation ---
93
  try:
94
  with open("config.yaml", 'r') as f:
95
  config = yaml.safe_load(f)
96
  WORKSPACE_DIR = config['application']['workspace_dir']
97
+
98
+ # Correctly instantiate the Deformes3DEngine class
99
  deformes3d_engine_singleton = Deformes3DEngine(workspace_dir=WORKSPACE_DIR)
100
+
101
  except Exception as e:
102
  logger.error(f"Could not initialize Deformes3DEngine: {e}", exc_info=True)
103
  deformes3d_engine_singleton = None