diff --git a/sdxl_tag_policy.py b/sdxl_tag_policy.py index 3d68bd1..7bcf4e4 100644 --- a/sdxl_tag_policy.py +++ b/sdxl_tag_policy.py @@ -56,6 +56,7 @@ def split_tag_text(text: Any) -> list[str]: text = re.sub(r"\bMan [A-Z]'s\b", "man's", text) text = re.sub(r"\bWoman [A-Z]\b", "woman", text) text = re.sub(r"\bMan [A-Z]\b", "man", text) + text = re.sub(r"\b(?:the\s+)?(?:woman|man)\s+has\s+", "", text, flags=re.IGNORECASE) text = re.sub( r"\b(?:Clothing state|Visual clothing state|visible remaining styling|teaser outfit detail|softcore visual reference|Sexual scene|Role graph):\s*", "", diff --git a/tools/prompt_route_simulation.py b/tools/prompt_route_simulation.py index 9b1d984..3fa7131 100644 --- a/tools/prompt_route_simulation.py +++ b/tools/prompt_route_simulation.py @@ -576,6 +576,12 @@ def _sdxl_composition_tag_issues(name: str, sdxl_prompt: str) -> list[str]: return [] +def _sdxl_expression_label_issues(name: str, sdxl_prompt: str) -> list[str]: + if re.search(r"\b(?:woman|man)\s+has\s+", sdxl_prompt, flags=re.IGNORECASE): + return [f"{name}.sdxl_prompt: character_has_expression_label"] + return [] + + def _trace_dict(formatter_name: str, payload: dict[str, Any]) -> tuple[dict[str, Any], str]: trace_text = str(payload.get("route_trace_json") or "") if not trace_text: @@ -713,6 +719,7 @@ def _formatter_issues( issues.extend(_krea_grammar_issues(name, krea_prompt)) issues.extend(_composition_label_issues(name, prompts)) issues.extend(_sdxl_composition_tag_issues(name, sdxl_prompt)) + issues.extend(_sdxl_expression_label_issues(name, sdxl_prompt)) for label, value in ( (f"{name}.krea_negative", krea.get("negative_prompt")), diff --git a/tools/prompt_smoke.py b/tools/prompt_smoke.py index 1e813f6..bd39a4d 100644 --- a/tools/prompt_smoke.py +++ b/tools/prompt_smoke.py @@ -4815,6 +4815,18 @@ def smoke_sdxl_tag_routes() -> None: ).as_text() _expect("tall-window depth behind them composition" not in composition_label_tags, "SDXL route kept raw composition label tag") _expect("tall-window depth behind them" in composition_label_tags, "SDXL route lost composition detail while removing label") + expression_label_row = _fixture_hardcore_row( + character_expression_text="Woman A has focused gaze; Man A has steady expression", + expression="stale expression", + ) + expression_label_tags = sdxl_tag_routes.row_core_tags_result( + sdxl_tag_routes.SDXLRowTagRequest(expression_label_row, 1.29), + deps, + ).as_text() + _expect("woman has" not in expression_label_tags.lower(), "SDXL route kept woman-has expression label") + _expect("man has" not in expression_label_tags.lower(), "SDXL route kept man-has expression label") + _expect("focused gaze" in expression_label_tags, "SDXL route lost cleaned woman expression") + _expect("steady expression" in expression_label_tags, "SDXL route lost cleaned man expression") stale_prompt_row = _fixture_hardcore_row( prompt="stale raw prompt mentions fully nude naked pussy penis oral anal semen penetration", item="standing portrait setup",