Report anatomy guard coverage in H3 plans

This commit is contained in:
2026-08-27 07:16:25 +00:00
parent 7ad087f781
commit d24f9b262f
2 changed files with 38 additions and 15 deletions
+31 -12
View File
@@ -6331,10 +6331,27 @@ class H3LongVideos:
override_notes = [beat_override_summary(beat, index) for index, beat in enumerate(beats, 1)] override_notes = [beat_override_summary(beat, index) for index, beat in enumerate(beats, 1)]
override_notes = [note for note in override_notes if note] override_notes = [note for note in override_notes if note]
any_tags_anywhere = any(picture_tags(g) for g in gens) any_tags_anywhere = any(picture_tags(g) for g in gens)
anatomy_shots = [
shot_index + 1
for shot_index, gen in enumerate(gens)
if ANATOMY_STATE.strip() in gen
]
anatomy_mode = ("forced" if anatomy_guard == "on" else
"auto" if anatomy_guard == "auto" else
"off")
anatomy_note = ""
if anatomy_shots:
if anatomy_mode == "forced":
anatomy_note = (f" ANATOMY -- guard injected on shot(s) "
f"{','.join(str(n) for n in anatomy_shots)}")
elif anatomy_mode == "auto":
anatomy_note = (f" ANATOMY -- guard injected on shot(s) "
f"{','.join(str(n) for n in anatomy_shots)} "
f"(auto: multi-person beats and/or sub-native or LoRA-biased runs)")
if plan_only: if plan_only:
# Preview the split using THIS node's own settings -- no render, near-instant. # Preview the split using THIS node's own settings -- no render, near-instant.
shots = len(gens) shots = len(gens)
plan_lens = (lens + [ln] * shots)[:shots] plan_lens = (lens + [ln] * shots)[:shots]
total = round(sum(plan_lens) / fps, 2) total = round(sum(plan_lens) / fps, 2)
uniform = len(set(plan_lens)) == 1 uniform = len(set(plan_lens)) == 1
@@ -6398,9 +6415,10 @@ class H3LongVideos:
(("DIALOGUE MAY BE CUT OFF -- " + "; ".join(fit_warnings) + ". ") if fit_warnings else "") + \ (("DIALOGUE MAY BE CUT OFF -- " + "; ".join(fit_warnings) + ". ") if fit_warnings else "") + \
(f"PLAN (no render): {shape} = ~{total:g}s at {w}x{h}. " (f"PLAN (no render): {shape} = ~{total:g}s at {w}x{h}. "
f"{len(beats) or 1} beat(s). decode {'tiled' if tiled else 'full'}. {vram_str}." f"{len(beats) or 1} beat(s). decode {'tiled' if tiled else 'full'}. {vram_str}."
+ (f" {beats_note}." if beats_note else "") + (f" {beats_note}." if beats_note else "")
+ (" ANCHOR: " + "; ".join(anchor_hazards) + "." + (" ANCHOR: " + "; ".join(anchor_hazards) + "."
if anchor_hazards else "") if anchor_hazards else "")
+ (f"{anatomy_note}." if anatomy_note else "")
+ (f"{plan_audio}." if plan_audio else "") + (f"{plan_audio}." if plan_audio else "")
+ (" EXPOSURE -- " + "; ".join(wardrobe_notes) + "." + (" EXPOSURE -- " + "; ".join(wardrobe_notes) + "."
if wardrobe_notes else "") if wardrobe_notes else "")
@@ -6814,13 +6832,14 @@ class H3LongVideos:
+ ("LoRA active -- count front-loaded so it binds before the scene" + ("LoRA active -- count front-loaded so it binds before the scene"
if lora_on else "") if lora_on else "")
+ ").") if count_subjects else "") + ").") if count_subjects else "")
+ ((" " + preflight_txt.strip()) if preflight_txt else "") + ((" " + preflight_txt.strip()) if preflight_txt else "")
+ (f" MOUTH -- shot(s) {','.join(str(n) for n in mouth_settled)} were seeded " + (f" MOUTH -- shot(s) {','.join(str(n) for n in mouth_settled)} were seeded "
f"from a settled mouth ({MOUTH_SETTLE_FRAMES}f before the cut), because the " f"from a settled mouth ({MOUTH_SETTLE_FRAMES}f before the cut), because the "
f"shot before them ended on dialogue." if mouth_settled else "") f"shot before them ended on dialogue." if mouth_settled else "")
+ (f"{latent_note}." if latent_note else "") + (f"{anatomy_note}." if anatomy_note else "")
+ (f" SLA LoRA '{os.path.basename(str(sla_name))}' paired with sparse attention." + (f"{latent_note}." if latent_note else "")
if sla_name and sparse_on else "") + (f" SLA LoRA '{os.path.basename(str(sla_name))}' paired with sparse attention."
if sla_name and sparse_on else "")
+ (f" {beats_note}." if beats_note else "") + (f" {beats_note}." if beats_note else "")
+ (f"{audio_note}." if audio_note else "") + (f"{audio_note}." if audio_note else "")
+ (" EXPOSURE -- " + "; ".join(wardrobe_notes) + "." + (" EXPOSURE -- " + "; ".join(wardrobe_notes) + "."
+7 -3
View File
@@ -437,7 +437,7 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
module.dialogue_filler_warnings = lambda *_args, **_kwargs: [] module.dialogue_filler_warnings = lambda *_args, **_kwargs: []
module.distribute_generations = lambda anchor, beats, *_args, **_kwargs: [ module.distribute_generations = lambda anchor, beats, *_args, **_kwargs: [
f"[Generation 1] {anchor}. {beats[0]}", f"[Generation 1] {anchor}. {beats[0]}",
f"[Generation 2] {anchor}. {beats[1]}", f"[Generation 2] {anchor}. {beats[1]}{module.ANATOMY_STATE}",
] ]
module.continuity_warnings = lambda _gens: [] module.continuity_warnings = lambda _gens: []
module._empty_av_latent = lambda *_args, **_kwargs: ({"samples": "latent"},) module._empty_av_latent = lambda *_args, **_kwargs: ({"samples": "latent"},)
@@ -459,13 +459,17 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
plan_only=True, plan_only=True,
) )
self.assertEqual( self.assertIn(
"[Generation 1] editorial room, soft practical lighting. Francine stands alone.",
result[3], result[3],
"[Generation 1] editorial room, soft practical lighting. Francine stands alone.\n---\n" )
self.assertIn(
"[Generation 2] editorial room, soft practical lighting. Francine and Frankie walk together.", "[Generation 2] editorial room, soft practical lighting. Francine and Frankie walk together.",
result[3],
) )
self.assertIn("2 beat(s)", result[2]) self.assertIn("2 beat(s)", result[2])
self.assertIn("2 shot(s)", result[2]) self.assertIn("2 shot(s)", result[2])
self.assertIn("ANATOMY -- guard injected on shot(s) 2", result[2])
self.assertEqual(result[-2:], ([], [])) self.assertEqual(result[-2:], ([], []))
finally: finally:
module.torch = original_torch module.torch = original_torch