Add prompt control and filter options
This commit is contained in:
+282
-27
@@ -49,6 +49,35 @@ SEED_AXIS_ALIASES = {
|
||||
"composition": ("composition_seed", "camera_seed", "composition"),
|
||||
}
|
||||
|
||||
SEED_LOCK_AXES = (
|
||||
"category",
|
||||
"subcategory",
|
||||
"content",
|
||||
"person",
|
||||
"scene",
|
||||
"pose",
|
||||
"role",
|
||||
"expression",
|
||||
"composition",
|
||||
)
|
||||
|
||||
ETHNICITY_FILTER_CHOICES = [
|
||||
"any",
|
||||
"european",
|
||||
"mediterranean_mena",
|
||||
"latina",
|
||||
"east_asian",
|
||||
"southeast_asian",
|
||||
"south_asian",
|
||||
"black_african",
|
||||
"indigenous",
|
||||
"mixed",
|
||||
"asian",
|
||||
"white_asian",
|
||||
]
|
||||
|
||||
CAMERA_DETAIL_CHOICES = ["off", "compact", "full"]
|
||||
|
||||
GENERIC_POSITIVE_SUFFIX = (
|
||||
"Use crisp clean comic linework, detailed hatching, soft blended shading, "
|
||||
"pastel skin tones, muted blues and pinks, warm sensual lighting, and tactile textured paper."
|
||||
@@ -79,6 +108,7 @@ LAYOUT_TEMPLATE = (
|
||||
)
|
||||
|
||||
CAMERA_MODE_PROMPTS = {
|
||||
"disabled": "",
|
||||
"standard": "",
|
||||
"handheld_selfie": (
|
||||
"Camera mode: handheld smartphone selfie, close arm-length framing, visible creator-shot perspective, "
|
||||
@@ -109,6 +139,47 @@ CAMERA_MODE_PROMPTS = {
|
||||
),
|
||||
}
|
||||
|
||||
CAMERA_COMPACT_LABELS = {
|
||||
"disabled": "",
|
||||
"standard": "",
|
||||
"handheld_selfie": "handheld smartphone selfie",
|
||||
"mirror_selfie": "mirror selfie",
|
||||
"phone_tripod": "phone tripod / ring-light setup",
|
||||
"creator_pov": "creator-held POV",
|
||||
"bed_selfie": "bed selfie",
|
||||
"bathroom_mirror": "bathroom mirror selfie",
|
||||
"phone_flash": "phone-flash selfie",
|
||||
"action_cam": "handheld action-camera view",
|
||||
"full_body": "full body",
|
||||
"three_quarter": "three-quarter body",
|
||||
"waist_up": "waist-up",
|
||||
"close_up": "close-up",
|
||||
"extreme_close_up": "extreme close-up",
|
||||
"eye_level": "eye-level",
|
||||
"high_angle": "high-angle",
|
||||
"low_angle": "low-angle",
|
||||
"overhead": "overhead",
|
||||
"side_profile": "side-profile",
|
||||
"rear_view": "rear-view",
|
||||
"mirror_reflection": "mirror reflection",
|
||||
"smartphone_wide": "smartphone wide-angle",
|
||||
"ultra_wide": "ultra-wide",
|
||||
"portrait_lens": "phone portrait lens",
|
||||
"telephoto": "telephoto-style",
|
||||
"macro_detail": "macro detail",
|
||||
"arm_length": "arm-length",
|
||||
"near_body": "near-body",
|
||||
"bedside": "bedside phone",
|
||||
"room_corner": "room-corner phone",
|
||||
"vertical_story": "vertical 9:16",
|
||||
"square_feed": "square feed",
|
||||
"horizontal": "horizontal",
|
||||
"phone_visible": "phone visible",
|
||||
"phone_hidden": "phone hidden",
|
||||
"screen_reflection": "screen reflection",
|
||||
"ring_light_visible": "ring light visible",
|
||||
}
|
||||
|
||||
CAMERA_SHOT_PROMPTS = {
|
||||
"auto": "",
|
||||
"full_body": "Shot size: full body visible, head-to-toe framing, no important body parts cropped out.",
|
||||
@@ -917,13 +988,46 @@ def build_filter_config_json(
|
||||
figure: str = "curvy",
|
||||
no_plus_women: bool = False,
|
||||
no_black: bool = False,
|
||||
include_european: bool = True,
|
||||
include_mediterranean_mena: bool = True,
|
||||
include_latina: bool = True,
|
||||
include_east_asian: bool = True,
|
||||
include_southeast_asian: bool = True,
|
||||
include_south_asian: bool = True,
|
||||
include_black_african: bool = True,
|
||||
include_indigenous: bool = True,
|
||||
include_mixed: bool = True,
|
||||
include_plus_size: bool = True,
|
||||
) -> str:
|
||||
include_flags = {
|
||||
"european": include_european,
|
||||
"mediterranean_mena": include_mediterranean_mena,
|
||||
"latina": include_latina,
|
||||
"east_asian": include_east_asian,
|
||||
"southeast_asian": include_southeast_asian,
|
||||
"south_asian": include_south_asian,
|
||||
"black_african": include_black_african,
|
||||
"indigenous": include_indigenous,
|
||||
"mixed": include_mixed,
|
||||
}
|
||||
selected_ethnicities = [key for key, enabled in include_flags.items() if enabled]
|
||||
disabled_ethnicities = [key for key, enabled in include_flags.items() if not enabled]
|
||||
enabled_ethnicities = list(selected_ethnicities)
|
||||
if enabled_ethnicities:
|
||||
enabled_ethnicities.extend(f"exclude_{key}" for key in disabled_ethnicities)
|
||||
if 0 < len(selected_ethnicities) < len(include_flags):
|
||||
ethnicity = "+".join(enabled_ethnicities)
|
||||
elif ethnicity not in ETHNICITY_FILTER_CHOICES:
|
||||
ethnicity = "any"
|
||||
return json.dumps(
|
||||
{
|
||||
"ethnicity": ethnicity if ethnicity in ("any", "asian", "white_asian") else "any",
|
||||
"ethnicity": ethnicity,
|
||||
"ethnicity_includes": selected_ethnicities,
|
||||
"figure": figure if figure in ("curvy", "balanced", "bombshell") else "curvy",
|
||||
"no_plus_women": bool(no_plus_women),
|
||||
"no_black": bool(no_black),
|
||||
"include_plus_size": bool(include_plus_size),
|
||||
"include_black_african": bool(include_black_african),
|
||||
"no_plus_women": not bool(include_plus_size) or bool(no_plus_women),
|
||||
"no_black": not bool(include_black_african) or bool(no_black),
|
||||
},
|
||||
ensure_ascii=True,
|
||||
sort_keys=True,
|
||||
@@ -931,7 +1035,14 @@ def build_filter_config_json(
|
||||
|
||||
|
||||
def _parse_filter_config(filter_config: str | dict[str, Any] | None) -> dict[str, Any]:
|
||||
defaults = {"ethnicity": "any", "figure": "curvy", "no_plus_women": False, "no_black": False}
|
||||
defaults = {
|
||||
"ethnicity": "any",
|
||||
"figure": "curvy",
|
||||
"no_plus_women": False,
|
||||
"no_black": False,
|
||||
"include_plus_size": True,
|
||||
"include_black_african": True,
|
||||
}
|
||||
if not filter_config:
|
||||
return defaults
|
||||
if isinstance(filter_config, dict):
|
||||
@@ -944,8 +1055,11 @@ def _parse_filter_config(filter_config: str | dict[str, Any] | None) -> dict[str
|
||||
if not isinstance(raw, dict):
|
||||
raise ValueError("filter_config must be a JSON object")
|
||||
parsed = {**defaults, **raw}
|
||||
parsed["ethnicity"] = parsed["ethnicity"] if parsed.get("ethnicity") in ("any", "asian", "white_asian") else "any"
|
||||
ethnicity = str(parsed.get("ethnicity") or "any")
|
||||
parsed["ethnicity"] = ethnicity if ethnicity == "any" or ethnicity in ETHNICITY_FILTER_CHOICES or "+" in ethnicity else "any"
|
||||
parsed["figure"] = parsed["figure"] if parsed.get("figure") in ("curvy", "balanced", "bombshell") else "curvy"
|
||||
parsed["include_plus_size"] = bool(parsed.get("include_plus_size"))
|
||||
parsed["include_black_african"] = bool(parsed.get("include_black_african"))
|
||||
parsed["no_plus_women"] = bool(parsed.get("no_plus_women"))
|
||||
parsed["no_black"] = bool(parsed.get("no_black"))
|
||||
return parsed
|
||||
@@ -997,6 +1111,34 @@ def build_seed_config_json(
|
||||
)
|
||||
|
||||
|
||||
def build_seed_lock_config_json(
|
||||
base_seed: int = 20260614,
|
||||
reroll_axis: str = "none",
|
||||
reroll_seed: int = -1,
|
||||
) -> str:
|
||||
base_seed = int(base_seed)
|
||||
reroll_seed = int(reroll_seed)
|
||||
reroll_groups = {
|
||||
"none": (),
|
||||
"category": ("category",),
|
||||
"subcategory": ("subcategory",),
|
||||
"content": ("content",),
|
||||
"person": ("person",),
|
||||
"scene": ("scene",),
|
||||
"pose": ("pose", "role"),
|
||||
"role": ("role",),
|
||||
"expression": ("expression",),
|
||||
"composition": ("composition",),
|
||||
"content_pose": ("content", "pose", "role"),
|
||||
"scene_pose": ("scene", "pose", "role"),
|
||||
}
|
||||
reroll = set(reroll_groups.get(str(reroll_axis or "none"), ()))
|
||||
config: dict[str, int] = {}
|
||||
for axis in SEED_LOCK_AXES:
|
||||
config[f"{axis}_seed"] = reroll_seed if axis in reroll else base_seed
|
||||
return json.dumps(config, ensure_ascii=True, sort_keys=True)
|
||||
|
||||
|
||||
def _parse_seed_config(seed_config: str | dict[str, Any] | None) -> dict[str, int]:
|
||||
if not seed_config:
|
||||
return {}
|
||||
@@ -1075,6 +1217,14 @@ def camera_mode_choices() -> list[str]:
|
||||
return list(CAMERA_MODE_PROMPTS)
|
||||
|
||||
|
||||
def ethnicity_choices() -> list[str]:
|
||||
return list(ETHNICITY_FILTER_CHOICES)
|
||||
|
||||
|
||||
def camera_detail_choices() -> list[str]:
|
||||
return list(CAMERA_DETAIL_CHOICES)
|
||||
|
||||
|
||||
def camera_shot_choices() -> list[str]:
|
||||
return list(CAMERA_SHOT_PROMPTS)
|
||||
|
||||
@@ -1112,6 +1262,7 @@ def build_camera_config_json(
|
||||
orientation: str = "auto",
|
||||
phone_visibility: str = "auto",
|
||||
priority: str = "strong",
|
||||
camera_detail: str = "compact",
|
||||
) -> str:
|
||||
return json.dumps(
|
||||
{
|
||||
@@ -1123,6 +1274,7 @@ def build_camera_config_json(
|
||||
"orientation": orientation,
|
||||
"phone_visibility": phone_visibility,
|
||||
"priority": priority,
|
||||
"camera_detail": camera_detail,
|
||||
},
|
||||
ensure_ascii=True,
|
||||
sort_keys=True,
|
||||
@@ -1144,6 +1296,7 @@ def _parse_camera_config(camera_config: str | dict[str, Any] | None) -> dict[str
|
||||
"orientation": "auto",
|
||||
"phone_visibility": "auto",
|
||||
"priority": "strong",
|
||||
"camera_detail": "compact",
|
||||
}
|
||||
if not camera_config:
|
||||
return defaults
|
||||
@@ -1166,6 +1319,9 @@ def _parse_camera_config(camera_config: str | dict[str, Any] | None) -> dict[str
|
||||
"orientation": _choice(parsed.get("orientation"), CAMERA_ORIENTATION_PROMPTS, defaults["orientation"]),
|
||||
"phone_visibility": _choice(parsed.get("phone_visibility"), CAMERA_PHONE_PROMPTS, defaults["phone_visibility"]),
|
||||
"priority": _choice(parsed.get("priority"), CAMERA_PRIORITY_PROMPTS, defaults["priority"]),
|
||||
"camera_detail": str(parsed.get("camera_detail") or defaults["camera_detail"])
|
||||
if str(parsed.get("camera_detail") or defaults["camera_detail"]) in CAMERA_DETAIL_CHOICES
|
||||
else defaults["camera_detail"],
|
||||
}
|
||||
|
||||
|
||||
@@ -1178,6 +1334,26 @@ def _camera_config_with_mode(camera_config: str | dict[str, Any] | None, camera_
|
||||
|
||||
def _camera_directive(camera_config: str | dict[str, Any] | None) -> tuple[str, dict[str, str]]:
|
||||
parsed = _parse_camera_config(camera_config)
|
||||
if parsed["camera_detail"] == "off" or parsed["camera_mode"] == "disabled":
|
||||
return "", parsed
|
||||
if parsed["camera_detail"] == "compact":
|
||||
values = [
|
||||
parsed["camera_mode"],
|
||||
parsed["shot_size"],
|
||||
parsed["angle"],
|
||||
parsed["lens"],
|
||||
parsed["distance"],
|
||||
parsed["orientation"],
|
||||
parsed["phone_visibility"],
|
||||
]
|
||||
labels = [CAMERA_COMPACT_LABELS.get(value, value.replace("_", " ")) for value in values]
|
||||
labels = [label for value, label in zip(values, labels) if label and value != "auto"]
|
||||
if not labels:
|
||||
return "", parsed
|
||||
directive = "Camera: " + ", ".join(labels) + "."
|
||||
if parsed["priority"] == "locked":
|
||||
directive += " Keep this camera framing."
|
||||
return directive, parsed
|
||||
parts = [
|
||||
CAMERA_MODE_PROMPTS[parsed["camera_mode"]],
|
||||
CAMERA_SHOT_PROMPTS[parsed["shot_size"]],
|
||||
@@ -1679,7 +1855,7 @@ def _appearance_for_subject(
|
||||
subject_type = "woman" if rng.random() < 0.82 else "man"
|
||||
|
||||
if subject_type == "man":
|
||||
men_ethnicity = ethnicity if ethnicity == "asian" else "any"
|
||||
men_ethnicity = ethnicity if ethnicity else "any"
|
||||
subject, age, body, skin, hair, eyes = g.choose(rng, g.by_ethnicity(g.MEN, men_ethnicity))
|
||||
return {
|
||||
"subject_type": "man",
|
||||
@@ -2452,7 +2628,7 @@ def build_prompt(
|
||||
start_index = max(1, int(start_index))
|
||||
seed = int(seed)
|
||||
clothing = clothing if clothing in ("full", "minimal") else "full"
|
||||
ethnicity = ethnicity if ethnicity in ("any", "asian", "white_asian") else "any"
|
||||
ethnicity = ethnicity if ethnicity == "any" or ethnicity in ETHNICITY_FILTER_CHOICES or "+" in str(ethnicity) else "any"
|
||||
poses = poses if poses in ("standard", "evocative") else "standard"
|
||||
figure = figure if figure in ("curvy", "balanced", "bombshell") else "curvy"
|
||||
minimal_ratio = _ratio_or_none(minimal_clothing_ratio)
|
||||
@@ -2574,6 +2750,7 @@ INSTA_OF_SOFT_LEVELS = {
|
||||
"lingerie_tease": "premium OF teaser set, lingerie-focused, sensual and intimate",
|
||||
"implied_nude": "implied nude creator set, strategically covered body and intimate teaser framing",
|
||||
"explicit_tease": "stronger adult teaser set with bolder nude-adjacent styling and solo-tease framing",
|
||||
"explicit_nude": "explicit nude creator set with fully nude solo-tease framing",
|
||||
}
|
||||
|
||||
INSTA_OF_HARDCORE_LEVELS = {
|
||||
@@ -2587,6 +2764,14 @@ INSTA_OF_PLATFORM_STYLES = {
|
||||
"onlyfans": "OnlyFans-inspired creator shoot, intimate subscriber-view camera and candid premium-content framing",
|
||||
}
|
||||
|
||||
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",
|
||||
}
|
||||
|
||||
INSTA_OF_NEGATIVE = (
|
||||
"minors, childlike appearance, teen, underage, schoolgirl, non-consensual, coercion, rape, "
|
||||
"violence, injury, blood, gore, incest, bestiality, watermark, logo, readable username, social media UI"
|
||||
@@ -2603,6 +2788,7 @@ INSTA_OF_SOFTCORE_SUBCATEGORY_BY_LEVEL = {
|
||||
"lingerie_tease": "Provocative erotic clothes / Provocative lingerie",
|
||||
"implied_nude": "Provocative erotic clothes / Provocative lingerie",
|
||||
"explicit_tease": "Provocative erotic clothes / Sheer exposed",
|
||||
"explicit_nude": "Provocative erotic clothes / Nude accessories",
|
||||
}
|
||||
|
||||
INSTA_OF_SOFTCORE_OUTFITS = {
|
||||
@@ -2642,6 +2828,14 @@ INSTA_OF_SOFTCORE_OUTFITS = {
|
||||
"bare-shoulder robe opened around covered lingerie, explicit adult tease without partnered contact",
|
||||
"strappy lingerie set with covered cups and high-waisted bottoms, styled as a stronger solo teaser",
|
||||
],
|
||||
"explicit_nude": [
|
||||
"fully nude creator styling with jewelry, heels, and direct adult selfie confidence",
|
||||
"fully nude mirror-selfie styling with jewelry only and bold creator-shot framing",
|
||||
"nude-on-sheets creator pose with lingerie discarded nearby and direct eye contact",
|
||||
"fully nude vanity-mirror pose with heels, necklace, and premium adult teaser styling",
|
||||
"nude shower-afterglow creator pose with wet hair, skin highlights, and phone-shot framing",
|
||||
"fully nude bedroom creator pose with one hand holding the phone and lingerie visible nearby",
|
||||
],
|
||||
}
|
||||
|
||||
INSTA_OF_SOFTCORE_POSES = {
|
||||
@@ -2677,6 +2871,14 @@ INSTA_OF_SOFTCORE_POSES = {
|
||||
"sitting at the vanity in a bolder covered lingerie pose with direct eye contact",
|
||||
"arching subtly in a solo adult tease while the styling keeps explicit anatomy obscured",
|
||||
],
|
||||
"explicit_nude": [
|
||||
"taking a bold nude mirror selfie with direct eye contact and the body clearly framed",
|
||||
"posing fully nude on the bed with jewelry and heels as the only styling",
|
||||
"standing at the vanity fully nude in a premium creator-shot pose",
|
||||
"reclining fully nude on soft sheets with the phone held close",
|
||||
"turning slightly in a nude mirror pose with the body framed head-to-thigh",
|
||||
"kneeling fully nude in a controlled adult teaser pose with direct phone-camera awareness",
|
||||
],
|
||||
}
|
||||
|
||||
INSTA_OF_SOFTCORE_PARTNER_WOMEN_OUTFITS = [
|
||||
@@ -2711,8 +2913,10 @@ def build_insta_of_options_json(
|
||||
hardcore_level: str = "hardcore",
|
||||
platform_style: str = "hybrid",
|
||||
continuity: str = "same_creator_same_room",
|
||||
hardcore_clothing_continuity: str = "partially_removed",
|
||||
softcore_camera_mode: str = "handheld_selfie",
|
||||
hardcore_camera_mode: str = "same_as_softcore",
|
||||
camera_detail: str = "compact",
|
||||
softcore_expression_intensity: float = 0.45,
|
||||
hardcore_expression_intensity: float = 0.85,
|
||||
) -> str:
|
||||
@@ -2726,8 +2930,10 @@ def build_insta_of_options_json(
|
||||
"hardcore_level": hardcore_level,
|
||||
"platform_style": platform_style,
|
||||
"continuity": continuity,
|
||||
"hardcore_clothing_continuity": hardcore_clothing_continuity,
|
||||
"softcore_camera_mode": softcore_camera_mode,
|
||||
"hardcore_camera_mode": hardcore_camera_mode,
|
||||
"camera_detail": camera_detail,
|
||||
"softcore_expression_intensity": _clamped_float(softcore_expression_intensity, 0.45),
|
||||
"hardcore_expression_intensity": _clamped_float(hardcore_expression_intensity, 0.85),
|
||||
},
|
||||
@@ -2746,8 +2952,10 @@ def _parse_insta_of_options(options_json: str | dict[str, Any] | None) -> dict[s
|
||||
"hardcore_level": "hardcore",
|
||||
"platform_style": "hybrid",
|
||||
"continuity": "same_creator_same_room",
|
||||
"hardcore_clothing_continuity": "partially_removed",
|
||||
"softcore_camera_mode": "handheld_selfie",
|
||||
"hardcore_camera_mode": "same_as_softcore",
|
||||
"camera_detail": "compact",
|
||||
"softcore_expression_intensity": 0.45,
|
||||
"hardcore_expression_intensity": 0.85,
|
||||
}
|
||||
@@ -2769,9 +2977,15 @@ def _parse_insta_of_options(options_json: str | dict[str, Any] | None) -> dict[s
|
||||
parsed["hardcore_level"] = parsed["hardcore_level"] if parsed["hardcore_level"] in INSTA_OF_HARDCORE_LEVELS else defaults["hardcore_level"]
|
||||
parsed["platform_style"] = parsed["platform_style"] if parsed["platform_style"] in INSTA_OF_PLATFORM_STYLES else defaults["platform_style"]
|
||||
parsed["continuity"] = parsed["continuity"] if parsed["continuity"] in ("same_creator_same_room", "same_creator_new_scene") else defaults["continuity"]
|
||||
parsed["hardcore_clothing_continuity"] = (
|
||||
parsed["hardcore_clothing_continuity"]
|
||||
if parsed["hardcore_clothing_continuity"] in INSTA_OF_HARDCORE_CLOTHING_CONTINUITY
|
||||
else defaults["hardcore_clothing_continuity"]
|
||||
)
|
||||
parsed["softcore_camera_mode"] = parsed["softcore_camera_mode"] if parsed["softcore_camera_mode"] in CAMERA_MODE_PROMPTS else defaults["softcore_camera_mode"]
|
||||
if parsed["hardcore_camera_mode"] not in CAMERA_MODE_PROMPTS and parsed["hardcore_camera_mode"] != "same_as_softcore":
|
||||
parsed["hardcore_camera_mode"] = defaults["hardcore_camera_mode"]
|
||||
parsed["camera_detail"] = parsed["camera_detail"] if parsed["camera_detail"] in CAMERA_DETAIL_CHOICES else defaults["camera_detail"]
|
||||
parsed["softcore_expression_intensity"] = _clamped_float(
|
||||
parsed.get("softcore_expression_intensity"),
|
||||
defaults["softcore_expression_intensity"],
|
||||
@@ -2865,13 +3079,17 @@ def _insta_of_cast_phrase(women_count: int, men_count: int) -> str:
|
||||
return context["cast_summary"]
|
||||
|
||||
|
||||
def _insta_of_prompt_cast_descriptors(text: str) -> str:
|
||||
return str(text or "").replace("Woman A / primary creator:", "Woman A:")
|
||||
|
||||
|
||||
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",
|
||||
"posing together 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",
|
||||
]
|
||||
@@ -2896,6 +3114,15 @@ def _insta_of_softcore_pose(rng: random.Random, level: str) -> str:
|
||||
return g.choose(rng, pool)
|
||||
|
||||
|
||||
def _insta_of_hardcore_clothing_state(mode: str, softcore_outfit: 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:
|
||||
return ""
|
||||
base = INSTA_OF_HARDCORE_CLOTHING_CONTINUITY[mode]
|
||||
return f"Clothing state: {base}; softcore visual reference: {outfit}."
|
||||
|
||||
|
||||
def _insta_of_partner_styling(
|
||||
seed_config: dict[str, int],
|
||||
seed: int,
|
||||
@@ -2934,12 +3161,19 @@ def build_insta_of_pair(
|
||||
prepend_trigger_to_prompt: bool,
|
||||
seed_config: str | dict[str, Any] | None = None,
|
||||
options_json: str | dict[str, Any] | None = None,
|
||||
filter_config: str | dict[str, Any] | None = None,
|
||||
camera_config: str | dict[str, Any] | None = None,
|
||||
character_profile: str | dict[str, Any] | None = "",
|
||||
extra_positive: str = "",
|
||||
extra_negative: str = "",
|
||||
) -> dict[str, Any]:
|
||||
options = _parse_insta_of_options(options_json)
|
||||
if filter_config:
|
||||
filters = _parse_filter_config(filter_config)
|
||||
ethnicity = filters["ethnicity"]
|
||||
figure = filters["figure"]
|
||||
no_plus_women = filters["no_plus_women"]
|
||||
no_black = filters["no_black"]
|
||||
hard_women_count, hard_men_count = _insta_of_hardcore_counts(options)
|
||||
active_trigger = trigger.strip() or g.TRIGGER
|
||||
parsed_seed_config = _parse_seed_config(seed_config)
|
||||
@@ -3015,11 +3249,11 @@ def build_insta_of_pair(
|
||||
hard_women_count,
|
||||
hard_men_count,
|
||||
)
|
||||
cast_descriptor_text = "; ".join(cast_descriptors)
|
||||
cast_descriptor_text = _insta_of_prompt_cast_descriptors("; ".join(cast_descriptors))
|
||||
soft_cast_descriptor_text = (
|
||||
cast_descriptor_text
|
||||
if options["softcore_cast"] == "same_as_hardcore"
|
||||
else f"Woman A / primary creator: {descriptor}"
|
||||
else f"Woman A: {descriptor}"
|
||||
)
|
||||
soft_partner_styling = _insta_of_partner_styling(
|
||||
parsed_seed_config,
|
||||
@@ -3039,33 +3273,44 @@ def build_insta_of_pair(
|
||||
hard_camera_mode = options["softcore_camera_mode"]
|
||||
soft_camera_config = _camera_config_with_mode(camera_config, options["softcore_camera_mode"])
|
||||
hard_camera_config = _camera_config_with_mode(camera_config, hard_camera_mode)
|
||||
soft_camera_config["camera_detail"] = options["camera_detail"]
|
||||
hard_camera_config["camera_detail"] = options["camera_detail"]
|
||||
soft_camera_directive, soft_camera_config = _camera_directive(soft_camera_config)
|
||||
hard_camera_directive, hard_camera_config = _camera_directive(hard_camera_config)
|
||||
soft_camera_sentence = f"Camera control: {soft_camera_directive} " if soft_camera_directive else ""
|
||||
hard_camera_sentence = f"Camera control: {hard_camera_directive} " if hard_camera_directive else ""
|
||||
hard_scene = soft_row["scene_text"] if options["continuity"] == "same_creator_same_room" else hard_row["scene_text"]
|
||||
hard_composition = soft_row["composition"] if options["continuity"] == "same_creator_same_room" else hard_row["composition"]
|
||||
hard_composition = hard_row["composition"]
|
||||
soft_cast = (
|
||||
"solo creator setup; the primary creator is alone in the softcore version"
|
||||
"solo creator setup with Woman A alone"
|
||||
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)}"
|
||||
else f"non-explicit teaser setup with {_insta_of_cast_phrase(hard_women_count, hard_men_count)}"
|
||||
)
|
||||
soft_cast_presence = (
|
||||
"Keep the same cast together in the softcore version in a non-explicit teaser pose with no sex act or genital contact. "
|
||||
"Place Woman A and the listed partners together 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']}. "
|
||||
f"Partner softcore styling: {soft_partner_outfit_text}. 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)
|
||||
hard_clothing_state = _insta_of_hardcore_clothing_state(
|
||||
options["hardcore_clothing_continuity"],
|
||||
soft_row["item"],
|
||||
)
|
||||
soft_descriptor_sentence = (
|
||||
f"Cast descriptors: {soft_cast_descriptor_text}. "
|
||||
if options["softcore_cast"] == "same_as_hardcore"
|
||||
else f"Woman A: {descriptor}. "
|
||||
)
|
||||
|
||||
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"Insta/OF softcore mode: {platform_style}. "
|
||||
f"{soft_descriptor_sentence}"
|
||||
f"Softcore setup: {soft_level}. Cast: {soft_cast}. "
|
||||
f"{soft_cast_presence}"
|
||||
f"{soft_cast_styling_sentence}"
|
||||
f"Outfit: {soft_row['item']}. Pose: {soft_row['pose']}. Setting: {soft_row['scene_text']}. "
|
||||
@@ -3075,10 +3320,11 @@ def build_insta_of_pair(
|
||||
f"{soft_row['positive_suffix']}."
|
||||
)
|
||||
hard_prompt = (
|
||||
f"Insta/OF hardcore mode: {platform_style}. Shared primary creator descriptor: {descriptor}. "
|
||||
f"Insta/OF hardcore mode: {platform_style}. "
|
||||
f"Hardcore setup: {hard_level}. Cast: {hard_cast}. "
|
||||
f"Shared cast descriptors: {cast_descriptor_text}. "
|
||||
"Apply the shared descriptor to the most visually central woman, keeping her continuous with the softcore version. "
|
||||
f"Cast descriptors: {cast_descriptor_text}. "
|
||||
"Keep Woman A visually central. "
|
||||
f"{hard_clothing_state} "
|
||||
f"Role graph: {hard_row['role_graph']} Sexual scene: {hard_row['item']}. "
|
||||
f"Setting: {hard_scene}. Facial expressions: {hard_row['expression']}. Composition: {hard_composition}. "
|
||||
f"{hard_camera_sentence}"
|
||||
@@ -3103,20 +3349,29 @@ def build_insta_of_pair(
|
||||
soft_partner_styling["pose"],
|
||||
soft_row["scene_text"],
|
||||
soft_row["composition"],
|
||||
f"{soft_camera_config['camera_mode'].replace('_', ' ')} camera",
|
||||
f"{soft_camera_config['camera_mode'].replace('_', ' ')} camera" if soft_camera_directive else "",
|
||||
]
|
||||
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}, "
|
||||
f"{hard_camera_config['camera_mode'].replace('_', ' ')} camera"
|
||||
)
|
||||
hard_caption_parts = [
|
||||
active_trigger,
|
||||
"Insta/OF hardcore mode",
|
||||
"Woman A",
|
||||
descriptor,
|
||||
hard_cast,
|
||||
hard_row["role_graph"],
|
||||
hard_row["item"],
|
||||
hard_scene,
|
||||
hard_composition,
|
||||
f"{hard_camera_config['camera_mode'].replace('_', ' ')} camera" if hard_camera_directive else "",
|
||||
]
|
||||
hard_caption = ", ".join(str(part).strip() for part in hard_caption_parts if str(part).strip())
|
||||
metadata = {
|
||||
"mode": "Insta/OF",
|
||||
"options": options,
|
||||
"shared_descriptor": descriptor,
|
||||
"shared_cast_descriptors": cast_descriptors,
|
||||
"softcore_partner_styling": soft_partner_styling,
|
||||
"hardcore_clothing_state": hard_clothing_state,
|
||||
"softcore_prompt": soft_prompt,
|
||||
"hardcore_prompt": hard_prompt,
|
||||
"softcore_negative_prompt": soft_negative,
|
||||
|
||||
Reference in New Issue
Block a user