diff --git a/docs/prompt-pool-routing-map.md b/docs/prompt-pool-routing-map.md index 28dde4a..85edd08 100644 --- a/docs/prompt-pool-routing-map.md +++ b/docs/prompt-pool-routing-map.md @@ -837,6 +837,9 @@ pair metadata through the core Python APIs, then verifies: - generated rows keep prompt, negative prompt, scene, composition, action item, and role graph metadata populated; +- a user-added JSON category in a temporary category directory reaches category + choices, subcategory choices, prompt generation, and formatter metadata + routes without Python glue code; - Krea2, SDXL, and natural caption routes use metadata instead of text fallback; - SDXL and caption trigger handling keeps one trigger; - negative prompts do not duplicate comma-list items; diff --git a/tools/prompt_smoke.py b/tools/prompt_smoke.py index 638b509..7f36eca 100644 --- a/tools/prompt_smoke.py +++ b/tools/prompt_smoke.py @@ -1497,6 +1497,80 @@ def smoke_category_extensions_policy() -> None: "JSON pool_extensions did not reach legacy group scenes", ) + previous_category_dir = category_library.CATEGORY_DIR + previous_extensions_applied = category_extensions._EXTENSIONS_APPLIED + try: + with tempfile.TemporaryDirectory() as temp_dir: + category_library.CATEGORY_DIR = Path(temp_dir) + category_extensions._EXTENSIONS_APPLIED = False + Path(temp_dir, "custom_category.json").write_text( + json.dumps( + { + "categories": { + "Dev Test Wear": { + "prompt_template": ( + "{subject_phrase}: clean test style. {item_label}: {item}. " + "Scene: {scene}. Pose: {pose}. Facial expression: {expression}. " + "Composition: {composition}." + ), + "caption_template": "{subject_phrase}, {item}, {scene}, {composition}", + "subcategories": { + "Layered Office": { + "items": ["structured test blazer over dark trousers"], + "scenes": ["temporary showroom with modular shelves"], + "poses": ["standing by a rail"], + "expressions": ["focused calm look"], + "compositions": ["centered catalog frame"], + } + }, + } + } + }, + ensure_ascii=True, + ), + encoding="utf-8", + ) + _expect("Dev Test Wear" in pb.category_choices(), "User-added JSON category did not reach category choices") + _expect( + "Dev Test Wear / Layered Office" in pb.subcategory_choices(), + "User-added JSON subcategory did not reach subcategory choices", + ) + row = pb.build_prompt( + category="Dev Test Wear", + subcategory="Dev Test Wear / Layered Office", + row_number=1, + start_index=1, + seed=4109, + clothing="random", + ethnicity="any", + poses="random", + backside_bias=0.0, + figure="random", + no_plus_women=False, + no_black=False, + minimal_clothing_ratio=0.0, + standard_pose_ratio=1.0, + trigger=Trigger, + prepend_trigger_to_prompt=True, + extra_positive="", + extra_negative="", + women_count=1, + men_count=0, + ) + _expect_row_base(row, "category_extensions_user_added_json") + _expect(row.get("source") == "json_category", "User-added JSON category did not use custom row route") + _expect(row.get("main_category") == "Dev Test Wear", "User-added JSON category name drifted") + _expect(row.get("subcategory") == "Layered Office", "User-added JSON subcategory name drifted") + _expect(row.get("item") == "structured test blazer over dark trousers", "User-added JSON item did not generate") + _expect(row.get("scene_text") == "temporary showroom with modular shelves", "User-added JSON scene did not generate") + _expect(row.get("pose") == "standing by a rail", "User-added JSON pose did not generate") + _expect(row.get("expression") == "focused calm look", "User-added JSON expression did not generate") + _expect(row.get("composition") == "centered catalog frame", "User-added JSON composition did not generate") + _expect_formatter_outputs(row, "category_extensions_user_added_json", target="single") + finally: + category_library.CATEGORY_DIR = previous_category_dir + category_extensions._EXTENSIONS_APPLIED = previous_extensions_applied + def smoke_category_cast_config_policy() -> None: _expect(pb.CATEGORY_PRESETS is category_cast_config.CATEGORY_PRESETS, "Prompt builder category presets are not delegated")