diff --git a/dumas_h3_longvideos.py b/dumas_h3_longvideos.py index 029fb39..49a7c6c 100644 --- a/dumas_h3_longvideos.py +++ b/dumas_h3_longvideos.py @@ -4486,10 +4486,20 @@ def _matched_reference_slots(text, ref_slots, normalized_refs=None): matched = [] seen = set() normalized_slots = normalized_refs if normalized_refs is not None else _normalized_ref_slots(ref_slots) - for slot_number, ref in ( - _slot_refs_for_text(text, normalized_slots) - + _named_refs_for_text(text, normalized_slots, kinds=("character", "location")) - ): + for slot_number, ref in _slot_refs_for_text(text, normalized_slots): + if slot_number in seen: + continue + seen.add(slot_number) + matched.append((slot_number, ref)) + # Character names should win before location names when a beat mentions both. + # That keeps the face conditioning in front of the scene conditioning instead + # of letting an early location slot dominate the named-ref list. + for slot_number, ref in _named_refs_for_text(text, normalized_slots, kinds=("character",)): + if slot_number in seen: + continue + seen.add(slot_number) + matched.append((slot_number, ref)) + for slot_number, ref in _named_refs_for_text(text, normalized_slots, kinds=("location",)): if slot_number in seen: continue seen.add(slot_number) @@ -4624,7 +4634,15 @@ def resolve_prompt_refs(text, ref_list, include_named=True, normalized_refs=None refs = list(tagged_refs) seen = {id(ref) for ref in refs} if include_named: - for _slot_number, ref in _named_refs_for_text(rewritten, normalized_refs, kinds=("character", "location")): + # Keep named character refs ahead of location refs so the identity image + # is the first named reference the model sees on untagged beats. + for _slot_number, ref in _named_refs_for_text(rewritten, normalized_refs, kinds=("character",)): + marker = id(ref) + if marker in seen: + continue + seen.add(marker) + refs.append(ref) + for _slot_number, ref in _named_refs_for_text(rewritten, normalized_refs, kinds=("location",)): marker = id(ref) if marker in seen: continue diff --git a/tests/test_dumas_h3_longvideos.py b/tests/test_dumas_h3_longvideos.py index b4c3330..e3be60c 100644 --- a/tests/test_dumas_h3_longvideos.py +++ b/tests/test_dumas_h3_longvideos.py @@ -479,6 +479,21 @@ class DumasH3LongVideosHelperTests(unittest.TestCase): self.assertFalse(shot_tag_driven) self.assertEqual(mode_eff, "auto ref2v") + def test_resolve_prompt_refs_prioritizes_characters_before_locations(self): + refs = [ + {"kind": "location", "image": "img1", "name": "Hangar"}, + {"kind": "character", "image": "img2", "name": "Mara"}, + ] + + text, references, dropped = self.module.resolve_prompt_refs( + "[Generation 1] Mara waits in the hangar.", + refs, + ) + + self.assertEqual(text, "[Generation 1] Mara waits in the hangar.") + self.assertEqual([self.module._reference_image(ref) for ref in references], ["img2", "img1"]) + self.assertEqual(dropped, []) + def test_shot_references_uses_all_connected_sparse_slots(self): refs = [ None,