Improve kneeling oral prompt geometry

This commit is contained in:
2026-06-25 18:00:56 +02:00
parent 5f439dc579
commit 7dc4333746
2 changed files with 202 additions and 1 deletions
+82
View File
@@ -829,6 +829,33 @@ def _is_outercourse_text(*parts: Any) -> bool:
)
def _is_oral_text(*parts: Any) -> bool:
text = " ".join(_clean(part).lower() for part in parts if _clean(part))
return any(
term in text
for term in (
"oral",
"fellatio",
"blowjob",
"deepthroat",
"penis sucking",
"penis in her mouth",
"penis in mouth",
"takes the man's penis",
"takes his penis",
"mouth at penis level",
"mouth on his penis",
"lips wrapped",
"cunnilingus",
"pussy licking",
"mouth on her pussy",
"mouth pressed to her pussy",
"face-sitting",
"sixty-nine",
)
)
def _is_toy_assisted_double_text(*parts: Any) -> bool:
text = " ".join(_clean(part).lower() for part in parts if _clean(part))
if "toy" not in text:
@@ -1444,6 +1471,56 @@ def _dedupe_outercourse_detail(detail: str, role_graph: str, hard_item: str = ""
return _join_detail_clauses(clauses)
def _dedupe_oral_detail(detail: str, role_graph: str, hard_item: str = "", axis_values: Any = None) -> str:
detail = _clean(detail)
if not detail:
return ""
context = _position_context_text(role_graph, hard_item, "", axis_values)
woman_gives = any(
term in context
for term in (
"takes the man's penis",
"takes his penis",
"penis in her mouth",
"mouth at penis level",
"mouth on his penis",
"fellatio",
"blowjob",
"deepthroat",
"penis sucking",
)
)
clauses: list[str] = []
for clause in _detail_clauses(detail):
lower = clause.lower()
if any(
term in lower
for term in (
"kneeling oral position",
"standing oral position",
"edge-of-bed oral position",
"side-lying oral position",
"chair oral position",
"reclining cunnilingus position",
"face-sitting position",
"sixty-nine position",
"fellatio with penis in mouth",
"deepthroat blowjob",
"penis sucking with visible saliva",
"cunnilingus with tongue on pussy",
"oral sex with tongue and fingers",
"oral contact with mouth on the visible genitals",
"bodies stacked close together",
"body angle keeps the penis and face readable",
)
):
continue
if woman_gives and lower == "wet shine on genitals":
clause = "saliva dripping on the penis"
clauses.append(clause)
return _join_detail_clauses(clauses)
def _detail_clauses(detail: str) -> list[str]:
return [part.strip(" ,;") for part in re.split(r",\s*(?:and\s+)?", _clean(detail)) if part.strip(" ,;")]
@@ -1768,6 +1845,7 @@ def _hardcore_action_sentence(
detail = _hardcore_item_detail(hard_item)
anchor = _hardcore_pose_anchor(role_graph, hard_item, composition, axis_values)
is_outercourse = _is_outercourse_text(role_graph, hard_item, composition, _axis_values_text(axis_values))
is_oral = _is_oral_text(role_graph, hard_item, composition, _axis_values_text(axis_values))
if _is_toy_assisted_double_text(role_graph, hard_item, composition, _axis_values_text(axis_values)):
role_graph = re.sub(
r"\s+while a toy adds (?:the|a) second penetration point\b",
@@ -1782,6 +1860,10 @@ def _hardcore_action_sentence(
anchor = ""
detail = _dedupe_outercourse_detail(detail, role_graph, hard_item, axis_values)
detail = _limit_detail_for_density(detail, detail_density, False)
elif is_oral and role_graph:
anchor = ""
detail = _dedupe_oral_detail(detail, role_graph, hard_item, axis_values)
detail = _limit_detail_for_density(detail, detail_density, False)
else:
detail = _dedupe_hardcore_detail(detail, anchor) if anchor else detail
if _is_toy_assisted_double_text(role_graph, hard_item, composition, _axis_values_text(axis_values)):