Add formatter metadata smoke fixtures
This commit is contained in:
@@ -257,8 +257,8 @@ Improve later:
|
|||||||
Near-term:
|
Near-term:
|
||||||
|
|
||||||
- Add final row hygiene already done through `prompt_hygiene.py`.
|
- Add final row hygiene already done through `prompt_hygiene.py`.
|
||||||
- Add a metadata smoke checker for representative rows through
|
- Add a metadata smoke checker for representative generated rows and static
|
||||||
`tools/prompt_smoke.py`.
|
formatter fixtures through `tools/prompt_smoke.py`.
|
||||||
- Normalize every row with one function before JSON serialization.
|
- Normalize every row with one function before JSON serialization.
|
||||||
|
|
||||||
Medium-term:
|
Medium-term:
|
||||||
@@ -359,5 +359,5 @@ Medium-term:
|
|||||||
checks.
|
checks.
|
||||||
2. Extract hardcore role graph generation from `prompt_builder.py` into a
|
2. Extract hardcore role graph generation from `prompt_builder.py` into a
|
||||||
dedicated `hardcore_role_graphs.py` module.
|
dedicated `hardcore_role_graphs.py` module.
|
||||||
3. Add route-level smoke fixtures for more representative Krea/SDXL/caption metadata
|
3. Add more route-level smoke fixtures for generated edge cases that are not
|
||||||
rows.
|
covered by the current static Krea/SDXL/caption metadata fixtures.
|
||||||
|
|||||||
@@ -722,6 +722,9 @@ pair metadata through the core Python APIs, then verifies:
|
|||||||
normal camera text, and preserve composition punctuation before the style
|
normal camera text, and preserve composition punctuation before the style
|
||||||
suffix;
|
suffix;
|
||||||
- expression-disabled rows do not fall back to generated expression text.
|
- expression-disabled rows do not fall back to generated expression text.
|
||||||
|
- static formatter metadata fixtures keep source-provided action families
|
||||||
|
stable across Krea2 prose, SDXL tags, and natural captions even when raw item
|
||||||
|
text contains distracting wording.
|
||||||
|
|
||||||
## Editing Cheatsheet
|
## Editing Cheatsheet
|
||||||
|
|
||||||
|
|||||||
@@ -273,6 +273,64 @@ def _prompt_row(
|
|||||||
return row
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def _fixture_hardcore_row(**overrides: Any) -> dict[str, Any]:
|
||||||
|
row: dict[str, Any] = {
|
||||||
|
"source": "json_category",
|
||||||
|
"prompt": "Fixture explicit adult prompt for metadata route.",
|
||||||
|
"caption": "fixture caption",
|
||||||
|
"negative_prompt": "low quality, bad anatomy",
|
||||||
|
"main_category": "Hardcore sexual poses",
|
||||||
|
"subcategory": "Penetrative sex",
|
||||||
|
"category_slug": "hardcore_sexual_poses",
|
||||||
|
"subcategory_slug": "penetrative_sex",
|
||||||
|
"subject_type": "configured_cast",
|
||||||
|
"subject_phrase": "1 adult woman and 1 adult man",
|
||||||
|
"cast_summary": "1 woman, 1 man",
|
||||||
|
"cast_descriptor_text": (
|
||||||
|
"Woman A: 25-year-old adult woman, slim figure, fair skin, blonde hair, blue eyes; "
|
||||||
|
"Man A: 40-year-old adult man, average figure, tan skin, dark hair"
|
||||||
|
),
|
||||||
|
"cast_descriptors": [
|
||||||
|
"Woman A: 25-year-old adult woman, slim figure, fair skin, blonde hair, blue eyes",
|
||||||
|
"Man A: 40-year-old adult man, average figure, tan skin, dark hair",
|
||||||
|
],
|
||||||
|
"women_count": 1,
|
||||||
|
"men_count": 1,
|
||||||
|
"person_count": 2,
|
||||||
|
"item": (
|
||||||
|
"missionary position while full-body penetrative sex, hands gripping the ass, "
|
||||||
|
"mouth close to the ear, and explicit genital contact visible"
|
||||||
|
),
|
||||||
|
"custom_item": "Penetrative sex",
|
||||||
|
"item_label": "Sexual pose",
|
||||||
|
"item_axis_values": {
|
||||||
|
"position": "missionary position",
|
||||||
|
"penetration_act": "full-body penetrative sex",
|
||||||
|
"mouth_detail": "mouth close to the ear",
|
||||||
|
},
|
||||||
|
"scene_text": "private studio room with warm light",
|
||||||
|
"scene_kind": "explicit adult sex scene",
|
||||||
|
"pose": "configured explicit pose",
|
||||||
|
"composition": "front-facing full-body frame",
|
||||||
|
"source_composition": "front-facing full-body frame",
|
||||||
|
"role_graph": (
|
||||||
|
"Woman A lies on her back with legs open around Man A's hips while Man A is above her between her thighs; "
|
||||||
|
"Man A's hips press close and Man A's penis thrusts into her pussy."
|
||||||
|
),
|
||||||
|
"source_role_graph": (
|
||||||
|
"Woman A lies on her back with legs open around Man A's hips while Man A is above her between her thighs; "
|
||||||
|
"Man A's hips press close and Man A's penis thrusts into her pussy."
|
||||||
|
),
|
||||||
|
"expression": "focused adult expression",
|
||||||
|
"action_family": "penetration",
|
||||||
|
"position_family": "penetrative",
|
||||||
|
"position_key": "missionary",
|
||||||
|
"position_keys": ["missionary"],
|
||||||
|
}
|
||||||
|
row.update(overrides)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
def smoke_builtin_single() -> None:
|
def smoke_builtin_single() -> None:
|
||||||
row = _prompt_row(name="builtin_single_woman", category="woman", subcategory="random", seed=1001, men_count=0)
|
row = _prompt_row(name="builtin_single_woman", category="woman", subcategory="random", seed=1001, men_count=0)
|
||||||
_expect(row.get("source") == "built_in_generator", "builtin row should come from built-in generator")
|
_expect(row.get("source") == "built_in_generator", "builtin row should come from built-in generator")
|
||||||
@@ -681,6 +739,99 @@ def smoke_no_expression_fallback() -> None:
|
|||||||
_expect_formatter_outputs(row, "hardcore_expression_disabled", target="single")
|
_expect_formatter_outputs(row, "hardcore_expression_disabled", target="single")
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_formatter_metadata_fixtures() -> None:
|
||||||
|
cases = [
|
||||||
|
{
|
||||||
|
"name": "fixture_penetration_text_noise",
|
||||||
|
"row": _fixture_hardcore_row(),
|
||||||
|
"krea_terms": ("penis thrusts",),
|
||||||
|
"sdxl_terms": ("penetrative sex", "missionary"),
|
||||||
|
"caption_terms": ("penetrative action",),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fixture_manual_source_family",
|
||||||
|
"row": _fixture_hardcore_row(
|
||||||
|
subcategory="Manual stimulation",
|
||||||
|
subcategory_slug="manual_stimulation",
|
||||||
|
item="wet fingers moving between the thighs, one hand braced on the hip, wet shine on fingers and inner thighs",
|
||||||
|
custom_item="Manual stimulation",
|
||||||
|
item_axis_values={
|
||||||
|
"position": "kneeling hand-between-thighs position",
|
||||||
|
"manual_act": "wet fingers moving between the thighs",
|
||||||
|
},
|
||||||
|
composition="close crop on hands and face",
|
||||||
|
source_composition="close crop on hands and face",
|
||||||
|
role_graph=(
|
||||||
|
"Woman A reclines with thighs open while Man A's hand is between her legs, "
|
||||||
|
"fingers visibly stimulating her pussy."
|
||||||
|
),
|
||||||
|
source_role_graph=(
|
||||||
|
"Woman A reclines with thighs open while Man A's hand is between her legs, "
|
||||||
|
"fingers visibly stimulating her pussy."
|
||||||
|
),
|
||||||
|
action_family="foreplay",
|
||||||
|
position_family="manual",
|
||||||
|
position_key="fingering",
|
||||||
|
position_keys=["fingering", "open_thighs"],
|
||||||
|
),
|
||||||
|
"krea_terms": ("fingers visibly stimulating",),
|
||||||
|
"sdxl_terms": ("manual stimulation", "fingering"),
|
||||||
|
"caption_terms": ("manual action",),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fixture_climax_family",
|
||||||
|
"row": _fixture_hardcore_row(
|
||||||
|
subcategory="Cumshot and climax",
|
||||||
|
subcategory_slug="cumshot_climax",
|
||||||
|
item="external cumshot with cum on lower back and ass, explicit semen aftermath visible",
|
||||||
|
custom_item="Cumshot and climax",
|
||||||
|
item_axis_values={"position": "on all fours with hips raised"},
|
||||||
|
composition="low-angle post-orgasm frame",
|
||||||
|
source_composition="low-angle post-orgasm frame",
|
||||||
|
role_graph=(
|
||||||
|
"Woman A is on all fours with hips raised while Man A is positioned behind her "
|
||||||
|
"and ejaculates semen across her ass, thighs, and lower back."
|
||||||
|
),
|
||||||
|
source_role_graph=(
|
||||||
|
"Woman A is on all fours with hips raised while Man A is positioned behind her "
|
||||||
|
"and ejaculates semen across her ass, thighs, and lower back."
|
||||||
|
),
|
||||||
|
action_family="climax",
|
||||||
|
position_family="climax",
|
||||||
|
position_key="doggy",
|
||||||
|
position_keys=["doggy"],
|
||||||
|
),
|
||||||
|
"krea_terms": ("ejaculates semen",),
|
||||||
|
"sdxl_terms": ("climax", "semen"),
|
||||||
|
"caption_terms": ("climax action",),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
for case in cases:
|
||||||
|
name = case["name"]
|
||||||
|
row = case["row"]
|
||||||
|
_expect_custom_row(row, name)
|
||||||
|
metadata = _json(row)
|
||||||
|
|
||||||
|
krea = krea_formatter.format_krea2_prompt("", metadata_json=metadata, target="single")
|
||||||
|
krea_prompt = _expect_text(f"{name}.krea_prompt", krea.get("krea_prompt"), 40).lower()
|
||||||
|
_expect("metadata" in krea.get("method", ""), f"{name}.krea did not use metadata")
|
||||||
|
_expect("role graph:" not in krea_prompt and "sexual pose:" not in krea_prompt, f"{name}.krea leaked raw labels")
|
||||||
|
for term in case["krea_terms"]:
|
||||||
|
_expect(term in krea_prompt, f"{name}.krea missing {term!r}")
|
||||||
|
|
||||||
|
sdxl = sdxl_formatter.format_sdxl_prompt("", metadata_json=metadata, target="single", trigger=SdxlTrigger, prepend_trigger=True)
|
||||||
|
sdxl_prompt = _expect_text(f"{name}.sdxl_prompt", sdxl.get("sdxl_prompt"), 40).lower()
|
||||||
|
_expect("metadata" in sdxl.get("method", ""), f"{name}.sdxl did not use metadata")
|
||||||
|
for term in case["sdxl_terms"]:
|
||||||
|
_expect(term in sdxl_prompt, f"{name}.sdxl missing {term!r}")
|
||||||
|
|
||||||
|
caption, method = caption_naturalizer.naturalize_caption("", metadata_json=metadata, trigger=Trigger, include_trigger=True)
|
||||||
|
caption_text = _expect_text(f"{name}.caption", caption, 40).lower()
|
||||||
|
_expect("metadata" in method, f"{name}.caption did not use metadata")
|
||||||
|
for term in case["caption_terms"]:
|
||||||
|
_expect(term in caption_text, f"{name}.caption missing {term!r}")
|
||||||
|
|
||||||
|
|
||||||
SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
||||||
("builtin_single_woman", smoke_builtin_single),
|
("builtin_single_woman", smoke_builtin_single),
|
||||||
("camera_scene_single", smoke_camera_scene_single),
|
("camera_scene_single", smoke_camera_scene_single),
|
||||||
@@ -694,6 +845,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("pov_camera_scene", smoke_pov_camera_scene),
|
("pov_camera_scene", smoke_pov_camera_scene),
|
||||||
("krea_pov_penetration_route", smoke_krea_pov_penetration_route),
|
("krea_pov_penetration_route", smoke_krea_pov_penetration_route),
|
||||||
("expression_disabled", smoke_no_expression_fallback),
|
("expression_disabled", smoke_no_expression_fallback),
|
||||||
|
("formatter_metadata_fixtures", smoke_formatter_metadata_fixtures),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user