diff --git a/modules/models/ltx/__init__.py b/modules/models/ltx/__init__.py index e0a72471..83d997e6 100644 --- a/modules/models/ltx/__init__.py +++ b/modules/models/ltx/__init__.py @@ -29,7 +29,7 @@ import torch from comfy.nested_tensor import NestedTensor from ..._core import log, streams as _streams, traits as _traits, vae_tiles -from .pipeline import optional_nodes as _optional_nodes, presets as _pipeline_presets +from .pipeline import optional_nodes as _optional_nodes, presets as _pipeline_presets, upgrade as _upgrade has_block = _traits.has_block @@ -150,4 +150,4 @@ def decode(latent, model=None, vae=None, audio_vae=None, tile_size=0): TRAITS = traits PROVIDES = {"empty_latent": empty_latent, "decode": decode, "detect": detect, "probe_traits": probe_traits, "pipeline_presets": _pipeline_presets, "optional_nodes": _optional_nodes, - "video_stream": _streams.av_video_stream} + "video_stream": _streams.av_video_stream, "upgrade_slots": _upgrade} diff --git a/modules/models/ltx/pipeline.py b/modules/models/ltx/pipeline.py index c7b8d15e..f0f2a7bc 100644 --- a/modules/models/ltx/pipeline.py +++ b/modules/models/ltx/pipeline.py @@ -172,6 +172,17 @@ def _uncrop(as_guide): OPTIONAL_NODES = {"FunUIIdentityTransfer": {"pass": {"0": "model", "1": "positive", "2": "negative"}}} +def upgrade(slots, _outputs=None): + """A pipeline saved while the picture inputs still read the loader's first output: a start slot that takes whole + videos feeds them from the frames output now (output 0 is always one frame, so such a pipeline ran on a single frame).""" + start = next((s for s in slots if s.get("id") == "source_image" and s.get("node") == "FunUILoadMedia" + and any(r.get("video_frames") for r in s.get("roles") or [])), None) + if not start: + return slots + return [dict(s, inputs={k: (["source_image", 1] if isinstance(v, (list, tuple)) and list(v) == ["source_image", 0] else v) + for k, v in (s.get("inputs") or {}).items()}) for s in slots] + + def optional_nodes(): return OPTIONAL_NODES diff --git a/modules/models/ltx/tests/test_ltx.py b/modules/models/ltx/tests/test_ltx.py index ca696c37..f77e2aa7 100644 --- a/modules/models/ltx/tests/test_ltx.py +++ b/modules/models/ltx/tests/test_ltx.py @@ -210,3 +210,13 @@ def test_what_a_run_puts_on_the_start_slot_is_accepted(registered, pid): assert problems == [] users = [(s["id"], k) for s in slots for k, v in s["inputs"].items() if isinstance(v, list) and v[0] == "source_image"] assert users and all(slots_v == 1 for slots_v in [next(s for s in slots if s["id"] == i)["inputs"][k][1] for i, k in users]) + + +def test_a_pipeline_saved_with_the_old_first_frame_wiring_is_brought_up_to_date(): + from modules.models.ltx.pipeline import presets, upgrade + slots = next(p["slots"] for p in presets() if p["id"] == "ltx23_video_to_video_direct") + old = [dict(s, inputs={k: (["source_image", 0] if v == ["source_image", 1] else v) for k, v in s["inputs"].items()}) for s in slots] + assert old != slots + assert upgrade(old) == slots + plain = [{"id": "source_image", "node": "FunUILoadMedia", "roles": [{"at": "assets.source_image"}], "inputs": {}}, {"id": "a", "node": "X", "inputs": {"image": ["source_image", 0]}}] + assert upgrade(plain) == plain