Improve same-cast softcore and solo hardcore prompts
This commit is contained in:
@@ -110,7 +110,10 @@ When the hardcore cast includes partners, pair mode also creates deterministic
|
||||
shared cast descriptors such as `woman A / primary creator` and `man A`. Use
|
||||
`softcore_cast=same_as_hardcore`, `hardcore_cast=couple`, and
|
||||
`continuity=same_creator_same_room` when you want a soft prompt with the same
|
||||
woman, man, and location as the hardcore prompt.
|
||||
woman, man, and location as the hardcore prompt. In that setup, the softcore
|
||||
prompt keeps the same listed adult cast physically present together in a
|
||||
non-explicit teaser pose, with deterministic non-explicit partner outfits and a
|
||||
shared cast pose.
|
||||
|
||||
It outputs:
|
||||
|
||||
|
||||
+19
-2
@@ -485,17 +485,34 @@ def _insta_of_pair_from_row(row: dict[str, Any], detail_level: str, keep_style:
|
||||
soft_text, _soft_method = _metadata_to_prose(soft_row, detail_level, keep_style)
|
||||
hard_text, _hard_method = _metadata_to_prose(hard_row_for_text, detail_level, keep_style)
|
||||
descriptor = _clean_text(row.get("shared_descriptor"))
|
||||
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)])
|
||||
else:
|
||||
cast_descriptor_text = _clean_text(cast_descriptors)
|
||||
|
||||
same_soft_cast = options.get("softcore_cast") == "same_as_hardcore"
|
||||
|
||||
parts = []
|
||||
if cast_descriptor_text:
|
||||
if cast_descriptor_text and same_soft_cast:
|
||||
parts.append(f"The shared cast descriptors are {cast_descriptor_text}")
|
||||
elif descriptor:
|
||||
parts.append(f"The shared creator descriptor is {descriptor}")
|
||||
parts.append(f"The softcore primary creator descriptor is {descriptor}")
|
||||
if cast_descriptor_text and not same_soft_cast:
|
||||
parts.append(f"The hardcore cast descriptors are {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")
|
||||
if isinstance(partner_styling, dict):
|
||||
outfits = partner_styling.get("outfits")
|
||||
if isinstance(outfits, list):
|
||||
outfit_text = _human_join([_clean_text(item) for item in outfits if _clean_text(item)])
|
||||
if outfit_text:
|
||||
parts.append(f"Softcore partner styling: {outfit_text}")
|
||||
pose = _clean_text(partner_styling.get("pose"))
|
||||
if pose:
|
||||
parts.append(f"The shared softcore cast pose is {pose}")
|
||||
if soft_text:
|
||||
parts.append(f"Softcore version: {soft_text}")
|
||||
if hard_text:
|
||||
|
||||
@@ -986,6 +986,10 @@
|
||||
"bed-level"
|
||||
],
|
||||
"body_contact": [
|
||||
"one hand gripping the sheets",
|
||||
"hips lifted toward the camera",
|
||||
"body arched on rumpled sheets",
|
||||
"thighs tense against the bedding",
|
||||
"bodies still pressed together",
|
||||
"hands gripping hips",
|
||||
"thighs spread open",
|
||||
@@ -1015,7 +1019,8 @@
|
||||
},
|
||||
{
|
||||
"text": "wet orgasm during strap-on penetration",
|
||||
"cast": "women_only"
|
||||
"cast": "women_only",
|
||||
"min_people": 2
|
||||
},
|
||||
{
|
||||
"text": "post-orgasm dripping arousal",
|
||||
@@ -1024,10 +1029,16 @@
|
||||
"external cumshot",
|
||||
"visible external ejaculation",
|
||||
"messy post-climax release",
|
||||
"orgasm during penetration",
|
||||
{
|
||||
"text": "orgasm during penetration",
|
||||
"min_people": 2
|
||||
},
|
||||
"post-orgasm hardcore climax",
|
||||
"visible orgasm aftermath",
|
||||
"shared climax after penetration",
|
||||
{
|
||||
"text": "shared climax after penetration",
|
||||
"min_people": 2
|
||||
},
|
||||
"hardcore ejaculation scene"
|
||||
],
|
||||
"expression_detail": [
|
||||
|
||||
+20
-2
@@ -299,10 +299,28 @@ def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
if options.get("softcore_cast") == "same_as_hardcore"
|
||||
else f"Woman A / primary creator: {descriptor}"
|
||||
)
|
||||
same_soft_cast = options.get("softcore_cast") == "same_as_hardcore"
|
||||
soft_cast_presence = (
|
||||
"The same listed adult cast is present together in this softcore version 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"
|
||||
)
|
||||
partner_styling = row.get("softcore_partner_styling")
|
||||
if isinstance(partner_styling, dict):
|
||||
outfits = partner_styling.get("outfits")
|
||||
partner_outfit_text = "; ".join(_clean(item) for item in outfits if _clean(item)) if isinstance(outfits, list) else ""
|
||||
partner_pose = _clean(partner_styling.get("pose"))
|
||||
else:
|
||||
partner_outfit_text = ""
|
||||
partner_pose = ""
|
||||
|
||||
soft_parts = [
|
||||
f"A visibly adult creator, {descriptor}",
|
||||
f"Shared cast descriptors: {soft_cast_descriptor_text}" if soft_cast_descriptor_text else "",
|
||||
f"Shared cast descriptors: {soft_cast_descriptor_text}" if same_soft_cast and soft_cast_descriptor_text else "",
|
||||
f"Softcore primary creator descriptor: {soft_cast_descriptor_text}" if not same_soft_cast and soft_cast_descriptor_text else "",
|
||||
soft_cast_presence,
|
||||
f"Partner softcore styling: {partner_outfit_text}" if partner_outfit_text else "",
|
||||
f"The shared softcore cast pose is {partner_pose}" if partner_pose else "",
|
||||
f"shown in a {soft_level or 'softcore'} Insta/OF creator image",
|
||||
f"wearing {soft.get('item')}" if soft.get("item") else "",
|
||||
f"{soft.get('pose')}" if soft.get("pose") else "",
|
||||
@@ -314,7 +332,7 @@ def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
]
|
||||
hard_parts = [
|
||||
f"The same visibly adult creator, {descriptor}, is the visually central woman in a consensual explicit adult {hard_level or 'hardcore'} scene",
|
||||
f"Shared cast descriptors: {cast_descriptor_text}" if cast_descriptor_text else "",
|
||||
f"{'Shared' if same_soft_cast else 'Hardcore'} cast descriptors: {cast_descriptor_text}" if cast_descriptor_text else "",
|
||||
f"all participants are 21+ and visibly adult; the cast includes {hard_cast_text}" if hard_cast_text else "all participants are 21+ and visibly adult",
|
||||
_clean(hard.get("role_graph")),
|
||||
f"The sexual action is {hard.get('item')}" if hard.get("item") else "",
|
||||
|
||||
+105
-5
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user