Update deformes4D_engine.py
Browse files- deformes4D_engine.py +18 -35
deformes4D_engine.py
CHANGED
|
@@ -2,8 +2,7 @@
|
|
| 2 |
# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
|
| 3 |
#
|
| 4 |
# MODIFICATIONS FOR ADUC-SDR:
|
| 5 |
-
# Copyright (C) 2025 Carlos Rodrigues dos Santos. All rights reserved
|
| 6 |
-
#
|
| 7 |
# This file is part of the ADUC-SDR project. It contains the core logic for
|
| 8 |
# video fragment generation, latent manipulation, and dynamic editing,
|
| 9 |
# governed by the ADUC orchestrator.
|
|
@@ -119,45 +118,38 @@ class Deformes4DEngine:
|
|
| 119 |
return output_path
|
| 120 |
|
| 121 |
def generate_full_movie(self, keyframes: list, global_prompt: str, storyboard: list,
|
| 122 |
-
# Os parâmetros a seguir
|
| 123 |
seconds_per_fragment: float, trim_chunks: int, echo_chunks: int,
|
| 124 |
# Parâmetros de força ainda são utilizados.
|
| 125 |
handler_strength: float, destination_convergence_strength: float,
|
| 126 |
video_resolution: int, use_continuity_director: bool,
|
| 127 |
progress: gr.Progress = gr.Progress()):
|
| 128 |
|
| 129 |
-
# ---
|
| 130 |
-
# AVISO: Esta função agora opera com uma estratégia de continuidade fixa, ignorando os parâmetros da UI
|
| 131 |
-
# 'seconds_per_fragment', 'trim_chunks', e 'echo_chunks' para garantir consistência máxima.
|
| 132 |
-
|
| 133 |
-
# Parâmetros Fixos de Geração
|
| 134 |
N_CHUNKS_TO_GENERATE = 13
|
| 135 |
-
FRAMES_TO_GENERATE = (N_CHUNKS_TO_GENERATE - 1) * 8 + 1 #
|
| 136 |
|
| 137 |
-
|
| 138 |
-
ECO_CHUNK_INDICES = slice(
|
| 139 |
-
HANDLER_CHUNK_INDICES = slice(11, 13)
|
| 140 |
-
VIDEO_CHUNK_INDICES = slice(0, 8) # Chunks 0 a 7 (resultando em 64 frames de vídeo)
|
| 141 |
|
| 142 |
-
#
|
| 143 |
-
|
| 144 |
-
DESTINATION_FRAME_TARGET = FRAMES_TO_GENERATE - 1 # O último frame (96)
|
| 145 |
|
| 146 |
logger.info("="*60)
|
| 147 |
-
logger.info("MODO DE GERAÇÃO
|
| 148 |
logger.info(f" - Geração Bruta por Fragmento: {N_CHUNKS_TO_GENERATE} chunks ({FRAMES_TO_GENERATE} frames)")
|
| 149 |
-
logger.info(f" - Clipe
|
| 150 |
logger.info(f" - Guia de Eco (Memória): Chunks {ECO_CHUNK_INDICES.start} a {ECO_CHUNK_INDICES.stop-1}")
|
| 151 |
logger.info(f" - Guia de Handler (Evolução): Chunks {HANDLER_CHUNK_INDICES.start} a {HANDLER_CHUNK_INDICES.stop-1}")
|
|
|
|
| 152 |
logger.info("="*60)
|
| 153 |
-
|
| 154 |
-
|
| 155 |
base_ltx_params = {"guidance_scale": 1.0, "stg_scale": 0.0, "rescaling_scale": 0.15, "num_inference_steps": 20}
|
| 156 |
keyframe_paths = [item[0] if isinstance(item, tuple) else item for item in keyframes]
|
| 157 |
video_clips_paths, story_history = [], ""
|
| 158 |
target_resolution_tuple = (video_resolution, video_resolution)
|
| 159 |
|
| 160 |
-
# Variáveis para carregar as guias da iteração anterior
|
| 161 |
eco_latent_for_next_loop = None
|
| 162 |
handler_latent_for_next_loop = None
|
| 163 |
|
|
@@ -172,13 +164,11 @@ class Deformes4DEngine:
|
|
| 172 |
logger.info(f"--- INICIANDO FRAGMENTO {i+1}/{num_transitions_to_generate} ---")
|
| 173 |
progress((i + 1) / num_transitions_to_generate, desc=f"Produzindo Transição {i+1}/{num_transitions_to_generate}")
|
| 174 |
|
| 175 |
-
# Define os keyframes de Passado, Presente e Futuro para esta iteração
|
| 176 |
past_keyframe_path = keyframe_paths[start_keyframe_index - 1]
|
| 177 |
start_keyframe_path = keyframe_paths[start_keyframe_index]
|
| 178 |
destination_keyframe_path = keyframe_paths[start_keyframe_index + 1]
|
| 179 |
future_story_prompt = storyboard[start_keyframe_index + 1] if (start_keyframe_index + 1) < len(storyboard) else "A cena final."
|
| 180 |
|
| 181 |
-
# Gemini decide o prompt de movimento com base no contexto completo
|
| 182 |
decision = gemini_singleton.get_cinematic_decision(
|
| 183 |
global_prompt, story_history, past_keyframe_path, start_keyframe_path, destination_keyframe_path,
|
| 184 |
storyboard[start_keyframe_index - 1], storyboard[start_keyframe_index], future_story_prompt
|
|
@@ -186,46 +176,39 @@ class Deformes4DEngine:
|
|
| 186 |
_, motion_prompt = decision["transition_type"], decision["motion_prompt"]
|
| 187 |
story_history += f"\n- Ato {i+1}: {motion_prompt}"
|
| 188 |
|
| 189 |
-
# Monta a lista de condicionamento para a geração atual
|
| 190 |
conditioning_items = []
|
| 191 |
logger.info(" [0. PREPARAÇÃO] Montando itens de condicionamento...")
|
| 192 |
|
| 193 |
-
if i == 0:
|
| 194 |
img_start = self._preprocess_image_for_latent_conversion(Image.open(start_keyframe_path).convert("RGB"), target_resolution_tuple)
|
| 195 |
conditioning_items.append(LatentConditioningItem(self.pil_to_latent(img_start), 0, 1.0))
|
| 196 |
logger.info(" - Condicionamento inicial: Imagem K1 no frame 0.")
|
| 197 |
-
else:
|
| 198 |
conditioning_items.append(LatentConditioningItem(eco_latent_for_next_loop, 0, 1.0))
|
| 199 |
conditioning_items.append(LatentConditioningItem(handler_latent_for_next_loop, HANDLER_FRAME_TARGET, handler_strength))
|
| 200 |
-
logger.info(f" -
|
| 201 |
-
logger.info(f" -
|
| 202 |
|
| 203 |
-
# O destino é sempre a próxima imagem-chave no final da geração
|
| 204 |
img_dest = self._preprocess_image_for_latent_conversion(Image.open(destination_keyframe_path).convert("RGB"), target_resolution_tuple)
|
| 205 |
conditioning_items.append(LatentConditioningItem(self.pil_to_latent(img_dest), DESTINATION_FRAME_TARGET, destination_convergence_strength))
|
| 206 |
-
logger.info(f" -
|
| 207 |
|
| 208 |
-
# Gera o tensor latente bruto de 13 chunks
|
| 209 |
current_ltx_params = {**base_ltx_params, "motion_prompt": motion_prompt}
|
| 210 |
new_full_latents = self._generate_latent_tensor_internal(conditioning_items, current_ltx_params, target_resolution_tuple, FRAMES_TO_GENERATE)
|
| 211 |
logger.info(f" [1. GERAÇÃO] Tensor latente bruto gerado com shape: {new_full_latents.shape}.")
|
| 212 |
|
| 213 |
-
# Extrai as guias para a PRÓXIMA iteração
|
| 214 |
eco_latent_for_next_loop = new_full_latents[:, :, ECO_CHUNK_INDICES, :, :].clone()
|
| 215 |
handler_latent_for_next_loop = new_full_latents[:, :, HANDLER_CHUNK_INDICES, :, :].clone()
|
| 216 |
logger.info(f" [GUIAS] Guias para a próxima iteração extraídas. Eco shape: {eco_latent_for_next_loop.shape}, Handler shape: {handler_latent_for_next_loop.shape}.")
|
| 217 |
|
| 218 |
-
# Extrai os chunks que se tornarão o clipe de vídeo final
|
| 219 |
latents_for_video = new_full_latents[:, :, VIDEO_CHUNK_INDICES, :, :]
|
| 220 |
logger.info(f" [2. EDIÇÃO] Tensor final para vídeo extraído com {latents_for_video.shape[2]} chunks.")
|
| 221 |
|
| 222 |
-
# Gera e salva o vídeo
|
| 223 |
base_name = f"fragment_{i}_{int(time.time())}"
|
| 224 |
video_path = self._generate_video_from_latents(latents_for_video, base_name)
|
| 225 |
video_clips_paths.append(video_path)
|
| 226 |
yield {"fragment_path": video_path}
|
| 227 |
|
| 228 |
-
# Concatena todos os fragmentos salvos
|
| 229 |
final_movie_path = os.path.join(self.workspace_dir, f"final_movie_silent_{int(time.time())}.mp4")
|
| 230 |
self.concatenate_videos_ffmpeg(video_clips_paths, final_movie_path)
|
| 231 |
|
|
|
|
| 2 |
# Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
|
| 3 |
#
|
| 4 |
# MODIFICATIONS FOR ADUC-SDR:
|
| 5 |
+
# Copyright (C) 2025 Carlos Rodrigues dos Santos. All rights reserved#
|
|
|
|
| 6 |
# This file is part of the ADUC-SDR project. It contains the core logic for
|
| 7 |
# video fragment generation, latent manipulation, and dynamic editing,
|
| 8 |
# governed by the ADUC orchestrator.
|
|
|
|
| 118 |
return output_path
|
| 119 |
|
| 120 |
def generate_full_movie(self, keyframes: list, global_prompt: str, storyboard: list,
|
| 121 |
+
# Os parâmetros a seguir da UI são ignorados por esta estratégia fixa.
|
| 122 |
seconds_per_fragment: float, trim_chunks: int, echo_chunks: int,
|
| 123 |
# Parâmetros de força ainda são utilizados.
|
| 124 |
handler_strength: float, destination_convergence_strength: float,
|
| 125 |
video_resolution: int, use_continuity_director: bool,
|
| 126 |
progress: gr.Progress = gr.Progress()):
|
| 127 |
|
| 128 |
+
# --- Estratégia de Geração com Cauda Longa Refinada (Lógica Fixa) ---
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
N_CHUNKS_TO_GENERATE = 13
|
| 130 |
+
FRAMES_TO_GENERATE = (N_CHUNKS_TO_GENERATE - 1) * 8 + 1 # 97 frames
|
| 131 |
|
| 132 |
+
VIDEO_CHUNK_INDICES = slice(0, 9) # Chunks 0-8 (gera vídeo de 65 frames)
|
| 133 |
+
ECO_CHUNK_INDICES = slice(9, 11) # Chunks 9 e 10
|
| 134 |
+
HANDLER_CHUNK_INDICES = slice(11, 13) # Chunks 11 e 12
|
|
|
|
| 135 |
|
| 136 |
+
HANDLER_FRAME_TARGET = 16 # <-- ALTERADO DE 32 PARA 16
|
| 137 |
+
DESTINATION_FRAME_TARGET = FRAMES_TO_GENERATE - 1
|
|
|
|
| 138 |
|
| 139 |
logger.info("="*60)
|
| 140 |
+
logger.info("MODO DE GERAÇÃO: Estratégia de Cauda Longa Refinada")
|
| 141 |
logger.info(f" - Geração Bruta por Fragmento: {N_CHUNKS_TO_GENERATE} chunks ({FRAMES_TO_GENERATE} frames)")
|
| 142 |
+
logger.info(f" - Clipe Final por Fragmento: Chunks {VIDEO_CHUNK_INDICES.start} a {VIDEO_CHUNK_INDICES.stop-1}")
|
| 143 |
logger.info(f" - Guia de Eco (Memória): Chunks {ECO_CHUNK_INDICES.start} a {ECO_CHUNK_INDICES.stop-1}")
|
| 144 |
logger.info(f" - Guia de Handler (Evolução): Chunks {HANDLER_CHUNK_INDICES.start} a {HANDLER_CHUNK_INDICES.stop-1}")
|
| 145 |
+
logger.info(f" - Ponto de Aplicação do Handler: Frame {HANDLER_FRAME_TARGET}")
|
| 146 |
logger.info("="*60)
|
| 147 |
+
|
|
|
|
| 148 |
base_ltx_params = {"guidance_scale": 1.0, "stg_scale": 0.0, "rescaling_scale": 0.15, "num_inference_steps": 20}
|
| 149 |
keyframe_paths = [item[0] if isinstance(item, tuple) else item for item in keyframes]
|
| 150 |
video_clips_paths, story_history = [], ""
|
| 151 |
target_resolution_tuple = (video_resolution, video_resolution)
|
| 152 |
|
|
|
|
| 153 |
eco_latent_for_next_loop = None
|
| 154 |
handler_latent_for_next_loop = None
|
| 155 |
|
|
|
|
| 164 |
logger.info(f"--- INICIANDO FRAGMENTO {i+1}/{num_transitions_to_generate} ---")
|
| 165 |
progress((i + 1) / num_transitions_to_generate, desc=f"Produzindo Transição {i+1}/{num_transitions_to_generate}")
|
| 166 |
|
|
|
|
| 167 |
past_keyframe_path = keyframe_paths[start_keyframe_index - 1]
|
| 168 |
start_keyframe_path = keyframe_paths[start_keyframe_index]
|
| 169 |
destination_keyframe_path = keyframe_paths[start_keyframe_index + 1]
|
| 170 |
future_story_prompt = storyboard[start_keyframe_index + 1] if (start_keyframe_index + 1) < len(storyboard) else "A cena final."
|
| 171 |
|
|
|
|
| 172 |
decision = gemini_singleton.get_cinematic_decision(
|
| 173 |
global_prompt, story_history, past_keyframe_path, start_keyframe_path, destination_keyframe_path,
|
| 174 |
storyboard[start_keyframe_index - 1], storyboard[start_keyframe_index], future_story_prompt
|
|
|
|
| 176 |
_, motion_prompt = decision["transition_type"], decision["motion_prompt"]
|
| 177 |
story_history += f"\n- Ato {i+1}: {motion_prompt}"
|
| 178 |
|
|
|
|
| 179 |
conditioning_items = []
|
| 180 |
logger.info(" [0. PREPARAÇÃO] Montando itens de condicionamento...")
|
| 181 |
|
| 182 |
+
if i == 0:
|
| 183 |
img_start = self._preprocess_image_for_latent_conversion(Image.open(start_keyframe_path).convert("RGB"), target_resolution_tuple)
|
| 184 |
conditioning_items.append(LatentConditioningItem(self.pil_to_latent(img_start), 0, 1.0))
|
| 185 |
logger.info(" - Condicionamento inicial: Imagem K1 no frame 0.")
|
| 186 |
+
else:
|
| 187 |
conditioning_items.append(LatentConditioningItem(eco_latent_for_next_loop, 0, 1.0))
|
| 188 |
conditioning_items.append(LatentConditioningItem(handler_latent_for_next_loop, HANDLER_FRAME_TARGET, handler_strength))
|
| 189 |
+
logger.info(f" - Guia de Memória (Eco) aplicada no frame 0 (shape: {eco_latent_for_next_loop.shape}).")
|
| 190 |
+
logger.info(f" - Guia de Evolução (Handler) aplicada no frame {HANDLER_FRAME_TARGET} (shape: {handler_latent_for_next_loop.shape}).")
|
| 191 |
|
|
|
|
| 192 |
img_dest = self._preprocess_image_for_latent_conversion(Image.open(destination_keyframe_path).convert("RGB"), target_resolution_tuple)
|
| 193 |
conditioning_items.append(LatentConditioningItem(self.pil_to_latent(img_dest), DESTINATION_FRAME_TARGET, destination_convergence_strength))
|
| 194 |
+
logger.info(f" - Guia de Destino: Imagem K{start_keyframe_index + 1} no frame {DESTINATION_FRAME_TARGET}.")
|
| 195 |
|
|
|
|
| 196 |
current_ltx_params = {**base_ltx_params, "motion_prompt": motion_prompt}
|
| 197 |
new_full_latents = self._generate_latent_tensor_internal(conditioning_items, current_ltx_params, target_resolution_tuple, FRAMES_TO_GENERATE)
|
| 198 |
logger.info(f" [1. GERAÇÃO] Tensor latente bruto gerado com shape: {new_full_latents.shape}.")
|
| 199 |
|
|
|
|
| 200 |
eco_latent_for_next_loop = new_full_latents[:, :, ECO_CHUNK_INDICES, :, :].clone()
|
| 201 |
handler_latent_for_next_loop = new_full_latents[:, :, HANDLER_CHUNK_INDICES, :, :].clone()
|
| 202 |
logger.info(f" [GUIAS] Guias para a próxima iteração extraídas. Eco shape: {eco_latent_for_next_loop.shape}, Handler shape: {handler_latent_for_next_loop.shape}.")
|
| 203 |
|
|
|
|
| 204 |
latents_for_video = new_full_latents[:, :, VIDEO_CHUNK_INDICES, :, :]
|
| 205 |
logger.info(f" [2. EDIÇÃO] Tensor final para vídeo extraído com {latents_for_video.shape[2]} chunks.")
|
| 206 |
|
|
|
|
| 207 |
base_name = f"fragment_{i}_{int(time.time())}"
|
| 208 |
video_path = self._generate_video_from_latents(latents_for_video, base_name)
|
| 209 |
video_clips_paths.append(video_path)
|
| 210 |
yield {"fragment_path": video_path}
|
| 211 |
|
|
|
|
| 212 |
final_movie_path = os.path.join(self.workspace_dir, f"final_movie_silent_{int(time.time())}.mp4")
|
| 213 |
self.concatenate_videos_ffmpeg(video_clips_paths, final_movie_path)
|
| 214 |
|