Route pair metadata structurally

This commit is contained in:
2026-06-27 15:13:31 +02:00
parent 728d3e559c
commit e7bc227c6f
6 changed files with 35 additions and 6 deletions
+3 -1
View File
@@ -5,8 +5,10 @@ from dataclasses import dataclass
from typing import Any, Callable
try:
from . import formatter_input as input_policy
from . import formatter_target as target_policy
except ImportError: # pragma: no cover - plain-script smoke tests
import formatter_input as input_policy
import formatter_target as target_policy
@@ -308,7 +310,7 @@ def insta_of_pair_from_row_result(
keep_style = request.keep_style
pair_target = target_policy.pair_policy(request.target)
target = pair_target.pair_target
if deps.clean_text(row.get("mode")).lower() != "insta/of":
if not input_policy.is_pair_metadata(row):
return None
soft_row = row.get("softcore_row")
hard_row = row.get("hardcore_row")
+7
View File
@@ -698,6 +698,13 @@ Important POV rule:
## Formatter Routes
Formatter metadata input is normalized by `formatter_input.py`. Pair routing is
structural: metadata with both a softcore side and a hardcore side
(`softcore_row`/`hardcore_row` or root soft/hard prompt/caption fields) is
treated as pair metadata even if the UI `mode` label is absent. Krea2, SDXL, and
caption routes share this detection to avoid hidden drift between formatter
paths.
### Krea2
`format_krea2_prompt` chooses between three roads:
+17 -1
View File
@@ -81,11 +81,27 @@ def maybe_json(text: Any) -> dict[str, Any] | None:
def normalize_input_metadata(row: dict[str, Any]) -> dict[str, Any]:
row = dict(row)
trigger = str(row.get("trigger") or "").strip()
if row.get("mode") == "Insta/OF":
if is_pair_metadata(row):
return row_normalization_policy.normalize_pair_metadata(row, active_trigger=trigger)
return row_normalization_policy.sanitize_metadata_row_text(row, active_trigger=trigger)
def is_pair_metadata(row: Any) -> bool:
if not isinstance(row, dict):
return False
soft_side = (
isinstance(row.get("softcore_row"), dict)
or bool(clean_text(row.get("softcore_prompt")))
or bool(clean_text(row.get("softcore_caption")))
)
hard_side = (
isinstance(row.get("hardcore_row"), dict)
or bool(clean_text(row.get("hardcore_prompt")))
or bool(clean_text(row.get("hardcore_caption")))
)
return soft_side and hard_side
def normalize_input_hint(value: Any, *, text_hint: str = INPUT_HINT_PROMPT) -> str:
hint = clean_text(value).lower().replace("-", "_")
hint = _INPUT_HINT_ALIASES.get(hint, hint)
+3 -1
View File
@@ -5,9 +5,11 @@ from typing import Any, Callable
try:
from . import formatter_detail as detail_policy
from . import formatter_input as input_policy
from . import formatter_target as target_policy
except ImportError: # pragma: no cover - plain-script smoke tests
import formatter_detail as detail_policy
import formatter_input as input_policy
import formatter_target as target_policy
@@ -68,7 +70,7 @@ def format_krea2_prompt_result(request: KreaFormatRequest, deps: KreaFormatDepen
target = target_policy.normalize_target(request.target)
row, method = deps.row_from_inputs(request.source_text, request.metadata_json, request.input_hint)
if row and row.get("mode") == "Insta/OF":
if row and input_policy.is_pair_metadata(row):
pair_target = target_policy.pair_policy(target)
soft_prompt, soft_negative, hard_prompt, hard_negative = deps.insta_pair_to_krea(
row,
+3 -1
View File
@@ -4,8 +4,10 @@ from dataclasses import dataclass
from typing import Any, Callable
try:
from . import formatter_input as input_policy
from . import formatter_target as target_policy
except ImportError: # pragma: no cover - plain-script smoke tests
import formatter_input as input_policy
import formatter_target as target_policy
@@ -65,7 +67,7 @@ def format_sdxl_prompt_result(request: SDXLFormatRequest, deps: SDXLFormatDepend
nude_weight = max(0.1, min(3.0, float(request.nude_weight)))
row, method = deps.row_from_inputs(request.source_text, request.metadata_json, request.input_hint)
if row and row.get("mode") == "Insta/OF":
if row and input_policy.is_pair_metadata(row):
pair_target = target_policy.pair_policy(target)
soft_row = row.get("softcore_row") if isinstance(row.get("softcore_row"), dict) else {}
hard_row = row.get("hardcore_row") if isinstance(row.get("hardcore_row"), dict) else {}
+2 -2
View File
@@ -2932,7 +2932,6 @@ def smoke_formatter_input_policy() -> None:
row, method = formatter_input.row_from_inputs(source_json, "", "prompt")
_expect(row is None and method == "text", "Formatter input parser should not parse source JSON in explicit prompt mode")
pair_metadata = {
"mode": "Insta/OF",
"trigger": Trigger,
"softcore_row": {
"prompt": f"{Trigger}, {Trigger}, embedded-only soft.",
@@ -2952,8 +2951,10 @@ def smoke_formatter_input_policy() -> None:
"camera_scene_directive": "Row hard scene camera layout.",
},
}
_expect(formatter_input.is_pair_metadata(pair_metadata), "Formatter input policy should detect structural pair metadata")
parsed_pair, pair_method = formatter_input.row_from_inputs("", _json(pair_metadata), "metadata_json")
_expect(pair_method == "metadata_json", "Formatter input parser should read pair metadata JSON")
_expect(formatter_input.is_pair_metadata(parsed_pair), "Formatter input parser should preserve structural pair metadata")
_expect_trigger_once("formatter_input.pair.soft_prompt", parsed_pair.get("softcore_prompt"), Trigger)
_expect(
parsed_pair.get("softcore_partner_styling") == parsed_pair["softcore_row"].get("softcore_partner_styling"),
@@ -6107,7 +6108,6 @@ def smoke_formatter_metadata_fixtures() -> None:
_expect("sdxl route tag" not in caption_text, "Caption naturalizer leaked SDXL formatter hint")
external_pair = {
"mode": "Insta/OF",
"trigger": Trigger,
"shared_descriptor": "25-year-old adult woman, slim figure, fair skin, blonde hair, blue eyes",
"shared_cast_descriptors": [