Use item axis values in SDXL tags
This commit is contained in:
@@ -140,7 +140,7 @@ Core helper ownership:
|
|||||||
| `server_routes.py` | Pure payload handlers for profile-save and accumulator server endpoints, used by ComfyUI routes and smoke tests without importing ComfyUI. |
|
| `server_routes.py` | Pure payload handlers for profile-save and accumulator server endpoints, used by ComfyUI routes and smoke tests without importing ComfyUI. |
|
||||||
| `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. |
|
||||||
| `sdxl_format_route.py` | Top-level SDXL dispatch, formatter profile application, target and nude-weight normalization, metadata-vs-text input selection, single-vs-pair branching, final prompt/negative output shape, and fallback routing. |
|
| `sdxl_format_route.py` | Top-level SDXL dispatch, formatter profile application, target and nude-weight normalization, metadata-vs-text input selection, single-vs-pair branching, final prompt/negative output shape, and fallback routing. |
|
||||||
| `sdxl_tag_policy.py` | SDXL tag splitting, tag-key dedupe, count inference, character descriptor tags, metadata-family/camera/explicit helper tags, and route dependency assembly used by `sdxl_formatter.py` and `sdxl_tag_routes.py`. |
|
| `sdxl_tag_policy.py` | SDXL tag splitting, tag-key dedupe, count inference, character descriptor tags, item-axis tags, metadata-family/camera/explicit helper tags, and route dependency assembly used by `sdxl_formatter.py` and `sdxl_tag_routes.py`. |
|
||||||
| `caption_format_route.py` | Top-level caption dispatch, input-hint and target normalization, caption profile application, metadata-vs-text branching, trigger wrapping, final prose hygiene, and method/output shape. |
|
| `caption_format_route.py` | Top-level caption dispatch, input-hint and target normalization, caption profile application, metadata-vs-text branching, trigger wrapping, final prose hygiene, and method/output shape. |
|
||||||
| `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. |
|
||||||
| `caption_text_policy.py` | Caption sentence helpers, trigger wrapping, formatter-hint append, row-value fallback wrappers, cast text wrappers, single-caption front parsing, and metadata-route dependency assembly used by `caption_naturalizer.py` and `caption_metadata_routes.py`. |
|
| `caption_text_policy.py` | Caption sentence helpers, trigger wrapping, formatter-hint append, row-value fallback wrappers, cast text wrappers, single-caption front parsing, and metadata-route dependency assembly used by `caption_naturalizer.py` and `caption_metadata_routes.py`. |
|
||||||
@@ -814,7 +814,7 @@ SDXL field consumption:
|
|||||||
|
|
||||||
| Branch | Reads most from | Key functions |
|
| Branch | Reads most from | Key functions |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Normal metadata | `cast_descriptor_text` or structured age/body/skin/hair/eyes, `action_family`, `position_family`, `position_keys`, item, role graph, clothing/body exposure state, scene, camera config/directive | `sdxl_tag_routes.row_core_tags_result`, `sdxl_tag_policy.normal_character_tags`, `sdxl_tag_policy.metadata_family_tags`, `sdxl_tag_policy.camera_tags` |
|
| Normal metadata | `cast_descriptor_text` or structured age/body/skin/hair/eyes, `action_family`, `position_family`, `position_keys`, `item_axis_values`, item, role graph, clothing/body exposure state, scene, camera config/directive | `sdxl_tag_routes.row_core_tags_result`, `sdxl_tag_policy.normal_character_tags`, `sdxl_tag_policy.metadata_family_tags`, `sdxl_tag_policy.axis_value_tags`, `sdxl_tag_policy.camera_tags` |
|
||||||
| Pair softcore | `softcore_row`, pair partner styling, root soft camera config | `sdxl_tag_routes.soft_tags_result` |
|
| Pair softcore | `softcore_row`, pair partner styling, root soft camera config | `sdxl_tag_routes.soft_tags_result` |
|
||||||
| Pair hardcore | `hardcore_row`, `action_family`, `position_family`, `position_keys`, role graph, item, `hardcore_clothing_state`, expression/composition, hard camera fields | `sdxl_tag_routes.hard_tags_result`, `sdxl_tag_policy.metadata_family_tags` |
|
| Pair hardcore | `hardcore_row`, `action_family`, `position_family`, `position_keys`, role graph, item, `hardcore_clothing_state`, expression/composition, hard camera fields | `sdxl_tag_routes.hard_tags_result`, `sdxl_tag_policy.metadata_family_tags` |
|
||||||
| Text fallback | `source_text`, preserve-trigger setting, shared field-label stripping, prompt labels such as `Characters:` | `_fallback_text_to_sdxl` |
|
| Text fallback | `source_text`, preserve-trigger setting, shared field-label stripping, prompt labels such as `Characters:` | `_fallback_text_to_sdxl` |
|
||||||
|
|||||||
@@ -102,6 +102,43 @@ def formatter_hint_tags(*rows: dict[str, Any]) -> list[str]:
|
|||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
|
||||||
|
def _axis_value_texts(value: Any) -> list[str]:
|
||||||
|
if isinstance(value, str):
|
||||||
|
text = clean(value)
|
||||||
|
return [text] if text and text.lower() not in ("any", "auto", "random", "none") else []
|
||||||
|
if isinstance(value, (int, float, bool)) or value is None:
|
||||||
|
return []
|
||||||
|
if isinstance(value, list):
|
||||||
|
texts: list[str] = []
|
||||||
|
for item in value:
|
||||||
|
texts.extend(_axis_value_texts(item))
|
||||||
|
return texts
|
||||||
|
if isinstance(value, dict):
|
||||||
|
for preferred in ("text", "prompt", "template", "value", "name"):
|
||||||
|
preferred_texts = _axis_value_texts(value.get(preferred))
|
||||||
|
if preferred_texts:
|
||||||
|
return preferred_texts
|
||||||
|
texts: list[str] = []
|
||||||
|
for item in value.values():
|
||||||
|
texts.extend(_axis_value_texts(item))
|
||||||
|
return texts
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def axis_value_tags(row: dict[str, Any]) -> list[str]:
|
||||||
|
if not isinstance(row, dict):
|
||||||
|
return []
|
||||||
|
axis_values = row.get("item_axis_values")
|
||||||
|
if not isinstance(axis_values, dict):
|
||||||
|
return []
|
||||||
|
tags: list[str] = []
|
||||||
|
seen: set[str] = set()
|
||||||
|
for value in axis_values.values():
|
||||||
|
for text in _axis_value_texts(value):
|
||||||
|
add(tags, seen, text)
|
||||||
|
return tags
|
||||||
|
|
||||||
|
|
||||||
def combine_tags(*parts: Any) -> str:
|
def combine_tags(*parts: Any) -> str:
|
||||||
tags: list[str] = []
|
tags: list[str] = []
|
||||||
seen: set[str] = set()
|
seen: set[str] = set()
|
||||||
@@ -261,6 +298,7 @@ def tag_route_dependencies() -> sdxl_tag_routes.SDXLTagRouteDependencies:
|
|||||||
character_tags_from_descriptor=character_tags_from_descriptor,
|
character_tags_from_descriptor=character_tags_from_descriptor,
|
||||||
metadata_family_tags=metadata_family_tags,
|
metadata_family_tags=metadata_family_tags,
|
||||||
formatter_hint_tags=formatter_hint_tags,
|
formatter_hint_tags=formatter_hint_tags,
|
||||||
|
axis_value_tags=axis_value_tags,
|
||||||
camera_tags=camera_tags,
|
camera_tags=camera_tags,
|
||||||
explicit_tags=explicit_tags,
|
explicit_tags=explicit_tags,
|
||||||
softcore_pair_tags=softcore_pair_tags,
|
softcore_pair_tags=softcore_pair_tags,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class SDXLTagRouteDependencies:
|
|||||||
character_tags_from_descriptor: Callable[[Any], list[str]]
|
character_tags_from_descriptor: Callable[[Any], list[str]]
|
||||||
metadata_family_tags: Callable[[dict[str, Any]], list[str]]
|
metadata_family_tags: Callable[[dict[str, Any]], list[str]]
|
||||||
formatter_hint_tags: Callable[..., list[str]]
|
formatter_hint_tags: Callable[..., list[str]]
|
||||||
|
axis_value_tags: Callable[[dict[str, Any]], list[str]]
|
||||||
camera_tags: Callable[..., list[str]]
|
camera_tags: Callable[..., list[str]]
|
||||||
explicit_tags: Callable[[str, float], list[str]]
|
explicit_tags: Callable[[str, float], list[str]]
|
||||||
softcore_pair_tags: Callable[[dict[str, Any], dict[str, Any]], list[str]]
|
softcore_pair_tags: Callable[[dict[str, Any], dict[str, Any]], list[str]]
|
||||||
@@ -109,6 +110,8 @@ def row_core_tags_result(request: SDXLRowTagRequest, deps: SDXLTagRouteDependenc
|
|||||||
deps.add_one(tags, seen, tag)
|
deps.add_one(tags, seen, tag)
|
||||||
for tag in deps.formatter_hint_tags(row):
|
for tag in deps.formatter_hint_tags(row):
|
||||||
deps.add(tags, seen, tag)
|
deps.add(tags, seen, tag)
|
||||||
|
for tag in deps.axis_value_tags(row):
|
||||||
|
deps.add(tags, seen, tag)
|
||||||
|
|
||||||
item = deps.row_value(row, "item", ("Sexual scene", "Sexual pose", "Erotic outfit", "Clothing")) or deps.clean(
|
item = deps.row_value(row, "item", ("Sexual scene", "Sexual pose", "Erotic outfit", "Clothing")) or deps.clean(
|
||||||
row.get("custom_item")
|
row.get("custom_item")
|
||||||
@@ -205,6 +208,8 @@ def hard_tags_result(request: SDXLPairTagRequest, deps: SDXLTagRouteDependencies
|
|||||||
deps.add_one(tags, seen, tag)
|
deps.add_one(tags, seen, tag)
|
||||||
for tag in deps.formatter_hint_tags(row, root):
|
for tag in deps.formatter_hint_tags(row, root):
|
||||||
deps.add(tags, seen, tag)
|
deps.add(tags, seen, tag)
|
||||||
|
for tag in deps.axis_value_tags(row):
|
||||||
|
deps.add(tags, seen, tag)
|
||||||
|
|
||||||
hard_scene = deps.clean(row.get("scene_text"))
|
hard_scene = deps.clean(row.get("scene_text"))
|
||||||
hard_item = deps.clean(row.get("item"))
|
hard_item = deps.clean(row.get("item"))
|
||||||
|
|||||||
@@ -4485,6 +4485,18 @@ def smoke_sdxl_tag_policy() -> None:
|
|||||||
sdxl_formatter._metadata_family_tags(row) == sdxl_tag_policy.metadata_family_tags(row),
|
sdxl_formatter._metadata_family_tags(row) == sdxl_tag_policy.metadata_family_tags(row),
|
||||||
"SDXL formatter metadata-family helper should delegate to sdxl_tag_policy",
|
"SDXL formatter metadata-family helper should delegate to sdxl_tag_policy",
|
||||||
)
|
)
|
||||||
|
axis_row = {
|
||||||
|
"item_axis_values": {
|
||||||
|
"position": "edge-supported kneeling pose",
|
||||||
|
"contact_detail": "hands braced on thighs, close body alignment",
|
||||||
|
"ignored": "random",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
axis_tags = sdxl_tag_policy.axis_value_tags(axis_row)
|
||||||
|
_expect("edge-supported kneeling pose" in axis_tags, "SDXL axis tags lost selected position axis")
|
||||||
|
_expect("hands braced on thighs" in axis_tags, "SDXL axis tags lost selected detail axis")
|
||||||
|
_expect("close body alignment" in axis_tags, "SDXL axis tags lost split detail axis")
|
||||||
|
_expect("random" not in axis_tags, "SDXL axis tags should ignore random placeholders")
|
||||||
_expect(
|
_expect(
|
||||||
sdxl_formatter._camera_tags(row) == sdxl_tag_policy.camera_tags(row),
|
sdxl_formatter._camera_tags(row) == sdxl_tag_policy.camera_tags(row),
|
||||||
"SDXL formatter camera helper should delegate to sdxl_tag_policy",
|
"SDXL formatter camera helper should delegate to sdxl_tag_policy",
|
||||||
@@ -4499,6 +4511,7 @@ def smoke_sdxl_tag_policy() -> None:
|
|||||||
_expect(deps.tag_key is sdxl_tag_policy.tag_key, "SDXL route deps lost policy tag_key")
|
_expect(deps.tag_key is sdxl_tag_policy.tag_key, "SDXL route deps lost policy tag_key")
|
||||||
_expect(deps.normal_character_tags is sdxl_tag_policy.normal_character_tags, "SDXL route deps lost character tag policy")
|
_expect(deps.normal_character_tags is sdxl_tag_policy.normal_character_tags, "SDXL route deps lost character tag policy")
|
||||||
_expect(deps.metadata_family_tags is sdxl_tag_policy.metadata_family_tags, "SDXL route deps lost metadata family policy")
|
_expect(deps.metadata_family_tags is sdxl_tag_policy.metadata_family_tags, "SDXL route deps lost metadata family policy")
|
||||||
|
_expect(deps.axis_value_tags is sdxl_tag_policy.axis_value_tags, "SDXL route deps lost axis-value tag policy")
|
||||||
_expect(deps.camera_tags is sdxl_tag_policy.camera_tags, "SDXL route deps lost camera tag policy")
|
_expect(deps.camera_tags is sdxl_tag_policy.camera_tags, "SDXL route deps lost camera tag policy")
|
||||||
_expect(deps.explicit_tags is sdxl_tag_policy.explicit_tags, "SDXL route deps lost explicit tag policy")
|
_expect(deps.explicit_tags is sdxl_tag_policy.explicit_tags, "SDXL route deps lost explicit tag policy")
|
||||||
_expect(deps.softcore_pair_tags is sdxl_tag_policy.softcore_pair_tags, "SDXL route deps lost softcore pair tag policy")
|
_expect(deps.softcore_pair_tags is sdxl_tag_policy.softcore_pair_tags, "SDXL route deps lost softcore pair tag policy")
|
||||||
@@ -4547,6 +4560,27 @@ def smoke_sdxl_tag_routes() -> None:
|
|||||||
"Typed SDXL row tag route should match legacy wrapper output",
|
"Typed SDXL row tag route should match legacy wrapper output",
|
||||||
)
|
)
|
||||||
_expect("sdxl route tag" in typed_row.as_text(), "Typed SDXL row tag route lost route-specific formatter hint")
|
_expect("sdxl route tag" in typed_row.as_text(), "Typed SDXL row tag route lost route-specific formatter hint")
|
||||||
|
axis_only_row = _fixture_hardcore_row(
|
||||||
|
item="generic configured adult action",
|
||||||
|
pose="configured explicit pose",
|
||||||
|
role_graph="",
|
||||||
|
source_role_graph="",
|
||||||
|
item_axis_values={
|
||||||
|
"position": "standing oral position",
|
||||||
|
"contact_detail": "mouth contact at hip height, hands on hips",
|
||||||
|
},
|
||||||
|
action_family="oral",
|
||||||
|
position_family="oral",
|
||||||
|
position_key="standing",
|
||||||
|
position_keys=["standing"],
|
||||||
|
)
|
||||||
|
axis_only_tags = sdxl_tag_routes.row_core_tags_result(
|
||||||
|
sdxl_tag_routes.SDXLRowTagRequest(axis_only_row, 1.29),
|
||||||
|
deps,
|
||||||
|
).as_text()
|
||||||
|
_expect("standing oral position" in axis_only_tags, "SDXL row route lost item axis position tag")
|
||||||
|
_expect("mouth contact at hip height" in axis_only_tags, "SDXL row route lost item axis contact tag")
|
||||||
|
_expect("hands on hips" in axis_only_tags, "SDXL row route lost split item axis detail tag")
|
||||||
stale_character_route_row = _fixture_hardcore_row(
|
stale_character_route_row = _fixture_hardcore_row(
|
||||||
prompt="Characters: stale prompt subject, stale body, stale skin, stale hair, stale eyes.",
|
prompt="Characters: stale prompt subject, stale body, stale skin, stale hair, stale eyes.",
|
||||||
cast_descriptor_text="",
|
cast_descriptor_text="",
|
||||||
@@ -4688,6 +4722,12 @@ def smoke_sdxl_tag_routes() -> None:
|
|||||||
).as_text()
|
).as_text()
|
||||||
for required in ("(naked:1.29)", "pussy", "penis", "penetration"):
|
for required in ("(naked:1.29)", "pussy", "penis", "penetration"):
|
||||||
_expect(required in pair_metadata_tags, f"SDXL pair tags lost structured explicit metadata tag: {required}")
|
_expect(required in pair_metadata_tags, f"SDXL pair tags lost structured explicit metadata tag: {required}")
|
||||||
|
pair_axis_tags = sdxl_tag_routes.hard_tags_result(
|
||||||
|
sdxl_tag_routes.SDXLPairTagRequest(axis_only_row, pair_metadata_root, 1.29),
|
||||||
|
deps,
|
||||||
|
).as_text()
|
||||||
|
_expect("standing oral position" in pair_axis_tags, "SDXL pair hard route lost item axis position tag")
|
||||||
|
_expect("mouth contact at hip height" in pair_axis_tags, "SDXL pair hard route lost item axis contact tag")
|
||||||
formatted = sdxl_formatter.format_sdxl_prompt(
|
formatted = sdxl_formatter.format_sdxl_prompt(
|
||||||
"",
|
"",
|
||||||
metadata_json=_json(pair),
|
metadata_json=_json(pair),
|
||||||
|
|||||||
Reference in New Issue
Block a user