Extract Krea row field policy
This commit is contained in:
@@ -342,8 +342,10 @@ Already isolated:
|
||||
wrapper helpers.
|
||||
- `krea_normal_formatter.py` owns normal metadata single/couple/generic Krea
|
||||
prose assembly behind `KreaNormalRowRequest`, `KreaNormalRowDependencies`,
|
||||
and `KreaNormalRowPrompt`; `krea_formatter.py` keeps common row-field
|
||||
extraction and route selection.
|
||||
and `KreaNormalRowPrompt`; `krea_formatter.py` keeps route selection.
|
||||
- `krea_row_fields.py` owns shared normal-row Krea field extraction for item,
|
||||
scene, pose, expression, composition/source-composition, camera, and style so
|
||||
normal and configured-cast Krea routes cannot drift independently.
|
||||
- `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`
|
||||
|
||||
@@ -115,6 +115,7 @@ Core helper ownership:
|
||||
| `pov_policy.py` | Shared POV slot detection, POV label merging/filtering, builder POV directives, source role-graph viewer replacement, and shared POV composition cleanup used by builder and Krea2 routes. |
|
||||
| `scene_camera_adapters.py` | Location-aware camera/scene prose such as coworking lounge camera layout. |
|
||||
| `row_camera.py` | Row-level camera insertion, contextual coworking composition mutation, subject-kind detection, POV label fallback, and POV suppression of normal camera directives. |
|
||||
| `krea_row_fields.py` | Shared Krea normal-row field extraction for item, scene, pose, expression, composition/source-composition, camera, and style used by normal and configured-cast routes. |
|
||||
| `krea_cast.py` | Shared formatter cast descriptor parsing, cast labels, cast prose, natural cast descriptor text, and label replacement used by Krea2 and caption routes. |
|
||||
| `prompt_hygiene.py` | Generic prompt, caption, and negative-prompt cleanup. |
|
||||
| `row_normalization.py` | Final prompt-row and pair metadata normalization: trigger prepending, extra-positive append, negative merge/dedupe, caption-part joining, embedded soft/hard row output and side-metadata synchronization, and embedded row sanitation. |
|
||||
|
||||
+41
-48
@@ -14,6 +14,7 @@ try:
|
||||
from . import krea_configured_cast_formatter
|
||||
from . import krea_normal_formatter
|
||||
from . import krea_pair_formatter
|
||||
from . import krea_row_fields
|
||||
from .hardcore_text_cleanup import (
|
||||
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
|
||||
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
|
||||
@@ -48,6 +49,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
||||
import krea_configured_cast_formatter
|
||||
import krea_normal_formatter
|
||||
import krea_pair_formatter
|
||||
import krea_row_fields
|
||||
from hardcore_text_cleanup import (
|
||||
sanitize_hardcore_axis_values as _sanitize_hardcore_axis_values,
|
||||
sanitize_hardcore_environment_anchors as _sanitize_hardcore_environment_anchors,
|
||||
@@ -399,6 +401,17 @@ def _style_phrase(row: dict[str, Any], style_mode: str) -> str:
|
||||
return style or suffix
|
||||
|
||||
|
||||
def _krea_row_field_dependencies() -> krea_row_fields.KreaRowFieldDependencies:
|
||||
return krea_row_fields.KreaRowFieldDependencies(
|
||||
clean=_clean,
|
||||
row_value=_row_value,
|
||||
camera_phrase=_camera_phrase,
|
||||
camera_scene_phrase=_camera_scene_phrase,
|
||||
style_phrase=_style_phrase,
|
||||
expression_disabled=_expression_disabled,
|
||||
)
|
||||
|
||||
|
||||
def _krea_normal_row_dependencies() -> krea_normal_formatter.KreaNormalRowDependencies:
|
||||
return krea_normal_formatter.KreaNormalRowDependencies(
|
||||
clean=_clean,
|
||||
@@ -416,33 +429,25 @@ def _krea_normal_row_request_from_row(
|
||||
detail_level: str,
|
||||
style_mode: str,
|
||||
) -> krea_normal_formatter.KreaNormalRowRequest:
|
||||
subject_type = _clean(row.get("subject_type"))
|
||||
primary = _clean(row.get("primary_subject"))
|
||||
item = _row_value(row, "item", ("Sexual pose", "Erotic outfit", "Clothing")) or _clean(row.get("custom_item"))
|
||||
item = re.sub(r",?\s*(fashion editorial|resort) styling$", "", item, flags=re.IGNORECASE)
|
||||
scene = _row_value(row, "scene_text", ("Setting", "Scene")) or _clean(row.get("scene"))
|
||||
pose = _row_value(row, "pose", ("Sexual pose", "Pose"))
|
||||
expression = ""
|
||||
if not _expression_disabled(row):
|
||||
expression = _row_value(row, "character_expression_text") or _row_value(row, "expression", ("Facial expressions", "Facial expression"))
|
||||
composition = re.sub(r"^vertical\s+", "", _row_value(row, "composition", ("Composition",)), flags=re.IGNORECASE)
|
||||
camera = _camera_phrase(row)
|
||||
camera_scene = _camera_scene_phrase(row)
|
||||
style = _style_phrase(row, style_mode)
|
||||
fields = krea_row_fields.extract_krea_row_fields(
|
||||
row,
|
||||
style_mode,
|
||||
_krea_row_field_dependencies(),
|
||||
)
|
||||
return krea_normal_formatter.KreaNormalRowRequest(
|
||||
row=row,
|
||||
detail_level=detail_level,
|
||||
style_mode=style_mode,
|
||||
subject_type=subject_type,
|
||||
primary=primary,
|
||||
item=item,
|
||||
scene=scene,
|
||||
pose=pose,
|
||||
expression=expression,
|
||||
composition=composition,
|
||||
camera=camera,
|
||||
camera_scene=camera_scene,
|
||||
style=style,
|
||||
subject_type=fields.subject_type,
|
||||
primary=fields.primary,
|
||||
item=fields.item,
|
||||
scene=fields.scene,
|
||||
pose=fields.pose,
|
||||
expression=fields.expression,
|
||||
composition=fields.composition,
|
||||
camera=fields.camera,
|
||||
camera_scene=fields.camera_scene,
|
||||
style=fields.style,
|
||||
)
|
||||
|
||||
|
||||
@@ -505,36 +510,24 @@ def _krea_configured_cast_request_from_row(
|
||||
detail_level: str,
|
||||
style_mode: str,
|
||||
) -> krea_configured_cast_formatter.KreaConfiguredCastRequest:
|
||||
primary = _clean(row.get("primary_subject"))
|
||||
item = _row_value(row, "item", ("Sexual pose", "Erotic outfit", "Clothing")) or _clean(row.get("custom_item"))
|
||||
item = re.sub(r",?\s*(fashion editorial|resort) styling$", "", item, flags=re.IGNORECASE)
|
||||
scene = _row_value(row, "scene_text", ("Setting", "Scene")) or _clean(row.get("scene"))
|
||||
expression = ""
|
||||
if not _expression_disabled(row):
|
||||
expression = _row_value(row, "character_expression_text") or _row_value(row, "expression", ("Facial expressions", "Facial expression"))
|
||||
composition = re.sub(r"^vertical\s+", "", _row_value(row, "composition", ("Composition",)), flags=re.IGNORECASE)
|
||||
source_composition = re.sub(
|
||||
r"^vertical\s+",
|
||||
"",
|
||||
_clean(row.get("source_composition")) or composition,
|
||||
flags=re.IGNORECASE,
|
||||
fields = krea_row_fields.extract_krea_row_fields(
|
||||
row,
|
||||
style_mode,
|
||||
_krea_row_field_dependencies(),
|
||||
)
|
||||
camera = _camera_phrase(row)
|
||||
camera_scene = _camera_scene_phrase(row)
|
||||
style = _style_phrase(row, style_mode)
|
||||
return _krea_configured_cast_request(
|
||||
row,
|
||||
detail_level,
|
||||
style_mode,
|
||||
primary,
|
||||
item,
|
||||
scene,
|
||||
expression,
|
||||
composition,
|
||||
source_composition,
|
||||
camera,
|
||||
camera_scene,
|
||||
style,
|
||||
fields.primary,
|
||||
fields.item,
|
||||
fields.scene,
|
||||
fields.expression,
|
||||
fields.composition,
|
||||
fields.source_composition,
|
||||
fields.camera,
|
||||
fields.camera_scene,
|
||||
fields.style,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class KreaRowFields:
|
||||
subject_type: str
|
||||
primary: str
|
||||
item: str
|
||||
scene: str
|
||||
pose: str
|
||||
expression: str
|
||||
composition: str
|
||||
source_composition: str
|
||||
camera: str
|
||||
camera_scene: str
|
||||
style: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class KreaRowFieldDependencies:
|
||||
clean: Callable[[Any], str]
|
||||
row_value: Callable[[dict[str, Any], str, tuple[str, ...]], str]
|
||||
camera_phrase: Callable[[dict[str, Any]], str]
|
||||
camera_scene_phrase: Callable[[dict[str, Any]], str]
|
||||
style_phrase: Callable[[dict[str, Any], str], str]
|
||||
expression_disabled: Callable[[dict[str, Any]], bool]
|
||||
|
||||
|
||||
def _without_vertical_prefix(text: str) -> str:
|
||||
return re.sub(r"^vertical\s+", "", text, flags=re.IGNORECASE)
|
||||
|
||||
|
||||
def _clean_item_suffix(text: str) -> str:
|
||||
return re.sub(r",?\s*(fashion editorial|resort) styling$", "", text, flags=re.IGNORECASE)
|
||||
|
||||
|
||||
def extract_krea_row_fields(
|
||||
row: dict[str, Any],
|
||||
style_mode: str,
|
||||
deps: KreaRowFieldDependencies,
|
||||
) -> KreaRowFields:
|
||||
item = deps.row_value(row, "item", ("Sexual pose", "Erotic outfit", "Clothing")) or deps.clean(
|
||||
row.get("custom_item")
|
||||
)
|
||||
item = _clean_item_suffix(item)
|
||||
expression = ""
|
||||
if not deps.expression_disabled(row):
|
||||
expression = deps.row_value(row, "character_expression_text", ()) or deps.row_value(
|
||||
row,
|
||||
"expression",
|
||||
("Facial expressions", "Facial expression"),
|
||||
)
|
||||
composition = _without_vertical_prefix(deps.row_value(row, "composition", ("Composition",)))
|
||||
source_composition = _without_vertical_prefix(deps.clean(row.get("source_composition")) or composition)
|
||||
return KreaRowFields(
|
||||
subject_type=deps.clean(row.get("subject_type")),
|
||||
primary=deps.clean(row.get("primary_subject")),
|
||||
item=item,
|
||||
scene=deps.row_value(row, "scene_text", ("Setting", "Scene")) or deps.clean(row.get("scene")),
|
||||
pose=deps.row_value(row, "pose", ("Sexual pose", "Pose")),
|
||||
expression=expression,
|
||||
composition=composition,
|
||||
source_composition=source_composition,
|
||||
camera=deps.camera_phrase(row),
|
||||
camera_scene=deps.camera_scene_phrase(row),
|
||||
style=deps.style_phrase(row, style_mode),
|
||||
)
|
||||
@@ -48,6 +48,7 @@ import krea_configured_cast_formatter # noqa: E402
|
||||
import krea_formatter # noqa: E402
|
||||
import krea_normal_formatter # noqa: E402
|
||||
import krea_pair_formatter # noqa: E402
|
||||
import krea_row_fields # noqa: E402
|
||||
import location_config # noqa: E402
|
||||
import loop_nodes # noqa: E402
|
||||
import pair_builder # noqa: E402
|
||||
@@ -649,6 +650,40 @@ def smoke_krea_normal_row_routes() -> None:
|
||||
_expect_krea_normal_route_parity(generic, "krea_normal_generic", "metadata(generic)")
|
||||
|
||||
|
||||
def smoke_krea_row_fields_policy() -> None:
|
||||
row = {
|
||||
"subject_type": "configured_cast",
|
||||
"primary_subject": "woman",
|
||||
"cast_summary": "1 woman, 1 man",
|
||||
"item": "lace bodysuit fashion editorial styling",
|
||||
"pose": "standing close together",
|
||||
"scene_text": "private room with warm lamps",
|
||||
"expression": "soft smile",
|
||||
"expression_enabled": False,
|
||||
"composition": "vertical tight two-person frame",
|
||||
"source_composition": "vertical source action frame",
|
||||
"camera_directive": "Camera: eye-level close-up",
|
||||
"camera_scene_directive": "Camera-aware scene layout.",
|
||||
"style": "realistic social photo",
|
||||
}
|
||||
fields = krea_row_fields.extract_krea_row_fields(
|
||||
row,
|
||||
"preserve",
|
||||
krea_formatter._krea_row_field_dependencies(),
|
||||
)
|
||||
normal_request = krea_formatter._krea_normal_row_request_from_row(row, "balanced", "preserve")
|
||||
cast_request = krea_formatter._krea_configured_cast_request_from_row(row, "balanced", "preserve")
|
||||
_expect(fields.item == "lace bodysuit", "Krea row fields did not strip generic styling suffix")
|
||||
_expect(fields.expression == "", "Krea row fields ignored expression disabled flag")
|
||||
_expect(fields.composition == "tight two-person frame", "Krea row fields did not normalize composition prefix")
|
||||
_expect(fields.source_composition == "source action frame", "Krea row fields did not normalize source composition")
|
||||
_expect(normal_request.item == fields.item, "Normal Krea route item extraction drifted")
|
||||
_expect(cast_request.item == fields.item, "Configured-cast Krea route item extraction drifted")
|
||||
_expect(normal_request.expression == cast_request.expression == fields.expression, "Krea route expression extraction drifted")
|
||||
_expect(normal_request.camera == cast_request.camera == fields.camera, "Krea route camera extraction drifted")
|
||||
_expect(cast_request.source_composition == fields.source_composition, "Configured-cast source composition drifted")
|
||||
|
||||
|
||||
def smoke_location_config_policy() -> None:
|
||||
_expect(pb.LOCATION_POOL_PRESETS is location_config.LOCATION_POOL_PRESETS, "Prompt builder location presets are not delegated")
|
||||
_expect(pb.COMPOSITION_POOL_PRESETS is location_config.COMPOSITION_POOL_PRESETS, "Prompt builder composition presets are not delegated")
|
||||
@@ -5256,6 +5291,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
||||
("row_camera_policy", smoke_row_camera_policy),
|
||||
("config_route_location_theme", smoke_config_route_location_theme),
|
||||
("krea_normal_row_routes", smoke_krea_normal_row_routes),
|
||||
("krea_row_fields_policy", smoke_krea_row_fields_policy),
|
||||
("location_config_policy", smoke_location_config_policy),
|
||||
("row_location_policy", smoke_row_location_policy),
|
||||
("row_expression_policy", smoke_row_expression_policy),
|
||||
|
||||
Reference in New Issue
Block a user