Clean up per-beat H3 script output

This commit is contained in:
2026-09-02 14:52:58 +00:00
parent 62fbbdd98e
commit 76b88b0c59
2 changed files with 95 additions and 62 deletions
+73 -59
View File
@@ -3247,65 +3247,79 @@ def dialogue_filler_warnings(beats, seconds_per_shot):
return out return out
def annotate_script_guards(gens, anatomy_shots, anatomy_mode): def _annotate_shot_refs(gen, ref_slots, shot_index):
"""Human-readable guard report prepended to the script socket. normalized_slots = _normalized_ref_slots(ref_slots)
tagged = _slot_refs_for_text(gen, normalized_slots)
The `script` output is for inspection, not for feeding back into the node, so named = _named_refs_for_text(gen, normalized_slots, kinds=("character", "location"))
a compact report there is the quickest way to see whether a guard actually made seen = set()
it into each shot's prompt text. merged = []
""" for slot_number, ref in tagged:
lines = [] key = (slot_number, "tag")
if anatomy_mode == "off": if key in seen:
lines.append("# anatomy_guard: off") continue
elif anatomy_shots: seen.add(key)
lines.append( merged.append((slot_number, ref, "tag"))
"# anatomy_guard: injected on shot(s) " for slot_number, ref in named:
+ ",".join(str(n) for n in anatomy_shots) key = (slot_number, "name")
) if key in seen or any(slot_number == existing[0] for existing in merged):
else: continue
lines.append("# anatomy_guard: no shots matched the auto gate") seen.add(key)
body = "\n---\n".join(gens) merged.append((slot_number, ref, "name"))
return "\n".join(lines + ["", body]) if body else "\n".join(lines) if not merged:
return f"# shot {shot_index} refs: none", "References used: none"
labels = []
def annotate_script_debug(gens, anatomy_shots, anatomy_mode, ref_slots): info_labels = []
parts = [annotate_script_guards(gens, anatomy_shots, anatomy_mode)] for slot_number, ref, source in merged:
ref_report = annotate_script_refs(gens, ref_slots) label = _reference_text(ref.get("name")) or _reference_text(ref.get("id")) or f"reference {slot_number}"
if ref_report: labels.append(f"Picture {slot_number} {label} (by {source})")
parts.insert(1, ref_report) info_labels.append(f"<Picture {slot_number}> {label} (matched by {source})")
return "\n".join(part for part in parts if part) return (
f"# shot {shot_index} refs: " + "; ".join(labels),
"References used: " + "; ".join(info_labels),
def annotate_script_refs(gens, ref_slots): )
"""Per-shot reference routing summary for the script socket."""
lines = []
normalized_slots = _normalized_ref_slots(ref_slots) def _annotate_shot_guard(shot_index, anatomy_shots, anatomy_mode):
for shot_index, gen in enumerate(gens or [], 1): anatomy_set = set(anatomy_shots or [])
tagged = _slot_refs_for_text(gen, normalized_slots) if anatomy_mode == "off":
named = _named_refs_for_text(gen, normalized_slots, kinds=("character", "location")) return "Anatomy guard: off"
seen = set() if shot_index in anatomy_set:
merged = [] return "Anatomy guard: injected into this prompt"
for slot_number, ref in tagged: if anatomy_mode == "forced":
key = (slot_number, "tag") return "Anatomy guard: forced on, but nothing was injected"
if key in seen: return "Anatomy guard: not injected for this prompt"
continue
seen.add(key)
merged.append((slot_number, ref, "tag")) def annotate_script_debug(gens, anatomy_shots, anatomy_mode, ref_slots):
for slot_number, ref in named: blocks = []
key = (slot_number, "name") for shot_index, gen in enumerate(gens or [], 1):
if key in seen or any(slot_number == existing[0] for existing in merged): _ref_report, ref_info = _annotate_shot_refs(gen, ref_slots, shot_index)
continue blocks.append(
seen.add(key) "\n".join(
merged.append((slot_number, ref, "name")) [
if not merged: f"Prompt {shot_index}",
lines.append(f"# shot {shot_index} refs: none") gen,
continue "",
labels = [] f"Beat {shot_index} info",
for slot_number, ref, source in merged: _annotate_shot_guard(shot_index, anatomy_shots, anatomy_mode),
label = _reference_text(ref.get("name")) or _reference_text(ref.get("id")) or f"reference {slot_number}" ref_info,
labels.append(f"Picture {slot_number} {label} (by {source})") ]
lines.append(f"# shot {shot_index} refs: " + "; ".join(labels)) )
return "\n".join(lines) )
if blocks:
return "\n\n---\n\n".join(blocks)
if anatomy_mode == "off":
return "Beat info\nAnatomy guard: off\nReferences used: none"
return "Beat info\nAnatomy guard: not injected for this prompt\nReferences used: none"
def annotate_script_refs(gens, ref_slots):
"""Per-shot reference routing summary for the script socket."""
lines = []
for shot_index, gen in enumerate(gens or [], 1):
shot_report, _shot_info = _annotate_shot_refs(gen, ref_slots, shot_index)
lines.append(shot_report)
return "\n".join(lines)
def speech_flags(beats): def speech_flags(beats):
+22 -3
View File
@@ -599,6 +599,25 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
self.assertIn("# shot 1 refs: Picture 1 Mara (by name); Picture 2 Hangar (by name)", report) self.assertIn("# shot 1 refs: Picture 1 Mara (by name); Picture 2 Hangar (by name)", report)
self.assertIn("# shot 2 refs: none", report) self.assertIn("# shot 2 refs: none", report)
def test_annotate_script_debug_groups_each_prompt_with_its_beat_info(self):
refs = [
{"kind": "character", "image": "img1", "name": "Mara"},
{"kind": "location", "image": "img2", "name": "Hangar"},
]
report = self.module.annotate_script_debug(
["[Generation 1] Mara waits in the Hangar.", "[Generation 2] Nobody else is here."],
[1],
"auto",
refs,
)
self.assertIn("Prompt 1\n[Generation 1] Mara waits in the Hangar.", report)
self.assertIn("Beat 1 info\nAnatomy guard: injected into this prompt", report)
self.assertIn("References used: <Picture 1> Mara (matched by name); <Picture 2> Hangar (matched by name)", report)
self.assertIn("Prompt 2\n[Generation 2] Nobody else is here.", report)
self.assertIn("Beat 2 info\nAnatomy guard: not injected for this prompt\nReferences used: none", report)
def test_input_types_expose_nine_ref_slots(self): def test_input_types_expose_nine_ref_slots(self):
optional = self.module.H3LongVideos.INPUT_TYPES()["optional"] optional = self.module.H3LongVideos.INPUT_TYPES()["optional"]
@@ -1038,9 +1057,9 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
plan_only=True, plan_only=True,
) )
self.assertIn("# anatomy_guard: injected on shot(s) 2", result[3]) self.assertIn("Prompt 1", result[3])
self.assertIn("# shot 1 refs: none", result[3]) self.assertIn("Beat 1 info\nAnatomy guard: not injected for this prompt\nReferences used: none", result[3])
self.assertIn("# shot 2 refs: none", result[3]) self.assertIn("Beat 2 info\nAnatomy guard: injected into this prompt\nReferences used: none", result[3])
self.assertIn( self.assertIn(
"[Generation 1] editorial room, soft practical lighting. Francine stands alone.", "[Generation 1] editorial room, soft practical lighting. Francine stands alone.",
result[3], result[3],