Extract Krea pair formatter route

This commit is contained in:
2026-06-27 11:09:59 +02:00
parent 8398a97cdf
commit 176d4c9257
5 changed files with 287 additions and 162 deletions
+5 -1
View File
@@ -329,12 +329,16 @@ Owner: `krea_formatter.py`.
Keep here: Keep here:
- Krea prose style; - Krea prose style;
- Krea route orchestration; - Krea top-level route orchestration;
- camera-scene preservation; - camera-scene preservation;
- fallback text parsing. - fallback text parsing.
Already isolated: Already isolated:
- `krea_pair_formatter.py` owns Insta/OF pair soft/hard Krea prose assembly
behind `KreaPairFormatRequest`, `KreaPairFormatDependencies`, and
`KreaPairPrompts`; `krea_formatter.py` keeps the `_insta_pair_to_krea`
compatibility wrapper.
- `krea_cast.py` owns cast descriptor parsing, cast labels, cast prose, label - `krea_cast.py` owns cast descriptor parsing, cast labels, cast prose, label
joining, natural cast descriptor text, and label replacement for formatter joining, natural cast descriptor text, and label replacement for formatter
routes, including the caption naturalizer's cast metadata path. routes, including the caption naturalizer's cast metadata path.
+6 -3
View File
@@ -648,7 +648,8 @@ Important POV rule:
`format_krea2_prompt` chooses between three roads: `format_krea2_prompt` chooses between three roads:
- Pair metadata: `_insta_pair_to_krea`. - Pair metadata: `krea_pair_formatter.format_insta_pair_result` through the
`_insta_pair_to_krea` compatibility wrapper.
- Normal metadata row: `_normal_row_to_krea`. - Normal metadata row: `_normal_row_to_krea`.
- Plain text fallback: `_fallback_text_to_krea`. - Plain text fallback: `_fallback_text_to_krea`.
@@ -663,6 +664,8 @@ Key Krea2 ownership:
- Climax role/detail cleanup: `krea_action_climax.py`. - Climax role/detail cleanup: `krea_action_climax.py`.
- Non-POV action-family routing: `krea_action_dispatch.py`. - Non-POV action-family routing: `krea_action_dispatch.py`.
- Non-POV hardcore action sentence: `krea_actions.hardcore_action_sentence`. - Non-POV hardcore action sentence: `krea_actions.hardcore_action_sentence`.
- Insta/OF pair soft/hard Krea prose assembly:
`krea_pair_formatter.format_insta_pair_result`.
- Shared POV labels/filtering/composition cleanup: `pov_policy.py`. - Shared POV labels/filtering/composition cleanup: `pov_policy.py`.
- Krea POV camera support: `krea_pov.py`. - Krea POV camera support: `krea_pov.py`.
- Detail clause splitting and density limiting: `krea_detail.py`. - Detail clause splitting and density limiting: `krea_detail.py`.
@@ -676,8 +679,8 @@ Krea2 field consumption:
| --- | --- | --- | | --- | --- | --- |
| Normal single row | `subject_type`, `item`, `pose`, `scene_text`, `expression`, `composition`, `camera_*`, style fields | `_normal_row_to_krea` | | Normal single row | `subject_type`, `item`, `pose`, `scene_text`, `expression`, `composition`, `camera_*`, style fields | `_normal_row_to_krea` |
| Normal configured cast/hardcore row | `cast_descriptor_text`, `women_count`, `men_count`, `source_role_graph`, `role_graph`, `item`, `item_axis_values`, `source_composition`, `pov_character_labels` | `_normal_row_to_krea`, `krea_actions.hardcore_action_sentence`, `krea_pov_actions.pov_action_phrase` | | Normal configured cast/hardcore row | `cast_descriptor_text`, `women_count`, `men_count`, `source_role_graph`, `role_graph`, `item`, `item_axis_values`, `source_composition`, `pov_character_labels` | `_normal_row_to_krea`, `krea_actions.hardcore_action_sentence`, `krea_pov_actions.pov_action_phrase` |
| Insta/OF pair softcore | `shared_descriptor`, `softcore_row`, `softcore_partner_styling`, options, soft camera fields | `_insta_pair_to_krea` | | Insta/OF pair softcore | `shared_descriptor`, `softcore_row`, `softcore_partner_styling`, options, soft camera fields | `krea_pair_formatter.format_insta_pair_result` |
| Insta/OF pair hardcore | `hardcore_row`, `shared_cast_descriptors`, `hardcore_clothing_state`, `hardcore_detail_density`, hard camera fields, POV labels | `_insta_pair_to_krea`, `krea_actions.hardcore_action_sentence`, `krea_pov_actions.pov_action_phrase`, `krea_clothing.natural_clothing_state` | | Insta/OF pair hardcore | `hardcore_row`, `shared_cast_descriptors`, `hardcore_clothing_state`, `hardcore_detail_density`, hard camera fields, POV labels | `krea_pair_formatter.format_insta_pair_result`, `krea_actions.hardcore_action_sentence`, `krea_pov_actions.pov_action_phrase`, `krea_clothing.natural_clothing_state` |
| Plain text fallback | `source_text` only | `_fallback_text_to_krea` | | Plain text fallback | `source_text` only | `_fallback_text_to_krea` |
If metadata is connected and `method` says `text(fallback)`, the formatter did If metadata is connected and `method` says `text(fallback)`, the formatter did
+40 -158
View File
@@ -11,6 +11,7 @@ try:
is_outercourse_text as _is_outercourse_text, is_outercourse_text as _is_outercourse_text,
normalize_hardcore_detail_density as _normalize_hardcore_detail_density, normalize_hardcore_detail_density as _normalize_hardcore_detail_density,
) )
from . import krea_pair_formatter
from .hardcore_text_cleanup import ( from .hardcore_text_cleanup import (
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values, sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors, sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
@@ -42,6 +43,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
is_outercourse_text as _is_outercourse_text, is_outercourse_text as _is_outercourse_text,
normalize_hardcore_detail_density as _normalize_hardcore_detail_density, normalize_hardcore_detail_density as _normalize_hardcore_detail_density,
) )
import krea_pair_formatter
from hardcore_text_cleanup import ( from hardcore_text_cleanup import (
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values, sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors, sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
@@ -536,166 +538,46 @@ def _normal_row_to_krea(row: dict[str, Any], detail_level: str, style_mode: str)
return _paragraph(parts), "metadata(generic)" return _paragraph(parts), "metadata(generic)"
def _krea_pair_format_dependencies() -> krea_pair_formatter.KreaPairFormatDependencies:
return krea_pair_formatter.KreaPairFormatDependencies(
clean=_clean,
prompt_cast_descriptors=_prompt_cast_descriptors,
pair_camera_phrase=_pair_camera_phrase,
camera_scene_phrase=_camera_scene_phrase,
style_phrase=_style_phrase,
sanitize_hardcore_environment_anchors=_sanitize_hardcore_environment_anchors,
sanitize_hardcore_axis_values=_sanitize_hardcore_axis_values,
sanitize_scene_text_for_cast=_sanitize_scene_text_for_cast,
normalize_hardcore_detail_density=_normalize_hardcore_detail_density,
row_action_family=route_metadata_policy.row_action_family,
hardcore_action_sentence=_hardcore_action_sentence,
pov_action_phrase=_pov_action_phrase,
pov_labels_from_value=_pov_labels_from_value,
merge_labels=_merge_labels,
cast_prose_omit=lambda text, omit_labels: _cast_prose(text, omit_labels=omit_labels),
label_join=_label_join,
filter_pov_labeled_clauses=_filter_pov_labeled_clauses,
natural_label_text=_natural_label_text,
expression_disabled=_expression_disabled,
expression_phrase=_expression_phrase,
pov_camera_phrase=lambda labels: _pov_camera_phrase(labels),
pov_soft_camera_phrase=lambda labels: _pov_camera_phrase(labels, softcore=True),
pov_composition_text=_pov_composition_text,
natural_clothing_state=_natural_clothing_state,
composition_phrase=_composition_phrase,
paragraph=_paragraph,
combine_negative=_combine_negative,
)
def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str) -> tuple[str, str, str, str]: def _insta_pair_to_krea(row: dict[str, Any], detail_level: str, style_mode: str) -> tuple[str, str, str, str]:
descriptor = _clean(row.get("shared_descriptor")) return krea_pair_formatter.format_insta_pair(
cast_descriptors = row.get("shared_cast_descriptors") krea_pair_formatter.KreaPairFormatRequest(
if isinstance(cast_descriptors, list): row=row,
cast_descriptor_text = "; ".join(_clean(item) for item in cast_descriptors if _clean(item)) detail_level=detail_level,
else: style_mode=style_mode,
cast_descriptor_text = _clean(cast_descriptors)
cast_descriptor_text = _prompt_cast_descriptors(cast_descriptor_text)
soft = row.get("softcore_row") if isinstance(row.get("softcore_row"), dict) else {}
hard = row.get("hardcore_row") if isinstance(row.get("hardcore_row"), dict) else {}
soft_camera = _pair_camera_phrase(row.get("softcore_camera_directive"), row.get("softcore_camera_config"), soft)
hard_camera = _pair_camera_phrase(row.get("hardcore_camera_directive"), row.get("hardcore_camera_config"), hard)
soft_camera_scene = _camera_scene_phrase(soft) or _clean(row.get("softcore_camera_scene_directive"))
hard_camera_scene = _camera_scene_phrase(hard) or _clean(row.get("hardcore_camera_scene_directive"))
soft_style = _style_phrase(soft, style_mode)
hard_style = _style_phrase(hard, style_mode)
options = row.get("options") if isinstance(row.get("options"), dict) else {}
soft_level = _clean(options.get("softcore_level")).replace("_", " ")
hard_level = _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_composition = _sanitize_hardcore_environment_anchors(hard.get("composition"))
hard_source_composition = _sanitize_hardcore_environment_anchors(hard.get("source_composition") or hard_composition)
pov_labels = _merge_labels(
_pov_labels_from_value(row.get("pov_character_labels")),
_pov_labels_from_value(soft.get("pov_character_labels")),
_pov_labels_from_value(hard.get("pov_character_labels")),
)
if pov_labels:
hard_camera = ""
if options.get("softcore_cast") == "same_as_hardcore":
soft_camera = ""
soft_cast_descriptor_text = (
cast_descriptor_text
if options.get("softcore_cast") == "same_as_hardcore"
else f"Woman A: {descriptor}"
)
soft_cast_prose, soft_labels = _cast_prose(
soft_cast_descriptor_text,
omit_labels=pov_labels if options.get("softcore_cast") == "same_as_hardcore" else [],
)
hard_cast_prose, hard_labels = _cast_prose(cast_descriptor_text, omit_labels=pov_labels)
soft_labels = _merge_labels(soft_labels, pov_labels if options.get("softcore_cast") == "same_as_hardcore" else [])
hard_labels = _merge_labels(hard_labels, pov_labels)
hard_item = _sanitize_scene_text_for_cast(_sanitize_hardcore_environment_anchors(hard.get("item")), hard_labels)
hard_role_graph = _sanitize_scene_text_for_cast(
_sanitize_hardcore_environment_anchors(hard.get("source_role_graph") or hard.get("role_graph")),
hard_labels,
)
hard_item = _natural_label_text(hard_item, hard_labels)
hard_role_graph = _natural_label_text(hard_role_graph, hard_labels)
hard_axis_values = _sanitize_hardcore_axis_values(hard.get("item_axis_values"))
hard_detail_density = _normalize_hardcore_detail_density(
hard.get("hardcore_detail_density") or row.get("hardcore_detail_density") or options.get("hardcore_detail_density")
)
hard_action = _hardcore_action_sentence(
hard_role_graph,
hard_item,
hard_source_composition,
hard_axis_values,
hard_detail_density,
route_metadata_policy.row_action_family(hard) or route_metadata_policy.row_action_family(row),
)
hard_action = _pov_action_phrase(
hard_action,
pov_labels,
hard_role_graph,
hard_item,
hard_source_composition,
hard_axis_values,
hard_detail_density,
)
hard_output_composition = _pov_composition_text(hard_composition, pov_labels)
same_soft_cast = options.get("softcore_cast") == "same_as_hardcore"
soft_output_composition = _pov_composition_text(soft.get("composition"), pov_labels if same_soft_cast else [])
if same_soft_cast and pov_labels:
soft_cast_presence = (
"the woman is framed from the POV participant's first-person camera in a soft creator-teaser pose, "
"with the POV participant kept off-camera as the viewpoint and implied by camera position or foreground cues"
)
else:
soft_cast_presence = (
f"{_label_join(soft_labels)} share the frame in a soft creator-teaser pose"
if same_soft_cast
else "The image focuses on the woman alone"
)
partner_styling = row.get("softcore_partner_styling")
if isinstance(partner_styling, dict):
outfits = partner_styling.get("outfits")
partner_outfit_text = "; ".join(_clean(item) for item in outfits if _clean(item)) if isinstance(outfits, list) else ""
partner_pose = _clean(partner_styling.get("pose"))
else:
partner_outfit_text = ""
partner_pose = ""
partner_outfit_text = _filter_pov_labeled_clauses(partner_outfit_text, pov_labels)
if pov_labels:
partner_pose = ""
partner_outfit_text = _natural_label_text(partner_outfit_text, soft_labels)
soft_expression = ""
if not _expression_disabled(soft):
soft_expression_source = _filter_pov_labeled_clauses(
_clean(soft.get("character_expression_text")) or _clean(soft.get("expression")),
pov_labels,
)
soft_expression = _natural_label_text(
soft_expression_source,
soft_labels,
)
hard_expression = ""
if not _expression_disabled(hard):
hard_expression_source = _filter_pov_labeled_clauses(
_clean(hard.get("character_expression_text")) or _clean(hard.get("expression")),
pov_labels,
)
hard_expression = _natural_label_text(
hard_expression_source,
hard_labels,
)
soft_item = _clean(soft.get("item"))
soft_item_label = _clean(soft.get("softcore_item_prompt_label"))
soft_item_phrase = ""
if soft_item:
soft_item_phrase = f"body exposure: {soft_item}" if soft_item_label == "Body exposure" else f"wearing {soft_item}"
soft_parts = [
soft_cast_prose,
soft_cast_presence,
partner_outfit_text,
partner_pose,
_pov_camera_phrase(pov_labels, softcore=True) if same_soft_cast else "",
soft_item_phrase,
f"{soft.get('pose')}" if soft.get("pose") else "",
_expression_phrase(soft_expression),
f"in {soft.get('scene_text')}" if soft.get("scene_text") else "",
soft_camera_scene,
f"framed as {soft_output_composition}" if soft_output_composition else "",
soft_camera,
soft_style if detail_level != "concise" else "",
]
hard_parts = [
hard_action,
_pov_camera_phrase(pov_labels),
_natural_label_text(
_filter_pov_labeled_clauses(_natural_clothing_state(row.get("hardcore_clothing_state"), hard_action), pov_labels),
hard_labels,
), ),
hard_cast_prose, _krea_pair_format_dependencies(),
f"set in {hard_scene}" if hard_scene else "",
hard_camera_scene,
_expression_phrase(hard_expression),
_composition_phrase(hard_output_composition, hard_action, detail_density=hard_detail_density),
hard_camera,
hard_style if detail_level != "concise" else "",
]
return (
_paragraph(soft_parts),
_combine_negative(row.get("softcore_negative_prompt")),
_paragraph(hard_parts),
_combine_negative(row.get("hardcore_negative_prompt")),
) )
+226
View File
@@ -0,0 +1,226 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Callable
@dataclass(frozen=True)
class KreaPairFormatRequest:
row: dict[str, Any]
detail_level: str
style_mode: str
@dataclass(frozen=True)
class KreaPairPrompts:
soft_prompt: str
soft_negative: str
hard_prompt: str
hard_negative: str
def as_tuple(self) -> tuple[str, str, str, str]:
return self.soft_prompt, self.soft_negative, self.hard_prompt, self.hard_negative
@dataclass(frozen=True)
class KreaPairFormatDependencies:
clean: Callable[[Any], str]
prompt_cast_descriptors: Callable[[str], str]
pair_camera_phrase: Callable[[Any, Any, dict[str, Any]], str]
camera_scene_phrase: Callable[[dict[str, Any]], str]
style_phrase: Callable[[dict[str, Any], str], str]
sanitize_hardcore_environment_anchors: Callable[[Any], str]
sanitize_hardcore_axis_values: Callable[[Any], Any]
sanitize_scene_text_for_cast: Callable[[Any, list[str]], str]
normalize_hardcore_detail_density: Callable[[Any], str]
row_action_family: Callable[[Any], str]
hardcore_action_sentence: Callable[[str, str, str, Any, str, str], str]
pov_action_phrase: Callable[[str, list[str], str, str, str, Any, str], str]
pov_labels_from_value: Callable[[Any], list[str]]
merge_labels: Callable[..., list[str]]
cast_prose_omit: Callable[[str, list[str]], tuple[str, list[str]]]
label_join: Callable[[list[str]], str]
filter_pov_labeled_clauses: Callable[[Any, list[str]], str]
natural_label_text: Callable[[Any, list[str]], str]
expression_disabled: Callable[[dict[str, Any]], bool]
expression_phrase: Callable[[Any], str]
pov_camera_phrase: Callable[[list[str]], str]
pov_soft_camera_phrase: Callable[[list[str]], str]
pov_composition_text: Callable[[Any, list[str]], str]
natural_clothing_state: Callable[[Any, str], str]
composition_phrase: Callable[..., str]
paragraph: Callable[[list[str]], str]
combine_negative: Callable[..., str]
def format_insta_pair_result(request: KreaPairFormatRequest, deps: KreaPairFormatDependencies) -> KreaPairPrompts:
row = request.row
detail_level = request.detail_level
style_mode = request.style_mode
descriptor = deps.clean(row.get("shared_descriptor"))
cast_descriptors = row.get("shared_cast_descriptors")
if isinstance(cast_descriptors, list):
cast_descriptor_text = "; ".join(deps.clean(item) for item in cast_descriptors if deps.clean(item))
else:
cast_descriptor_text = deps.clean(cast_descriptors)
cast_descriptor_text = deps.prompt_cast_descriptors(cast_descriptor_text)
soft = row.get("softcore_row") if isinstance(row.get("softcore_row"), dict) else {}
hard = row.get("hardcore_row") if isinstance(row.get("hardcore_row"), dict) else {}
soft_camera = deps.pair_camera_phrase(row.get("softcore_camera_directive"), row.get("softcore_camera_config"), soft)
hard_camera = deps.pair_camera_phrase(row.get("hardcore_camera_directive"), row.get("hardcore_camera_config"), hard)
soft_camera_scene = deps.camera_scene_phrase(soft) or deps.clean(row.get("softcore_camera_scene_directive"))
hard_camera_scene = deps.camera_scene_phrase(hard) or deps.clean(row.get("hardcore_camera_scene_directive"))
soft_style = deps.style_phrase(soft, style_mode)
hard_style = deps.style_phrase(hard, style_mode)
options = row.get("options") if isinstance(row.get("options"), dict) else {}
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_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(
deps.pov_labels_from_value(row.get("pov_character_labels")),
deps.pov_labels_from_value(soft.get("pov_character_labels")),
deps.pov_labels_from_value(hard.get("pov_character_labels")),
)
if pov_labels:
hard_camera = ""
if options.get("softcore_cast") == "same_as_hardcore":
soft_camera = ""
soft_cast_descriptor_text = (
cast_descriptor_text
if options.get("softcore_cast") == "same_as_hardcore"
else f"Woman A: {descriptor}"
)
soft_cast_prose, soft_labels = deps.cast_prose_omit(
soft_cast_descriptor_text,
pov_labels if options.get("softcore_cast") == "same_as_hardcore" else [],
)
hard_cast_prose, hard_labels = deps.cast_prose_omit(cast_descriptor_text, pov_labels)
soft_labels = deps.merge_labels(soft_labels, pov_labels if options.get("softcore_cast") == "same_as_hardcore" else [])
hard_labels = deps.merge_labels(hard_labels, pov_labels)
hard_item = deps.sanitize_scene_text_for_cast(
deps.sanitize_hardcore_environment_anchors(hard.get("item")),
hard_labels,
)
hard_role_graph = deps.sanitize_scene_text_for_cast(
deps.sanitize_hardcore_environment_anchors(hard.get("source_role_graph") or hard.get("role_graph")),
hard_labels,
)
hard_item = deps.natural_label_text(hard_item, hard_labels)
hard_role_graph = deps.natural_label_text(hard_role_graph, hard_labels)
hard_axis_values = deps.sanitize_hardcore_axis_values(hard.get("item_axis_values"))
hard_detail_density = deps.normalize_hardcore_detail_density(
hard.get("hardcore_detail_density") or row.get("hardcore_detail_density") or options.get("hardcore_detail_density")
)
hard_action = deps.hardcore_action_sentence(
hard_role_graph,
hard_item,
hard_source_composition,
hard_axis_values,
hard_detail_density,
deps.row_action_family(hard) or deps.row_action_family(row),
)
hard_action = deps.pov_action_phrase(
hard_action,
pov_labels,
hard_role_graph,
hard_item,
hard_source_composition,
hard_axis_values,
hard_detail_density,
)
hard_output_composition = deps.pov_composition_text(hard_composition, pov_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 [])
if same_soft_cast and pov_labels:
soft_cast_presence = (
"the woman is framed from the POV participant's first-person camera in a soft creator-teaser pose, "
"with the POV participant kept off-camera as the viewpoint and implied by camera position or foreground cues"
)
else:
soft_cast_presence = (
f"{deps.label_join(soft_labels)} share the frame in a soft creator-teaser pose"
if same_soft_cast
else "The image focuses on the woman alone"
)
partner_styling = row.get("softcore_partner_styling")
if isinstance(partner_styling, dict):
outfits = partner_styling.get("outfits")
partner_outfit_text = "; ".join(deps.clean(item) for item in outfits if deps.clean(item)) if isinstance(outfits, list) else ""
partner_pose = deps.clean(partner_styling.get("pose"))
else:
partner_outfit_text = ""
partner_pose = ""
partner_outfit_text = deps.filter_pov_labeled_clauses(partner_outfit_text, pov_labels)
if pov_labels:
partner_pose = ""
partner_outfit_text = deps.natural_label_text(partner_outfit_text, soft_labels)
soft_expression = ""
if not deps.expression_disabled(soft):
soft_expression_source = deps.filter_pov_labeled_clauses(
deps.clean(soft.get("character_expression_text")) or deps.clean(soft.get("expression")),
pov_labels,
)
soft_expression = deps.natural_label_text(
soft_expression_source,
soft_labels,
)
hard_expression = ""
if not deps.expression_disabled(hard):
hard_expression_source = deps.filter_pov_labeled_clauses(
deps.clean(hard.get("character_expression_text")) or deps.clean(hard.get("expression")),
pov_labels,
)
hard_expression = deps.natural_label_text(
hard_expression_source,
hard_labels,
)
soft_item = deps.clean(soft.get("item"))
soft_item_label = deps.clean(soft.get("softcore_item_prompt_label"))
soft_item_phrase = ""
if soft_item:
soft_item_phrase = f"body exposure: {soft_item}" if soft_item_label == "Body exposure" else f"wearing {soft_item}"
soft_parts = [
soft_cast_prose,
soft_cast_presence,
partner_outfit_text,
partner_pose,
deps.pov_soft_camera_phrase(pov_labels) if same_soft_cast else "",
soft_item_phrase,
f"{soft.get('pose')}" if soft.get("pose") else "",
deps.expression_phrase(soft_expression),
f"in {soft.get('scene_text')}" if soft.get("scene_text") else "",
soft_camera_scene,
f"framed as {soft_output_composition}" if soft_output_composition else "",
soft_camera,
soft_style if detail_level != "concise" else "",
]
hard_parts = [
hard_action,
deps.pov_camera_phrase(pov_labels),
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_cast_prose,
f"set in {hard_scene}" if hard_scene else "",
hard_camera_scene,
deps.expression_phrase(hard_expression),
deps.composition_phrase(hard_output_composition, hard_action, detail_density=hard_detail_density),
hard_camera,
hard_style if detail_level != "concise" else "",
]
return KreaPairPrompts(
soft_prompt=deps.paragraph(soft_parts),
soft_negative=deps.combine_negative(row.get("softcore_negative_prompt")),
hard_prompt=deps.paragraph(hard_parts),
hard_negative=deps.combine_negative(row.get("hardcore_negative_prompt")),
)
def format_insta_pair(request: KreaPairFormatRequest, deps: KreaPairFormatDependencies) -> tuple[str, str, str, str]:
return format_insta_pair_result(request, deps).as_tuple()
+10
View File
@@ -43,6 +43,7 @@ import generation_profile_config # noqa: E402
import index_switch_policy # noqa: E402 import index_switch_policy # noqa: E402
import krea_cast # noqa: E402 import krea_cast # noqa: E402
import krea_formatter # noqa: E402 import krea_formatter # noqa: E402
import krea_pair_formatter # noqa: E402
import location_config # noqa: E402 import location_config # noqa: E402
import loop_nodes # noqa: E402 import loop_nodes # noqa: E402
import pair_builder # noqa: E402 import pair_builder # noqa: E402
@@ -3196,6 +3197,15 @@ def smoke_krea_pair_clothing_state() -> None:
hardcore_position_config=_action_filter("penetration_only"), hardcore_position_config=_action_filter("penetration_only"),
) )
_expect_pair(pair, "krea_pair_clothing_state") _expect_pair(pair, "krea_pair_clothing_state")
typed_route = krea_pair_formatter.format_insta_pair_result(
krea_pair_formatter.KreaPairFormatRequest(pair, "balanced", "preserve"),
krea_formatter._krea_pair_format_dependencies(),
)
legacy_route = krea_formatter._insta_pair_to_krea(pair, "balanced", "preserve")
_expect(
typed_route.as_tuple() == legacy_route,
"Typed Krea pair formatter route should match legacy wrapper output",
)
krea = krea_formatter.format_krea2_prompt("", metadata_json=_json(pair), target="hardcore") krea = krea_formatter.format_krea2_prompt("", metadata_json=_json(pair), target="hardcore")
prompt = _expect_text("krea_pair_clothing_state.krea_prompt", krea.get("krea_prompt"), 60) prompt = _expect_text("krea_pair_clothing_state.krea_prompt", krea.get("krea_prompt"), 60)
lower = prompt.lower() lower = prompt.lower()