Tighten hardcore Krea action wording
This commit is contained in:
+53
-5
@@ -83,6 +83,52 @@ def _human_join(parts: list[str]) -> str:
|
||||
return f"{', '.join(parts[:-1])}, and {parts[-1]}"
|
||||
|
||||
|
||||
def _prompt_cast_descriptors(text: str) -> str:
|
||||
return _clean_text(text).replace("Woman A / primary creator:", "Woman A:")
|
||||
|
||||
|
||||
def _cast_entries(text: str) -> list[tuple[str, str]]:
|
||||
text = _prompt_cast_descriptors(text)
|
||||
entries: list[tuple[str, str]] = []
|
||||
for part in text.split(";"):
|
||||
part = _clean_text(part)
|
||||
match = re.match(r"^((?:Woman|Man) [A-Z]):\s*(.+)$", part)
|
||||
if match:
|
||||
entries.append((match.group(1), _clean_text(match.group(2))))
|
||||
return entries
|
||||
|
||||
|
||||
def _natural_cast_descriptor_text(text: str) -> str:
|
||||
entries = _cast_entries(text)
|
||||
if not entries:
|
||||
return _clean_text(text)
|
||||
labels = [label for label, _descriptor in entries]
|
||||
if labels == ["Woman A"] or labels == ["Man A"]:
|
||||
return f"A {entries[0][1]}"
|
||||
if set(labels) == {"Woman A", "Man A"} and len(labels) == 2:
|
||||
by_label = {label: descriptor for label, descriptor in entries}
|
||||
return f"A {by_label['Woman A']} alongside a {by_label['Man A']}"
|
||||
return " ".join(f"{label} is {descriptor}." for label, descriptor in entries)
|
||||
|
||||
|
||||
def _cast_labels(text: str) -> list[str]:
|
||||
return [label for label, _descriptor in _cast_entries(text)]
|
||||
|
||||
|
||||
def _natural_label_text(text: Any, labels: list[str]) -> str:
|
||||
text = _clean_text(text)
|
||||
if not text:
|
||||
return ""
|
||||
if set(labels) == {"Woman A", "Man A"}:
|
||||
text = re.sub(r"\bWoman A\b", "the woman", text)
|
||||
text = re.sub(r"\bMan A\b", "the man", text)
|
||||
elif labels == ["Woman A"]:
|
||||
text = re.sub(r"\bWoman A\b", "the woman", text)
|
||||
elif labels == ["Man A"]:
|
||||
text = re.sub(r"\bMan A\b", "the man", text)
|
||||
return text
|
||||
|
||||
|
||||
def _strip_style_tail(text: str) -> str:
|
||||
text = _clean_text(text)
|
||||
for tail in STYLE_TAILS:
|
||||
@@ -428,7 +474,7 @@ def _configured_cast_from_row(row: dict[str, Any], detail_level: str, keep_style
|
||||
|
||||
parts = [f"{_cap_first(subject)} {verb} shown as a consensual {scene_kind}"]
|
||||
if cast_descriptor_text:
|
||||
parts.append(f"The named characters are {cast_descriptor_text}")
|
||||
parts.append(_natural_cast_descriptor_text(cast_descriptor_text))
|
||||
if cast and not cast_descriptor_text:
|
||||
parts.append(f"The cast is {cast}")
|
||||
if role_graph:
|
||||
@@ -505,19 +551,20 @@ def _insta_of_pair_from_row(row: dict[str, Any], detail_level: str, keep_style:
|
||||
options = row.get("options") if isinstance(row.get("options"), dict) else {}
|
||||
cast_descriptors = row.get("shared_cast_descriptors")
|
||||
if isinstance(cast_descriptors, list):
|
||||
cast_descriptor_text = _human_join([_clean_text(item) for item in cast_descriptors if _clean_text(item)])
|
||||
cast_descriptor_text = "; ".join(_clean_text(item) for item in cast_descriptors if _clean_text(item))
|
||||
else:
|
||||
cast_descriptor_text = _clean_text(cast_descriptors)
|
||||
labels = _cast_labels(cast_descriptor_text)
|
||||
|
||||
same_soft_cast = options.get("softcore_cast") == "same_as_hardcore"
|
||||
|
||||
parts = []
|
||||
if cast_descriptor_text and same_soft_cast:
|
||||
parts.append(f"The shared cast descriptors are {cast_descriptor_text}")
|
||||
parts.append(_natural_cast_descriptor_text(cast_descriptor_text))
|
||||
elif descriptor:
|
||||
parts.append(f"The softcore primary creator descriptor is {descriptor}")
|
||||
parts.append(f"A {descriptor}")
|
||||
if cast_descriptor_text and not same_soft_cast:
|
||||
parts.append(f"The hardcore cast descriptors are {cast_descriptor_text}")
|
||||
parts.append(_natural_cast_descriptor_text(cast_descriptor_text))
|
||||
if same_soft_cast:
|
||||
parts.append("The softcore version keeps the same adult cast present together in a non-explicit teaser setup")
|
||||
partner_styling = row.get("softcore_partner_styling")
|
||||
@@ -525,6 +572,7 @@ def _insta_of_pair_from_row(row: dict[str, Any], detail_level: str, keep_style:
|
||||
outfits = partner_styling.get("outfits")
|
||||
if isinstance(outfits, list):
|
||||
outfit_text = _human_join([_clean_text(item) for item in outfits if _clean_text(item)])
|
||||
outfit_text = _natural_label_text(outfit_text, labels)
|
||||
if outfit_text:
|
||||
parts.append(f"Softcore partner styling: {outfit_text}")
|
||||
pose = _clean_text(partner_styling.get("pose"))
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
"cast": "women_only"
|
||||
},
|
||||
{
|
||||
"text": "cock entering ass between men",
|
||||
"text": "penis entering ass between men",
|
||||
"cast": "men_only"
|
||||
},
|
||||
{
|
||||
@@ -203,8 +203,8 @@
|
||||
"vaginal penetration with visible genital contact",
|
||||
"deep vaginal sex",
|
||||
"explicit penetrative sex",
|
||||
"cock entering pussy",
|
||||
"pussy stretched around a cock",
|
||||
"penis entering pussy",
|
||||
"pussy stretched around a penis",
|
||||
"hardcore vaginal thrusting",
|
||||
"full-body penetrative sex",
|
||||
"close-contact vaginal sex"
|
||||
@@ -244,7 +244,7 @@
|
||||
"visibility": [
|
||||
"genitals clearly visible",
|
||||
"penetration clearly visible",
|
||||
"pussy and cock visible",
|
||||
"pussy and penis visible",
|
||||
"explicit genital contact visible",
|
||||
"wetness visible between the thighs",
|
||||
"hips framed in the foreground",
|
||||
@@ -317,7 +317,7 @@
|
||||
"hand_detail": [
|
||||
"hands spreading thighs",
|
||||
"hands holding hips",
|
||||
"one hand stroking a cock",
|
||||
"one hand stroking a penis",
|
||||
"fingers gripping sheets",
|
||||
"hands holding the head gently in place",
|
||||
"hands cupping breasts",
|
||||
@@ -332,17 +332,17 @@
|
||||
"deep mouth contact",
|
||||
"tongue pressed to genitals",
|
||||
"saliva shining on lips",
|
||||
"mouth stretched around a cock"
|
||||
"mouth stretched around a penis"
|
||||
],
|
||||
"oral_act": [
|
||||
"fellatio with cock in mouth",
|
||||
"fellatio with penis in mouth",
|
||||
"deepthroat blowjob",
|
||||
"cunnilingus with tongue on pussy",
|
||||
"face-sitting cunnilingus",
|
||||
"sixty-nine oral sex",
|
||||
{"text": "blowjob while another partner watches", "min_people": 3},
|
||||
"pussy licking with thighs spread",
|
||||
"cock sucking with visible saliva",
|
||||
"penis sucking with visible saliva",
|
||||
"oral sex with tongue and fingers",
|
||||
"mouth on genitals with explicit contact"
|
||||
],
|
||||
@@ -381,7 +381,7 @@
|
||||
"visibility": [
|
||||
"mouth and genitals clearly visible",
|
||||
"tongue contact clearly visible",
|
||||
"cock and lips visible",
|
||||
"penis and lips visible",
|
||||
"pussy and tongue visible",
|
||||
"saliva and arousal visible",
|
||||
"face pressed to genitals",
|
||||
@@ -426,8 +426,8 @@
|
||||
},
|
||||
"anal penetration with visible genital contact",
|
||||
"deep anal sex",
|
||||
"cock entering ass",
|
||||
"ass stretched around a cock",
|
||||
"penis entering ass",
|
||||
"ass stretched around a penis",
|
||||
"hardcore anal thrusting",
|
||||
"bent-over anal sex",
|
||||
"rear-entry anal penetration",
|
||||
@@ -494,7 +494,7 @@
|
||||
"min_people": 2
|
||||
},
|
||||
{
|
||||
"text": "cock and toy double penetration",
|
||||
"text": "penis and toy double penetration",
|
||||
"cast": "mixed",
|
||||
"min_people": 2
|
||||
},
|
||||
@@ -511,7 +511,7 @@
|
||||
"double penetration with pussy and ass filled",
|
||||
"vaginal and anal penetration at the same time",
|
||||
"front-and-back double penetration",
|
||||
"one cock in pussy and one cock in ass",
|
||||
"one penis in pussy and one penis in ass",
|
||||
"hardcore double penetration",
|
||||
"kneeling double penetration",
|
||||
"standing supported double penetration",
|
||||
@@ -588,10 +588,10 @@
|
||||
"wet skin sliding together"
|
||||
],
|
||||
"visibility": [
|
||||
"ass and cock clearly visible",
|
||||
"ass and penis clearly visible",
|
||||
"anal penetration clearly visible",
|
||||
"double penetration clearly visible",
|
||||
"pussy, ass, and cocks visible",
|
||||
"pussy, ass, and penises visible",
|
||||
"genital contact anatomically clear",
|
||||
"spread cheeks exposing penetration",
|
||||
"open thighs exposing both entries",
|
||||
@@ -668,7 +668,7 @@
|
||||
"hands holding breasts",
|
||||
"fingers spreading thighs",
|
||||
"hands tangled in hair",
|
||||
"one hand stroking a cock",
|
||||
"one hand stroking a penis",
|
||||
"hands braced on the mattress",
|
||||
"fingers digging into ass",
|
||||
"hands pulling bodies closer"
|
||||
@@ -710,10 +710,10 @@
|
||||
"one partner licking pussy",
|
||||
"sixty-nine oral contact",
|
||||
"mouth on genitals while penetration happens",
|
||||
"one partner sucking cock from the front",
|
||||
"one partner sucking penis from the front",
|
||||
"one partner licking from behind",
|
||||
"oral sex and penetration at the same time",
|
||||
"a mouth full of cock with saliva visible"
|
||||
"a mouth full of penis with saliva visible"
|
||||
],
|
||||
"penetration_detail": [
|
||||
{
|
||||
@@ -731,8 +731,8 @@
|
||||
"visible vaginal penetration",
|
||||
"visible anal penetration",
|
||||
"front-and-back penetration",
|
||||
"one cock in pussy",
|
||||
"one cock in ass",
|
||||
"one penis in pussy",
|
||||
"one penis in ass",
|
||||
"penetration while another partner uses their mouth",
|
||||
"deep thrusting into the center partner",
|
||||
"explicit genital contact"
|
||||
@@ -772,7 +772,7 @@
|
||||
"visibility": [
|
||||
"all genitals clearly visible",
|
||||
"penetration and oral contact visible",
|
||||
"pussy, cock, and mouth contact visible",
|
||||
"pussy, penis, and mouth contact visible",
|
||||
"explicit genital contact from two angles",
|
||||
"open thighs and spread bodies visible",
|
||||
"anatomically clear hardcore contact",
|
||||
@@ -898,10 +898,10 @@
|
||||
"cast": "women_only"
|
||||
},
|
||||
{
|
||||
"text": "one mouth on a cock",
|
||||
"text": "one mouth on a penis",
|
||||
"cast": "men_only"
|
||||
},
|
||||
"one mouth on a cock",
|
||||
"one mouth on a penis",
|
||||
"one mouth on a pussy",
|
||||
"multiple mouths giving oral sex",
|
||||
"sixty-nine contact inside the group",
|
||||
@@ -926,7 +926,7 @@
|
||||
"visible vaginal penetration",
|
||||
"visible anal penetration",
|
||||
"double penetration visible",
|
||||
"multiple cocks penetrating",
|
||||
"multiple penises penetrating",
|
||||
"front-and-back penetration",
|
||||
"genitals pressed together",
|
||||
"open thighs exposing penetration",
|
||||
@@ -1097,7 +1097,7 @@
|
||||
],
|
||||
"hand_detail": [
|
||||
"hands spreading thighs",
|
||||
"one hand holding a cock",
|
||||
"one hand holding a penis",
|
||||
"hands gripping sheets",
|
||||
"hands rubbing cum into skin",
|
||||
"fingers holding the mouth open",
|
||||
|
||||
+113
-16
@@ -185,20 +185,46 @@ def _label_join(labels: list[str]) -> str:
|
||||
labels = [_clean(label) for label in labels if _clean(label)]
|
||||
if not labels:
|
||||
return "the named adults"
|
||||
if set(labels) == {"Woman A", "Man A"}:
|
||||
return "the woman and man"
|
||||
if len(labels) == 1:
|
||||
if labels[0] == "Woman A":
|
||||
return "the woman"
|
||||
if labels[0] == "Man A":
|
||||
return "the man"
|
||||
return labels[0]
|
||||
if len(labels) == 2:
|
||||
return f"{labels[0]} and {labels[1]}"
|
||||
return f"{', '.join(labels[:-1])}, and {labels[-1]}"
|
||||
|
||||
|
||||
def _natural_label_text(text: Any, labels: list[str]) -> str:
|
||||
text = _clean(text)
|
||||
if not text:
|
||||
return ""
|
||||
if set(labels) == {"Woman A", "Man A"}:
|
||||
text = re.sub(r"\bWoman A\b", "the woman", text)
|
||||
text = re.sub(r"\bMan A\b", "the man", text)
|
||||
elif labels == ["Woman A"]:
|
||||
text = re.sub(r"\bWoman A\b", "the woman", text)
|
||||
elif labels == ["Man A"]:
|
||||
text = re.sub(r"\bMan A\b", "the man", text)
|
||||
return text
|
||||
|
||||
|
||||
def _cast_prose(text: str, central_label: str = "Woman A") -> tuple[str, list[str]]:
|
||||
entries = _cast_entries(text)
|
||||
if not entries:
|
||||
return (f"{central_label} is {_clean(text)}" if _clean(text) else "", [])
|
||||
labels = [label for label, _descriptor in entries]
|
||||
count_phrase = "one named adult" if len(entries) == 1 else f"{len(entries)} named adults"
|
||||
sentences = [f"The scene contains {count_phrase}."]
|
||||
if labels == ["Woman A"]:
|
||||
return f"A {entries[0][1]}", labels
|
||||
if labels == ["Man A"]:
|
||||
return f"A {entries[0][1]}", labels
|
||||
if set(labels) == {"Woman A", "Man A"} and len(labels) == 2:
|
||||
by_label = {label: descriptor for label, descriptor in entries}
|
||||
return f"A {by_label['Woman A']} alongside a {by_label['Man A']}", labels
|
||||
sentences = []
|
||||
for label, descriptor in entries:
|
||||
sentences.append(f"{label} is {descriptor}.")
|
||||
if central_label in labels:
|
||||
@@ -225,10 +251,72 @@ def _natural_clothing_state(text: Any) -> str:
|
||||
if not text:
|
||||
return ""
|
||||
text = re.sub(r"^Clothing state:\s*", "", text, flags=re.IGNORECASE)
|
||||
text = re.sub(r";\s*softcore visual reference:\s*", ". Softcore visual reference: ", text, flags=re.IGNORECASE)
|
||||
match = re.match(
|
||||
r"^(.*?)\b(?:softcore|teaser) outfit is (.*?)(?: for the (?:hardcore|sex) scene)?;\s*(?:softcore visual reference|teaser outfit detail):\s*(.*?)\.?$",
|
||||
text,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
if match:
|
||||
owner = _natural_label_text(match.group(1).strip(" 's"), ["Woman A", "Man A"]).strip() or "the woman"
|
||||
state = _clean(match.group(2)).lower()
|
||||
outfit = _clean(match.group(3)).rstrip(".")
|
||||
if "fully nude" in state:
|
||||
return f"{owner.capitalize()} is fully nude, with the removed {outfit} visible nearby"
|
||||
if "nude-adjacent" in state:
|
||||
return f"{owner.capitalize()} is partly nude, with the {outfit} slipping off and no abstract clothing-reference wording"
|
||||
if "partially removed" in state or "pushed aside" in state:
|
||||
return f"{owner.capitalize()}'s {outfit} is pushed aside and partly removed, exposing the sexual contact clearly"
|
||||
if "keeps" in state:
|
||||
return f"{owner.capitalize()} keeps the {outfit} on while the sexual contact stays visible"
|
||||
text = re.sub(r";\s*(?:softcore visual reference|teaser outfit detail):\s*", ". Visual clothing state: ", text, flags=re.IGNORECASE)
|
||||
text = text.replace("softcore outfit", "outfit")
|
||||
text = text.replace("teaser outfit", "outfit")
|
||||
text = text.replace("hardcore scene", "sex scene")
|
||||
return text
|
||||
|
||||
|
||||
def _hardcore_action_sentence(role_graph: str, hard_item: str) -> str:
|
||||
role_graph = _clean(role_graph).rstrip(".")
|
||||
hard_item = _clean(hard_item).rstrip(".")
|
||||
role_graph = re.sub(
|
||||
r"\bthe man penetrates the woman while a toy adds a second point of contact\b",
|
||||
"the man's penis thrusts into the woman while a toy adds a second penetration point",
|
||||
role_graph,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
role_graph = re.sub(
|
||||
r"\bthe man penetrates the woman anally\b",
|
||||
"the man's penis thrusts into the woman's ass",
|
||||
role_graph,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
role_graph = re.sub(
|
||||
r"\bthe man penetrates the woman\b",
|
||||
"the man's penis thrusts into the woman",
|
||||
role_graph,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
role_graph = re.sub(
|
||||
r"\bthe woman and the man are in mutual oral contact with mouth-to-genital contact visible\b",
|
||||
"the woman has the man's penis in her mouth while the man uses his mouth on her pussy",
|
||||
role_graph,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
role_graph = re.sub(
|
||||
r"\bthe woman gives oral to the man\b",
|
||||
"the woman takes the man's penis in her mouth",
|
||||
role_graph,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
if hard_item and role_graph:
|
||||
return f"Explicit hardcore action: {role_graph}; {hard_item}"
|
||||
if role_graph:
|
||||
return f"Explicit hardcore action: {role_graph}"
|
||||
if hard_item:
|
||||
return f"Explicit hardcore action: {hard_item}"
|
||||
return ""
|
||||
|
||||
|
||||
def _clean_age(age: Any) -> str:
|
||||
return _clean(age)
|
||||
|
||||
@@ -353,19 +441,27 @@ def _normal_row_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
if subject_type == "configured_cast" or _clean(row.get("cast_summary")):
|
||||
subject = _clean(row.get("subject_phrase") or primary or "adult sexual scene")
|
||||
cast = _clean(row.get("cast_summary"))
|
||||
try:
|
||||
women_count = int(row.get("women_count") or 0)
|
||||
men_count = int(row.get("men_count") or 0)
|
||||
except (TypeError, ValueError):
|
||||
women_count = men_count = 0
|
||||
cast_descriptor_text = (
|
||||
_clean(row.get("cast_descriptor_text"))
|
||||
or _prompt_field(_clean(row.get("prompt")), "Characters")
|
||||
or _prompt_field(_clean(row.get("prompt")), "Cast descriptors")
|
||||
)
|
||||
cast_prose, _cast_labels = _cast_prose(cast_descriptor_text)
|
||||
role_graph = _clean(row.get("role_graph"))
|
||||
cast_prose, cast_labels = _cast_prose(cast_descriptor_text)
|
||||
if not cast_labels and women_count == 1 and men_count == 1:
|
||||
cast_labels = ["Woman A", "Man A"]
|
||||
role_graph = _natural_label_text(_clean(row.get("role_graph")), cast_labels)
|
||||
item = _natural_label_text(item, cast_labels)
|
||||
action = _hardcore_action_sentence(role_graph, item)
|
||||
parts = [
|
||||
f"A consensual explicit adult scene with {subject}",
|
||||
action,
|
||||
cast_prose,
|
||||
f"The cast includes {cast}" if cast and not cast_prose else "",
|
||||
role_graph,
|
||||
f"The sexual action is {item}" if item else "",
|
||||
f"A consensual explicit adult scene with {subject}" if not action else "",
|
||||
f"The cast includes {cast}" if cast and not cast_prose and not (women_count == 1 and men_count == 1) else "",
|
||||
f"The setting is {scene}" if scene else "",
|
||||
f"Facial expressions are {expression}" if expression else "",
|
||||
f"The image is framed as {composition}" if composition else "",
|
||||
@@ -452,11 +548,14 @@ def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
hard_cast_prose, hard_labels = _cast_prose(cast_descriptor_text)
|
||||
hard_item = _sanitize_scene_text_for_cast(hard.get("item"), hard_labels)
|
||||
hard_role_graph = _sanitize_scene_text_for_cast(hard.get("role_graph"), hard_labels)
|
||||
hard_item = _natural_label_text(hard_item, hard_labels)
|
||||
hard_role_graph = _natural_label_text(hard_role_graph, hard_labels)
|
||||
hard_action = _hardcore_action_sentence(hard_role_graph, hard_item)
|
||||
same_soft_cast = options.get("softcore_cast") == "same_as_hardcore"
|
||||
soft_cast_presence = (
|
||||
f"{_label_join(soft_labels)} are together in a non-explicit teaser pose, with no sex act or genital contact"
|
||||
if same_soft_cast
|
||||
else "The softcore version focuses on Woman A alone"
|
||||
else "The image focuses on the woman alone"
|
||||
)
|
||||
partner_styling = row.get("softcore_partner_styling")
|
||||
if isinstance(partner_styling, dict):
|
||||
@@ -466,13 +565,13 @@ def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
else:
|
||||
partner_outfit_text = ""
|
||||
partner_pose = ""
|
||||
partner_outfit_text = _natural_label_text(partner_outfit_text, soft_labels)
|
||||
|
||||
soft_parts = [
|
||||
f"Softcore {soft_level or 'creator'} Insta/OF image",
|
||||
soft_cast_prose,
|
||||
soft_cast_presence,
|
||||
partner_outfit_text,
|
||||
f"The cast is {partner_pose}" if partner_pose else "",
|
||||
partner_pose,
|
||||
f"wearing {soft.get('item')}" if soft.get("item") else "",
|
||||
f"{soft.get('pose')}" if soft.get("pose") else "",
|
||||
f"with {soft.get('expression')}" if soft.get("expression") else "",
|
||||
@@ -482,11 +581,9 @@ def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
soft_style if detail_level != "concise" else "",
|
||||
]
|
||||
hard_parts = [
|
||||
f"{hard_level or 'hardcore'} scene",
|
||||
hard_cast_prose,
|
||||
hard_action,
|
||||
_natural_clothing_state(row.get("hardcore_clothing_state")),
|
||||
hard_role_graph,
|
||||
f"The explicit detail shows {hard_item}" if hard_item else "",
|
||||
hard_cast_prose,
|
||||
f"set in {hard_scene}" if hard_scene else "",
|
||||
f"with {hard.get('expression')}" if hard.get("expression") else "",
|
||||
f"framed as {hard_composition}" if hard_composition else "",
|
||||
|
||||
+24
-24
@@ -551,7 +551,7 @@ def _heuristic_cast_compatible(text: str, women_count: int, men_count: int) -> b
|
||||
"double penetration" in text
|
||||
or "two partners penetrating" in text
|
||||
or "front-and-back penetration" in text
|
||||
or "one cock in pussy and one cock in ass" in text
|
||||
or "one penis in pussy and one penis in ass" in text
|
||||
or "pussy and ass filled" in text
|
||||
or "vaginal and anal penetration at the same time" in text
|
||||
or "front-and-back double penetration" in text
|
||||
@@ -582,9 +582,9 @@ def _heuristic_cast_compatible(text: str, women_count: int, men_count: int) -> b
|
||||
if any(term in text for term in penetration_terms) and not any(term in text for term in toy_terms):
|
||||
return False
|
||||
male_terms = (
|
||||
" cock",
|
||||
"cock ",
|
||||
"cocks",
|
||||
" penis",
|
||||
"penis ",
|
||||
"penises",
|
||||
"cum",
|
||||
"creampie",
|
||||
"facial",
|
||||
@@ -596,7 +596,7 @@ def _heuristic_cast_compatible(text: str, women_count: int, men_count: int) -> b
|
||||
)
|
||||
if any(term in text for term in male_terms) and not any(term in text for term in toy_terms):
|
||||
return False
|
||||
elif men_count < 2 and "cocks" in text:
|
||||
elif men_count < 2 and "penises" in text:
|
||||
return False
|
||||
if women_count == 0:
|
||||
if "penetrative sex" in text and not any(term in text for term in ("anal", "ass", "male/male", "men")):
|
||||
@@ -2484,7 +2484,7 @@ def _role_graph(
|
||||
return f"{solo} is shown in a solo explicit climax pose with thighs open, one hand on her body, and visible arousal on skin and sheets."
|
||||
return f"{solo} is shown in a solo explicit adult pose with self-touch, open body framing, and direct camera awareness."
|
||||
if "cumshot" in slug or "climax" in slug:
|
||||
return f"{solo} is shown in a solo explicit climax pose with one hand on his cock, body angled toward the camera, and visible ejaculation detail."
|
||||
return f"{solo} is shown in a solo explicit climax pose with one hand on his penis, body angled toward the camera, and visible ejaculation detail."
|
||||
return f"{solo} is shown in a solo explicit adult pose with direct camera awareness and clear body framing."
|
||||
|
||||
if women_count > 0 and men_count == 0:
|
||||
@@ -2510,7 +2510,7 @@ def _role_graph(
|
||||
c = any_man({a, b}) if len(men) >= 3 else ""
|
||||
used = {a, b}
|
||||
if "oral" in slug:
|
||||
graph = f"{a} kneels and takes {b}'s cock in his mouth while holding his hips."
|
||||
graph = f"{a} kneels and takes {b}'s penis in his mouth while holding his hips."
|
||||
elif "anal" in slug or "double" in slug or "penetrative" in slug:
|
||||
graph = f"{a} penetrates {b} anally while {b}'s hips are held open."
|
||||
elif "threesome" in slug or "group" in slug or "orgy" in slug:
|
||||
@@ -2518,9 +2518,9 @@ def _role_graph(
|
||||
graph = f"{a} penetrates {b} anally while {helper} gives oral contact from the front."
|
||||
used.add(helper)
|
||||
elif "cumshot" in slug or "climax" in slug:
|
||||
graph = f"{a} climaxes over {b}'s body while {b} keeps eye contact and one hand on his cock."
|
||||
graph = f"{a} climaxes over {b}'s body while {b} keeps eye contact and one hand on his penis."
|
||||
else:
|
||||
graph = f"{a} and {b} keep explicit cock and anal contact visible."
|
||||
graph = f"{a} and {b} keep explicit penis and anal contact visible."
|
||||
return graph + support_sentence(used)
|
||||
|
||||
# Mixed cast.
|
||||
@@ -2529,29 +2529,29 @@ def _role_graph(
|
||||
third = any_person({woman, man}) if people_count >= 3 else ""
|
||||
if "oral" in slug:
|
||||
if "sixty-nine" in item_text or ("blowjob" in item_text and ("cunnilingus" in item_text or "pussy" in item_text)):
|
||||
graph = f"{woman} and {man} are in mutual oral contact with mouth-to-genital contact visible."
|
||||
graph = f"{woman} has {man}'s penis in her mouth while {man} uses his mouth on {woman}'s pussy, with both mouths pressed to genitals."
|
||||
elif any(term in item_text for term in ("cunnilingus", "pussy licking", "tongue on pussy", "mouth on pussy")):
|
||||
graph = f"{man} gives oral to {woman} while {woman}'s thighs are held open for the camera."
|
||||
graph = f"{man} gives oral to {woman}, mouth on her pussy while {woman}'s thighs are held open for the camera."
|
||||
else:
|
||||
graph = f"{woman} gives oral to {man} while {man} holds her hair and hips."
|
||||
graph = f"{woman} takes {man}'s penis in her mouth while {man} holds her hair and hips."
|
||||
elif "anal" in slug or "double" in slug:
|
||||
if "double" in item_text or "toy" in item_text:
|
||||
if people_count >= 3:
|
||||
graph = f"{man} penetrates {woman} while {third} adds a second point of contact from the front."
|
||||
graph = f"{man} thrusts his penis into {woman} while {third} adds a second penetration point from the front."
|
||||
else:
|
||||
graph = f"{man} penetrates {woman} while a toy adds a second point of contact."
|
||||
graph = f"{man} thrusts his penis into {woman} while a toy adds a second penetration point."
|
||||
elif people_count >= 3:
|
||||
graph = f"{man} penetrates {woman} while {third} gives oral contact from the front."
|
||||
graph = f"{man} thrusts his penis into {woman} while {third} gives oral contact from the front."
|
||||
else:
|
||||
graph = f"{man} penetrates {woman} anally while keeping her hips held open."
|
||||
graph = f"{man} thrusts his penis into {woman}'s ass while keeping her hips held open."
|
||||
elif "threesome" in slug:
|
||||
graph = f"{man} penetrates {woman} while {third or any_person({woman, man})} uses mouth or hands on the exposed body."
|
||||
graph = f"{man} thrusts his penis into {woman} while {third or any_person({woman, man})} uses mouth or hands on the exposed body."
|
||||
elif "group" in slug or "orgy" in slug:
|
||||
graph = f"{man} penetrates {woman} while surrounding partners give oral contact and keep hands on hips, breasts, and thighs."
|
||||
graph = f"{man} thrusts his penis into {woman} while surrounding partners give oral contact and keep hands on hips, breasts, and thighs."
|
||||
elif "cumshot" in slug or "climax" in slug:
|
||||
graph = f"{man} climaxes on {woman}'s body while {woman} stays posed with thighs open and direct eye contact."
|
||||
else:
|
||||
graph = f"{man} and {woman} keep penetration and body contact visible."
|
||||
graph = f"{man}'s penis thrusts into {woman} with penetration and body contact visible."
|
||||
return graph + support_sentence({woman, man, third} if third else {woman, man})
|
||||
|
||||
|
||||
@@ -3251,10 +3251,10 @@ INSTA_OF_PLATFORM_STYLES = {
|
||||
|
||||
INSTA_OF_HARDCORE_CLOTHING_CONTINUITY = {
|
||||
"none": "",
|
||||
"same_outfit": "Woman A keeps the softcore outfit in the hardcore scene",
|
||||
"partially_removed": "Woman A's softcore outfit is partially removed or pushed aside for the hardcore scene",
|
||||
"implied_nude": "Woman A is nude-adjacent in the hardcore scene, with the softcore outfit slipping off or covering only part of the body",
|
||||
"explicit_nude": "Woman A is fully nude in the hardcore scene, with the removed softcore outfit visible nearby",
|
||||
"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",
|
||||
"implied_nude": "Woman A is partly nude, with the teaser outfit slipping off or covering only part of the body",
|
||||
"explicit_nude": "Woman A is fully nude, with the removed teaser outfit visible nearby",
|
||||
}
|
||||
|
||||
INSTA_OF_NEGATIVE = (
|
||||
@@ -3609,7 +3609,7 @@ def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: str) -> str:
|
||||
if mode == "none" or not outfit:
|
||||
return ""
|
||||
base = INSTA_OF_HARDCORE_CLOTHING_CONTINUITY[mode]
|
||||
return f"Clothing state: {base}; softcore visual reference: {outfit}."
|
||||
return f"Clothing state: {base}; teaser outfit detail: {outfit}."
|
||||
|
||||
|
||||
def _insta_of_partner_styling(
|
||||
|
||||
Reference in New Issue
Block a user