Support structured custom location entries

This commit is contained in:
2026-06-27 13:36:39 +02:00
parent 17c6d34784
commit 194eb06465
4 changed files with 175 additions and 6 deletions
+98
View File
@@ -521,6 +521,69 @@ def smoke_camera_scene_single() -> None:
_expect("45-degree front-right quarter view" in prompt, "Krea single prompt lost camera directive")
_expect_formatter_outputs(row, "camera_scene_single", target="single")
custom_location = pb.build_location_pool_json(
enabled=True,
combine_mode="replace",
preset="custom_only",
custom_locations=json.dumps(
{
"slug": "greenhouse_suite",
"prompt": "private room with soft daylight",
"camera_profile": {
"key": "glass_conservatory",
"family": "greenhouse",
"layout_label": "Glass conservatory camera layout",
"place": "glass conservatory",
"foreground": "plant shelf edge, fern leaves, and iron table corner",
"midground": "glass panes, iron ribs, and potted palms",
"background": "hanging vines, greenhouse windows, and layered plant depth",
"detail_label": "conservatory details",
"composition": {
"woman": "glass conservatory frame with the woman beside fern leaves and greenhouse depth behind her",
"default": "glass conservatory frame with the subjects beside fern leaves and greenhouse depth behind them",
},
},
},
sort_keys=True,
),
)
custom_composition = pb.build_composition_pool_json(
enabled=True,
combine_mode="replace",
preset="custom_only",
custom_compositions=json.dumps({"prompt": "polished mirror view with bag and shoes visible"}, sort_keys=True),
)
custom_row = _prompt_row(
name="camera_scene_custom_inline_profile",
category="woman",
subcategory="random",
seed=1061,
men_count=0,
camera_config=_orbit_camera(
horizontal_angle=45,
vertical_angle=30,
zoom=5.0,
subject_focus="environment",
),
location_config=custom_location,
composition_config=custom_composition,
)
custom_scene = _expect_text(
"camera_scene_custom_inline_profile.camera_scene_directive",
custom_row.get("camera_scene_directive"),
40,
)
custom_composition_text = _expect_text(
"camera_scene_custom_inline_profile.composition",
custom_row.get("composition"),
20,
)
_expect("Glass conservatory camera layout" in custom_scene, "custom Location Pool JSON camera profile did not drive scene layout")
_expect(custom_row.get("scene_camera_profile_key") == "glass_conservatory", "custom Location Pool JSON profile key was not exposed")
_expect(custom_row.get("scene_entry", {}).get("camera_profile", {}).get("family") == "greenhouse", "custom Location Pool JSON profile metadata was not preserved")
_expect("glass conservatory" in custom_composition_text.lower(), "custom Location Pool JSON profile did not clean composition")
_expect("bag" not in custom_composition_text.lower() and "shoes" not in custom_composition_text.lower(), "custom inline profile composition leaked unrelated props")
def smoke_row_camera_policy() -> None:
row = {
@@ -1037,6 +1100,30 @@ def smoke_location_config_policy() -> None:
_expect(custom.get("enabled") is True, "Custom location config should be active")
_expect(custom.get("apply_mode") == "replace", "Custom location config lost replace mode")
_expect(custom.get("scene_entries", [{}])[0].get("slug") == "custom_room", "Custom location slug parser changed")
structured_custom = json.loads(
pb.build_location_pool_json(
enabled=True,
combine_mode="replace",
preset="custom_only",
custom_locations=json.dumps(
{
"slug": "structured_room",
"text": "structured room with preserved metadata",
"camera_profile": {
"key": "structured_camera_profile",
"foreground": "foreground test anchor",
"midground": "middle test anchor",
"background": "background test anchor",
},
},
sort_keys=True,
),
)
)
structured_entry = structured_custom.get("scene_entries", [{}])[0]
_expect(structured_entry.get("slug") == "structured_room", "Structured custom location lost slug")
_expect(structured_entry.get("prompt") == "structured room with preserved metadata", "Structured custom location did not normalize prompt text")
_expect(structured_entry.get("camera_profile", {}).get("key") == "structured_camera_profile", "Structured custom location lost camera profile metadata")
added = json.loads(
location_config.build_location_pool_json(
@@ -1063,6 +1150,17 @@ def smoke_location_config_policy() -> None:
any("outfit-check" in str(entry) for entry in composition.get("composition_entries") or []),
"Composition inline preset no_outfit_check was not applied",
)
structured_composition = json.loads(
pb.build_composition_pool_json(
enabled=True,
combine_mode="replace",
preset="custom_only",
custom_compositions=json.dumps({"text": "structured composition frame", "source": "json_line"}, sort_keys=True),
)
)
structured_composition_entry = structured_composition.get("composition_entries", [{}])[0]
_expect(structured_composition_entry.get("prompt") == "structured composition frame", "Structured custom composition did not normalize prompt text")
_expect(structured_composition_entry.get("source") == "json_line", "Structured custom composition lost metadata")
parsed = pb._parse_location_config({"enabled": True, "pool_names": [], "scene_entries": custom["scene_entries"]})
_expect(pb._location_config_active(parsed), "Prompt builder location parser wrapper is inactive")