LTX video-in pipelines saved with the first-frame wiring are upgraded on run
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzJLJWVu7RZnbRqm3nYAnX
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user