Add MiniMax H3 per-row inpainting workflow
This commit is contained in:
@@ -89,6 +89,19 @@ By default, white mask pixels are regenerated and black pixels are preserved. A
|
||||
|
||||
The source video belongs in the main latent. Do not also pass it as an H3 `<Video>` reference merely to make masking work.
|
||||
|
||||
## Example workflow
|
||||
|
||||
Load [`MiniMax H3 Per-Row Video Inpaint.json`](example_workflows/MiniMax%20H3%20Per-Row%20Video%20Inpaint.json)
|
||||
in ComfyUI for a complete source-video inpainting graph. It includes source AV extraction,
|
||||
automatic `17k+5` trimming, exact H3 canvas resizing, a replaceable static-mask input,
|
||||
32x32 grid verification, source AV encoding, per-row masked sampling, and synchronized
|
||||
video/audio decoding.
|
||||
|
||||
The example expects a 24 fps source video with an audio track. Its **Load Image (as Mask)**
|
||||
node reads white from the selected image's red channel and broadcasts that mask across time;
|
||||
replace this connection with ComfyUI's **SAM3 Track to Mask** output for a moving temporal
|
||||
mask. Select your own source video and mask after loading the workflow.
|
||||
|
||||
## Compatibility
|
||||
|
||||
- Developed against ComfyUI `6f7cd7fceaaf60d2669b554936394a7412c6fde5` (v0.30.0 development series).
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
WORKFLOW = (
|
||||
Path(__file__).parents[1]
|
||||
/ "example_workflows"
|
||||
/ "MiniMax H3 Per-Row Video Inpaint.json"
|
||||
)
|
||||
|
||||
|
||||
def _load_workflow():
|
||||
return json.loads(WORKFLOW.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def test_inpaint_workflow_links_are_consistent():
|
||||
workflow = _load_workflow()
|
||||
nodes = {node["id"]: node for node in workflow["nodes"]}
|
||||
link_ids = set()
|
||||
|
||||
for link in workflow["links"]:
|
||||
link_id, origin_id, origin_slot, target_id, target_slot, link_type = link
|
||||
assert link_id not in link_ids
|
||||
link_ids.add(link_id)
|
||||
assert origin_id in nodes
|
||||
assert target_id in nodes
|
||||
output = nodes[origin_id]["outputs"][origin_slot]
|
||||
input_ = nodes[target_id]["inputs"][target_slot]
|
||||
assert link_id in output["links"]
|
||||
assert input_["link"] == link_id
|
||||
assert output["type"] == link_type
|
||||
assert input_["type"] in {link_type, "*"}
|
||||
|
||||
assert workflow["last_link_id"] == max(link_ids)
|
||||
assert workflow["last_node_id"] == max(nodes)
|
||||
|
||||
|
||||
def test_inpaint_workflow_contains_complete_h3_mask_path():
|
||||
workflow = _load_workflow()
|
||||
types = {node["type"] for node in workflow["nodes"]}
|
||||
assert {
|
||||
"MiniMaxH3TrimSourceAV",
|
||||
"MiniMaxH3MaskGridPreview",
|
||||
"MiniMaxH3SetGenerationMask",
|
||||
"MiniMaxH3SigmaShift",
|
||||
"MiniMaxH3PerRowMaskPatch",
|
||||
"MiniMaxH3ImageToVideo",
|
||||
"LTXVConcatAVLatent",
|
||||
"SamplerCustomAdvanced",
|
||||
"LTXVSeparateAVLatent",
|
||||
} <= types
|
||||
|
||||
|
||||
def test_trimmed_length_controls_conditioning_and_source_latent_controls_sampler():
|
||||
workflow = _load_workflow()
|
||||
nodes = {node["id"]: node for node in workflow["nodes"]}
|
||||
links = {link[0]: link for link in workflow["links"]}
|
||||
|
||||
trim = next(node for node in nodes.values() if node["type"] == "MiniMaxH3TrimSourceAV")
|
||||
conditioning = next(
|
||||
node for node in nodes.values() if node["type"] == "MiniMaxH3ImageToVideo"
|
||||
)
|
||||
sampler = next(node for node in nodes.values() if node["type"] == "SamplerCustomAdvanced")
|
||||
set_mask = next(
|
||||
node for node in nodes.values() if node["type"] == "MiniMaxH3SetGenerationMask"
|
||||
)
|
||||
|
||||
length_link = links[conditioning["inputs"][7]["link"]]
|
||||
assert length_link[1:3] == [trim["id"], 2]
|
||||
|
||||
latent_link = links[sampler["inputs"][4]["link"]]
|
||||
assert latent_link[1:3] == [set_mask["id"], 0]
|
||||
assert conditioning["outputs"][1]["links"] is None
|
||||
Reference in New Issue
Block a user