Whyx-PROmpTea / src /synonym_filter.py
ArtShumov's picture
feat(prod): rewrite pipeline + NoobAI + ensemble tagger (3xWD14+DeepDanbooru-ready) + 1000 artists + negative templates + history ext + scoring config
e6404d0
Raw
History Blame
2.67 kB
from copy import deepcopy
from src.prompt_parser import ParsedPrompt
from src.tag_warehouse import TagWarehouse
from src.synonym_data import _load_groups, _find_synonym_group
def get_synonym_conflicts(tag: str, other_tags: list[str]) -> list[str]:
if not other_tags:
return []
tag_group = _find_synonym_group(tag)
if tag_group is None:
return []
other_lower = {o.lower().strip() for o in other_tags}
return [o for o in other_tags if o.lower().strip() in tag_group and o.lower().strip() != tag.lower().strip()]
def has_synonym_conflict(tag: str, existing: list[str]) -> bool:
group = _find_synonym_group(tag)
if group is None:
return False
tag_lower = tag.lower().strip()
existing_lower = {e.lower().strip() for e in existing}
for member in group:
if member != tag_lower and member in existing_lower:
return True
return False
def filter_synonym_duplicates(tags: list[str]) -> list[str]:
if not tags:
return []
result = []
for t in tags:
if not has_synonym_conflict(t, result):
result.append(t)
return result
def filter_user_against_category_tags(
user_tags: list[str],
category_tags: list[str],
) -> list[str]:
"""Preserve the user's explicit tags.
Previously this stripped any user tag that shared a synonym group with the
selected category pools, which silently erased the user's stated intent
(e.g. "blue hair" vanished because "blue hair" also lives in the hair pool).
Generation now keeps the user's tags and only drops internal synonym
duplicates, relying on the engine's protected-set / head-noun guard to avoid
re-adding redundant tags.
"""
if not user_tags:
return []
return filter_synonym_duplicates(user_tags)
def apply_synonym_filter(
parsed: ParsedPrompt,
selected_categories: list[str],
warehouse: TagWarehouse,
model: str = "anima",
rating: str = "pg",
) -> ParsedPrompt:
"""Drop internal synonym duplicates from the user's own tags.
Category pool membership is intentionally NOT consulted here: the previous
behavior of stripping user tags that collide with a pool erased explicit
user intent. `warehouse`/`rating` stay in the signature for API compat.
"""
if parsed is None:
return parsed
result = deepcopy(parsed)
if result.general_tags is None:
result.general_tags = []
result.general_tags = filter_synonym_duplicates(result.general_tags)
return result
def reload_groups():
from src.synonym_data import reload_synonym_groups
reload_synonym_groups()
_load_groups()