Improve same-cast softcore and solo hardcore prompts

This commit is contained in:
2026-06-24 11:13:59 +02:00
parent 51d351679f
commit af8fe355f7
5 changed files with 162 additions and 13 deletions
+105 -5
View File
@@ -343,6 +343,29 @@ def _heuristic_cast_compatible(text: str, women_count: int, men_count: int) -> b
if not text:
return True
total = women_count + men_count
if total == 1:
solo_blocked_terms = (
"partner",
"partners",
"two bodies",
"three bodies",
"bodies still pressed",
"bodies pressed",
"bodies tangled",
"wet bodies",
"chests heaving together",
"straddling a partner",
"shared climax",
"between two",
"from both sides",
"front-and-back",
"body contact",
)
if any(term in text for term in solo_blocked_terms):
return False
solo_toy_terms = ("toy", "dildo", "finger", "fingers", "self")
if "penetration" in text and not any(term in text for term in solo_toy_terms):
return False
if total < 3 and "threesome" in text:
return False
if total != 3 and ("centered threesome" in text or "three-way" in text):
@@ -395,6 +418,7 @@ def _heuristic_cast_compatible(text: str, women_count: int, men_count: int) -> b
"blowjob",
"fellatio",
"deepthroat",
"ejaculation",
"semen",
)
if any(term in text for term in male_terms) and not any(term in text for term in toy_terms):
@@ -1270,6 +1294,16 @@ def _role_graph(
]
return f" {extra} {rng.choice(actions)}."
if people_count == 1:
solo = people[0]
if women_count == 1:
if "cumshot" in slug or "climax" in slug:
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 adult pose with direct camera awareness and clear body framing."
if women_count > 0 and men_count == 0:
a, b = _pick_distinct(rng, women, 2)
c = any_woman({a, b}) if len(women) >= 3 else ""
@@ -2074,6 +2108,40 @@ def _insta_of_cast_phrase(women_count: int, men_count: int) -> str:
return context["cast_summary"]
SOFTCORE_CAST_POSES = [
"standing together for a mirror selfie with bodies close but no sexual contact",
"posing shoulder-to-shoulder in a creator-shot group teaser",
"leaning together on the bed in a non-explicit subscriber preview",
"sitting close together with hands kept above clothing",
"arranged around Woman A in a flirtatious non-explicit teaser pose",
"posing in the same room as a coordinated adult creator set",
"standing near the phone tripod with relaxed teasing body language",
"framed together in a softcore cast reveal with no sex act",
]
def _insta_of_partner_styling(
seed_config: dict[str, int],
seed: int,
row_number: int,
women_count: int,
men_count: int,
) -> dict[str, Any]:
content_rng = _axis_rng(seed_config, "content", seed, row_number + 421)
pose_rng = _axis_rng(seed_config, "pose", seed, row_number + 421)
outfits: list[str] = []
for index in range(max(0, women_count - 1)):
label = chr(ord("B") + index)
outfits.append(f"Woman {label} wears {g.choose(content_rng, g.WOMEN_CLOTHES_MINIMAL)}")
for index in range(max(0, men_count)):
label = chr(ord("A") + index)
outfits.append(f"Man {label} wears {g.choose(content_rng, g.MEN_CLOTHES_MINIMAL)}")
return {
"outfits": outfits,
"pose": g.choose(pose_rng, SOFTCORE_CAST_POSES),
}
def _insta_of_active_trigger(prompt: str, trigger: str, enabled: bool) -> str:
return _prepend_trigger(prompt, trigger, enabled)
@@ -2167,6 +2235,16 @@ def build_insta_of_pair(
if options["softcore_cast"] == "same_as_hardcore"
else f"Woman A / primary creator: {descriptor}"
)
soft_partner_styling = _insta_of_partner_styling(
parsed_seed_config,
seed,
row_number,
hard_women_count if options["softcore_cast"] == "same_as_hardcore" else 1,
hard_men_count if options["softcore_cast"] == "same_as_hardcore" else 0,
)
if options["softcore_cast"] != "same_as_hardcore":
soft_partner_styling = {"outfits": [], "pose": ""}
soft_partner_outfit_text = "; ".join(soft_partner_styling["outfits"])
platform_style = INSTA_OF_PLATFORM_STYLES[options["platform_style"]]
soft_level = INSTA_OF_SOFT_LEVELS[options["softcore_level"]]
hard_level = INSTA_OF_HARDCORE_LEVELS[options["hardcore_level"]]
@@ -2186,12 +2264,24 @@ def build_insta_of_pair(
if options["softcore_cast"] == "solo"
else f"non-explicit teaser setup with the same adult cast as the hardcore version: {_insta_of_cast_phrase(hard_women_count, hard_men_count)}"
)
soft_cast_presence = (
"Show the same listed adult cast together in the softcore version, present in the same location in a non-explicit teaser pose with no sex act or genital contact. "
if options["softcore_cast"] == "same_as_hardcore"
else "Keep the softcore version focused on Woman A alone. "
)
soft_cast_styling_sentence = (
f"Partner softcore styling: {soft_partner_outfit_text}. Shared softcore cast pose: {soft_partner_styling['pose']}. "
if options["softcore_cast"] == "same_as_hardcore" and soft_partner_outfit_text
else ""
)
hard_cast = _insta_of_cast_phrase(hard_women_count, hard_men_count)
soft_prompt = (
f"Insta/OF softcore mode: {platform_style}. Shared primary creator descriptor: {descriptor}. "
f"Softcore setup: {soft_level}. Cast continuity: {soft_cast}. "
f"Shared cast descriptors: {soft_cast_descriptor_text}. "
f"{soft_cast_presence}"
f"{soft_cast_styling_sentence}"
f"Outfit: {soft_row['item']}. Pose: {soft_row['pose']}. Setting: {soft_row['scene_text']}. "
f"Facial expression: {soft_row['expression']}. Composition: {soft_row['composition']}. "
f"{soft_camera_sentence}"
@@ -2217,11 +2307,20 @@ def build_insta_of_pair(
hard_prompt = _insta_of_active_trigger(hard_prompt, active_trigger, bool(prepend_trigger_to_prompt))
soft_negative = _combined_negative(INSTA_OF_SOFT_NEGATIVE, extra_negative)
hard_negative = _combined_negative(INSTA_OF_NEGATIVE, extra_negative)
soft_caption = (
f"{active_trigger}, Insta/OF softcore mode, {descriptor}, {soft_level}, "
f"{soft_row['item']}, {soft_row['pose']}, {soft_row['scene_text']}, {soft_row['composition']}, "
f"{soft_camera_config['camera_mode'].replace('_', ' ')} camera"
)
soft_caption_parts = [
active_trigger,
"Insta/OF softcore mode",
descriptor,
soft_level,
soft_row["item"],
soft_row["pose"],
soft_partner_outfit_text,
soft_partner_styling["pose"],
soft_row["scene_text"],
soft_row["composition"],
f"{soft_camera_config['camera_mode'].replace('_', ' ')} camera",
]
soft_caption = ", ".join(str(part).strip() for part in soft_caption_parts if str(part).strip())
hard_caption = (
f"{active_trigger}, Insta/OF hardcore mode, same primary creator descriptor, {descriptor}, "
f"{hard_cast}, {hard_row['role_graph']}, {hard_row['item']}, {hard_scene}, {hard_composition}, "
@@ -2232,6 +2331,7 @@ def build_insta_of_pair(
"options": options,
"shared_descriptor": descriptor,
"shared_cast_descriptors": cast_descriptors,
"softcore_partner_styling": soft_partner_styling,
"softcore_prompt": soft_prompt,
"hardcore_prompt": hard_prompt,
"softcore_negative_prompt": soft_negative,