Improve hardcore prompt wording QA

This commit is contained in:
2026-06-25 15:07:42 +02:00
parent 9c86151b89
commit 186f225778
3 changed files with 257 additions and 40 deletions
+145 -22
View File
@@ -5104,7 +5104,7 @@ def _role_graph(
"hands pressing both breasts together around the shaft while the glans stays near her mouth."
)
return (
f"{man} sits or reclines with legs apart while {woman} kneels between his thighs, squeezing her breasts "
f"{man} sits with legs apart while {woman} kneels between his thighs, squeezing her breasts "
f"around {man}'s penis with both hands while the glans stays near her mouth."
)
if any(term in text for term in ("testicle", "balls-licking", "balls licking", "balls and mouth", "balls held")):
@@ -5227,7 +5227,7 @@ def _role_graph(
if "kneeling oral" in position_text or ("kneeling oral" in text and not position_text):
if man_gives and not woman_gives:
return f"{woman} kneels with thighs parted and hips angled forward while {man} kneels in front of her with his mouth on her pussy."
return f"{woman} kneels in front of {man}'s hips with her mouth at penis level while {man} stands or sits close above her."
return f"{woman} kneels in front of {man}'s hips with her mouth at penis level while {man} stands close above her."
if man_gives and not woman_gives:
return f"{woman} lies on her back with thighs open while {man} kneels between her legs with his mouth pressed to her pussy."
return f"{woman} kneels in front of {man}'s hips and takes his penis in her mouth while {man} keeps his hips aligned with her face."
@@ -6143,8 +6143,8 @@ INSTA_OF_PLATFORM_STYLES = {
INSTA_OF_HARDCORE_CLOTHING_CONTINUITY = {
"none": "",
"same_outfit": "Woman A keeps her teaser outfit on, with sexual contact still clearly visible",
"partially_removed": "Woman A's teaser outfit is pushed aside and partly removed, exposing the sexual contact clearly",
"same_outfit": "Woman A keeps her teaser outfit on with the body contact readable",
"partially_removed": "Woman A's teaser outfit is pushed aside and partly removed where needed, leaving body contact unobstructed",
"implied_nude": "Woman A's body is partly exposed, with fabric slipping off or covering only part of the body",
"explicit_nude": "Woman A's body is fully exposed, bare skin unobstructed",
}
@@ -6301,9 +6301,9 @@ def character_hardcore_clothing_values(state: str, custom_clothing: str = "") ->
if state == "partly_exposed":
return ["partly nude, body exposed"]
if state == "same_outfit":
return ["keeps the teaser outfit on, with sexual contact clearly visible"]
return ["keeps the teaser outfit on with the body contact readable"]
if state == "partially_removed":
return ["teaser outfit is pushed aside and partly removed, exposing the sexual contact clearly"]
return ["teaser outfit is pushed aside and partly removed where needed, leaving body contact unobstructed"]
if state == "custom":
return _normalize_characteristic_values(custom_clothing, None, allow_free_text=True)
return []
@@ -6559,7 +6559,7 @@ def _insta_of_softcore_pose(rng: random.Random, level: str) -> str:
return g.choose(rng, pool)
PENETRATION_LOWER_ACCESS_TERMS = (
WOMAN_LOWER_ACCESS_TERMS = (
"penetrat",
"thrust",
"vaginal",
@@ -6577,10 +6577,59 @@ PENETRATION_LOWER_ACCESS_TERMS = (
"penis into",
"penis inside",
"penis entering",
"mouth on her pussy",
"mouth pressed to her pussy",
"pussy licking",
"cunnilingus",
"thighs spread",
"thighs open",
"legs spread",
"legs open",
"cum on pussy",
"cum across her pussy",
"cum dripping from pussy",
"cum dripping from ass",
"cum on belly",
"cum on thighs",
"cum across her ass",
"cum across her lower back",
"toy aligned",
"second penetration point",
)
WOMAN_UPPER_ACCESS_TERMS = (
"boobjob",
"titjob",
"breast sex",
"breasts around",
"breasts tightly",
"hands pressing both breasts",
"breasts together",
"cum on breasts",
"cum across her breasts",
"cum on chest",
)
MAN_LOWER_ACCESS_TERMS = (
"penis",
"glans",
"testicle",
"balls",
"cumshot",
"ejaculat",
"semen",
"boobjob",
"titjob",
"breast sex",
"footjob",
"blowjob",
"fellatio",
"penis sucking",
"penis in mouth",
"mouth on penis",
"penis licking",
)
LOWER_BODY_CLOTHING_TERMS = (
"panty",
"panties",
@@ -6603,15 +6652,38 @@ LOWER_BODY_CLOTHING_TERMS = (
"blanket",
)
UPPER_BODY_CLOTHING_TERMS = (
"bra",
"cup",
"cups",
"corset",
"bodysuit",
"bustier",
"top",
"camisole",
"shirt",
"blouse",
"bodice",
"dress",
"robe",
"jacket",
"sweater",
"harness",
"chest",
"cleavage",
"panel",
"panels",
)
INSTA_OF_HARDCORE_MEN_CLOTHING_LOWER_ACCESS = [
"wears an open button shirt with jeans lowered below the hips for sexual contact",
"wears an open button shirt with jeans lowered below the hips for genital access",
"wears a fitted tee pushed up with trousers lowered below the hips",
"keeps a dark shirt on while pants and underwear are pulled down enough for penetration",
"keeps a dark shirt on while pants and underwear are pulled down below the hips",
"wears an open overshirt with jeans pushed down at the thighs",
"wears a hoodie lifted at the waist with sweatpants lowered below the hips",
"wears gym shorts pulled down enough for sexual contact with his shirt still on",
"wears gym shorts pulled down below the hips with his shirt still on",
"keeps a casual shirt on with belt open and pants lowered below the hips",
"wears a half-open shirt with lower garments pushed down for clear sexual contact",
"wears a half-open shirt with lower garments pushed down below the hips",
]
INSTA_OF_HARDCORE_MEN_CLOTHING_VISIBLE = [
@@ -6619,28 +6691,38 @@ INSTA_OF_HARDCORE_MEN_CLOTHING_VISIBLE = [
"wears a fitted tee with pants opened at the waist",
"keeps a dark shirt on with trousers loosened",
"wears an open overshirt with jeans partly lowered",
"wears gym shorts lowered enough for sexual contact with a towel nearby",
"wears gym shorts loose at the waist with a towel nearby",
"wears a hoodie lifted at the waist with sweatpants loosened",
"wears a casual shirt with belt open and pants partly lowered",
"wears a half-open shirt with underwear waistband visible",
"wears a half-open shirt with dark trousers",
]
def _hardcore_row_needs_lower_access(row: dict[str, Any]) -> bool:
def _hardcore_row_access_flags(row: dict[str, Any]) -> dict[str, bool]:
axis_values = row.get("item_axis_values")
axis_text = " ".join(str(value) for value in axis_values.values()) if isinstance(axis_values, dict) else ""
text = " ".join(
role_text = " ".join(
str(part or "")
for part in (
row.get("source_role_graph"),
row.get("role_graph"),
)
).lower()
detail_text = " ".join(
str(part or "")
for part in (
row.get("item"),
row.get("source_composition"),
row.get("composition"),
axis_text,
)
).lower()
return any(term in text for term in PENETRATION_LOWER_ACCESS_TERMS)
full_text = f"{role_text} {detail_text}"
return {
"woman_lower": any(term in role_text for term in WOMAN_LOWER_ACCESS_TERMS),
"woman_upper": any(term in full_text for term in WOMAN_UPPER_ACCESS_TERMS),
"man_lower": any(term in role_text for term in MAN_LOWER_ACCESS_TERMS),
}
def _outfit_without_lower_body_blockers(outfit: str) -> str:
@@ -6654,6 +6736,7 @@ def _outfit_without_lower_body_blockers(outfit: str) -> str:
kept = []
for fragment in fragments:
fragment = fragment.strip(" ,.;")
fragment = re.sub(r"^(?:and|with|under|over)\s+", "", fragment, flags=re.IGNORECASE)
if not fragment:
continue
lower = fragment.lower()
@@ -6672,7 +6755,36 @@ def _outfit_without_lower_body_blockers(outfit: str) -> str:
return ", ".join(deduped)
def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str, needs_lower_access: bool = False) -> str:
def _outfit_without_upper_body_blockers(outfit: str) -> str:
text = str(outfit or "").strip()
if not text:
return ""
text = re.sub(r"\blingerie set\b", "lingerie styling", text, flags=re.IGNORECASE)
text = re.sub(r"\bbalconette bra and brief set\b", "briefs and garter styling", text, flags=re.IGNORECASE)
fragments = re.split(r"\s*,\s*|\s+\band\s+|\s+\bwith\s+|\s+\bunder\s+|\s+\bover\s+", text)
kept = []
for fragment in fragments:
fragment = fragment.strip(" ,.;")
fragment = re.sub(r"^(?:and|with|under|over)\s+", "", fragment, flags=re.IGNORECASE)
if not fragment:
continue
lower = fragment.lower()
if any(term in lower for term in UPPER_BODY_CLOTHING_TERMS):
continue
kept.append(fragment)
if not kept:
return ""
deduped = []
seen = set()
for fragment in kept:
key = re.sub(r"\W+", " ", fragment.lower()).strip()
if key and key not in seen:
deduped.append(fragment)
seen.add(key)
return ", ".join(deduped)
def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str, woman_access: str = "") -> str:
mode = mode if mode in INSTA_OF_HARDCORE_CLOTHING_CONTINUITY else "none"
outfit = str(softcore_outfit or "").strip()
if mode == "none" or not outfit:
@@ -6682,14 +6794,24 @@ def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str, needs_low
return f"Body exposure: {base}."
if mode == "implied_nude":
return f"Body exposure: {base}."
if mode == "partially_removed" and needs_lower_access:
if mode == "partially_removed" and woman_access == "lower":
detail = _outfit_without_lower_body_blockers(outfit)
base = (
"Woman A's lower body is clear for penetration; any lower garment is pulled aside or removed below the hips"
"Woman A's lower body is clear; any lower garment is pulled aside or removed below the hips"
)
if detail:
return f"Clothing state: {base}; visible remaining styling: {detail}."
return f"Clothing state: {base}."
if mode == "partially_removed" and woman_access == "upper":
detail = _outfit_without_upper_body_blockers(outfit)
base = (
"Woman A's breasts and upper body are clear; any bra cup, bodice, or top panel is pulled aside or removed"
)
if detail:
return f"Clothing state: {base}; visible remaining styling: {detail}."
return f"Clothing state: {base}."
if mode == "partially_removed":
return f"Clothing state: Woman A keeps the outfit mostly on; teaser outfit detail: {outfit}."
return f"Clothing state: {base}; teaser outfit detail: {outfit}."
@@ -6995,19 +7117,20 @@ def build_insta_of_pair(
pov_character_labels,
hard_content_rng,
)
needs_lower_access = _hardcore_row_needs_lower_access(hard_row)
access_flags = _hardcore_row_access_flags(hard_row)
woman_access = "lower" if access_flags["woman_lower"] else "upper" if access_flags["woman_upper"] else ""
default_man_hardcore_clothing_entries = _default_man_hardcore_clothing_entries(
hard_men_count,
pov_character_labels,
character_hardcore_clothing_entries,
hard_content_rng,
needs_lower_access,
access_flags["man_lower"],
)
has_primary_hardcore_clothing = any(entry.startswith("Woman A") for entry in character_hardcore_clothing_entries)
fallback_hard_clothing_state = "" if has_primary_hardcore_clothing else _insta_of_hardcore_clothing_state(
options["hardcore_clothing_continuity"],
soft_row["item"],
needs_lower_access=needs_lower_access,
woman_access=woman_access,
)
hard_clothing_parts = [
part.strip().rstrip(".")