Extract fallback role graph wording

This commit is contained in:
2026-06-26 17:53:27 +02:00
parent dcddfe5d61
commit 7a1d1dcac0
6 changed files with 317 additions and 77 deletions
+146
View File
@@ -180,6 +180,29 @@ def _character_cast_two_men(*, pov_first_man: bool = False) -> str:
)["character_cast"]
def _character_cast_subjects(subjects: list[str] | tuple[str, ...]) -> str:
cast = ""
counts = {"woman": 0, "man": 0}
for subject in subjects:
subject = str(subject)
counts[subject] += 1
label = chr(ord("A") + counts[subject] - 1)
cast = pb.build_character_slot_json(
subject_type=subject,
label=label,
age="25-year-old adult" if subject == "woman" else "40-year-old adult",
ethnicity="western_european",
figure="balanced",
body="slim" if subject == "woman" else "average",
descriptor_detail="compact",
expression_intensity=0.55,
softcore_expression_intensity=0.35,
hardcore_expression_intensity=0.75,
character_cast=cast,
)["character_cast"]
return cast
def _action_filter(focus: str, hardcore_position_config: str | dict[str, Any] | None = "") -> str:
kwargs = {
"allow_toys": False,
@@ -1325,6 +1348,128 @@ def smoke_interaction_role_graph_routes() -> None:
_expect_formatter_outputs(row, name, target="single")
def smoke_fallback_role_graph_routes() -> None:
cases = [
(
"fallback_solo_woman_manual",
("woman",),
"Manual stimulation",
"manual_only",
"manual",
"fingering",
4401,
1,
0,
("reclines with thighs open", "one hand between her legs"),
("one hand between her legs", "fingers visibly stimulating"),
),
(
"fallback_solo_man_climax",
("man",),
"Cumshot and climax",
"climax_only",
"climax",
"open_thighs",
4401,
0,
1,
("solo visible ejaculation pose", "semen visible"),
("solo visible ejaculation pose", "visible semen on skin"),
),
(
"fallback_women_only_oral",
("woman", "woman"),
"Oral sex",
"oral_only",
"oral",
"reclining_oral",
4401,
2,
0,
("woman a kneels between woman b", "uses tongue and fingers"),
("woman a kneels between woman b", "uses tongue and fingers"),
),
(
"fallback_women_only_threesome",
("woman", "woman", "woman"),
"Threesomes",
"threesome_only",
"threesome",
"front_back",
4401,
3,
0,
("uses a strap-on", "gives oral contact"),
("uses a strap-on", "gives oral contact"),
),
(
"fallback_men_only_oral",
("man", "man"),
"Oral sex",
"oral_only",
"oral",
"kneeling",
4401,
0,
2,
("man a kneels", "takes man b's penis"),
("man a kneels", "takes man b's penis"),
),
(
"fallback_men_only_threesome",
("man", "man", "man"),
"Threesomes",
"threesome_only",
"threesome",
"front_back",
4401,
0,
3,
("penetrates man b anally", "gives oral contact"),
("penetrates man b anally", "gives oral contact"),
),
(
"fallback_mixed_threesome",
("woman", "man", "man"),
"Threesomes",
"threesome_only",
"threesome",
"front_back",
4401,
1,
2,
("thrusts his penis into woman a", "uses mouth and hands"),
("thrusts his penis into woman a", "uses mouth and hands"),
),
]
for name, subjects, subcategory, focus, family, position_key, seed, women_count, men_count, role_terms, krea_terms in cases:
row = _prompt_row(
name=name,
category="Hardcore sexual poses",
subcategory=subcategory,
seed=seed,
character_cast=_character_cast_subjects(subjects),
women_count=women_count,
men_count=men_count,
hardcore_position_config=_position_filter(focus, family, [position_key]),
)
_expect_custom_row(row, name)
_expect(row.get("position_family") == family, f"{name} position_family mismatch: {row.get('position_family')}")
_expect(position_key in (row.get("position_keys") or []), f"{name} lost position key {position_key!r}")
role_graph = _expect_text(f"{name}.source_role_graph", row.get("source_role_graph"), 30).lower()
for term in role_terms:
_expect(term in role_graph, f"{name} role graph missing {term!r}: {role_graph}")
krea = krea_formatter.format_krea2_prompt("", metadata_json=_json(row), target="single")
prompt = _expect_text(f"{name}.krea_prompt", krea.get("krea_prompt"), 60).lower()
_expect("metadata" in krea.get("method", ""), f"{name}.krea did not use metadata")
_expect("role graph:" not in prompt and "sexual scene:" not in prompt, f"{name} Krea leaked raw labels")
for term in krea_terms:
_expect(term in prompt, f"{name} Krea prompt missing {term!r}: {prompt}")
if name == "fallback_solo_man_climax":
_expect("lower back and ass" not in prompt, f"{name} Krea kept conflicting solo male climax detail: {prompt}")
_expect_formatter_outputs(row, name, target="single")
def smoke_no_expression_fallback() -> None:
cast = pb.build_character_slot_json(
subject_type="woman",
@@ -1463,6 +1608,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
("double_front_back_route", smoke_double_front_back_route),
("climax_position_routes", smoke_climax_position_routes),
("interaction_role_graph_routes", smoke_interaction_role_graph_routes),
("fallback_role_graph_routes", smoke_fallback_role_graph_routes),
("expression_disabled", smoke_no_expression_fallback),
("formatter_metadata_fixtures", smoke_formatter_metadata_fixtures),
]