Add POV foreground clothing cues
This commit is contained in:
@@ -247,6 +247,8 @@ def build_insta_of_pair(request: InstaPairBuildRequest, deps: InstaPairBuildDepe
|
||||
rng=hard_content_rng,
|
||||
continuity_map=deps.hardcore_clothing_continuity,
|
||||
choose=deps.choose,
|
||||
label_map=character_slot_map,
|
||||
slot_hardcore_clothing=deps.slot_hardcore_clothing,
|
||||
)
|
||||
if clothing_route.requires_body_exposure_scene:
|
||||
hard_scene = pair_clothing.body_exposure_scene_text(hard_scene)
|
||||
@@ -295,6 +297,7 @@ def build_insta_of_pair(request: InstaPairBuildRequest, deps: InstaPairBuildDepe
|
||||
camera_caption_text=deps.camera_caption_text,
|
||||
cast_descriptors=cast_context["cast_descriptors"],
|
||||
character_hardcore_clothing_entries=character_hardcore_clothing_entries,
|
||||
pov_hardcore_clothing_entries=clothing_route.pov_hardcore_clothing,
|
||||
default_man_hardcore_clothing_entries=clothing_route.default_man_hardcore_clothing,
|
||||
hard_clothing_state=clothing_route.hardcore_clothing_state,
|
||||
hard_detail_density=hard_detail_density,
|
||||
|
||||
@@ -437,10 +437,51 @@ def default_man_hardcore_clothing_entries(
|
||||
return entries
|
||||
|
||||
|
||||
def _pov_clothing_sentence(clothing: str, needs_lower_access: bool) -> str:
|
||||
clothing = _clean_pair_punctuation(str(clothing or "").strip().rstrip("."))
|
||||
if not clothing:
|
||||
return ""
|
||||
lower = clothing.lower()
|
||||
if lower.startswith(("fully nude", "nude")):
|
||||
if needs_lower_access:
|
||||
return "POV foreground body cue: the viewer's bare hips, thighs, hands, and penis are visible only as first-person body cues"
|
||||
return "POV foreground body cue: the viewer's bare hands, forearms, or torso edge are visible only as first-person body cues"
|
||||
clothing = re.sub(r"^(?:wears|wearing|keeps|has|with)\s+", "", clothing, flags=re.IGNORECASE).strip()
|
||||
if needs_lower_access:
|
||||
return (
|
||||
f"POV foreground clothing cue: {clothing}, visible only as the viewer's hands, hips, thighs, or lowered waistband"
|
||||
)
|
||||
return (
|
||||
f"POV foreground clothing cue: {clothing}, visible only as the viewer's hands, forearms, sleeves, or torso edge"
|
||||
)
|
||||
|
||||
|
||||
def pov_hardcore_clothing_entries(
|
||||
label_map: dict[str, dict[str, Any]],
|
||||
pov_labels: list[str] | None,
|
||||
rng: Any,
|
||||
needs_lower_access: bool,
|
||||
choose: Callable[[Any, list[str]], str],
|
||||
slot_hardcore_clothing: Callable[[dict[str, Any] | None, Any], str] | None = None,
|
||||
) -> list[str]:
|
||||
entries: list[str] = []
|
||||
pool = INSTA_OF_HARDCORE_MEN_CLOTHING_LOWER_ACCESS if needs_lower_access else INSTA_OF_HARDCORE_MEN_CLOTHING_VISIBLE
|
||||
for label in pov_labels or []:
|
||||
slot = label_map.get(label)
|
||||
clothing = slot_hardcore_clothing(slot, rng) if slot_hardcore_clothing is not None else ""
|
||||
if not clothing:
|
||||
clothing = choose(rng, pool)
|
||||
sentence = _pov_clothing_sentence(clothing, needs_lower_access)
|
||||
if sentence:
|
||||
entries.append(sentence)
|
||||
return entries
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HardcorePairClothingRoute:
|
||||
access_flags: dict[str, bool]
|
||||
woman_access: str
|
||||
pov_hardcore_clothing: list[str]
|
||||
default_man_hardcore_clothing: list[str]
|
||||
hardcore_clothing_state: str
|
||||
hardcore_clothing_sentence: str
|
||||
@@ -450,6 +491,7 @@ class HardcorePairClothingRoute:
|
||||
return {
|
||||
"access_flags": dict(self.access_flags),
|
||||
"woman_access": self.woman_access,
|
||||
"pov_hardcore_clothing": list(self.pov_hardcore_clothing),
|
||||
"default_man_hardcore_clothing": list(self.default_man_hardcore_clothing),
|
||||
"hardcore_clothing_state": self.hardcore_clothing_state,
|
||||
"hardcore_clothing_sentence": self.hardcore_clothing_sentence,
|
||||
@@ -468,9 +510,19 @@ def resolve_hardcore_pair_clothing_result(
|
||||
rng: Any,
|
||||
continuity_map: dict[str, str],
|
||||
choose: Callable[[Any, list[str]], str],
|
||||
label_map: dict[str, dict[str, Any]] | None = None,
|
||||
slot_hardcore_clothing: Callable[[dict[str, Any] | None, Any], str] | None = None,
|
||||
) -> HardcorePairClothingRoute:
|
||||
access_flags = hardcore_row_access_flags(hard_row)
|
||||
woman_access = "lower" if access_flags["woman_lower"] else "upper" if access_flags["woman_upper"] else ""
|
||||
pov_entries = pov_hardcore_clothing_entries(
|
||||
label_map or {},
|
||||
pov_labels,
|
||||
rng,
|
||||
access_flags["man_lower"],
|
||||
choose,
|
||||
slot_hardcore_clothing,
|
||||
)
|
||||
default_man_entries = default_man_hardcore_clothing_entries(
|
||||
men_count,
|
||||
pov_labels,
|
||||
@@ -491,6 +543,7 @@ def resolve_hardcore_pair_clothing_result(
|
||||
for part in (
|
||||
fallback_state,
|
||||
*character_hardcore_clothing_entries,
|
||||
*pov_entries,
|
||||
*default_man_entries,
|
||||
)
|
||||
if str(part or "").strip()
|
||||
@@ -510,6 +563,7 @@ def resolve_hardcore_pair_clothing_result(
|
||||
return HardcorePairClothingRoute(
|
||||
access_flags=access_flags,
|
||||
woman_access=woman_access,
|
||||
pov_hardcore_clothing=pov_entries,
|
||||
default_man_hardcore_clothing=default_man_entries,
|
||||
hardcore_clothing_state=hard_clothing_state,
|
||||
hardcore_clothing_sentence=f"{hard_clothing_state}. " if hard_clothing_state else "",
|
||||
@@ -531,6 +585,8 @@ def resolve_hardcore_pair_clothing(
|
||||
rng: Any,
|
||||
continuity_map: dict[str, str],
|
||||
choose: Callable[[Any, list[str]], str],
|
||||
label_map: dict[str, dict[str, Any]] | None = None,
|
||||
slot_hardcore_clothing: Callable[[dict[str, Any] | None, Any], str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
return resolve_hardcore_pair_clothing_result(
|
||||
hard_row=hard_row,
|
||||
@@ -542,4 +598,6 @@ def resolve_hardcore_pair_clothing(
|
||||
rng=rng,
|
||||
continuity_map=continuity_map,
|
||||
choose=choose,
|
||||
label_map=label_map,
|
||||
slot_hardcore_clothing=slot_hardcore_clothing,
|
||||
).as_dict()
|
||||
|
||||
@@ -67,6 +67,7 @@ def assemble_insta_pair_metadata(
|
||||
camera_caption_text: Callable[[dict[str, Any]], str],
|
||||
cast_descriptors: list[str],
|
||||
character_hardcore_clothing_entries: list[str],
|
||||
pov_hardcore_clothing_entries: list[str],
|
||||
default_man_hardcore_clothing_entries: list[str],
|
||||
hard_clothing_state: str,
|
||||
hard_detail_density: str,
|
||||
@@ -154,6 +155,7 @@ def assemble_insta_pair_metadata(
|
||||
"pov_prompt_directive": pov_directive,
|
||||
"softcore_partner_styling": soft_partner_styling,
|
||||
"character_hardcore_clothing": character_hardcore_clothing_entries,
|
||||
"pov_hardcore_clothing": pov_hardcore_clothing_entries,
|
||||
"default_man_hardcore_clothing": default_man_hardcore_clothing_entries,
|
||||
"hardcore_clothing_state": hard_clothing_state,
|
||||
"hardcore_detail_density": hard_detail_density,
|
||||
|
||||
+21
-1
@@ -6311,6 +6311,20 @@ def smoke_pair_route_policy() -> None:
|
||||
implied_lower = implied_route.hardcore_clothing_state.lower()
|
||||
_expect("fabric slipping off" not in implied_lower, "Implied nude clothing should not fall back to generic fabric slipping")
|
||||
_expect("denim shorts" in implied_lower and "fitted bralette" in implied_lower, "Implied nude clothing should mirror softcore outfit pieces")
|
||||
pov_clothing_route = pair_clothing.resolve_hardcore_pair_clothing_result(
|
||||
**{
|
||||
**clothing_common,
|
||||
"men_count": 1,
|
||||
"pov_labels": ["Man A"],
|
||||
"label_map": {"Man A": {"hardcore_clothing": "open shirt with jeans lowered below the hips"}},
|
||||
"slot_hardcore_clothing": lambda slot, _rng: str((slot or {}).get("hardcore_clothing") or ""),
|
||||
}
|
||||
)
|
||||
pov_clothing_lower = pov_clothing_route.hardcore_clothing_state.lower()
|
||||
_expect("pov foreground clothing cue" in pov_clothing_lower, "POV man clothing should become a foreground cue")
|
||||
_expect("jeans lowered below the hips" in pov_clothing_lower, "POV lower-access clothing lost configured lower garment state")
|
||||
_expect("man a wears" not in pov_clothing_lower, "POV clothing should not describe the POV man as a visible partner")
|
||||
_expect(not pov_clothing_route.default_man_hardcore_clothing, "POV man should not also receive default visible-man clothing")
|
||||
structured_axis_clothing = pair_clothing.resolve_hardcore_pair_clothing_result(
|
||||
**{
|
||||
**clothing_common,
|
||||
@@ -6585,9 +6599,15 @@ def smoke_insta_pair_pov() -> None:
|
||||
_expect("Man A" in pov_labels, "pair POV labels should include Man A")
|
||||
hard_row = pair.get("hardcore_row") or {}
|
||||
_expect("Man A" in (hard_row.get("pov_character_labels") or []), "hard row POV labels should include Man A")
|
||||
pov_clothing = " ".join(pair.get("pov_hardcore_clothing") or []).lower()
|
||||
_expect("pov foreground clothing cue" in pov_clothing, "pair POV man should get foreground clothing metadata")
|
||||
_expect("viewer" in pov_clothing, "POV clothing metadata should be phrased through the viewer")
|
||||
_expect("man a wears" not in (pair.get("hardcore_clothing_state") or "").lower(), "POV clothing state should not describe Man A as visible")
|
||||
krea = krea_formatter.format_krea2_prompt("", metadata_json=_json(pair), target="hardcore")
|
||||
prompt = krea.get("krea_prompt") or ""
|
||||
_expect("viewer" in prompt.lower(), "POV Krea prompt should mention viewer perspective")
|
||||
prompt_lower = prompt.lower()
|
||||
_expect("viewer" in prompt_lower, "POV Krea prompt should mention viewer perspective")
|
||||
_expect("pov foreground clothing cue" in prompt_lower, "POV Krea prompt lost foreground clothing cue")
|
||||
|
||||
|
||||
def smoke_insta_pair_camera_split() -> None:
|
||||
|
||||
Reference in New Issue
Block a user