Synchronize pair side metadata
This commit is contained in:
@@ -195,7 +195,9 @@ Already isolated:
|
|||||||
- final row and pair text normalization lives in `row_normalization.py`,
|
- final row and pair text normalization lives in `row_normalization.py`,
|
||||||
covering trigger prepending, extra-positive append, negative merge/dedupe,
|
covering trigger prepending, extra-positive append, negative merge/dedupe,
|
||||||
caption-part joining, embedded soft/hard row output synchronization, and row
|
caption-part joining, embedded soft/hard row output synchronization, and row
|
||||||
sanitation before metadata leaves generation.
|
sanitation before metadata leaves generation. It also copies side-specific
|
||||||
|
pair metadata, such as soft partner styling and hardcore clothing/detail
|
||||||
|
state, onto the embedded soft/hard rows.
|
||||||
|
|
||||||
### Pair / Adapter Layer
|
### Pair / Adapter Layer
|
||||||
|
|
||||||
@@ -232,7 +234,9 @@ Already isolated:
|
|||||||
shape; the final cleanup step is delegated to `row_normalization.py`.
|
shape; the final cleanup step is delegated to `row_normalization.py`.
|
||||||
Embedded soft/hard rows are synchronized to the final pair prompt, caption,
|
Embedded soft/hard rows are synchronized to the final pair prompt, caption,
|
||||||
and negative outputs during normalization so serialized pair metadata does
|
and negative outputs during normalization so serialized pair metadata does
|
||||||
not carry stale standalone row text.
|
not carry stale standalone row text. Side-specific structured fields are
|
||||||
|
synchronized there too, including soft partner styling and hardcore clothing
|
||||||
|
continuity metadata.
|
||||||
|
|
||||||
### Krea2 Formatter Path
|
### Krea2 Formatter Path
|
||||||
|
|
||||||
@@ -441,7 +445,7 @@ Medium-term:
|
|||||||
Near-term:
|
Near-term:
|
||||||
|
|
||||||
- Normalize pair metadata with one helper, including embedded row prompt,
|
- Normalize pair metadata with one helper, including embedded row prompt,
|
||||||
caption, and negative synchronization.
|
caption, negative, and side-specific metadata synchronization.
|
||||||
- Confirm pair prompts, captions, and soft/hard rows carry the same sanitized
|
- Confirm pair prompts, captions, and soft/hard rows carry the same sanitized
|
||||||
scene/camera/clothing fields.
|
scene/camera/clothing fields.
|
||||||
- Keep same-room pair continuity synchronized in both assembled prompt text and
|
- Keep same-room pair continuity synchronized in both assembled prompt text and
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Core helper ownership:
|
|||||||
| `scene_camera_adapters.py` | Location-aware camera/scene prose such as coworking lounge camera layout. |
|
| `scene_camera_adapters.py` | Location-aware camera/scene prose such as coworking lounge camera layout. |
|
||||||
| `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. |
|
| `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. |
|
| `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 synchronization, and embedded row sanitation. |
|
| `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. |
|
||||||
| `formatter_input.py` | Shared formatter input parsing: text cleanup, metadata/source JSON detection, trigger-prefix stripping, shared prompt field-label inventory, fallback field-label stripping, `Avoid:` splitting, prompt-field extraction, and metadata row-value fallback. |
|
| `formatter_input.py` | Shared formatter input parsing: text cleanup, metadata/source JSON detection, trigger-prefix stripping, shared prompt field-label inventory, fallback field-label stripping, `Avoid:` splitting, prompt-field extraction, and metadata row-value fallback. |
|
||||||
| `sdxl_presets.py` | SDXL formatter profiles, style presets, quality presets, default negative prompt, and metadata-family tag hints used by the SDXL formatter and node choice lists. |
|
| `sdxl_presets.py` | SDXL formatter profiles, style presets, quality presets, default negative prompt, and metadata-family tag hints used by the SDXL formatter and node choice lists. |
|
||||||
| `caption_policy.py` | Caption naturalizer policy data and helpers: caption profiles, style tails, item labels, metadata-family caption labels, detail/style-policy normalization, clothing cleanup, and composition cleanup. |
|
| `caption_policy.py` | Caption naturalizer policy data and helpers: caption profiles, style tails, item labels, metadata-family caption labels, detail/style-policy normalization, clothing cleanup, and composition cleanup. |
|
||||||
@@ -494,7 +494,7 @@ plain prompt text. When debugging, inspect these fields before editing pools.
|
|||||||
| `options` | `SxCP Insta/OF Options` | Formatters/debug | Soft/hard level, cast mode, continuity, camera modes, expression settings. |
|
| `options` | `SxCP Insta/OF Options` | Formatters/debug | Soft/hard level, cast mode, continuity, camera modes, expression settings. |
|
||||||
| `shared_descriptor` | `pair_cast.py` | Pair formatters | Primary creator descriptor. |
|
| `shared_descriptor` | `pair_cast.py` | Pair formatters | Primary creator descriptor. |
|
||||||
| `shared_cast_descriptors` | `pair_cast.py` | Pair formatters | Full cast descriptor list. |
|
| `shared_cast_descriptors` | `pair_cast.py` | Pair formatters | Full cast descriptor list. |
|
||||||
| `softcore_row`, `hardcore_row` | Pair route | Pair formatters | Full normal metadata rows for each side; their prompt, caption, and negative fields are synchronized to the final pair outputs during pair normalization. |
|
| `softcore_row`, `hardcore_row` | Pair route | Pair formatters | Full normal metadata rows for each side; their prompt, caption, negative, and side-specific metadata fields are synchronized to the final pair outputs/root fields during pair normalization. |
|
||||||
| `softcore_prompt`, `hardcore_prompt` | `pair_output.py` | Direct output/fallback | Raw pair prompts before formatter rewrite. |
|
| `softcore_prompt`, `hardcore_prompt` | `pair_output.py` | Direct output/fallback | Raw pair prompts before formatter rewrite. |
|
||||||
| `softcore_negative_prompt`, `hardcore_negative_prompt` | `pair_output.py` | Formatter negatives | Separate negatives for each side. |
|
| `softcore_negative_prompt`, `hardcore_negative_prompt` | `pair_output.py` | Formatter negatives | Separate negatives for each side. |
|
||||||
| `softcore_partner_styling` | `pair_cast.py` | Krea/SDXL pair branch | Partner softcore clothing and pose when same-cast softcore is enabled. |
|
| `softcore_partner_styling` | `pair_cast.py` | Krea/SDXL pair branch | Partner softcore clothing and pose when same-cast softcore is enabled. |
|
||||||
|
|||||||
@@ -119,10 +119,34 @@ def synchronize_pair_row_outputs(pair: dict[str, Any]) -> dict[str, Any]:
|
|||||||
return pair
|
return pair
|
||||||
|
|
||||||
|
|
||||||
|
def synchronize_pair_side_metadata(pair: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
side_keys = {
|
||||||
|
"softcore_row": (
|
||||||
|
"softcore_partner_styling",
|
||||||
|
),
|
||||||
|
"hardcore_row": (
|
||||||
|
"hardcore_clothing_state",
|
||||||
|
"character_hardcore_clothing",
|
||||||
|
"default_man_hardcore_clothing",
|
||||||
|
"hardcore_detail_density",
|
||||||
|
"hardcore_position_config",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
for row_key, keys in side_keys.items():
|
||||||
|
row = pair.get(row_key)
|
||||||
|
if not isinstance(row, dict):
|
||||||
|
continue
|
||||||
|
for key in keys:
|
||||||
|
if key in pair:
|
||||||
|
row[key] = pair.get(key)
|
||||||
|
return pair
|
||||||
|
|
||||||
|
|
||||||
def normalize_pair_metadata(pair: dict[str, Any], *, active_trigger: str = "") -> dict[str, Any]:
|
def normalize_pair_metadata(pair: dict[str, Any], *, active_trigger: str = "") -> dict[str, Any]:
|
||||||
trigger = str(active_trigger or "").strip()
|
trigger = str(active_trigger or "").strip()
|
||||||
triggers = _trigger_tuple(trigger)
|
triggers = _trigger_tuple(trigger)
|
||||||
synchronize_pair_row_outputs(pair)
|
synchronize_pair_row_outputs(pair)
|
||||||
|
synchronize_pair_side_metadata(pair)
|
||||||
for key in ("softcore_prompt", "hardcore_prompt"):
|
for key in ("softcore_prompt", "hardcore_prompt"):
|
||||||
if key in pair:
|
if key in pair:
|
||||||
pair[key] = sanitize_prompt_text(pair.get(key, ""), triggers=triggers)
|
pair[key] = sanitize_prompt_text(pair.get(key, ""), triggers=triggers)
|
||||||
|
|||||||
@@ -835,6 +835,12 @@ def smoke_row_normalization_policy() -> None:
|
|||||||
"hardcore_caption": f"{Trigger}, {Trigger}, hard caption.",
|
"hardcore_caption": f"{Trigger}, {Trigger}, hard caption.",
|
||||||
"softcore_negative_prompt": "bad anatomy, bad anatomy",
|
"softcore_negative_prompt": "bad anatomy, bad anatomy",
|
||||||
"hardcore_negative_prompt": "bad anatomy, low quality, bad anatomy",
|
"hardcore_negative_prompt": "bad anatomy, low quality, bad anatomy",
|
||||||
|
"softcore_partner_styling": {"outfits": ["partner outfit"], "pose": "partner pose"},
|
||||||
|
"hardcore_clothing_state": "structured hard clothing state",
|
||||||
|
"character_hardcore_clothing": ["Woman A custom hard clothing"],
|
||||||
|
"default_man_hardcore_clothing": ["Man A default hard clothing"],
|
||||||
|
"hardcore_detail_density": "dense",
|
||||||
|
"hardcore_position_config": {"family": "oral"},
|
||||||
"softcore_row": {
|
"softcore_row": {
|
||||||
"prompt": f"{Trigger}, {Trigger}, embedded soft.",
|
"prompt": f"{Trigger}, {Trigger}, embedded soft.",
|
||||||
"caption": f"{Trigger}, {Trigger}, embedded soft caption.",
|
"caption": f"{Trigger}, {Trigger}, embedded soft caption.",
|
||||||
@@ -860,6 +866,18 @@ def smoke_row_normalization_policy() -> None:
|
|||||||
pair["hardcore_row"].get("caption") == pair.get("hardcore_caption"),
|
pair["hardcore_row"].get("caption") == pair.get("hardcore_caption"),
|
||||||
"Pair normalization left stale hard row caption text",
|
"Pair normalization left stale hard row caption text",
|
||||||
)
|
)
|
||||||
|
_expect(
|
||||||
|
pair["softcore_row"].get("softcore_partner_styling") == pair.get("softcore_partner_styling"),
|
||||||
|
"Pair normalization left stale soft side metadata",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
pair["hardcore_row"].get("hardcore_clothing_state") == pair.get("hardcore_clothing_state"),
|
||||||
|
"Pair normalization left stale hard clothing metadata",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
pair["hardcore_row"].get("default_man_hardcore_clothing") == pair.get("default_man_hardcore_clothing"),
|
||||||
|
"Pair normalization left stale hard default clothing metadata",
|
||||||
|
)
|
||||||
_expect_no_duplicate_comma_items("row_normalization.pair.soft_negative", pair.get("softcore_negative_prompt"))
|
_expect_no_duplicate_comma_items("row_normalization.pair.soft_negative", pair.get("softcore_negative_prompt"))
|
||||||
_expect_no_duplicate_comma_items("row_normalization.pair.hard_row_negative", pair["hardcore_row"].get("negative_prompt"))
|
_expect_no_duplicate_comma_items("row_normalization.pair.hard_row_negative", pair["hardcore_row"].get("negative_prompt"))
|
||||||
|
|
||||||
@@ -1511,6 +1529,20 @@ def _expect_pair(pair: dict[str, Any], name: str) -> None:
|
|||||||
pair["hardcore_row"].get("negative_prompt") == pair.get("hardcore_negative_prompt"),
|
pair["hardcore_row"].get("negative_prompt") == pair.get("hardcore_negative_prompt"),
|
||||||
f"{name}.hardcore_row negative drifted from pair negative",
|
f"{name}.hardcore_row negative drifted from pair negative",
|
||||||
)
|
)
|
||||||
|
if "softcore_partner_styling" in pair:
|
||||||
|
_expect(
|
||||||
|
pair["softcore_row"].get("softcore_partner_styling") == pair.get("softcore_partner_styling"),
|
||||||
|
f"{name}.softcore_row partner styling drifted from pair root",
|
||||||
|
)
|
||||||
|
for key in (
|
||||||
|
"hardcore_clothing_state",
|
||||||
|
"character_hardcore_clothing",
|
||||||
|
"default_man_hardcore_clothing",
|
||||||
|
"hardcore_detail_density",
|
||||||
|
"hardcore_position_config",
|
||||||
|
):
|
||||||
|
if key in pair:
|
||||||
|
_expect(pair["hardcore_row"].get(key) == pair.get(key), f"{name}.hardcore_row {key} drifted from pair root")
|
||||||
_expect_no_duplicate_comma_items(f"{name}.softcore_negative", pair.get("softcore_negative_prompt"))
|
_expect_no_duplicate_comma_items(f"{name}.softcore_negative", pair.get("softcore_negative_prompt"))
|
||||||
_expect_no_duplicate_comma_items(f"{name}.hardcore_negative", pair.get("hardcore_negative_prompt"))
|
_expect_no_duplicate_comma_items(f"{name}.hardcore_negative", pair.get("hardcore_negative_prompt"))
|
||||||
_expect_formatter_outputs(pair, name, target="softcore")
|
_expect_formatter_outputs(pair, name, target="softcore")
|
||||||
|
|||||||
Reference in New Issue
Block a user