Tune hardcore detail density
This commit is contained in:
+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 "",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user