From b7381b9d518845e13c8333b5a58ee4557a74e233 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Wed, 1 Jul 2026 00:31:58 +0200 Subject: [PATCH] Honor softcore clothing restore for atlas prompts --- krea_pair_formatter.py | 25 +++++++++++++++++++------ krea_pov_actions.py | 24 +++++++++++++++++++++++- tools/prompt_smoke.py | 30 ++++++++++++++++++++++++++++-- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/krea_pair_formatter.py b/krea_pair_formatter.py index 511ee87..86473f9 100644 --- a/krea_pair_formatter.py +++ b/krea_pair_formatter.py @@ -97,6 +97,16 @@ def _has_krea2_atlas_variant(row: dict[str, Any]) -> bool: return any(krea2_pose_variant_catalog.get_variant(key) for key in _krea2_variant_keys(row)) +def _restores_krea2_prompt_axis(row: dict[str, Any], axis_name: str) -> bool: + config = row.get("hardcore_position_config") if isinstance(row.get("hardcore_position_config"), dict) else {} + axis_values = row.get("item_axis_values") if isinstance(row.get("item_axis_values"), dict) else {} + restored_axes = [ + *_list_values(config.get("restore_prompt_axes")), + *_list_values(axis_values.get("restored_prompt_axes")), + ] + return axis_name in restored_axes + + def _has_krea2_top_down_variant(row: dict[str, Any]) -> bool: for key in _krea2_variant_keys(row): variant = krea2_pose_variant_catalog.get_variant(key) @@ -214,6 +224,14 @@ def format_insta_pair_result(request: KreaPairFormatRequest, deps: KreaPairForma ) hard_has_atlas_variant = _has_krea2_atlas_variant(hard) hard_output_composition = "" if hard_has_atlas_variant else deps.pov_composition_text(hard_composition, pov_labels) + hard_restores_clothing = hard_has_atlas_variant and _restores_krea2_prompt_axis(hard, "clothing_detail") + hard_clothing = deps.natural_label_text( + deps.filter_pov_labeled_clauses( + deps.natural_clothing_state(row.get("hardcore_clothing_state"), hard_action), + pov_labels, + ), + hard_labels, + ) same_soft_cast = options.get("softcore_cast") == "same_as_hardcore" soft_output_composition = deps.pov_composition_text(soft.get("composition"), pov_labels if same_soft_cast else []) soft_cast_presence = deps.softcore_cast_presence_phrase( @@ -284,12 +302,7 @@ def format_insta_pair_result(request: KreaPairFormatRequest, deps: KreaPairForma hard_cast_prose, hard_action, deps.pov_camera_phrase(pov_labels), - "" - if hard_has_atlas_variant - else deps.natural_label_text( - deps.filter_pov_labeled_clauses(deps.natural_clothing_state(row.get("hardcore_clothing_state"), hard_action), pov_labels), - hard_labels, - ), + hard_clothing if (not hard_has_atlas_variant or hard_restores_clothing) else "", f"set in {hard_scene}" if hard_scene else "", hard_camera_scene, deps.expression_phrase(hard_expression), diff --git a/krea_pov_actions.py b/krea_pov_actions.py index e4b4891..29f577b 100644 --- a/krea_pov_actions.py +++ b/krea_pov_actions.py @@ -105,6 +105,28 @@ def _unique_texts(values: list[Any]) -> list[str]: return texts +def _restored_visible_details(axis_values: dict[str, Any]) -> list[str]: + restored_details = _list_values(axis_values.get("restored_prompt_details")) + restored_axes = _list_values(axis_values.get("restored_prompt_axes")) + if restored_axes and len(restored_axes) == len(restored_details): + return _unique_texts( + [ + detail + for axis, detail in zip(restored_axes, restored_details) + if axis != "clothing_detail" + ] + ) + + clothing_detail = _clean(axis_values.get("clothing_detail")).lower() + return _unique_texts( + [ + detail + for detail in restored_details + if not clothing_detail or _clean(detail).lower() != clothing_detail + ] + ) + + def _krea2_atlas_variant_sentence(axis_values: Any) -> str: variant = _selected_krea2_atlas_variant(axis_values) if not variant: @@ -123,7 +145,7 @@ def _krea2_atlas_variant_sentence(axis_values: Any) -> str: cues = _unique_texts(cue_sets[selected_index] if cue_sets else [variant.get("canonical_geometry")]) sentence = _clean(". ".join(cues)).rstrip(".") if isinstance(axis_values, dict): - restored_details = _unique_texts(_list_values(axis_values.get("restored_prompt_details"))) + restored_details = _restored_visible_details(axis_values) if restored_details: sentence = f"{sentence}. Additional visible detail: {'; '.join(restored_details)}" return sentence diff --git a/tools/prompt_smoke.py b/tools/prompt_smoke.py index 092045a..218f6b7 100644 --- a/tools/prompt_smoke.py +++ b/tools/prompt_smoke.py @@ -8639,9 +8639,35 @@ def smoke_pov_oral_position_routes() -> None: clothing_only_top_krea.get("krea_prompt"), 60, ).lower() + clothing_only_prompt_key = _clean_key(clothing_only_top_prompt) + clothing_only_state = _clean_key(clothing_only_top_pair.get("hardcore_clothing_state")) + expected_clothing_terms = [ + term + for term in ( + "body is fully exposed", + "bare skin unobstructed", + "pushed aside", + "partly removed", + "oral contact unobstructed", + "belt open and pants lowered below the hips", + ) + if term in clothing_only_state + ] _expect( - any(str(detail).lower() in clothing_only_top_prompt for detail in clothing_only_details), - f"Krea2 POV Prompt Restore clothing-only final prompt did not include sampled clothing detail: {clothing_only_top_prompt}", + expected_clothing_terms, + f"Krea2 POV Prompt Restore clothing-only fixture lost softcore-derived clothing state: {clothing_only_state}", + ) + _expect( + any(term in clothing_only_prompt_key for term in expected_clothing_terms), + f"Krea2 POV Prompt Restore clothing-only final prompt did not follow softcore clothing continuity: {clothing_only_top_prompt}", + ) + _expect( + "clothing state:" not in clothing_only_top_prompt, + f"Krea2 POV Prompt Restore clothing-only final prompt leaked raw clothing label: {clothing_only_top_prompt}", + ) + _expect( + not any(str(detail).lower() in clothing_only_top_prompt for detail in clothing_only_details), + f"Krea2 POV Prompt Restore clothing-only final prompt should not dump raw clothing_detail: {clothing_only_top_prompt}", ) sitting_variant_config = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPKrea2POVOralFilter"]().build(