Reduce split-view cues in POV prompts

This commit is contained in:
2026-06-26 12:25:12 +02:00
parent 3a3771eed5
commit 0a9a82991e
2 changed files with 64 additions and 5 deletions
+61 -2
View File
@@ -675,10 +675,10 @@ def _pov_camera_phrase(pov_labels: list[str], softcore: bool = False) -> str:
return "" return ""
if softcore: if softcore:
return ( return (
"Camera is the male participant's first-person creator view, with him implied by perspective or foreground cues" "Camera is the male participant's first-person creator view in one continuous frame, with him implied by perspective or foreground cues"
) )
return ( return (
"Camera is the male participant's first-person view; only his foreground hands or body cues appear" "Camera is the male participant's first-person view in one continuous frame; only his foreground hands or body cues appear"
) )
@@ -908,6 +908,57 @@ def _is_foreplay_text(*parts: Any) -> bool:
) )
def _is_close_foreplay_text(*parts: Any) -> bool:
text = " ".join(_clean(part).lower() for part in parts if _clean(part))
if not text or not _is_foreplay_text(text):
return False
return any(
term in text
for term in (
"stand close",
"stand face-to-face",
"press their bodies",
"bodies pressed close",
"hips pressed close",
"mouth-to-mouth",
"deep kissing",
"heated kiss",
"hands pull clothing",
"pull clothing aside",
"clothing being removed",
)
)
def _sanitize_foreplay_detail(detail: str, role_graph: str = "", composition: str = "") -> str:
detail = _clean(detail)
if not detail:
return ""
if not _is_close_foreplay_text(role_graph, detail, composition):
return detail
detail = re.sub(
r"\b(?:raised edge|edge-supported|edge-of-bed|bed-edge)\s+undressing position\s+(?:featuring|while|with)\s+",
"",
detail,
flags=re.IGNORECASE,
)
detail = re.sub(
r"\b(?:standing kissing|wall-pressed kissing|mirror undressing)\s+position\s+(?:featuring|while|with)\s+",
"",
detail,
flags=re.IGNORECASE,
)
detail = re.sub(
r"\b(?:raised edge|edge-supported|edge-of-bed|bed-edge)\s+undressing position\b",
"close standing undressing",
detail,
flags=re.IGNORECASE,
)
detail = re.sub(r"\braised-edge open-thigh position\b", "close-body first-person position", detail, flags=re.IGNORECASE)
detail = re.sub(r"\s*,\s*", ", ", detail).strip(" ,;")
return _clean(detail)
def _is_vaginal_penetration_text(*parts: Any) -> bool: def _is_vaginal_penetration_text(*parts: Any) -> bool:
text = " ".join(_clean(part).lower() for part in parts if _clean(part)) text = " ".join(_clean(part).lower() for part in parts if _clean(part))
if not text or _is_outercourse_text(text) or _is_oral_text(text) or _is_foreplay_text(text): if not text or _is_outercourse_text(text) or _is_oral_text(text) or _is_foreplay_text(text):
@@ -1695,6 +1746,8 @@ def _join_detail_clauses(clauses: list[str]) -> str:
def _action_position_phrase(action: str) -> str: def _action_position_phrase(action: str) -> str:
action = _clean(action).lower() action = _clean(action).lower()
if _is_close_foreplay_text(action):
return "single-frame close-body first-person position"
if "pov reverse cowgirl" in action: if "pov reverse cowgirl" in action:
return "reverse-cowgirl first-person position" return "reverse-cowgirl first-person position"
if "pov cowgirl" in action: if "pov cowgirl" in action:
@@ -2013,6 +2066,10 @@ def _hardcore_action_sentence(
if is_climax: if is_climax:
anchor = "" anchor = ""
detail = _dedupe_climax_detail(detail, role_graph, detail_density) detail = _dedupe_climax_detail(detail, role_graph, detail_density)
elif _is_foreplay_text(role_graph, hard_item, composition, _axis_values_text(axis_values)):
anchor = ""
detail = _sanitize_foreplay_detail(detail, role_graph, composition)
detail = _limit_detail_for_density(detail, detail_density, False)
elif is_outercourse: elif is_outercourse:
anchor = "" anchor = ""
detail = _dedupe_outercourse_detail(detail, role_graph, hard_item, axis_values) detail = _dedupe_outercourse_detail(detail, role_graph, hard_item, axis_values)
@@ -2097,6 +2154,8 @@ def _composition_phrase(
token in composition_lower token in composition_lower
for token in ("close-up", "close crop", "tight", "direct-flash", "subscriber-view", "post-ejaculation", "aftermath") for token in ("close-up", "close crop", "tight", "direct-flash", "subscriber-view", "post-ejaculation", "aftermath")
) )
if _is_close_foreplay_text(action_lower) and close_or_aftermath:
return f"{prefix} {composition}, in one continuous first-person close-body frame"
if position and close_or_aftermath: if position and close_or_aftermath:
if detail_density == "compact": if detail_density == "compact":
return f"{prefix} {composition}, with the {position} still readable" return f"{prefix} {composition}, with the {position} still readable"
+3 -3
View File
@@ -3628,7 +3628,7 @@ def _coworking_direction_detail(
if "left side" in direction: if "left side" in direction:
return f"{subject} is in left-side profile; {midground} run behind {pronoun} toward {background}, with coworking details kept at the frame edges" return f"{subject} is in left-side profile; {midground} run behind {pronoun} toward {background}, with coworking details kept at the frame edges"
if "back-right" in direction or "back-left" in direction: if "back-right" in direction or "back-left" in direction:
return f"{subject} is seen from a rear-quarter angle, turning back over one shoulder; {midground} and {background} stay beyond {pronoun}, not in the lower foreground" return f"{subject} stays close in one continuous diagonal first-person body angle; {midground} lead toward {background} behind {pronoun} at the edges, not in the lower foreground"
if direction == "back view": if direction == "back view":
return f"the viewer looks past {subject}'s back toward {midground}, then into {background}; only POV body cues sit low in frame" return f"the viewer looks past {subject}'s back toward {midground}, then into {background}; only POV body cues sit low in frame"
if "front-right" in direction or "front-left" in direction: if "front-right" in direction or "front-left" in direction:
@@ -3663,12 +3663,12 @@ def _coworking_distance_detail(distance: str, profile: dict[str, str], subject_k
def _coworking_elevation_detail(elevation: str, profile: dict[str, str], subject_kind: str, pov_labels: list[str] | None = None) -> str: def _coworking_elevation_detail(elevation: str, profile: dict[str, str], subject_kind: str, pov_labels: list[str] | None = None) -> str:
elevation = str(elevation or "").strip().lower() elevation = str(elevation or "").strip().lower()
_subject, pronoun = _coworking_subject_terms(subject_kind, pov_labels) subject, pronoun = _coworking_subject_terms(subject_kind, pov_labels)
if pov_labels: if pov_labels:
if "low-angle" in elevation: if "low-angle" in elevation:
return f"low angle keeps POV body cues low while windows and partition lines rise behind {pronoun}" return f"low angle keeps POV body cues low while windows and partition lines rise behind {pronoun}"
if "elevated" in elevation: if "elevated" in elevation:
return f"elevated angle shows {pronoun} from above with tabletop and glass lines only behind or beside the action" return f"elevated POV keeps the viewer's eye line slightly higher than {subject}, with tabletop and glass lines only behind or at the side edges"
if "high-angle" in elevation: if "high-angle" in elevation:
return f"high angle looks down from the viewer's position with desks and aisle only in the background" return f"high angle looks down from the viewer's position with desks and aisle only in the background"
return f"eye-level angle keeps tabletop lines and glass seams behind {pronoun}" return f"eye-level angle keeps tabletop lines and glass seams behind {pronoun}"