140 lines
4.5 KiB
Python
140 lines
4.5 KiB
Python
import json
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
import torch
|
|
|
|
from h3_guidemaster.core import compiler as compiler_module
|
|
from h3_guidemaster.core.compat import assert_native_h3_support
|
|
|
|
|
|
class FakeNested:
|
|
def __init__(self, tensors):
|
|
self.is_nested = True
|
|
self.tensors = tuple(tensors)
|
|
|
|
def unbind(self):
|
|
return self.tensors
|
|
|
|
|
|
def h3_latent():
|
|
return {
|
|
"samples": FakeNested((
|
|
torch.zeros((1, 24, 7, 48, 84)),
|
|
torch.zeros((1, 32, 2, 37)),
|
|
)),
|
|
"keep_me": 123,
|
|
}
|
|
|
|
|
|
def setter(conditioning, values):
|
|
out = []
|
|
for embedding, metadata in conditioning:
|
|
merged = dict(metadata)
|
|
merged.update(values)
|
|
out.append([embedding, merged])
|
|
return out
|
|
|
|
|
|
def test_compiler_preserves_existing_keyframes_and_latent_metadata(monkeypatch):
|
|
monkeypatch.setattr(
|
|
compiler_module,
|
|
"compile_keyframes",
|
|
lambda *args, **kwargs: [{"resolved_frame_index": 10, "latent": "new"}],
|
|
)
|
|
positive = [["embed", {"minimax_keyframes": [{"resolved_frame_index": 0, "latent": "old"}]}]]
|
|
latent = h3_latent()
|
|
out_positive, out_latent = compiler_module.compile_guidemaster(
|
|
positive,
|
|
latent,
|
|
json.dumps({"version": 1, "fps": 24}),
|
|
conditioning_setter=setter,
|
|
)
|
|
assert [k["resolved_frame_index"] for k in out_positive[0][1]["minimax_keyframes"]] == [0, 10]
|
|
assert out_latent["samples"] is latent["samples"]
|
|
assert out_latent["keep_me"] == 123
|
|
|
|
|
|
def test_compiler_leaves_the_latent_untouched(monkeypatch):
|
|
monkeypatch.setattr(compiler_module, "compile_keyframes", lambda *a, **k: [])
|
|
latent = h3_latent()
|
|
latent["noise_mask"] = "existing"
|
|
out_positive, out_latent = compiler_module.compile_guidemaster(
|
|
[["embed", {}]], latent, "", conditioning_setter=setter
|
|
)
|
|
assert out_latent["noise_mask"] == "existing"
|
|
assert out_latent is not latent
|
|
assert "minimax_keyframes" not in out_positive[0][1]
|
|
|
|
|
|
def test_compiler_rejects_empty_conditioning():
|
|
with pytest.raises(ValueError, match="conditioning"):
|
|
compiler_module.compile_guidemaster([], h3_latent(), "", conditioning_setter=setter)
|
|
|
|
|
|
def test_compiler_rejects_malformed_conditioning_entry(monkeypatch):
|
|
monkeypatch.setattr(
|
|
compiler_module, "compile_keyframes", lambda *a, **k: [{"resolved_frame_index": 0}]
|
|
)
|
|
with pytest.raises(ValueError, match="standard CONDITIONING"):
|
|
compiler_module.compile_guidemaster(
|
|
[torch.zeros((1, 4))], h3_latent(), "", conditioning_setter=setter
|
|
)
|
|
|
|
|
|
def test_compat_accepts_required_native_h3_features():
|
|
assert_native_h3_support(
|
|
h3_nodes=SimpleNamespace(MiniMaxH3AddGuide=object()),
|
|
h3_model=SimpleNamespace(FRAME_PER_TOKEN=(1, 4, 4, 4, 4), FRAME_RESCALE=5 / 3),
|
|
)
|
|
|
|
|
|
def test_compat_names_missing_upstream_prs():
|
|
common = dict(
|
|
h3_model=SimpleNamespace(FRAME_PER_TOKEN=(1, 4, 4, 4, 4), FRAME_RESCALE=5 / 3),
|
|
)
|
|
with pytest.raises(RuntimeError, match="#15439"):
|
|
assert_native_h3_support(h3_nodes=SimpleNamespace(), **common)
|
|
|
|
|
|
def test_compiler_does_not_emit_guide_intent_metadata(monkeypatch):
|
|
monkeypatch.setattr(
|
|
compiler_module,
|
|
"compile_keyframes",
|
|
lambda *args, **kwargs: [{"resolved_frame_index": 10, "latent": "guide-latent"}],
|
|
)
|
|
timeline = json.dumps({
|
|
"version": 1, "fps": 24,
|
|
"reference": {"selected_frame": 10},
|
|
"guides": [{
|
|
"id": "g1", "enabled": True, "frame": 10, "image_slot": 0,
|
|
"intent": "legacy text that must be ignored",
|
|
}],
|
|
})
|
|
|
|
out_positive, _ = compiler_module.compile_guidemaster(
|
|
[["embed", {}]], h3_latent(), timeline,
|
|
guide_images={"guide_image_0": object()}, conditioning_setter=setter
|
|
)
|
|
metadata = out_positive[0][1]
|
|
assert "majoor_guide_intents" not in metadata
|
|
assert set(metadata["minimax_keyframes"][-1]) == {"resolved_frame_index", "latent"}
|
|
|
|
|
|
def test_compiler_passes_first_and_last_frames_to_keyframe_compiler(monkeypatch):
|
|
captured = {}
|
|
|
|
def fake_compile(*args, **kwargs):
|
|
captured.update(kwargs)
|
|
return []
|
|
|
|
monkeypatch.setattr(compiler_module, "compile_keyframes", fake_compile)
|
|
first = object()
|
|
last = object()
|
|
compiler_module.compile_guidemaster(
|
|
[["embed", {}]], h3_latent(), json.dumps({"version": 2, "fps": 24}),
|
|
first_frame=first, last_frame=last, conditioning_setter=setter,
|
|
)
|
|
assert captured["first_frame"] is first
|
|
assert captured["last_frame"] is last
|