Sanitize hard pair scene continuity
This commit is contained in:
@@ -320,9 +320,9 @@ def insta_of_pair_from_row_result(
|
||||
hard_row_for_text = dict(hard_row)
|
||||
options = row.get("options")
|
||||
if isinstance(options, dict) and options.get("continuity") == "same_creator_same_room":
|
||||
if soft_row.get("scene_text"):
|
||||
if not hard_row_for_text.get("scene_text") and soft_row.get("scene_text"):
|
||||
hard_row_for_text["scene_text"] = soft_row["scene_text"]
|
||||
if soft_row.get("composition"):
|
||||
if not hard_row_for_text.get("composition") and soft_row.get("composition"):
|
||||
hard_row_for_text["composition"] = soft_row["composition"]
|
||||
|
||||
include_soft = pair_target.include_softcore
|
||||
|
||||
@@ -56,6 +56,11 @@ flowchart TD
|
||||
The config nodes mostly emit JSON. The final builder nodes parse that JSON and
|
||||
call the same core generation functions.
|
||||
|
||||
For Insta/OF pair formatting, the embedded `hardcore_row` is authoritative for
|
||||
hardcore scene/composition text. Same-room continuity may copy the soft scene
|
||||
into that row earlier, but formatter routes should not bypass later hard-row
|
||||
cleanup such as clothing/body-access scene sanitization.
|
||||
|
||||
## Main Entry Points
|
||||
|
||||
| ComfyUI node | Python entry | What it owns |
|
||||
|
||||
@@ -76,7 +76,7 @@ def format_insta_pair_result(request: KreaPairFormatRequest, deps: KreaPairForma
|
||||
soft_level = deps.clean(options.get("softcore_level")).replace("_", " ")
|
||||
hard_level = deps.clean(options.get("hardcore_level")).replace("_", " ")
|
||||
same_room = options.get("continuity") == "same_creator_same_room"
|
||||
hard_scene = soft.get("scene_text") if same_room and soft.get("scene_text") else hard.get("scene_text")
|
||||
hard_scene = hard.get("scene_text") or (soft.get("scene_text") if same_room else "")
|
||||
hard_composition = deps.sanitize_hardcore_environment_anchors(hard.get("composition"))
|
||||
hard_source_composition = deps.sanitize_hardcore_environment_anchors(hard.get("source_composition") or hard_composition)
|
||||
pov_labels = deps.merge_labels(
|
||||
|
||||
+17
-2
@@ -169,6 +169,10 @@ def body_exposure_scene_text(scene: Any) -> str:
|
||||
(r",?\s*\blingerie visible nearby\b", ""),
|
||||
(r"\boutfit racks\b", "mirror shelves"),
|
||||
(r"\bcostume racks\b", "mirror shelves"),
|
||||
(r"\bshoe shelves\b", "side shelves"),
|
||||
(r"\bshoes visible\b", "body placement visible"),
|
||||
(r"\bbag and shoes visible\b", "nearby floor edge visible"),
|
||||
(r"\bshoes and bag visible\b", "nearby floor edge visible"),
|
||||
(r"\bhanging outfits\b", "hanging fabric"),
|
||||
(r"\bclothing hooks\b", "wall hooks"),
|
||||
(r"\boutfit-check\b", "creator-shot"),
|
||||
@@ -433,6 +437,17 @@ def resolve_hardcore_pair_clothing_result(
|
||||
if str(part or "").strip()
|
||||
]
|
||||
hard_clothing_state = "; ".join(hard_clothing_parts)
|
||||
scene_cleanup_terms = (
|
||||
"body is fully exposed",
|
||||
"bare skin unobstructed",
|
||||
"body is partly exposed",
|
||||
"lower body is clear",
|
||||
"upper body are clear",
|
||||
"pulled aside",
|
||||
"removed below the hips",
|
||||
"pants and underwear are pulled down",
|
||||
)
|
||||
hard_clothing_lower = hard_clothing_state.lower()
|
||||
return HardcorePairClothingRoute(
|
||||
access_flags=access_flags,
|
||||
woman_access=woman_access,
|
||||
@@ -440,8 +455,8 @@ def resolve_hardcore_pair_clothing_result(
|
||||
hardcore_clothing_state=hard_clothing_state,
|
||||
hardcore_clothing_sentence=f"{hard_clothing_state}. " if hard_clothing_state else "",
|
||||
requires_body_exposure_scene=(
|
||||
"body is fully exposed" in hard_clothing_state.lower()
|
||||
or "bare skin unobstructed" in hard_clothing_state.lower()
|
||||
any(access_flags.values())
|
||||
or any(term in hard_clothing_lower for term in scene_cleanup_terms)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -4711,6 +4711,12 @@ def smoke_pair_options_policy() -> None:
|
||||
"creator-shot" in pair_clothing.body_exposure_scene_text("outfit-check framing"),
|
||||
"Pair clothing body exposure scene cleanup should replace outfit-check wording",
|
||||
)
|
||||
sanitized_closet_scene = pair_clothing.body_exposure_scene_text(
|
||||
"full-length closet mirror with outfit racks, shoe shelves, and soft boutique lighting"
|
||||
).lower()
|
||||
_expect("outfit racks" not in sanitized_closet_scene, "Pair clothing body exposure scene cleanup should remove outfit racks")
|
||||
_expect("shoe shelves" not in sanitized_closet_scene, "Pair clothing body exposure scene cleanup should remove shoe shelves")
|
||||
_expect("mirror shelves" in sanitized_closet_scene, "Pair clothing body exposure scene cleanup should keep neutral mirror detail")
|
||||
_expect(
|
||||
pair_clothing.softcore_outfit_sentence("Man A", "wears hoodie and joggers")
|
||||
== "Man A wears hoodie and joggers",
|
||||
@@ -5012,6 +5018,19 @@ def smoke_pair_route_policy() -> None:
|
||||
_expect(clothing_route.as_dict() == clothing_legacy, "Typed pair clothing route should match legacy dict route")
|
||||
_expect(clothing_route.woman_access == "lower", "Typed pair clothing route lost lower-access detection")
|
||||
_expect(clothing_route.requires_body_exposure_scene is True, "Typed pair clothing route lost exposure-scene flag")
|
||||
partial_common = {**clothing_common, "mode": "partially_removed"}
|
||||
partial_route = pair_clothing.resolve_hardcore_pair_clothing_result(**partial_common)
|
||||
_expect(partial_route.requires_body_exposure_scene is True, "Partial lower-access clothing should request scene cleanup")
|
||||
oral_common = {
|
||||
**clothing_common,
|
||||
"hard_row": {
|
||||
"role_graph": "the woman takes the man's penis in her mouth",
|
||||
"item": "standing oral test item",
|
||||
},
|
||||
"mode": "partially_removed",
|
||||
}
|
||||
oral_route = pair_clothing.resolve_hardcore_pair_clothing_result(**oral_common)
|
||||
_expect(oral_route.requires_body_exposure_scene is True, "Man lower-access clothing should request scene cleanup")
|
||||
|
||||
|
||||
def smoke_pair_builder_policy() -> None:
|
||||
@@ -5138,6 +5157,12 @@ def smoke_insta_pair() -> None:
|
||||
|
||||
|
||||
def smoke_krea_pair_clothing_state() -> None:
|
||||
forced_location = pb.build_location_pool_json(
|
||||
enabled=True,
|
||||
combine_mode="replace",
|
||||
preset="custom_only",
|
||||
custom_locations="closet_scene: full-length closet mirror with outfit racks, shoe shelves, and soft boutique lighting",
|
||||
)
|
||||
pair = pb.build_insta_of_pair(
|
||||
row_number=1,
|
||||
start_index=1,
|
||||
@@ -5151,6 +5176,7 @@ def smoke_krea_pair_clothing_state() -> None:
|
||||
options_json=_insta_options(hardcore_clothing_continuity="partially_removed"),
|
||||
character_cast=_character_cast(),
|
||||
hardcore_position_config=_action_filter("penetration_only"),
|
||||
location_config=forced_location,
|
||||
)
|
||||
_expect_pair(pair, "krea_pair_clothing_state")
|
||||
typed_route = krea_pair_formatter.format_insta_pair_result(
|
||||
@@ -5174,6 +5200,16 @@ def smoke_krea_pair_clothing_state() -> None:
|
||||
_expect("softcore outfit" not in lower and "teaser outfit" not in lower, "Krea clothing route leaked softcore outfit label")
|
||||
_expect("lower body is clear" in lower, "Krea clothing route lost generated clothing continuity")
|
||||
_expect("the man keeps" in lower, "Krea clothing route lost partner clothing continuity")
|
||||
_expect("outfit racks" not in lower and "shoe shelves" not in lower, "Krea pair formatter leaked unsanitized hard scene")
|
||||
hard_scene = _clean_key(pair["hardcore_row"].get("scene_text"))
|
||||
_expect("outfit racks" not in hard_scene and "shoe shelves" not in hard_scene, "Pair builder leaked outfit-check scene clutter into hardcore row")
|
||||
_expect("mirror shelves" in hard_scene, "Pair builder lost neutralized scene anchor")
|
||||
caption_text, _caption_method = caption_naturalizer.naturalize_caption("", metadata_json=_json(pair), target="hardcore")
|
||||
caption_lower = caption_text.lower()
|
||||
_expect("outfit racks" not in caption_lower and "shoe shelves" not in caption_lower, "Caption pair formatter leaked unsanitized hard scene")
|
||||
sdxl = sdxl_formatter.format_sdxl_prompt("", metadata_json=_json(pair), target="hardcore")
|
||||
sdxl_lower = sdxl.get("sdxl_prompt", "").lower()
|
||||
_expect("outfit racks" not in sdxl_lower and "shoe shelves" not in sdxl_lower, "SDXL pair formatter leaked unsanitized hard scene")
|
||||
|
||||
|
||||
def smoke_insta_pair_pov() -> None:
|
||||
|
||||
Reference in New Issue
Block a user