Files

69 lines
2.7 KiB
Python

"""Guide frames: the real LTX guide logic with a stand-in picture VAE, and a crop that undoes it."""
import json
import pytest
import torch
@pytest.fixture(autouse=True)
def _needs_comfy(comfyui):
"""Imports comfy."""
class _Vae:
downscale_index_formula = (8, 32, 32)
def encode(self, pixels): # [frames, H, W, 3] -> [1, 128, (frames-1)//8+1, H/32, W/32]
frames, h, w = pixels.shape[0], pixels.shape[1], pixels.shape[2]
return torch.ones(1, 128, (frames - 1) // 8 + 1, h // 32, w // 32) * 0.5
def _inputs(length=4):
cond = [[torch.zeros(1, 3, 8), {}]]
return cond, [[torch.zeros(1, 3, 8), {}]], {"samples": torch.zeros(1, 128, length, 2, 2)}
def _picture(monkeypatch, got=None):
from modules.conditioning.guide_frames import nodes
monkeypatch.setattr(nodes, "read", lambda mid: None if mid == "gone" else torch.rand(1, 64, 64, 3))
return nodes
def test_no_list_changes_nothing(monkeypatch):
nodes = _picture(monkeypatch)
pos, neg, lat = _inputs()
out = nodes.FunUIGuideFrames.execute(pos, neg, _Vae(), lat, "").result
assert out[0] is pos and out[1] is neg and out[2] is lat
def test_each_picture_adds_a_guide_frame_and_the_crop_takes_them_off_again(monkeypatch):
from comfy_extras.nodes_lt import LTXVCropGuides
nodes = _picture(monkeypatch)
pos, neg, lat = _inputs(length=5)
frames = json.dumps([{"media_id": "a", "at": 0.5, "strength": 0.25}, {"media_id": "b", "at": 0.0, "strength": 0.4}])
p, n, latent = nodes.FunUIGuideFrames.execute(pos, neg, _Vae(), lat, frames).result
assert latent["samples"].shape[2] == 5 + 2 # one latent frame per picture, at the tail
assert p[0][1].get("keyframe_idxs") is not None
mask = latent["noise_mask"]
assert abs(float(mask[0, 0, 5, 0, 0]) - 0.75) < 1e-6 and abs(float(mask[0, 0, 6, 0, 0]) - 0.6) < 1e-6 # 1 - strength
cropped = LTXVCropGuides.execute(p, n, latent).result
assert cropped[2]["samples"].shape == lat["samples"].shape
assert cropped[0][0][1].get("keyframe_idxs") is None
def test_a_picture_gone_from_the_library_is_left_out_and_bad_lists_are_refused(monkeypatch):
nodes = _picture(monkeypatch)
pos, neg, lat = _inputs()
p, n, latent = nodes.FunUIGuideFrames.execute(
pos, neg, _Vae(), lat, json.dumps([{"media_id": "gone"}, {"media_id": "a"}])).result
assert latent["samples"].shape[2] == 4 + 1
for bad in ("not json", '{"a": 1}', '[{"nothing": 1}]'):
with pytest.raises(RuntimeError):
nodes.FunUIGuideFrames.execute(pos, neg, _Vae(), lat, bad)
def test_a_nan_position_is_refused_not_crashed():
from modules.conditioning.guide_frames import nodes
assert isinstance(nodes.parse('[{"media_id": "a", "at": NaN}]'), str)