@@ -289,6 +289,8 @@ def INPUT_TYPES(s):
289289 },
290290 "optional" : {
291291 "start_latent" : ("LATENT" , {"tooltip" : "init Latents to use for image2video" } ),
292+ "end_latent" : ("LATENT" , {"tooltip" : "end Latents to use for image2video" } ),
293+ "end_image_embeds" : ("CLIP_VISION_OUTPUT" , {"tooltip" : "end Image's clip embeds" } ),
292294 "initial_samples" : ("LATENT" , {"tooltip" : "init Latents to use for video2video" } ),
293295 "denoise_strength" : ("FLOAT" , {"default" : 1.0 , "min" : 0.0 , "max" : 1.0 , "step" : 0.01 }),
294296 }
@@ -299,8 +301,8 @@ def INPUT_TYPES(s):
299301 FUNCTION = "process"
300302 CATEGORY = "FramePackWrapper"
301303
302- def process (self , model , shift , positive , negative , latent_window_size , use_teacache , total_second_length , teacache_rel_l1_thresh , image_embeds , steps , cfg ,
303- guidance_scale , seed , sampler , gpu_memory_preservation , start_latent = None , initial_samples = None , denoise_strength = 1.0 ):
304+ def process (self , model , shift , positive , negative , latent_window_size , use_teacache , total_second_length , teacache_rel_l1_thresh , image_embeds , steps , cfg ,
305+ guidance_scale , seed , sampler , gpu_memory_preservation , start_latent = None , end_latent = None , end_image_embeds = None , initial_samples = None , denoise_strength = 1.0 ):
304306 total_latent_sections = (total_second_length * 30 ) / (latent_window_size * 4 )
305307 total_latent_sections = int (max (round (total_latent_sections ), 1 ))
306308 print ("total_latent_sections: " , total_latent_sections )
@@ -318,11 +320,20 @@ def process(self, model, shift, positive, negative, latent_window_size, use_teac
318320 start_latent = start_latent ["samples" ] * vae_scaling_factor
319321 if initial_samples is not None :
320322 initial_samples = initial_samples ["samples" ] * vae_scaling_factor
323+ if end_latent is not None :
324+ end_latent = end_latent ["samples" ] * vae_scaling_factor
325+ has_end_image = end_latent is not None
321326 print ("start_latent" , start_latent .shape )
322327 B , C , T , H , W = start_latent .shape
323328
324329 image_encoder_last_hidden_state = image_embeds ["last_hidden_state" ].to (base_dtype ).to (device )
325330
331+ if has_end_image :
332+ assert end_image_embeds is not None
333+ end_image_encoder_last_hidden_state = end_image_embeds ["last_hidden_state" ].to (base_dtype ).to (device )
334+ # Combine both image embeddings or use a weighted approach
335+ image_encoder_last_hidden_state = (image_encoder_last_hidden_state + end_image_encoder_last_hidden_state ) / 2
336+
326337 llama_vec = positive [0 ][0 ].to (base_dtype ).to (device )
327338 clip_l_pooler = positive [0 ][1 ]["pooled_output" ].to (base_dtype ).to (device )
328339
@@ -373,9 +384,10 @@ def process(self, model, shift, positive, negative, latent_window_size, use_teac
373384 for latent_padding in latent_paddings :
374385 print (f"latent_padding: { latent_padding } " )
375386 is_last_section = latent_padding == 0
387+ is_first_section = latent_padding == latent_paddings [0 ]
376388 latent_padding_size = latent_padding * latent_window_size
377389
378- print (f'latent_padding_size = { latent_padding_size } , is_last_section = { is_last_section } ' )
390+ print (f'latent_padding_size = { latent_padding_size } , is_last_section = { is_last_section } , is_first_section = { is_first_section } ' )
379391
380392 indices = torch .arange (0 , sum ([1 , latent_padding_size , latent_window_size , 1 , 2 , 16 ])).unsqueeze (0 )
381393 clean_latent_indices_pre , blank_indices , latent_indices , clean_latent_indices_post , clean_latent_2x_indices , clean_latent_4x_indices = indices .split ([1 , latent_padding_size , latent_window_size , 1 , 2 , 16 ], dim = 1 )
@@ -385,6 +397,11 @@ def process(self, model, shift, positive, negative, latent_window_size, use_teac
385397 clean_latents_post , clean_latents_2x , clean_latents_4x = history_latents [:, :, :1 + 2 + 16 , :, :].split ([1 , 2 , 16 ], dim = 2 )
386398 clean_latents = torch .cat ([clean_latents_pre , clean_latents_post ], dim = 2 )
387399
400+ # Use end image latent for the first section if provided
401+ if has_end_image and is_first_section :
402+ clean_latents_post = end_latent .to (history_latents )
403+ clean_latents = torch .cat ([clean_latents_pre , clean_latents_post ], dim = 2 )
404+
388405 #vid2vid
389406
390407 if initial_samples is not None :
@@ -455,7 +472,7 @@ def process(self, model, shift, positive, negative, latent_window_size, use_teac
455472 total_generated_latent_frames += int (generated_latents .shape [2 ])
456473 history_latents = torch .cat ([generated_latents .to (history_latents ), history_latents ], dim = 2 )
457474
458- real_history_latents = history_latents [:, :, :total_generated_latent_frames , :, :]
475+ real_history_latents = history_latents [:, :, :total_generated_latent_frames , :, :]
459476
460477 if is_last_section :
461478 break
0 commit comments