77 lines
4.2 KiB
Python
77 lines
4.2 KiB
Python
"""Capture wiring, including the native 0.4.74 audio-lock path; no models needed."""
|
|
import importlib.util
|
|
from pathlib import Path
|
|
import unittest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
spec = importlib.util.spec_from_file_location("h3_capture_validation", ROOT / "nodes/h3_continuity/validation.py")
|
|
assert spec is not None and spec.loader is not None
|
|
validation = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(validation)
|
|
|
|
|
|
def graph():
|
|
return {
|
|
"guide": {"class_type": "MiniMaxH3DirectorGuide", "inputs": {}},
|
|
"split": {"class_type": "LTXVSeparateAVLatent", "inputs": {"av_latent": ["guide", 1]}},
|
|
"lock": {"class_type": "SetLatentNoiseMask", "inputs": {"samples": ["external-audio", 0]}},
|
|
"join": {"class_type": "LTXVConcatAVLatent", "inputs": {"video_latent": ["split", 0], "audio_latent": ["lock", 0]}},
|
|
"sampler": {"class_type": "SamplerCustomAdvanced", "inputs": {"latent_image": ["join", 0]}},
|
|
"append": {"class_type": "DaSiWaH3ContinuityAppend", "inputs": {"sampled": ["sampler", 0], "context": ["guide", 2]}},
|
|
"decode": {"class_type": "VAEDecode", "inputs": {"samples": ["append", 0]}},
|
|
"export": {"class_type": "DaSiWa_EnhancedVideoCombine", "inputs": {"images": ["decode", 0], "container": "MP4", "pingpong": False, "crop_to_audio": False}},
|
|
"publish": {"class_type": "DaSiWaH3ContinuityPublish", "inputs": {"filename": ["export", 1], "ticket": ["append", 1]}},
|
|
}
|
|
|
|
|
|
class CaptureValidationTests(unittest.TestCase):
|
|
def test_direct_and_locked_audio_paths_keep_the_guide_video(self):
|
|
p = graph()
|
|
validation.validate_capture_graph(p, "guide")
|
|
p["sampler"]["inputs"]["latent_image"] = ["guide", 1]
|
|
validation.validate_capture_graph(p, "guide")
|
|
p["lock"]["inputs"]["samples"] = ["guide", 1]
|
|
p["sampler"]["inputs"]["latent_image"] = ["lock", 0]
|
|
validation.validate_capture_graph(p, "guide")
|
|
|
|
def test_audio_only_or_mask_only_guide_link_does_not_authorize_video(self):
|
|
for video in (["split", 1], ["unrelated-video", 0]):
|
|
with self.subTest(video=video):
|
|
p = graph()
|
|
p["join"]["inputs"].update(video_latent=video, audio_latent=["split", 1])
|
|
p["lock"]["inputs"]["mask"] = ["guide", 1]
|
|
with self.assertRaisesRegex(ValueError, "sampler driven by this Director Guide"):
|
|
validation.validate_capture_graph(p, "guide")
|
|
|
|
def test_cyclic_latent_chain_fails_without_recursion_overflow(self):
|
|
p = graph()
|
|
p["split"]["inputs"]["av_latent"] = ["join", 0]
|
|
with self.assertRaises(ValueError):
|
|
validation.validate_capture_graph(p, "guide")
|
|
|
|
def test_export_audio_alone_cannot_satisfy_capture(self):
|
|
p = graph()
|
|
p["export"]["inputs"].update(images=["unrelated-images", 0], audio=["append", 0])
|
|
with self.assertRaisesRegex(ValueError, "images must come from this cumulative latent"):
|
|
validation.validate_capture_graph(p, "guide")
|
|
|
|
def test_segment_exporter_behind_select_filename_in_a_subgraph(self):
|
|
# Issue #90: subgraph-flattened ids and a VHS_SelectFilename between exporter and Publish.
|
|
p = {
|
|
"guide": {"class_type": "MiniMaxH3DirectorGuide", "inputs": {}},
|
|
"7:1": {"class_type": "SamplerCustomAdvanced", "inputs": {"latent_image": ["guide", 1]}},
|
|
"7:2": {"class_type": "DaSiWaH3ContinuitySegmentPrepare", "inputs": {"sampled": ["7:1", 0], "context": ["guide", 2]}},
|
|
"7:3": {"class_type": "DaSiWaH3ContinuitySegmentDecode", "inputs": {"latent": ["7:2", 0], "context": ["7:2", 1]}},
|
|
"9": {"class_type": "VHS_VideoCombine", "inputs": {"images": ["7:3", 0], "audio": ["7:3", 1]}},
|
|
"7:4": {"class_type": "VHS_SelectFilename", "inputs": {"filenames": ["9", 0], "index": -1}},
|
|
"7:5": {"class_type": "DaSiWaH3ContinuityPublish", "inputs": {"filename": ["7:4", 0], "ticket": ["7:2", 2]}},
|
|
}
|
|
validation.validate_capture_graph(p, "guide", "segment")
|
|
p["9"]["inputs"]["audio"] = ["elsewhere", 0]
|
|
with self.assertRaisesRegex(ValueError, "same Segment Decode"):
|
|
validation.validate_capture_graph(p, "guide", "segment")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|