feat(video): support first-last-frame for Wan 2.2 I2V

The I2V path forwards a last-frame image to the pipeline when one is supplied and the loaded pipeline accepts it, turning the run into first-last-frame interpolation. supports_last_frame() gates on the pipeline taking a last_image argument and not running expand_timesteps, which conditions on the first frame only, so a model that cannot use a last frame logs a warning instead of silently ignoring it.
This commit is contained in:
CalamitousFelicitousness
2026-06-30 22:32:10 +01:00
parent 10647c7b67
commit 888cdd1eca
2 changed files with 20 additions and 1 deletions
+7 -1
View File
@@ -67,7 +67,13 @@ def generate(*args, **kwargs):
if init_image is None:
return video_utils.queue_err('No input image provided. Please upload or select an image.')
p.task_args['image'] = images.resize_image(resize_mode=2, im=init_image, width=p.width, height=p.height, upscaler_name=None, output_type='pil')
log.debug(f'Video: op=I2V init={init_image} resized={p.task_args["image"]}')
if last_image is not None and video_utils.supports_last_frame(shared.sd_model):
p.task_args['last_image'] = images.resize_image(resize_mode=2, im=last_image, width=p.width, height=p.height, upscaler_name=None, output_type='pil')
log.debug(f'Video: op=FLF2V init={init_image} last={last_image} resized={p.task_args["image"]}')
elif last_image is not None:
log.warning(f'Video: op=I2V model="{model}" last frame not supported, ignoring')
else:
log.debug(f'Video: op=I2V init={init_image} resized={p.task_args["image"]}')
elif 'FLF2V' in model:
if init_image is None:
return video_utils.queue_err('No input image provided. Please upload or select an image.')
+13
View File
@@ -1,6 +1,7 @@
import os
import sys
import time
import inspect
from PIL import Image
from installer import install
from modules import shared, sd_models, timer, errors, devices
@@ -19,6 +20,18 @@ def get_url(url):
return f'<a href="{url}" target="_blank" rel="noopener noreferrer" class="video-model-link">{url}</a><br><br>' if url else '<br><br>'
def supports_last_frame(model):
# last-frame (FLF2V) conditioning needs a pipeline whose __call__ accepts `last_image`.
# wan 2.2 5b accepts the arg but masks timesteps from the first frame only, so it drops the last frame.
try:
params = list(inspect.signature(type(model).__call__, follow_wrapped=True).parameters)
except (ValueError, TypeError):
return False
if 'last_image' not in params:
return False
return not getattr(getattr(model, 'config', None), 'expand_timesteps', False)
def check_av():
install('av')
try: