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
def annotate_script_guards(gens, anatomy_shots, anatomy_mode):
"""Human-readable guard report prepended to the script socket.
The `script` output is for inspection, not for feeding back into the node, so
a compact report there is the quickest way to see whether a guard actually made
it into each shot's prompt text.
"""
lines = []
if anatomy_mode == "off":
lines.append("# anatomy_guard: off")
elif anatomy_shots:
lines.append(
"# anatomy_guard: injected on shot(s) "
+ ",".join(str(n) for n in anatomy_shots)
)
else:
lines.append("# anatomy_guard: no shots matched the auto gate")
body = "\n---\n".join(gens)
return "\n".join(lines + ["", body]) if body else "\n".join(lines)
def annotate_script_debug(gens, anatomy_shots, anatomy_mode, ref_slots):
parts = [annotate_script_guards(gens, anatomy_shots, anatomy_mode)]
ref_report = annotate_script_refs(gens, ref_slots)
if ref_report:
parts.insert(1, ref_report)
return "\n".join(part for part in parts if part)
def annotate_script_refs(gens, ref_slots):
"""Per-shot reference routing summary for the script socket."""
lines = []
normalized_slots = _normalized_ref_slots(ref_slots)
for shot_index, gen in enumerate(gens or [], 1):
tagged = _slot_refs_for_text(gen, normalized_slots)
named = _named_refs_for_text(gen, normalized_slots, kinds=("character", "location"))
seen = set()
merged = []
for slot_number, ref in tagged:
key = (slot_number, "tag")
if key in seen:
continue
seen.add(key)
merged.append((slot_number, ref, "tag"))
for slot_number, ref in named:
key = (slot_number, "name")
if key in seen or any(slot_number == existing[0] for existing in merged):
continue
seen.add(key)
merged.append((slot_number, ref, "name"))
if not merged:
lines.append(f"# shot {shot_index} refs: none")
continue
labels = []
for slot_number, ref, source in merged:
label = _reference_text(ref.get("name")) or _reference_text(ref.get("id")) or f"reference {slot_number}"
labels.append(f"Picture {slot_number} {label} (by {source})")
lines.append(f"# shot {shot_index} refs: " + "; ".join(labels))
return "\n".join(lines)
def _annotate_shot_refs(gen, ref_slots, shot_index):
normalized_slots = _normalized_ref_slots(ref_slots)
tagged = _slot_refs_for_text(gen, normalized_slots)
named = _named_refs_for_text(gen, normalized_slots, kinds=("character", "location"))
seen = set()
merged = []
for slot_number, ref in tagged:
key = (slot_number, "tag")
if key in seen:
continue
seen.add(key)
merged.append((slot_number, ref, "tag"))
for slot_number, ref in named:
key = (slot_number, "name")
if key in seen or any(slot_number == existing[0] for existing in merged):
continue
seen.add(key)
merged.append((slot_number, ref, "name"))
if not merged:
return f"# shot {shot_index} refs: none", "References used: none"
labels = []
info_labels = []
for slot_number, ref, source in merged:
label = _reference_text(ref.get("name")) or _reference_text(ref.get("id")) or f"reference {slot_number}"
labels.append(f"Picture {slot_number} {label} (by {source})")
info_labels.append(f"<Picture {slot_number}> {label} (matched by {source})")
return (
f"# shot {shot_index} refs: " + "; ".join(labels),
"References used: " + "; ".join(info_labels),
)
def _annotate_shot_guard(shot_index, anatomy_shots, anatomy_mode):
anatomy_set = set(anatomy_shots or [])
if anatomy_mode == "off":
return "Anatomy guard: off"
if shot_index in anatomy_set:
return "Anatomy guard: injected into this prompt"
if anatomy_mode == "forced":
return "Anatomy guard: forced on, but nothing was injected"
return "Anatomy guard: not injected for this prompt"
def annotate_script_debug(gens, anatomy_shots, anatomy_mode, ref_slots):
blocks = []
for shot_index, gen in enumerate(gens or [], 1):
_ref_report, ref_info = _annotate_shot_refs(gen, ref_slots, shot_index)
blocks.append(
"\n".join(
[
f"Prompt {shot_index}",
gen,
"",
f"Beat {shot_index} info",
_annotate_shot_guard(shot_index, anatomy_shots, anatomy_mode),
ref_info,
]
)
)
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):
+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 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):
optional = self.module.H3LongVideos.INPUT_TYPES()["optional"]
@@ -1038,9 +1057,9 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
plan_only=True,
)
self.assertIn("# anatomy_guard: injected on shot(s) 2", result[3])
self.assertIn("# shot 1 refs: none", result[3])
self.assertIn("# shot 2 refs: none", result[3])
self.assertIn("Prompt 1", result[3])
self.assertIn("Beat 1 info\nAnatomy guard: not injected for this prompt\nReferences used: none", result[3])
self.assertIn("Beat 2 info\nAnatomy guard: injected into this prompt\nReferences used: none", result[3])
self.assertIn(
"[Generation 1] editorial room, soft practical lighting. Francine stands alone.",
result[3],