Tune hardcore detail density
This commit is contained in:
@@ -320,6 +320,10 @@ Options:
|
||||
neutral with no connected camera config, and uses `SxCP Camera Control` when
|
||||
one is connected.
|
||||
- `camera_detail`: `off`, `compact`, or `full` for the pair prompt camera text.
|
||||
- `hardcore_detail_density`: `compact` keeps the Krea hardcore rewrite mostly
|
||||
to the position/action sentence, `balanced` keeps one useful non-duplicated
|
||||
motion or aftermath detail, and `dense` keeps more detail after dedupe. This
|
||||
is separate from expression intensity.
|
||||
|
||||
## Built-In Categories
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ try:
|
||||
character_woman_body_choices,
|
||||
ethnicity_choices,
|
||||
generation_profile_choices,
|
||||
hardcore_detail_density_choices,
|
||||
load_character_profile_json,
|
||||
seed_mode_choices,
|
||||
subcategory_choices,
|
||||
@@ -85,6 +86,7 @@ except ImportError:
|
||||
character_woman_body_choices,
|
||||
ethnicity_choices,
|
||||
generation_profile_choices,
|
||||
hardcore_detail_density_choices,
|
||||
load_character_profile_json,
|
||||
seed_mode_choices,
|
||||
subcategory_choices,
|
||||
@@ -1040,6 +1042,7 @@ class SxCPInstaOFOptions:
|
||||
"softcore_camera_mode": (camera_mode_choices(), {"default": "handheld_selfie"}),
|
||||
"hardcore_camera_mode": (["from_camera_config", "same_as_softcore"] + camera_mode_choices(), {"default": "from_camera_config"}),
|
||||
"camera_detail": (camera_detail_choices(), {"default": "compact"}),
|
||||
"hardcore_detail_density": (hardcore_detail_density_choices(), {"default": "balanced"}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,6 +1069,7 @@ class SxCPInstaOFOptions:
|
||||
softcore_camera_mode,
|
||||
hardcore_camera_mode,
|
||||
camera_detail,
|
||||
hardcore_detail_density,
|
||||
):
|
||||
return (
|
||||
build_insta_of_options_json(
|
||||
@@ -1085,6 +1089,7 @@ class SxCPInstaOFOptions:
|
||||
softcore_camera_mode=softcore_camera_mode,
|
||||
hardcore_camera_mode=hardcore_camera_mode,
|
||||
camera_detail=camera_detail,
|
||||
hardcore_detail_density=hardcore_detail_density,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -516,15 +516,15 @@
|
||||
{"text": "full-room group-sex composition with clear adult spacing", "min_people": 4}
|
||||
],
|
||||
"climax_compositions": [
|
||||
{"text": "tight post-ejaculation crop on face, body, hands, and visible fluids", "min_people": 1},
|
||||
{"text": "direct-flash close-up of orgasm aftermath", "min_people": 1},
|
||||
{"text": "tight post-ejaculation crop with body position, hands, and visible fluids readable", "min_people": 1},
|
||||
{"text": "direct-flash close-up of aftermath with the body position still readable", "min_people": 1},
|
||||
{"text": "bed-level ejaculation frame with thighs, face, and fluid detail visible", "min_people": 1},
|
||||
{"text": "mirror-reflected post-ejaculation composition", "min_people": 1},
|
||||
{"text": "front-facing cumshot composition with body and expression centered", "min_people": 1},
|
||||
{"text": "overhead post-orgasm frame on rumpled sheets", "min_people": 1},
|
||||
{"text": "kneeling ejaculation frame with open mouth and body visible", "min_people": 1},
|
||||
{"text": "wide aftermath composition with all adult bodies visible", "min_people": 2},
|
||||
{"text": "tight subscriber-view crop of orgasm expression and fluid detail", "min_people": 1},
|
||||
{"text": "tight subscriber-view crop with body position and fluid detail readable", "min_people": 1},
|
||||
{"text": "side-profile post-ejaculation body-line composition", "min_people": 1}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -967,10 +967,10 @@
|
||||
"item_templates": [
|
||||
"{climax_act} with {fluid_location}, {body_position}, {expression_detail}, and {visibility}",
|
||||
"{body_position} during {climax_act}, with {hand_detail}, {fluid_location}, and {fluid_detail}",
|
||||
"{angle} ejaculation view featuring {climax_act}, {body_position}, {body_contact}, {fluid_detail}, and {visibility}",
|
||||
"{angle} aftermath view with {body_position}, {body_contact}, and {visibility}",
|
||||
"hardcore post-ejaculation scene with {fluid_location}, {body_position}, {expression_detail}, and {visibility}",
|
||||
"{climax_act} on {surface}, with {body_position}, {body_contact}, {hand_detail}, and {fluid_detail}",
|
||||
"{angle} view of {fluid_location}, {body_position}, {climax_act}, and {visibility}",
|
||||
"{angle} aftermath view of {body_position}, with {fluid_location} and {visibility}",
|
||||
"explicit orgasm scene: {climax_act}, {body_position}, {fluid_detail}, {expression_detail}, and {body_contact}",
|
||||
"{body_position} with {fluid_location}, {hand_detail}, {visibility}, and {climax_act}"
|
||||
],
|
||||
@@ -1137,8 +1137,8 @@
|
||||
"post-ejaculation fluids anatomically clear",
|
||||
"face and body covered in visible cum",
|
||||
"open thighs and wetness visible",
|
||||
"explicit semen aftermath visible",
|
||||
"hardcore ejaculation detail visible",
|
||||
"aftermath detail visible",
|
||||
"ejaculation detail visible",
|
||||
"sexual fluids and body contact visible"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
"id": 12,
|
||||
"type": "SxCPInstaOFOptions",
|
||||
"pos": [-1220, 290],
|
||||
"size": [360, 366],
|
||||
"size": [360, 390],
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
@@ -219,7 +219,7 @@
|
||||
{"name": "options_json", "type": "STRING", "links": [10], "slot_index": 0}
|
||||
],
|
||||
"properties": {"Node name for S&R": "SxCPInstaOFOptions"},
|
||||
"widgets_values": ["same_as_hardcore", "couple", 1, 1, "lingerie_tease", "hardcore", true, true, 0.45, 0.85, "hybrid", "same_creator_same_room", "partially_removed", "handheld_selfie", "from_camera_config", "compact"]
|
||||
"widgets_values": ["same_as_hardcore", "couple", 1, 1, "lingerie_tease", "hardcore", true, true, 0.45, 0.85, "hybrid", "same_creator_same_room", "partially_removed", "handheld_selfie", "from_camera_config", "compact", "balanced"]
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
|
||||
+163
-10
@@ -9,6 +9,7 @@ TRIGGER_CANDIDATES = (
|
||||
"sxcpinup_coloredpencil",
|
||||
"sxcppnl7",
|
||||
)
|
||||
HARDCORE_DETAIL_DENSITY_CHOICES = {"compact", "balanced", "dense"}
|
||||
|
||||
PROMPT_FIELD_LABELS = (
|
||||
"Ages",
|
||||
@@ -52,6 +53,11 @@ def _expression_disabled(row: dict[str, Any]) -> bool:
|
||||
return bool(row.get("expression_disabled")) or _is_false(row.get("expression_enabled", True))
|
||||
|
||||
|
||||
def _normalize_hardcore_detail_density(value: Any) -> str:
|
||||
text = _clean(value).lower()
|
||||
return text if text in HARDCORE_DETAIL_DENSITY_CHOICES else "balanced"
|
||||
|
||||
|
||||
def _sentence(text: str) -> str:
|
||||
text = _clean(text).strip(" ,;")
|
||||
if not text:
|
||||
@@ -747,6 +753,112 @@ def _dedupe_hardcore_detail(detail: str, anchor: str) -> str:
|
||||
return _clean(detail).strip(" ,;")
|
||||
|
||||
|
||||
def _detail_clauses(detail: str) -> list[str]:
|
||||
return [part.strip(" ,;") for part in re.split(r",\s*(?:and\s+)?", _clean(detail)) if part.strip(" ,;")]
|
||||
|
||||
|
||||
def _join_detail_clauses(clauses: list[str]) -> str:
|
||||
cleaned: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for clause in clauses:
|
||||
clause = _clean(clause).strip(" ,;")
|
||||
key = clause.lower()
|
||||
if clause and key not in seen:
|
||||
cleaned.append(clause)
|
||||
seen.add(key)
|
||||
return ", ".join(cleaned)
|
||||
|
||||
|
||||
def _action_position_phrase(action: str) -> str:
|
||||
action = _clean(action).lower()
|
||||
if "face-down" in action and "ass raised" in action:
|
||||
return "face-down raised-hip position"
|
||||
if "on all fours" in action:
|
||||
return "all-fours raised-hip position"
|
||||
if "bends forward" in action or "bent forward" in action:
|
||||
return "bent-over raised-hip position"
|
||||
if "lies on her back" in action and ("thighs open" in action or "legs open" in action):
|
||||
return "open-thigh reclined position"
|
||||
if "lies at the bed edge" in action or "bed edge" in action:
|
||||
return "bed-edge position"
|
||||
if "lies on her side" in action:
|
||||
return "side-lying position"
|
||||
if "kneels in front" in action:
|
||||
return "kneeling-at-hip-height position"
|
||||
if "straddles" in action or "squats over" in action:
|
||||
return "straddling position"
|
||||
if "sits in the man's lap" in action:
|
||||
return "lap-straddling position"
|
||||
if "stands braced" in action:
|
||||
return "standing braced position"
|
||||
if "held between" in action or "front-and-back" in action:
|
||||
return "front-and-back position"
|
||||
if "lies between" in action:
|
||||
return "between-partners position"
|
||||
return ""
|
||||
|
||||
|
||||
def _normalize_climax_view_clause(clause: str, role_graph: str) -> str:
|
||||
lower = clause.lower()
|
||||
if "view" not in lower and "frame" not in lower:
|
||||
return clause
|
||||
angle_match = re.search(
|
||||
r"\b(front-facing|close-up|wide full-body|wide|overhead|mirror-reflected|low-angle|side-profile|bed-level)\b",
|
||||
lower,
|
||||
)
|
||||
if not angle_match:
|
||||
return clause
|
||||
angle = angle_match.group(1)
|
||||
if angle == "wide":
|
||||
angle = "wide full-body"
|
||||
position = _action_position_phrase(role_graph)
|
||||
if position:
|
||||
return f"{angle} aftermath view with the {position} readable"
|
||||
return f"{angle} aftermath view"
|
||||
|
||||
|
||||
def _climax_clause_duplicates_role(clause: str, role_graph: str) -> bool:
|
||||
clause_lower = clause.lower()
|
||||
role_lower = role_graph.lower()
|
||||
role_has_ejaculation = any(token in role_lower for token in ("ejaculates semen", "visible semen", "semen lands"))
|
||||
if role_has_ejaculation and re.search(
|
||||
r"\b(?:cum clearly visible|explicit semen aftermath visible|hardcore ejaculation detail visible|"
|
||||
r"post-ejaculation fluids anatomically clear|sexual fluids and body contact visible|"
|
||||
r"visible external ejaculation|hardcore ejaculation scene|visible orgasm aftermath)\b",
|
||||
clause_lower,
|
||||
):
|
||||
return True
|
||||
duplicate_pairs = (
|
||||
(("lower back", "ass"), ("lower back", "ass")),
|
||||
(("ass",), ("ass",)),
|
||||
(("pussy", "thigh"), ("pussy", "thigh")),
|
||||
(("face", "lips"), ("face", "lips")),
|
||||
(("tongue", "chin"), ("face", "lips", "mouth", "tongue")),
|
||||
(("breast",), ("breast", "chest")),
|
||||
(("belly",), ("belly", "torso")),
|
||||
(("body",), ("body",)),
|
||||
)
|
||||
if any(token in clause_lower for token in ("cum", "semen", "fluid")):
|
||||
for clause_tokens, role_tokens in duplicate_pairs:
|
||||
if any(token in clause_lower for token in clause_tokens) and any(token in role_lower for token in role_tokens):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _limit_detail_for_density(detail: str, density: str, is_climax: bool) -> str:
|
||||
density = _normalize_hardcore_detail_density(density)
|
||||
if density == "compact":
|
||||
return ""
|
||||
clauses = _detail_clauses(detail)
|
||||
if not clauses:
|
||||
return ""
|
||||
if density == "balanced":
|
||||
limit = 1 if is_climax else 2
|
||||
else:
|
||||
limit = 3 if is_climax else 4
|
||||
return _join_detail_clauses(clauses[:limit])
|
||||
|
||||
|
||||
def _is_climax_text(*parts: str) -> bool:
|
||||
text = " ".join(_clean(part).lower() for part in parts if _clean(part))
|
||||
return any(
|
||||
@@ -790,7 +902,7 @@ def _climax_role_graph(role_graph: str, hard_item: str, axis_values: Any = None)
|
||||
return "the woman lies on her back with thighs open while the man kneels between her legs and ejaculates semen across her pussy and thighs"
|
||||
if "on all fours with hips raised" in text:
|
||||
return "the woman is on all fours with hips raised while the man is positioned behind her and ejaculates semen across her ass, thighs, and lower back"
|
||||
if "face-down ass-up" in text:
|
||||
if "face-down ass-up" in text or "lies face-down" in text or "face down" in text:
|
||||
return "the woman lies face-down with ass raised while the man is positioned behind her and ejaculates semen across her lower back and ass"
|
||||
if "bent over with ass raised" in text or "bent over" in text:
|
||||
return "the woman bends forward with hips raised while the man stands behind her with visible semen across her lower back, ass, and thighs"
|
||||
@@ -823,7 +935,7 @@ def _climax_role_graph(role_graph: str, hard_item: str, axis_values: Any = None)
|
||||
return "the woman lies on her back with thighs open while the man kneels between her legs and ejaculates semen across her body"
|
||||
|
||||
|
||||
def _dedupe_climax_detail(detail: str, role_graph: str) -> str:
|
||||
def _dedupe_climax_detail(detail: str, role_graph: str, density: str = "balanced") -> str:
|
||||
detail = _clean(detail)
|
||||
lower = role_graph.lower()
|
||||
patterns: list[str] = []
|
||||
@@ -870,10 +982,25 @@ def _dedupe_climax_detail(detail: str, role_graph: str) -> str:
|
||||
detail = re.sub(r"\bwith\s*,\s*", "with ", detail, flags=re.IGNORECASE)
|
||||
detail = re.sub(r"^with\s+", "", detail, flags=re.IGNORECASE)
|
||||
detail = re.sub(r"^and\s+", "", detail, flags=re.IGNORECASE)
|
||||
return _clean(detail).strip(" ,;")
|
||||
clauses: list[str] = []
|
||||
for clause in _detail_clauses(detail):
|
||||
normalized = _normalize_climax_view_clause(clause, role_graph)
|
||||
if _climax_clause_duplicates_role(normalized, role_graph):
|
||||
continue
|
||||
if density != "dense" and normalized.lower() in ("orgasm during penetration", "post-orgasm visible release"):
|
||||
continue
|
||||
clauses.append(normalized)
|
||||
return _limit_detail_for_density(_join_detail_clauses(clauses), density, True)
|
||||
|
||||
|
||||
def _hardcore_action_sentence(role_graph: str, hard_item: str, composition: str = "", axis_values: Any = None) -> str:
|
||||
def _hardcore_action_sentence(
|
||||
role_graph: str,
|
||||
hard_item: str,
|
||||
composition: str = "",
|
||||
axis_values: Any = None,
|
||||
detail_density: str = "balanced",
|
||||
) -> str:
|
||||
detail_density = _normalize_hardcore_detail_density(detail_density)
|
||||
role_graph = _clean(role_graph).rstrip(".")
|
||||
hard_item = _clean(hard_item).rstrip(".")
|
||||
role_graph = re.sub(
|
||||
@@ -938,9 +1065,10 @@ def _hardcore_action_sentence(role_graph: str, hard_item: str, composition: str
|
||||
)
|
||||
if is_climax:
|
||||
anchor = ""
|
||||
detail = _dedupe_climax_detail(detail, role_graph)
|
||||
detail = _dedupe_climax_detail(detail, role_graph, detail_density)
|
||||
else:
|
||||
detail = _dedupe_hardcore_detail(detail, anchor) if anchor else detail
|
||||
detail = _limit_detail_for_density(detail, detail_density, False)
|
||||
arrangement = _hardcore_pose_arrangement(anchor, role_graph, hard_item, composition, axis_values)
|
||||
anchor_phrase = _with_indefinite_article(anchor) if anchor else ""
|
||||
if arrangement and anchor_phrase:
|
||||
@@ -960,12 +1088,18 @@ def _hardcore_action_sentence(role_graph: str, hard_item: str, composition: str
|
||||
return sentence
|
||||
|
||||
|
||||
def _composition_phrase(composition: Any, action: str = "", prefix: str = "framed as") -> str:
|
||||
def _composition_phrase(
|
||||
composition: Any,
|
||||
action: str = "",
|
||||
prefix: str = "framed as",
|
||||
detail_density: str = "balanced",
|
||||
) -> str:
|
||||
composition = _clean(composition)
|
||||
if not composition:
|
||||
return ""
|
||||
action_lower = _clean(action).lower()
|
||||
composition_lower = composition.lower()
|
||||
detail_density = _normalize_hardcore_detail_density(detail_density)
|
||||
oral_pose_tokens = (
|
||||
"kneeling oral",
|
||||
"side-lying oral",
|
||||
@@ -983,6 +1117,15 @@ def _composition_phrase(composition: Any, action: str = "", prefix: str = "frame
|
||||
if composition_oral_tokens and not any(token in action_lower for token in composition_oral_tokens):
|
||||
match = re.search(r"\bwith\s+(.+)$", composition, flags=re.IGNORECASE)
|
||||
return f"framed with {match.group(1)}" if match else ""
|
||||
position = _action_position_phrase(action)
|
||||
close_or_aftermath = any(
|
||||
token in composition_lower
|
||||
for token in ("close-up", "close crop", "tight", "direct-flash", "subscriber-view", "post-ejaculation", "aftermath")
|
||||
)
|
||||
if position and close_or_aftermath:
|
||||
if detail_density == "compact":
|
||||
return f"{prefix} {composition}, with the {position} still readable"
|
||||
return f"{prefix} {composition}, keeping the {position} and action geography readable"
|
||||
return f"{prefix} {composition}"
|
||||
|
||||
|
||||
@@ -1140,7 +1283,8 @@ def _normal_row_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
role_graph = _natural_label_text(role_graph, cast_labels)
|
||||
item = _natural_label_text(item, cast_labels)
|
||||
axis_values = row.get("item_axis_values") if isinstance(row.get("item_axis_values"), dict) else {}
|
||||
action = _hardcore_action_sentence(role_graph, item, composition, axis_values)
|
||||
detail_density = _normalize_hardcore_detail_density(row.get("hardcore_detail_density"))
|
||||
action = _hardcore_action_sentence(role_graph, item, composition, axis_values, detail_density)
|
||||
parts = [
|
||||
action,
|
||||
cast_prose,
|
||||
@@ -1148,7 +1292,7 @@ def _normal_row_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
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 "",
|
||||
_expression_phrase(expression),
|
||||
_composition_phrase(composition, action, "The image is framed as"),
|
||||
_composition_phrase(composition, action, "The image is framed as", detail_density),
|
||||
camera,
|
||||
style if detail_level != "concise" else "",
|
||||
]
|
||||
@@ -1235,7 +1379,16 @@ def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
hard_item = _natural_label_text(hard_item, hard_labels)
|
||||
hard_role_graph = _natural_label_text(hard_role_graph, hard_labels)
|
||||
hard_axis_values = hard.get("item_axis_values") if isinstance(hard.get("item_axis_values"), dict) else {}
|
||||
hard_action = _hardcore_action_sentence(hard_role_graph, hard_item, hard_composition, hard_axis_values)
|
||||
hard_detail_density = _normalize_hardcore_detail_density(
|
||||
hard.get("hardcore_detail_density") or row.get("hardcore_detail_density") or options.get("hardcore_detail_density")
|
||||
)
|
||||
hard_action = _hardcore_action_sentence(
|
||||
hard_role_graph,
|
||||
hard_item,
|
||||
hard_composition,
|
||||
hard_axis_values,
|
||||
hard_detail_density,
|
||||
)
|
||||
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"
|
||||
@@ -1284,7 +1437,7 @@ def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
|
||||
hard_cast_prose,
|
||||
f"set in {hard_scene}" if hard_scene else "",
|
||||
_expression_phrase(hard_expression),
|
||||
_composition_phrase(hard_composition, hard_action),
|
||||
_composition_phrase(hard_composition, hard_action, detail_density=hard_detail_density),
|
||||
hard_camera,
|
||||
hard_style if detail_level != "concise" else "",
|
||||
]
|
||||
|
||||
@@ -178,6 +178,7 @@ CHARACTER_DESCRIPTOR_DETAIL_CHOICES = ["auto", "full", "medium", "compact", "min
|
||||
CHARACTER_RANDOM_TOKENS = {"", "random", "auto", "global", "from_global", "default"}
|
||||
|
||||
CAMERA_DETAIL_CHOICES = ["off", "compact", "full"]
|
||||
HARDCORE_DETAIL_DENSITY_CHOICES = ["compact", "balanced", "dense"]
|
||||
|
||||
GENERIC_POSITIVE_SUFFIX = (
|
||||
"Use crisp clean comic linework, detailed hatching, soft blended shading, "
|
||||
@@ -1440,6 +1441,10 @@ def camera_detail_choices() -> list[str]:
|
||||
return list(CAMERA_DETAIL_CHOICES)
|
||||
|
||||
|
||||
def hardcore_detail_density_choices() -> list[str]:
|
||||
return list(HARDCORE_DETAIL_DENSITY_CHOICES)
|
||||
|
||||
|
||||
def camera_shot_choices() -> list[str]:
|
||||
return list(CAMERA_SHOT_PROMPTS)
|
||||
|
||||
@@ -3785,7 +3790,11 @@ def build_insta_of_options_json(
|
||||
hardcore_expression_intensity: float = 0.85,
|
||||
softcore_expression_enabled: bool = True,
|
||||
hardcore_expression_enabled: bool = True,
|
||||
hardcore_detail_density: str = "balanced",
|
||||
) -> str:
|
||||
hardcore_detail_density = (
|
||||
hardcore_detail_density if hardcore_detail_density in HARDCORE_DETAIL_DENSITY_CHOICES else "balanced"
|
||||
)
|
||||
return json.dumps(
|
||||
{
|
||||
"softcore_cast": softcore_cast,
|
||||
@@ -3804,6 +3813,7 @@ def build_insta_of_options_json(
|
||||
"hardcore_expression_enabled": not _is_false(hardcore_expression_enabled),
|
||||
"softcore_expression_intensity": _clamped_float(softcore_expression_intensity, 0.45),
|
||||
"hardcore_expression_intensity": _clamped_float(hardcore_expression_intensity, 0.85),
|
||||
"hardcore_detail_density": hardcore_detail_density,
|
||||
},
|
||||
ensure_ascii=True,
|
||||
sort_keys=True,
|
||||
@@ -3828,6 +3838,7 @@ def _parse_insta_of_options(options_json: str | dict[str, Any] | None) -> dict[s
|
||||
"hardcore_expression_enabled": True,
|
||||
"softcore_expression_intensity": 0.45,
|
||||
"hardcore_expression_intensity": 0.85,
|
||||
"hardcore_detail_density": "balanced",
|
||||
}
|
||||
if not options_json:
|
||||
return defaults
|
||||
@@ -3869,6 +3880,11 @@ def _parse_insta_of_options(options_json: str | dict[str, Any] | None) -> dict[s
|
||||
parsed.get("hardcore_expression_intensity"),
|
||||
defaults["hardcore_expression_intensity"],
|
||||
)
|
||||
parsed["hardcore_detail_density"] = (
|
||||
parsed["hardcore_detail_density"]
|
||||
if parsed.get("hardcore_detail_density") in HARDCORE_DETAIL_DENSITY_CHOICES
|
||||
else defaults["hardcore_detail_density"]
|
||||
)
|
||||
for key in ("hardcore_women_count", "hardcore_men_count"):
|
||||
try:
|
||||
parsed[key] = max(0, min(12, int(parsed[key])))
|
||||
@@ -4153,6 +4169,7 @@ def build_insta_of_pair(
|
||||
expression_intensity=options["hardcore_expression_intensity"],
|
||||
character_cast=character_cast or "",
|
||||
)
|
||||
hard_row["hardcore_detail_density"] = options["hardcore_detail_density"]
|
||||
|
||||
descriptor = _insta_of_descriptor(soft_row)
|
||||
cast_descriptors = _insta_of_cast_descriptors(
|
||||
@@ -4220,6 +4237,12 @@ def build_insta_of_pair(
|
||||
options["hardcore_clothing_continuity"],
|
||||
soft_row["item"],
|
||||
)
|
||||
hard_detail_density = options["hardcore_detail_density"]
|
||||
hard_detail_directive = {
|
||||
"compact": "Use one compact position-first sexual action sentence; avoid repeated aftermath wording. ",
|
||||
"balanced": "",
|
||||
"dense": "Use dense but coherent motion, contact, and aftermath detail while keeping one readable body position. ",
|
||||
}[hard_detail_density]
|
||||
soft_descriptor_sentence = (
|
||||
f"Cast descriptors: {soft_cast_descriptor_text}. "
|
||||
if options["softcore_cast"] == "same_as_hardcore"
|
||||
@@ -4249,6 +4272,7 @@ def build_insta_of_pair(
|
||||
f"Setting: {hard_scene}. "
|
||||
f"{_labeled_expression_sentence('Facial expressions', hard_row.get('expression'))}"
|
||||
f"Composition: {hard_composition}. "
|
||||
f"{hard_detail_directive}"
|
||||
f"{hard_camera_sentence}"
|
||||
f"{hard_row['positive_suffix']}."
|
||||
)
|
||||
@@ -4294,6 +4318,7 @@ def build_insta_of_pair(
|
||||
"shared_cast_descriptors": cast_descriptors,
|
||||
"softcore_partner_styling": soft_partner_styling,
|
||||
"hardcore_clothing_state": hard_clothing_state,
|
||||
"hardcore_detail_density": hard_detail_density,
|
||||
"softcore_prompt": soft_prompt,
|
||||
"hardcore_prompt": hard_prompt,
|
||||
"softcore_negative_prompt": soft_negative,
|
||||
|
||||
Reference in New Issue
Block a user