from __future__ import annotations import re from typing import Any def _clean(value: Any) -> str: text = "" if value is None else str(value) text = text.replace("\n", " ") text = re.sub(r"\s+", " ", text).strip() text = re.sub(r"\s+([,.;:])", r"\1", text) return text def pov_labels_from_value(value: Any) -> list[str]: labels: list[str] = [] if isinstance(value, list): candidates = value else: candidates = re.split(r"[,;]\s*", _clean(value)) if _clean(value) else [] for candidate in candidates: label = _clean(candidate) if re.match(r"^Man [A-Z]$", label) and label not in labels: labels.append(label) return labels def merge_labels(*groups: list[str]) -> list[str]: merged: list[str] = [] for group in groups: for label in group: if label and label not in merged: merged.append(label) return merged def filter_pov_labeled_clauses(text: Any, pov_labels: list[str]) -> str: rendered = _clean(text) if not rendered or not pov_labels: return rendered clauses = [clause.strip() for clause in rendered.split(";") if clause.strip()] filtered = [ clause for clause in clauses if not any(re.match(rf"^{re.escape(label)}\b", clause) for label in pov_labels) ] return "; ".join(filtered) def pov_camera_phrase(pov_labels: list[str], softcore: bool = False) -> str: if not pov_labels: return "" if softcore: return ( "Camera is the male participant's first-person creator view in one continuous frame, with him implied by perspective or foreground cues" ) return ( "Camera is the male participant's first-person view in one continuous frame; only his foreground hands or body cues appear" ) def pov_composition_text(composition: Any, pov_labels: list[str]) -> str: text = _clean(composition) if not text or not pov_labels: return text text = re.sub(r"\ball participants visible\b", "visible partners readable", text, flags=re.IGNORECASE) text = re.sub(r"\ball adult bodies visible\b", "visible partners readable", text, flags=re.IGNORECASE) text = re.sub(r"\ball bodies visible\b", "visible partners readable", text, flags=re.IGNORECASE) text = re.sub(r"\ball three bodies readable\b", "visible partner bodies readable", text, flags=re.IGNORECASE) text = re.sub(r"\bwide group-sex composition\b", "first-person group-sex POV composition", text, flags=re.IGNORECASE) text = re.sub( r",?\s*adapted for first-person POV with the POV participant kept off-camera\b", "", text, flags=re.IGNORECASE, ) text = re.sub(r",?\s*with the POV participant kept off-camera\b", "", text, flags=re.IGNORECASE) return _clean(text)