From c4cd4121b852209f98248ed43f89c6d5ca78a036 Mon Sep 17 00:00:00 2001 From: Chris Dumas Date: Wed, 26 Aug 2026 22:13:18 +0000 Subject: [PATCH] Remove long video plan integration --- README.md | 3 +- dumas_h3_longvideos.py | 60 ++----------------------------- tests/test_dumas_h3_longvideos.py | 47 ------------------------ 3 files changed, 3 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index a6bd109..8fddc74 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,13 @@ - Reads back the nine optional images for a selected MiniMax H3 plan scene, for example by connecting the current `clip_index`. - `Dumas H3 Long Videos (FL2VA + REF2VA)` - - Inputs: H3 model stack, prompt socket, optional `first_frame`, optional `ref_1`..`ref_9`, optional `plan`, optional `plan_scene_index`, plus the upstream long-video control surface for pacing, continuity, audio, overlays, and guards + - Inputs: H3 model stack, prompt socket, optional `first_frame`, optional `ref_1`..`ref_9`, plus the upstream long-video control surface for pacing, continuity, audio, overlays, and guards - Outputs: `images`, `audio`, `info`, `script`, `frames_per_shot`, `total_frames`, `shots`, `video_seconds`, `fps`, `fps_int`, `latent`, `soundscape` - First-pass Dumas port of the `MiniMax-H3-Longvideos` sampler, brought in as a local starting point for long-form H3 chaining work. - Keeps the upstream split-beats / handoff / ref-routing behavior close to source so future Dumas-specific improvements can be compared against a known baseline. - Only the canonical `DumasH3LongVideos` node key is exposed now; the older FL2VA/REF2VA alias entries are no longer duplicated in the Add Node menu. - Prompt `` tags now map to the actual ref socket numbers you wire, even with gaps such as only `ref_2` and `ref_7` connected. - Character refs now contribute appearance and wardrobe context from the same structured object, while location refs contribute environment context from theirs. - - A connected H3 plan can now supply the current scene’s 9-image bundle directly; any directly-wired `ref_*` socket overrides the same numbered plan slot. - The default ref2v bias is now stronger: `ref_mode` defaults to `auto ref2v` so untagged prompts condition every shot instead of only shot 1, and `ref_noise_aug` defaults to `0.95` rather than the upstream-literal `0.999`. - `Dumas H3 Shot Length` diff --git a/dumas_h3_longvideos.py b/dumas_h3_longvideos.py index b2fccae..306a209 100644 --- a/dumas_h3_longvideos.py +++ b/dumas_h3_longvideos.py @@ -276,7 +276,6 @@ ADDED_WIDGETS = ( "motion_guard", "contact_guard", "auto_soundscape", "allow_nonspeech_vocals", "ref_5", "ref_6", "ref_7", "ref_8", "ref_9", - "plan", "plan_scene_index", ) NL = "\n" @@ -4176,33 +4175,6 @@ def _connected_refs(ref_slots): return [ref for ref in (ref_slots or []) if _reference_image(ref) is not None] -def _plan_scene_refs(plan, scene_index): - """Nine ref slots for one plan scene, or all-empty when no usable binding exists.""" - if plan is None: - return (None,) * _image_nodes._H3_PLAN_IMAGE_SLOTS - extracted = _image_nodes.DumasH3PlanExtractSceneImagesNode().extract(plan, scene_index) - refs = [] - for slot_number, image in enumerate( - extracted[1:1 + _image_nodes._H3_PLAN_IMAGE_SLOTS], - 1, - ): - refs.append(_reference_slot(image, slot_number) if image is not None else None) - return tuple(refs) - - -def _merge_ref_slots(direct_slots, plan_slots): - """Directly-wired refs win; plan-scene refs fill the empty sockets.""" - direct_slots = tuple(direct_slots or ()) - plan_slots = tuple(plan_slots or ()) - width = max(len(direct_slots), len(plan_slots), _image_nodes._H3_PLAN_IMAGE_SLOTS) - out = [] - for index in range(width): - direct = direct_slots[index] if index < len(direct_slots) else None - plan_ref = plan_slots[index] if index < len(plan_slots) else None - out.append(direct if direct is not None else plan_ref) - return tuple(out) - - def resolve_tagged_refs(text, ref_list): """(rewritten text, images, dropped) for the tags in ONE shot. @@ -5473,26 +5445,6 @@ class H3LongVideos: "ref_7": ("REFERENCE", {"tooltip": "Reference object for ."}), "ref_8": ("REFERENCE", {"tooltip": "Reference object for ."}), "ref_9": ("REFERENCE", {"tooltip": "Reference object for ."}), - "plan": ( - "H3_CHAIN_PLAN", - { - "tooltip": "Optional H3 plan enriched by Dumas H3 Plan Attach Scene Images. " - "When connected, this node can pull the selected scene's nine " - "image slots directly instead of rewiring them by hand." - }, - ), - "plan_scene_index": ( - "INT", - { - "default": 1, - "min": 1, - "max": 9999, - "step": 1, - "tooltip": "1-based plan scene index to read from `plan`. " - "Any directly-wired ref socket overrides the same slot " - "from the plan scene." - }, - ), "plan_only": ("BOOLEAN", {"default": False, "tooltip": "Preview the shot split WITHOUT rendering. Uses THIS node's own settings (no " "second node, no duplicate entry): returns the plan in 'info' and the " @@ -5989,7 +5941,6 @@ class H3LongVideos: ref_1=None, ref_2=None, ref_3=None, ref_4=None, ref_5=None, ref_6=None, ref_7=None, ref_8=None, ref_9=None, - plan=None, plan_scene_index=1, ref_mode="where tagged", ref_image_size="match", ref_noise_aug=0.999, graph=None, node_id=None): @@ -6014,9 +5965,7 @@ class H3LongVideos: ref_1, ref_2, ref_3, ref_4, ref_5, ref_6, ref_7, ref_8, ref_9, ) - plan_ref_slots = _plan_scene_refs(plan, plan_scene_index) - ref_slots = _merge_ref_slots(direct_ref_slots, plan_ref_slots) - plan_ref_count = len(_connected_refs(plan_ref_slots)) + ref_slots = direct_ref_slots direct_ref_count = len(_connected_refs(direct_ref_slots)) derived_character_memory = _reference_character_memory(ref_slots) effective_character_memory = (character_memory or "").strip() or derived_character_memory @@ -6311,8 +6260,6 @@ class H3LongVideos: src = [] if direct_ref_count: src.append(f"{direct_ref_count} direct") - if plan_ref_count: - src.append(f"{plan_ref_count} from plan scene {int(plan_scene_index)}") plan_ref = (f" ref2va: {n_refs} reference image(s) at '{ref_image_size}' on shot(s) " f"{','.join(str(n) for n in on) or 'none'} ({how}) -> those shots keep " f"the previous frame as their keyframe too, unless ref_noise_aug was lowered" @@ -6664,8 +6611,6 @@ class H3LongVideos: ref_source = [] if direct_ref_count: ref_source.append(f"{direct_ref_count} direct") - if plan_ref_count: - ref_source.append(f"{plan_ref_count} from plan scene {int(plan_scene_index)}") ref_note = (f" ref2va: {connected_ref_count} reference image(s) at '{ref_image_size}' on shot(s) " f"{','.join(str(n) for n in ref_shots)} " f"({ref_placement})" @@ -6687,8 +6632,7 @@ class H3LongVideos: elif connected_ref_count: ref_note = (f" ref2va: {connected_ref_count} reference image(s) connected but ref_mode " f"'{ref_mode}' applied them to no shot" - + (f" (source {' + '.join(([f'{direct_ref_count} direct'] if direct_ref_count else []) + ([f'{plan_ref_count} from plan scene {int(plan_scene_index)}'] if plan_ref_count else []))})" - if (direct_ref_count or plan_ref_count) else "")) + + (f" (source {direct_ref_count} direct)" if direct_ref_count else "")) else: ref_note = "" info = ((anchor_note + " ") if anchor_note else "") + \ diff --git a/tests/test_dumas_h3_longvideos.py b/tests/test_dumas_h3_longvideos.py index 7e46170..04e4fee 100644 --- a/tests/test_dumas_h3_longvideos.py +++ b/tests/test_dumas_h3_longvideos.py @@ -230,53 +230,6 @@ class DumasH3LongVideosHelperTests(unittest.TestCase): for index in range(1, 10): self.assertIn(f"ref_{index}", optional) - self.assertIn("plan", optional) - self.assertIn("plan_scene_index", optional) - - def test_plan_scene_refs_reads_bound_images(self): - attach = self.image_module.DumasH3PlanAttachSceneImagesNode() - plan = {"shots": [{"id": "one"}, {"id": "two"}]} - image2 = object() - image7 = object() - - plan, _ = attach.attach(plan=plan, scene_index=2, image2=image2, image7=image7) - refs = self.module._plan_scene_refs(plan, 2) - - self.assertEqual(len(refs), 9) - self.assertIsNone(refs[0]) - self.assertIs(self.module._reference_image(refs[1]), image2) - self.assertIs(self.module._reference_image(refs[6]), image7) - - def test_merge_ref_slots_prefers_direct_refs_over_plan_refs(self): - merged = self.module._merge_ref_slots( - ( - None, - {"kind": "character", "image": "direct2"}, - None, - None, - {"kind": "character", "image": "direct5"}, - None, - None, - None, - None, - ), - ( - {"kind": "location", "image": "plan1"}, - {"kind": "location", "image": "plan2"}, - {"kind": "location", "image": "plan3"}, - None, - {"kind": "location", "image": "plan5"}, - None, - {"kind": "location", "image": "plan7"}, - None, - None, - ), - ) - - self.assertEqual( - [self.module._reference_image(ref) if ref is not None else None for ref in merged], - ["plan1", "direct2", "plan3", None, "direct5", None, "plan7", None, None], - ) def test_reference_context_matches_character_names_and_location_tags(self): refs = [