Carlexxx commited on
Commit
86b5eb7
·
1 Parent(s): 239727a

feat: Implement self-contained specialist managers

Browse files
aduc_framework/engineers/deformes3D.py CHANGED
@@ -2,7 +2,7 @@
2
  #
3
  # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
4
  #
5
- # Versão 3.1.1 (Framework-Compliant com Inicialização Explícita)
6
  #
7
  # Este engenheiro é o "Diretor de Arte" do framework. Sua responsabilidade
8
  # é ler o estado de geração (storyboard, parâmetros) e orquestrar a criação
@@ -15,11 +15,12 @@ import yaml
15
  import torch
16
  import numpy as np
17
  from PIL import Image, ImageOps
18
- from typing import List, Dict, Callable, Optional
19
 
20
- # --- Imports Relativos Corrigidos ---
21
- # Importa componentes de pacotes "irmãos" ou "pais" dentro do framework.
 
22
 
 
23
  from .deformes2D_thinker import deformes2d_thinker_singleton
24
  from ..types import LatentConditioningItem
25
  from ..managers.ltx_manager import ltx_manager_singleton
 
2
  #
3
  # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
4
  #
5
+ # Versão 3.1.2 (Com correção de import de 'typing')
6
  #
7
  # Este engenheiro é o "Diretor de Arte" do framework. Sua responsabilidade
8
  # é ler o estado de geração (storyboard, parâmetros) e orquestrar a criação
 
15
  import torch
16
  import numpy as np
17
  from PIL import Image, ImageOps
 
18
 
19
+ # >>> INÍCIO DA CORREÇÃO <<<
20
+ from typing import List, Dict, Any, Callable, Optional
21
+ # >>> FIM DA CORREÇÃO <<<
22
 
23
+ # --- Imports Relativos Corrigidos ---
24
  from .deformes2D_thinker import deformes2d_thinker_singleton
25
  from ..types import LatentConditioningItem
26
  from ..managers.ltx_manager import ltx_manager_singleton
aduc_framework/engineers/deformes7D.py CHANGED
@@ -1,34 +1,12 @@
1
- # engineers/deformes7D.py
2
  #
3
- # AducSdr: Uma implementação aberta e funcional da arquitetura ADUC-SDR
4
- # Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
5
  #
6
- # Contato:
7
- # Carlos Rodrigues dos Santos
8
- # carlex22@gmail.com
9
- # Rua Eduardo Carlos Pereira, 4125, B1 Ap32, Curitiba, PR, Brazil, CEP 8102025
10
  #
11
- # Repositórios e Projetos Relacionados:
12
- # GitHub: https://github.com/carlex22/Aduc-sdr
13
- #
14
- # This program is free software: you can redistribute it and/or modify
15
- # it under the terms of the GNU Affero General Public License as published by
16
- # the Free Software Foundation, either version 3 of the License, or
17
- # (at your option) any later version.
18
- #
19
- # This program is distributed in the hope that it will be useful,
20
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
21
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
- # GNU Affero General Public License for more details.
23
- #
24
- # You should have received a copy of the GNU Affero General Public License
25
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
26
- #
27
- # This program is free software: you can redistribute it and/or modify
28
- # it under the terms of the GNU Affero General Public License...
29
- # PENDING PATENT NOTICE: Please see NOTICE.md.
30
- #
31
- # Version 3.2.1
32
 
33
  import os
34
  import time
@@ -37,122 +15,90 @@ import numpy as np
37
  import torch
38
  import logging
39
  from PIL import Image, ImageOps
40
- import gradio as gr
41
  import subprocess
42
  import gc
43
  import yaml
44
  import shutil
45
  from pathlib import Path
46
- from typing import List, Tuple, Dict, Generator
47
 
 
48
  from ..types import LatentConditioningItem
49
  from ..managers.ltx_manager import ltx_manager_singleton
50
  from ..managers.latent_enhancer_manager import latent_enhancer_specialist_singleton
51
  from ..managers.vae_manager import vae_manager_singleton
52
- from ..engineers.deformes2D_thinker import deformes2d_thinker_singleton
53
- from ..engineers.deformes3D_thinker import deformes3d_thinker_singleton
54
  from ..managers.seedvr_manager import seedvr_manager_singleton
55
  from ..managers.mmaudio_manager import mmaudio_manager_singleton
56
  from ..tools.video_encode_tool import video_encode_tool_singleton
57
 
58
  logger = logging.getLogger(__name__)
59
 
 
 
60
  class Deformes7DEngine:
61
- # ... (todo o corpo da classe permanece exatamente o mesmo da nossa última versão) ...
62
  """
63
- Unified 3D/4D engine for continuous, interleaved generation of keyframes and video fragments.
 
64
  """
65
- def __init__(self, workspace_dir="deformes_workspace"):
66
- self.workspace_dir = workspace_dir
 
67
  self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
68
- logger.info("Deformes7D Unified Engine initialized.")
69
- os.makedirs(self.workspace_dir, exist_ok=True)
70
-
71
- # --- HELPER METHODS ---
72
- def save_video_from_tensor(self, video_tensor: torch.Tensor, path: str, fps: int = 24):
73
- """Saves a pixel-space tensor as an MP4 video file."""
74
- if video_tensor is None or video_tensor.ndim != 5 or video_tensor.shape[2] == 0: return
75
- video_tensor = video_tensor.squeeze(0).permute(1, 2, 3, 0)
76
- video_tensor = (video_tensor.clamp(-1, 1) + 1) / 2.0
77
- video_np = (video_tensor.detach().cpu().float().numpy() * 255).astype(np.uint8)
78
- with imageio.get_writer(path, fps=fps, codec='libx264', quality=8, output_params=['-pix_fmt', 'yuv420p']) as writer:
79
- for frame in video_np: writer.append_data(frame)
80
-
81
- def read_video_to_tensor(self, video_path: str) -> torch.Tensor:
82
- """Reads a video file and converts it into a pixel-space tensor."""
83
- with imageio.get_reader(video_path, 'ffmpeg') as reader:
84
- frames = [frame for frame in reader]
85
- frames_np = np.stack(frames, axis=0).astype(np.float32) / 255.0
86
- tensor = torch.from_numpy(frames_np).permute(3, 0, 1, 2)
87
- tensor = tensor.unsqueeze(0)
88
- tensor = (tensor * 2.0) - 1.0
89
- return tensor.to(self.device)
90
-
91
- def _preprocess_image(self, image: Image.Image, target_resolution: tuple) -> Image.Image:
92
- if image.size != target_resolution:
93
- return ImageOps.fit(image, target_resolution, Image.Resampling.LANCZOS)
94
- return image
95
 
96
- def _pil_to_pixel_tensor(self, pil_image: Image.Image) -> torch.Tensor:
97
- image_np = np.array(pil_image).astype(np.float32) / 255.0
98
- tensor = torch.from_numpy(image_np).permute(2, 0, 1).unsqueeze(0).unsqueeze(2)
99
- return (tensor * 2.0) - 1.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- def _save_image_from_tensor(self, pixel_tensor: torch.Tensor, path: str):
102
- tensor_chw = pixel_tensor.squeeze(0).squeeze(1)
103
- tensor_hwc = tensor_chw.permute(1, 2, 0)
104
- tensor_hwc = (tensor_hwc.clamp(-1, 1) + 1) / 2.0
105
- image_np = (tensor_hwc.cpu().float().numpy() * 255).astype(np.uint8)
106
- Image.fromarray(image_np).save(path)
107
-
108
- def _quantize_to_multiple(self, n, m):
109
- if m == 0: return n
110
- quantized = int(round(n / m) * m)
111
- return m if n > 0 and quantized == 0 else quantized
112
-
113
- # --- CORE GENERATION LOGIC ---
114
- def _generate_next_causal_keyframe(self, base_keyframe_path: str, all_ref_paths: list,
115
- prompt: str, resolution_tuple: tuple) -> Tuple[str, torch.Tensor]:
116
- # (código interno deste método permanece o mesmo)
117
- ltx_context_paths = [base_keyframe_path] + [p for p in all_ref_paths if p != base_keyframe_path][:3]
118
- ltx_conditioning_items = []
119
- weight = 1.0
120
- for path in ltx_context_paths:
121
- img_pil = Image.open(path).convert("RGB")
122
- img_processed = self._preprocess_image(img_pil, resolution_tuple)
123
- pixel_tensor = self._pil_to_pixel_tensor(img_processed)
124
- latent_tensor = vae_manager_singleton.encode(pixel_tensor)
125
- ltx_conditioning_items.append(LatentConditioningItem(latent_tensor, 0, weight))
126
- if weight == 1.0: weight = -0.2
127
- else: weight -= 0.2
128
- ltx_base_params = {"guidance_scale": 3.0, "stg_scale": 0.1, "num_inference_steps": 25}
129
- generated_latents, _ = ltx_manager_singleton.generate_latent_fragment(
130
- height=resolution_tuple[0], width=resolution_tuple[1],
131
- conditioning_items_data=ltx_conditioning_items, motion_prompt=prompt,
132
- video_total_frames=48, video_fps=24, **ltx_base_params
133
- )
134
- final_latent = generated_latents[:, :, -1:, :, :]
135
- upscaled_latent = latent_enhancer_specialist_singleton.upscale(final_latent)
136
- pixel_tensor_out = vae_manager_singleton.decode(upscaled_latent)
137
- timestamp = int(time.time() * 1000)
138
- output_path = os.path.join(self.workspace_dir, f"keyframe_{timestamp}.png")
139
- self._save_image_from_tensor(pixel_tensor_out, output_path)
140
- return output_path, final_latent
141
-
142
- def generate_full_movie_interleaved(self, initial_ref_paths: list, storyboard: list, global_prompt: str,
143
- video_resolution: int, seconds_per_fragment: float, trim_percent: int,
144
- handler_strength: float, dest_strength: float, ltx_params: dict,
145
- progress=gr.Progress()):
146
- # (código interno deste método permanece o mesmo)
147
- logger.info("--- DEFORMES 7D: INITIATING INTERLEAVED RENDERING PIPELINE ---")
148
  run_timestamp = int(time.time())
149
- temp_video_clips_dir = os.path.join(self.workspace_dir, f"temp_clips_{run_timestamp}")
150
  os.makedirs(temp_video_clips_dir, exist_ok=True)
151
  FPS = 24
152
  FRAMES_PER_LATENT_CHUNK = 8
153
  resolution_tuple = (video_resolution, video_resolution)
154
  generated_keyframe_paths, generated_keyframe_latents, generated_video_fragment_paths = [], [], []
155
- progress(0, desc="Bootstrap: Processing K0...")
 
156
  k0_path = initial_ref_paths[0]
157
  k0_pil = Image.open(k0_path).convert("RGB")
158
  k0_processed_pil = self._preprocess_image(k0_pil, resolution_tuple)
@@ -160,13 +106,15 @@ class Deformes7DEngine:
160
  k0_latent = vae_manager_singleton.encode(k0_pixel_tensor)
161
  generated_keyframe_paths.append(k0_path)
162
  generated_keyframe_latents.append(k0_latent)
163
- progress(0.01, desc="Bootstrap: Generating K1...")
 
164
  prompt_k1 = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
165
- global_prompt, "Initial scene.", storyboard[0], storyboard[1], k0_path, initial_ref_paths
166
  )
167
  k1_path, k1_latent = self._generate_next_causal_keyframe(k0_path, initial_ref_paths, prompt_k1, resolution_tuple)
168
  generated_keyframe_paths.append(k1_path)
169
  generated_keyframe_latents.append(k1_latent)
 
170
  story_history = ""
171
  eco_latent_for_next_loop, dejavu_latent_for_next_loop = None, None
172
  num_transitions = len(storyboard) - 1
@@ -174,8 +122,9 @@ class Deformes7DEngine:
174
 
175
  for i in range(1, num_transitions):
176
  act_progress = i / num_transitions
177
- progress(act_progress, desc=f"Processing Act {i+1}/{num_transitions} (Keyframe Gen)...")
178
- logger.info(f"--> Step 3D: Generating Keyframe K{i+1}")
 
179
  kx_path = generated_keyframe_paths[i]
180
  prompt_ky = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
181
  global_prompt, story_history, storyboard[i], storyboard[i+1], kx_path, initial_ref_paths
@@ -183,15 +132,16 @@ class Deformes7DEngine:
183
  ky_path, ky_latent = self._generate_next_causal_keyframe(kx_path, initial_ref_paths, prompt_ky, resolution_tuple)
184
  generated_keyframe_paths.append(ky_path)
185
  generated_keyframe_latents.append(ky_latent)
186
- progress(act_progress, desc=f"Processing Act {i+1}/{num_transitions} (Video Gen)...")
187
- logger.info(f"--> Step 4D: Generating Video Fragment V{i-1}")
 
 
188
  kb_path, kx_path, ky_path = generated_keyframe_paths[i-1], generated_keyframe_paths[i], generated_keyframe_paths[i+1]
189
  motion_prompt = deformes3d_thinker_singleton.get_enhanced_motion_prompt(
190
  global_prompt, story_history, kb_path, kx_path, ky_path,
191
  storyboard[i-1], storyboard[i], storyboard[i+1]
192
  )
193
- transition_type = "continuous"
194
- story_history += f"\n- Act {i}: {motion_prompt}"
195
  total_frames_brutos = self._quantize_to_multiple(int(seconds_per_fragment * FPS), FRAMES_PER_LATENT_CHUNK)
196
  frames_a_podar = self._quantize_to_multiple(int(total_frames_brutos * (trim_percent / 100)), FRAMES_PER_LATENT_CHUNK)
197
  latents_a_podar = frames_a_podar // FRAMES_PER_LATENT_CHUNK
@@ -203,100 +153,81 @@ class Deformes7DEngine:
203
  else:
204
  conditioning_items.append(LatentConditioningItem(eco_latent_for_next_loop, 0, 1.0))
205
  conditioning_items.append(LatentConditioningItem(dejavu_latent_for_next_loop, DEJAVU_FRAME_TARGET, handler_strength))
206
- if transition_type != "cut":
207
- conditioning_items.append(LatentConditioningItem(ky_latent, DESTINATION_FRAME_TARGET, dest_strength))
208
  fragment_latents_brutos, _ = ltx_manager_singleton.generate_latent_fragment(
209
  height=video_resolution, width=video_resolution,
210
  conditioning_items_data=conditioning_items, motion_prompt=motion_prompt,
211
  video_total_frames=total_frames_brutos, video_fps=FPS, **base_4d_ltx_params
212
  )
 
213
  last_trim = fragment_latents_brutos[:, :, -(latents_a_podar+1):, :, :].clone()
214
  eco_latent_for_next_loop = last_trim[:, :, :2, :, :].clone()
215
  dejavu_latent_for_next_loop = last_trim[:, :, -1:, :, :].clone()
216
  final_fragment_latents = fragment_latents_brutos[:, :, :-(latents_a_podar-1), :, :].clone()
217
  final_fragment_latents = final_fragment_latents[:, :, 1:, :, :]
218
  pixel_tensor = vae_manager_singleton.decode(final_fragment_latents)
219
- fragment_path = os.path.join(temp_video_clips_dir, f"fragment_{i-1}.mp4")
220
  self.save_video_from_tensor(pixel_tensor, fragment_path, fps=FPS)
221
  generated_video_fragment_paths.append(fragment_path)
222
- logger.info(f"Video Fragment V{i-1} saved to {fragment_path}")
223
 
224
- logger.info("--- Final Assembly of Video Fragments ---")
 
225
  final_video_path = os.path.join(self.workspace_dir, f"movie_7D_{run_timestamp}.mp4")
226
  video_encode_tool_singleton.concatenate_videos(generated_video_fragment_paths, final_video_path, self.workspace_dir)
227
  shutil.rmtree(temp_video_clips_dir)
228
- logger.info(f"Full movie generated at: {final_video_path}")
229
- return {"final_path": final_video_path, "all_keyframes": generated_keyframe_paths, "latent_paths": "NOT_IMPLEMENTED_YET"}
230
 
231
- # --- POST-PRODUCTION METHODS ---
232
- def task_run_latent_upscaling(self, latent_paths: list, chunk_size: int, progress: gr.Progress) -> Generator[Dict[str, any], None, None]:
233
- # (código interno deste método permanece o mesmo)
234
- if not latent_paths:
235
- raise gr.Error("Cannot perform upscaling: no latent paths were provided from the main generation.")
236
- logger.info("--- POST-PRODUCTION: Latent Upscaling ---")
237
- run_timestamp = int(time.time())
238
- temp_upscaled_clips_dir = os.path.join(self.workspace_dir, f"temp_upscaled_clips_{run_timestamp}")
239
- os.makedirs(temp_upscaled_clips_dir, exist_ok=True)
240
- final_upscaled_clip_paths = []
241
- num_chunks = -(-len(latent_paths) // chunk_size)
242
- for i in range(num_chunks):
243
- chunk_start_index = i * chunk_size
244
- chunk_end_index = chunk_start_index + chunk_size
245
- chunk_paths = latent_paths[chunk_start_index:chunk_end_index]
246
- progress(i / num_chunks, desc=f"Upscaling & Decoding Batch {i+1}/{num_chunks}")
247
- tensors_in_chunk = [torch.load(p, map_location=self.device) for p in chunk_paths]
248
- tensors_para_concatenar = [frag[:, :, :-1, :, :] if j < len(tensors_in_chunk) - 1 else frag for j, frag in enumerate(tensors_in_chunk)]
249
- sub_group_latent = torch.cat(tensors_para_concatenar, dim=2)
250
- del tensors_in_chunk, tensors_para_concatenar; gc.collect(); torch.cuda.empty_cache()
251
- upscaled_latent_chunk = latent_enhancer_specialist_singleton.upscale(sub_group_latent)
252
- del sub_group_latent; gc.collect(); torch.cuda.empty_cache()
253
- pixel_tensor = vae_manager_singleton.decode(upscaled_latent_chunk)
254
- del upscaled_latent_chunk; gc.collect(); torch.cuda.empty_cache()
255
- base_name = f"upscaled_clip_{i:04d}_{run_timestamp}"
256
- current_clip_path = os.path.join(temp_upscaled_clips_dir, f"{base_name}.mp4")
257
- self.save_video_from_tensor(pixel_tensor, current_clip_path, fps=24)
258
- final_upscaled_clip_paths.append(current_clip_path)
259
- del pixel_tensor; gc.collect(); torch.cuda.empty_cache()
260
- progress(0.98, desc="Assembling upscaled clips...")
261
- final_video_path = os.path.join(self.workspace_dir, f"upscaled_movie_{run_timestamp}.mp4")
262
- video_encode_tool_singleton.concatenate_videos(video_paths=final_upscaled_clip_paths, output_path=final_video_path, workspace_dir=self.workspace_dir)
263
- shutil.rmtree(temp_upscaled_clips_dir)
264
- logger.info(f"Latent upscaling complete! Final video at: {final_video_path}")
265
- yield {"final_path": final_video_path}
266
 
267
- def master_video_hd(self, source_video_path: str, model_version: str, steps: int, prompt: str, progress: gr.Progress):
268
- # (código interno deste método permanece o mesmo)
269
- logger.info(f"--- POST-PRODUCTION: HD Mastering with SeedVR {model_version} ---")
270
- run_timestamp = int(time.time())
271
- output_path = os.path.join(self.workspace_dir, f"{Path(source_video_path).stem}_hd.mp4")
272
- try:
273
- final_path = seedvr_manager_singleton.process_video(
274
- input_video_path=source_video_path, output_video_path=output_path,
275
- prompt=prompt, model_version=model_version, steps=steps, progress=progress
276
- )
277
- yield {"final_path": final_path}
278
- except Exception as e:
279
- logger.error(f"HD Mastering failed: {e}", exc_info=True)
280
- raise gr.Error(f"HD Mastering failed. Details: {e}")
281
-
282
- def generate_audio(self, source_video_path: str, audio_prompt: str, progress: gr.Progress):
283
- # (código interno deste método permanece o mesmo)
284
- logger.info(f"--- POST-PRODUCTION: Audio Generation ---")
285
- run_timestamp = int(time.time())
286
- output_path = os.path.join(self.workspace_dir, f"{Path(source_video_path).stem}_audio.mp4")
287
- try:
288
- result = subprocess.run(
289
- ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", source_video_path],
290
- capture_output=True, text=True, check=True)
291
- duration = float(result.stdout.strip())
292
- progress(0.5, desc="Generating audio track...")
293
- final_path = mmaudio_manager_singleton.generate_audio_for_video(
294
- video_path=source_video_path, prompt=audio_prompt,
295
- duration_seconds=duration, output_path_override=output_path
296
- )
297
- yield {"final_path": final_path}
298
- except Exception as e:
299
- logger.error(f"Audio generation failed: {e}", exc_info=True)
300
- raise gr.Error(f"Audio generation failed. Details: {e}")
301
 
302
- deformes7d_engine_singleton = Deformes7DEngine()
 
 
1
+ # aduc_framework/engineers/deformes7D.py
2
  #
3
+ # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos
 
4
  #
5
+ # Versão 3.2.3 (Framework-Compliant com Inicialização Explícita)
 
 
 
6
  #
7
+ # Este é o motor de geração unificado. Ele intercala a criação de keyframes (3D)
8
+ # e fragmentos de vídeo (4D) em um único processo contínuo, potencialmente
9
+ # economizando recursos e melhorando a coerência.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  import os
12
  import time
 
15
  import torch
16
  import logging
17
  from PIL import Image, ImageOps
 
18
  import subprocess
19
  import gc
20
  import yaml
21
  import shutil
22
  from pathlib import Path
23
+ from typing import List, Tuple, Dict, Generator, Callable, Optional
24
 
25
+ # --- Imports Relativos Corrigidos ---
26
  from ..types import LatentConditioningItem
27
  from ..managers.ltx_manager import ltx_manager_singleton
28
  from ..managers.latent_enhancer_manager import latent_enhancer_specialist_singleton
29
  from ..managers.vae_manager import vae_manager_singleton
30
+ from .deformes2D_thinker import deformes2d_thinker_singleton
31
+ from .deformes3D_thinker import deformes3d_thinker_singleton
32
  from ..managers.seedvr_manager import seedvr_manager_singleton
33
  from ..managers.mmaudio_manager import mmaudio_manager_singleton
34
  from ..tools.video_encode_tool import video_encode_tool_singleton
35
 
36
  logger = logging.getLogger(__name__)
37
 
38
+ ProgressCallback = Optional[Callable[[float, str], None]]
39
+
40
  class Deformes7DEngine:
 
41
  """
42
+ Motor unificado 3D/4D para geração contínua e intercalada de keyframes e
43
+ fragmentos de vídeo.
44
  """
45
+ def __init__(self):
46
+ """O construtor é leve e não recebe argumentos."""
47
+ self.workspace_dir: Optional[str] = None
48
  self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
49
+ logger.info("Deformes7DEngine instanciado (não inicializado).")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ def initialize(self, workspace_dir: str):
52
+ """Inicializa o motor unificado com as configurações necessárias."""
53
+ if self.workspace_dir is not None:
54
+ return # Evita reinicialização
55
+ self.workspace_dir = workspace_dir
56
+ os.makedirs(self.workspace_dir, exist_ok=True)
57
+ logger.info(f"Deformes7D Unified Engine inicializado com workspace: {self.workspace_dir}.")
58
+
59
+ def generate_full_movie_interleaved(
60
+ self,
61
+ generation_state: Dict[str, Any],
62
+ progress_callback: ProgressCallback = None
63
+ ) -> Dict[str, Any]:
64
+ """
65
+ Gera um filme completo de forma intercalada, lendo todos os parâmetros
66
+ do estado de geração.
67
+ """
68
+ if not self.workspace_dir:
69
+ raise RuntimeError("Deformes7DEngine não foi inicializado. Chame o método initialize() antes de usar.")
70
+
71
+ logger.info("--- DEFORMES 7D: INICIANDO PIPELINE DE RENDERIZAÇÃO INTERCALADA ---")
72
 
73
+ # 1. Extrai todos os parâmetros do estado
74
+ pre_prod_params = generation_state.get("parametros_geracao", {}).get("pre_producao", {})
75
+ prod_params = generation_state.get("parametros_geracao", {}).get("producao", {})
76
+ storyboard = [ato["resumo_ato"] for ato in generation_state.get("Atos", [])]
77
+ global_prompt = generation_state.get("Promt_geral", "")
78
+ initial_ref_paths = [media["caminho"] for media in generation_state.get("midias_referencia", [])]
79
+
80
+ video_resolution = pre_prod_params.get('resolution', 480)
81
+ seconds_per_fragment = pre_prod_params.get('duration_per_fragment', 4.0)
82
+
83
+ trim_percent = prod_params.get('trim_percent', 50)
84
+ handler_strength = prod_params.get('handler_strength', 0.5)
85
+ dest_strength = prod_params.get('destination_convergence_strength', 0.75)
86
+ ltx_params = {
87
+ "guidance_scale": prod_params.get('guidance_scale', 2.0),
88
+ "stg_scale": prod_params.get('stg_scale', 0.025),
89
+ "num_inference_steps": prod_params.get('inference_steps', 20)
90
+ }
91
+
92
+ # 2. Inicia o processo de geração
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  run_timestamp = int(time.time())
94
+ temp_video_clips_dir = os.path.join(self.workspace_dir, f"temp_clips_7D_{run_timestamp}")
95
  os.makedirs(temp_video_clips_dir, exist_ok=True)
96
  FPS = 24
97
  FRAMES_PER_LATENT_CHUNK = 8
98
  resolution_tuple = (video_resolution, video_resolution)
99
  generated_keyframe_paths, generated_keyframe_latents, generated_video_fragment_paths = [], [], []
100
+
101
+ if progress_callback: progress_callback(0, "Bootstrap: Processando K0...")
102
  k0_path = initial_ref_paths[0]
103
  k0_pil = Image.open(k0_path).convert("RGB")
104
  k0_processed_pil = self._preprocess_image(k0_pil, resolution_tuple)
 
106
  k0_latent = vae_manager_singleton.encode(k0_pixel_tensor)
107
  generated_keyframe_paths.append(k0_path)
108
  generated_keyframe_latents.append(k0_latent)
109
+
110
+ if progress_callback: progress_callback(0.01, "Bootstrap: Gerando K1...")
111
  prompt_k1 = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
112
+ global_prompt, "Cena inicial.", storyboard[0], storyboard[1], k0_path, initial_ref_paths
113
  )
114
  k1_path, k1_latent = self._generate_next_causal_keyframe(k0_path, initial_ref_paths, prompt_k1, resolution_tuple)
115
  generated_keyframe_paths.append(k1_path)
116
  generated_keyframe_latents.append(k1_latent)
117
+
118
  story_history = ""
119
  eco_latent_for_next_loop, dejavu_latent_for_next_loop = None, None
120
  num_transitions = len(storyboard) - 1
 
122
 
123
  for i in range(1, num_transitions):
124
  act_progress = i / num_transitions
125
+ if progress_callback: progress_callback(act_progress, f"Ato {i+1}/{num_transitions} (Gerando Keyframe)...")
126
+
127
+ logger.info(f"--> Etapa 3D: Gerando Keyframe K{i+1}")
128
  kx_path = generated_keyframe_paths[i]
129
  prompt_ky = deformes2d_thinker_singleton.get_anticipatory_keyframe_prompt(
130
  global_prompt, story_history, storyboard[i], storyboard[i+1], kx_path, initial_ref_paths
 
132
  ky_path, ky_latent = self._generate_next_causal_keyframe(kx_path, initial_ref_paths, prompt_ky, resolution_tuple)
133
  generated_keyframe_paths.append(ky_path)
134
  generated_keyframe_latents.append(ky_latent)
135
+
136
+ if progress_callback: progress_callback(act_progress + (0.5 / num_transitions), f"Ato {i+1}/{num_transitions} (Gerando Vídeo)...")
137
+
138
+ logger.info(f"--> Etapa 4D: Gerando Fragmento de Vídeo V{i-1}")
139
  kb_path, kx_path, ky_path = generated_keyframe_paths[i-1], generated_keyframe_paths[i], generated_keyframe_paths[i+1]
140
  motion_prompt = deformes3d_thinker_singleton.get_enhanced_motion_prompt(
141
  global_prompt, story_history, kb_path, kx_path, ky_path,
142
  storyboard[i-1], storyboard[i], storyboard[i+1]
143
  )
144
+ story_history += f"\n- Ato {i}: {motion_prompt}"
 
145
  total_frames_brutos = self._quantize_to_multiple(int(seconds_per_fragment * FPS), FRAMES_PER_LATENT_CHUNK)
146
  frames_a_podar = self._quantize_to_multiple(int(total_frames_brutos * (trim_percent / 100)), FRAMES_PER_LATENT_CHUNK)
147
  latents_a_podar = frames_a_podar // FRAMES_PER_LATENT_CHUNK
 
153
  else:
154
  conditioning_items.append(LatentConditioningItem(eco_latent_for_next_loop, 0, 1.0))
155
  conditioning_items.append(LatentConditioningItem(dejavu_latent_for_next_loop, DEJAVU_FRAME_TARGET, handler_strength))
156
+ conditioning_items.append(LatentConditioningItem(ky_latent, DESTINATION_FRAME_TARGET, dest_strength))
157
+
158
  fragment_latents_brutos, _ = ltx_manager_singleton.generate_latent_fragment(
159
  height=video_resolution, width=video_resolution,
160
  conditioning_items_data=conditioning_items, motion_prompt=motion_prompt,
161
  video_total_frames=total_frames_brutos, video_fps=FPS, **base_4d_ltx_params
162
  )
163
+
164
  last_trim = fragment_latents_brutos[:, :, -(latents_a_podar+1):, :, :].clone()
165
  eco_latent_for_next_loop = last_trim[:, :, :2, :, :].clone()
166
  dejavu_latent_for_next_loop = last_trim[:, :, -1:, :, :].clone()
167
  final_fragment_latents = fragment_latents_brutos[:, :, :-(latents_a_podar-1), :, :].clone()
168
  final_fragment_latents = final_fragment_latents[:, :, 1:, :, :]
169
  pixel_tensor = vae_manager_singleton.decode(final_fragment_latents)
170
+ fragment_path = os.path.join(temp_video_clips_dir, f"fragment_{i-1:04d}.mp4")
171
  self.save_video_from_tensor(pixel_tensor, fragment_path, fps=FPS)
172
  generated_video_fragment_paths.append(fragment_path)
173
+ logger.info(f"Fragmento de Vídeo V{i-1} salvo em {fragment_path}")
174
 
175
+ logger.info("--- Montagem Final dos Fragmentos de Vídeo ---")
176
+ if progress_callback: progress_callback(0.98, "Montando o filme final...")
177
  final_video_path = os.path.join(self.workspace_dir, f"movie_7D_{run_timestamp}.mp4")
178
  video_encode_tool_singleton.concatenate_videos(generated_video_fragment_paths, final_video_path, self.workspace_dir)
179
  shutil.rmtree(temp_video_clips_dir)
180
+ logger.info(f"Filme completo gerado em: {final_video_path}")
181
+ return {"final_path": final_video_path, "all_keyframes": generated_keyframe_paths}
182
 
183
+ def _generate_next_causal_keyframe(self, base_keyframe_path: str, all_ref_paths: list,
184
+ prompt: str, resolution_tuple: tuple) -> Tuple[str, torch.Tensor]:
185
+ ltx_context_paths = [base_keyframe_path] + [p for p in all_ref_paths if p != base_keyframe_path][:3]
186
+ ltx_conditioning_items = []
187
+ weight = 1.0
188
+ for path in ltx_context_paths:
189
+ img_pil = Image.open(path).convert("RGB")
190
+ img_processed = self._preprocess_image(img_pil, resolution_tuple)
191
+ pixel_tensor = self._pil_to_pixel_tensor(img_processed)
192
+ latent_tensor = vae_manager_singleton.encode(pixel_tensor)
193
+ ltx_conditioning_items.append(LatentConditioningItem(latent_tensor, 0, weight))
194
+ if weight == 1.0: weight = -0.2
195
+ else: weight -= 0.2
196
+ ltx_base_params = {"guidance_scale": 3.0, "stg_scale": 0.1, "num_inference_steps": 25}
197
+ generated_latents, _ = ltx_manager_singleton.generate_latent_fragment(
198
+ height=resolution_tuple[0], width=resolution_tuple[1],
199
+ conditioning_items_data=ltx_conditioning_items, motion_prompt=prompt,
200
+ video_total_frames=48, video_fps=24, **ltx_base_params
201
+ )
202
+ final_latent = generated_latents[:, :, -1:, :, :]
203
+ upscaled_latent = latent_enhancer_specialist_singleton.upscale(final_latent)
204
+ pixel_tensor_out = vae_manager_singleton.decode(upscaled_latent)
205
+ timestamp = int(time.time() * 1000)
206
+ output_path = os.path.join(self.workspace_dir, f"keyframe_7D_{timestamp}.png")
207
+ self._save_image_from_tensor(pixel_tensor_out, output_path)
208
+ return output_path, final_latent
 
 
 
 
 
 
 
 
 
209
 
210
+ def _preprocess_image(self, image: Image.Image, target_resolution: tuple) -> Image.Image:
211
+ if image.size != target_resolution:
212
+ return ImageOps.fit(image, target_resolution, Image.Resampling.LANCZOS)
213
+ return image
214
+
215
+ def _pil_to_pixel_tensor(self, pil_image: Image.Image) -> torch.Tensor:
216
+ image_np = np.array(pil_image).astype(np.float32) / 255.0
217
+ tensor = torch.from_numpy(image_np).permute(2, 0, 1).unsqueeze(0).unsqueeze(2)
218
+ return (tensor * 2.0) - 1.0
219
+
220
+ def _save_image_from_tensor(self, pixel_tensor: torch.Tensor, path: str):
221
+ tensor_chw = pixel_tensor.squeeze(0).squeeze(1)
222
+ tensor_hwc = tensor_chw.permute(1, 2, 0)
223
+ tensor_hwc = (tensor_hwc.clamp(-1, 1) + 1) / 2.0
224
+ image_np = (tensor_hwc.cpu().float().numpy() * 255).astype(np.uint8)
225
+ Image.fromarray(image_np).save(path)
226
+
227
+ def _quantize_to_multiple(self, n, m):
228
+ if m == 0: return n
229
+ quantized = int(round(n / m) * m)
230
+ return m if n > 0 and quantized == 0 else quantized
 
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
+ # --- Instanciação Singleton ---
233
+ deformes7d_engine_singleton = Deformes7DEngine()```