Improve hardcore prompt wording QA
This commit is contained in:
+145
-22
@@ -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(".")
|
||||
|
||||
Reference in New Issue
Block a user