Tighten tagged ref routing and anchor presets

This commit is contained in:
2026-08-28 15:45:22 +00:00
parent ddd7dbb5af
commit e29d01ad24
4 changed files with 56 additions and 19 deletions
+25 -14
View File
@@ -4405,15 +4405,20 @@ def _named_refs_for_text(text, ref_slots, kinds=None):
haystack = str(text or "")
matched = []
wanted = {str(k).strip().lower() for k in (kinds or ()) if str(k).strip()}
by_name = {}
for slot_number, ref in enumerate(ref_slots or [], 1):
if ref is None or _reference_image(ref) is None:
continue
if wanted and str(ref.get("kind") or "").strip().lower() not in wanted:
continue
for name in _reference_name_keys(ref):
if re.search(r"\b" + re.escape(name) + r"\b", haystack, re.I):
matched.append((slot_number, ref))
break
by_name.setdefault(name.lower(), []).append((slot_number, ref, name))
for entries in by_name.values():
if len(entries) != 1:
continue
slot_number, ref, name = entries[0]
if re.search(r"\b" + re.escape(name) + r"\b", haystack, re.I):
matched.append((slot_number, ref))
return matched
@@ -4533,7 +4538,7 @@ def resolve_tagged_refs(text, ref_list):
return out.strip(), [normalized_refs[n - 1] for n in live], dropped
def resolve_prompt_refs(text, ref_list):
def resolve_prompt_refs(text, ref_list, include_named=True):
"""(rewritten text, refs, dropped) for the refs a shot actually carries.
Explicit <Picture N> tags still decide which slot numbers the prompt points at,
@@ -4545,12 +4550,13 @@ def resolve_prompt_refs(text, ref_list):
rewritten, tagged_refs, dropped = resolve_tagged_refs(text, normalized_refs)
refs = list(tagged_refs)
seen = {id(ref) for ref in refs}
for _slot_number, ref in _named_refs_for_text(rewritten, normalized_refs, kinds=("character", "location")):
marker = id(ref)
if marker in seen:
continue
seen.add(marker)
refs.append(ref)
if include_named:
for _slot_number, ref in _named_refs_for_text(rewritten, normalized_refs, kinds=("character", "location")):
marker = id(ref)
if marker in seen:
continue
seen.add(marker)
refs.append(ref)
return rewritten, refs, dropped
@@ -5999,8 +6005,9 @@ class H3LongVideos:
"for long chains where identity drift matters more than strict per-shot "
"routing. 'where tagged' keeps the old strict behavior, including the "
"first-shot fallback when no tags are found. Tags are renumbered per shot, "
"so <Picture 2> alone still resolves. Character names in the beat can also "
"pull their matching character refs into the real image-conditioning list. "
"so <Picture 2> alone still resolves. In 'auto ref2v', character and "
"location names in the beat can also pull their matching refs into the "
"real image-conditioning list; 'where tagged' does NOT do that. "
"'first shot' / 'every shot' / "
"'every shot + handoff ref' go purely by position. Ignored when no "
"ref_image is connected."}),
@@ -6702,7 +6709,7 @@ class H3LongVideos:
for shot_index, gen in enumerate(gens):
shot_mode = beat_ref_mode_directive(beats[shot_index] if shot_index < len(beats) else "") or ref_mode
if shot_mode in ("where tagged", "auto ref2v") and any_tags_anywhere:
if resolve_prompt_refs(gen, ref_slots)[1]:
if resolve_prompt_refs(gen, ref_slots, include_named=(shot_mode == "auto ref2v"))[1]:
on.append(shot_index + 1)
tagged_used = True
else:
@@ -6796,7 +6803,11 @@ class H3LongVideos:
# The prompt itself says where each reference belongs: the shot whose
# text names <Picture N> gets image N, renumbered to match what that
# shot actually carries. Every untagged shot keeps its handoff.
gen_prompt, shot_refs, dropped = resolve_prompt_refs(gen_prompt, ref_slots)
gen_prompt, shot_refs, dropped = resolve_prompt_refs(
gen_prompt,
ref_slots,
include_named=(shot_mode == "auto ref2v"),
)
for n in dropped:
if n not in ref_missing:
ref_missing.append(n)