diff --git a/docs/prompt-pool-routing-map.md b/docs/prompt-pool-routing-map.md index b979c7d..d19e92d 100644 --- a/docs/prompt-pool-routing-map.md +++ b/docs/prompt-pool-routing-map.md @@ -132,7 +132,7 @@ Core helper ownership: | `krea_row_fields.py` | Shared Krea normal-row field extraction for item, scene, pose, expression, composition/source-composition, camera, and style used by normal and configured-cast routes. | | `krea_cast.py` | Shared formatter cast descriptor parsing, cast labels, cast prose, natural cast descriptor text, and label replacement used by Krea2 and caption routes. | | `prompt_hygiene.py` | Generic prompt, caption, and negative-prompt cleanup, including route-agnostic negative-prompt merge/dedupe. | -| `row_normalization.py` | Final prompt-row and pair metadata normalization: legacy built-in subject/count metadata enrichment, trigger prepending, extra-positive append, negative merge/dedupe, caption-part joining, embedded soft/hard row output and side-metadata synchronization, and embedded row sanitation. | +| `row_normalization.py` | Final prompt-row and pair metadata normalization: legacy built-in subject/count/scene metadata enrichment, trigger prepending, extra-positive append, negative merge/dedupe, caption-part joining, embedded soft/hard row output and side-metadata synchronization, and embedded row sanitation. | | `formatter_detail.py` | Shared formatter detail-level choices, normalization, and concise/balanced/dense gates used by Krea2 and caption routes. | | `formatter_input.py` | Shared formatter input parsing: text cleanup, metadata/source JSON detection, trigger-prefix stripping, shared prompt field-label inventory, fallback field-label stripping, `Avoid:` splitting, prompt-field extraction, and metadata row-value fallback. | | `formatter_target.py` | Shared formatter target choices and normalization for `auto`, `single`, `softcore`, and `hardcore`, including pair-side selection and combined-caption inclusion policy. | diff --git a/row_normalization.py b/row_normalization.py index 8c25f62..dd71af1 100644 --- a/row_normalization.py +++ b/row_normalization.py @@ -3,8 +3,10 @@ from __future__ import annotations from typing import Any try: + from . import row_location as row_location_policy from .prompt_hygiene import combine_negative_text, sanitize_caption_text, sanitize_negative_text, sanitize_prompt_text except ImportError: # Allows local smoke tests with `python tools/prompt_smoke.py`. + import row_location as row_location_policy from prompt_hygiene import combine_negative_text, sanitize_caption_text, sanitize_negative_text, sanitize_prompt_text @@ -77,8 +79,14 @@ def enrich_legacy_row_metadata(row: dict[str, Any]) -> dict[str, Any]: _setdefault_count(row, "men_count", men_count) if women_count is not None and men_count is not None and not str(row.get("person_count") or "").strip(): row["person_count"] = int(women_count) + int(men_count) - if str(row.get("scene") or "").strip() and not str(row.get("scene_slug") or "").strip(): - row["scene_slug"] = row.get("scene") + scene_slug = str(row.get("scene") or row.get("scene_slug") or "").strip() + if scene_slug and not str(row.get("scene_slug") or "").strip(): + row["scene_slug"] = scene_slug + if scene_slug and not str(row.get("scene_text") or "").strip(): + scene_text = row_location_policy.legacy_scene_text_for_slug(scene_slug) + if scene_text: + row["scene_text"] = scene_text + row.setdefault("scene_entry", {"slug": scene_slug, "prompt": scene_text}) return row diff --git a/tools/prompt_smoke.py b/tools/prompt_smoke.py index 5d66efc..52e4d90 100644 --- a/tools/prompt_smoke.py +++ b/tools/prompt_smoke.py @@ -575,13 +575,24 @@ def smoke_builtin_single() -> None: _expect(row.get("subject_phrase") == "woman", "builtin single row lost normalized subject_phrase") _expect(row.get("women_count") == 1 and row.get("men_count") == 0, "builtin single row lost normalized cast counts") _expect(row.get("person_count") == 1, "builtin single row lost normalized person count") + _expect_text("builtin_single_woman.scene_text", row.get("scene_text"), 12) + _expect(row.get("scene_slug") == row.get("scene"), "builtin single row lost legacy scene slug metadata") + _expect(row.get("scene_entry", {}).get("slug") == row.get("scene"), "builtin single row lost scene_entry slug") _expect("cast_summary" not in row, "builtin single row should not masquerade as configured cast") _expect_trigger_once("builtin_single_woman.prompt", row.get("prompt"), Trigger) + krea = krea_formatter.format_krea2_prompt("", metadata_json=_json(row), target="single") + _expect(row.get("scene_text") in str(krea.get("krea_prompt", "")), "builtin single Krea route used scene slug instead of scene text") sdxl = sdxl_formatter.format_sdxl_prompt("", metadata_json=_json(row), target="single", trigger=SdxlTrigger, prepend_trigger=True) _expect("1woman" in str(sdxl.get("sdxl_prompt", "")).lower(), "builtin single SDXL route lost normalized woman count") + sdxl_scene_text = str(sdxl.get("sdxl_prompt", "")).lower() + scene_words = re.findall(r"[a-z0-9]+", str(row.get("scene_text", "")).split(",", 1)[0].lower()) + scene_anchor = " ".join(scene_words[:2]) + _expect(scene_anchor in sdxl_scene_text, "builtin single SDXL route lost readable scene text") + _expect(str(row.get("scene_slug", "")).lower() not in sdxl_scene_text, "builtin single SDXL route leaked raw scene slug") caption, caption_method = caption_naturalizer.naturalize_caption("", metadata_json=_json(row), target="single", trigger=Trigger, include_trigger=True) _expect(caption_method.endswith("metadata(single)"), "builtin single caption route did not use single metadata branch") _expect("woman" in caption.lower(), "builtin single caption route lost normalized subject") + _expect(row.get("scene_text") in caption, "builtin single caption route used scene slug instead of scene text") _expect_formatter_outputs(row, "builtin_single_woman", target="single") @@ -2814,6 +2825,7 @@ def smoke_row_normalization_policy() -> None: { "source": "built_in_generator", "primary_subject": "two women", + "scene": "office", "prompt": "Two adults in a clean legacy prompt.", "caption": "legacy couple caption", "negative_prompt": "bad anatomy", @@ -2824,6 +2836,9 @@ def smoke_row_normalization_policy() -> None: _expect(legacy_couple.get("subject_type") == "couple", "Legacy couple row lost normalized subject_type") _expect(legacy_couple.get("women_count") == 2 and legacy_couple.get("men_count") == 0, "Legacy couple row lost normalized counts") _expect(legacy_couple.get("person_count") == 2, "Legacy couple row lost normalized person count") + _expect(legacy_couple.get("scene_slug") == "office", "Legacy couple row lost scene slug") + _expect("cozy office desk" in str(legacy_couple.get("scene_text", "")), "Legacy couple row lost readable scene text") + _expect(legacy_couple.get("scene_entry", {}).get("slug") == "office", "Legacy couple row lost scene entry") _expect("cast_summary" not in legacy_couple, "Legacy couple row should not gain configured-cast summary") legacy_group = row_normalization.normalize_prompt_row(