Sort tags

This commit is contained in:
rainlizard
2026-06-07 06:19:56 +10:00
parent f5f671ec40
commit 3d42e6646a
3 changed files with 190 additions and 2 deletions
+38
View File
@@ -0,0 +1,38 @@
.gitattributes
.github/workflows/publish.yml
.gitignore
Raffle Example.json
__init__.py
curved_rescale_cfg.py
dev/categorizer/Cursor Composer Prompt.txt
dev/categorizer/extract_categories.bat
dev/categorizer/extract_categories.py
dev/categorizer/manual_categorization (outdated).txt
dev/categorizer/split_n_combine/split_and_combine_script.py
dev/check-missing-tags.py
dev/copy-categories-over.py
dev/find_tags.py
dev/remove-numbers-at-end-of-each-line.py
dev/swap-in-new-categories.py
dev/tag-scraper/tag-scraper.py
dev/tag-scraper/tag_lists/all_tags.txt
dev/tag-scraper/tag_lists/artist.txt
dev/tag-scraper/tag_lists/categorize_files.py
dev/tag-scraper/tag_lists/character.txt
dev/tag-scraper/tag_lists/copyright.txt
dev/tag-scraper/tag_lists/general.txt
dev/tag-scraper/tag_lists/meta.txt
dev/taglist-scraper/danbooru-taglist-scraper.bat
dev/taglist-scraper/danbooru-taglist-scraper.py
dev/taglist-scraper/rearranger.py
lists/!notes.txt
lists/categorized_tags.txt
lists/taglists-explicit.txt
lists/taglists-general.txt
lists/taglists-questionable.txt
lists/taglists-sensitive.txt
preview_history.py
pyproject.toml
raffle.py
readme.md
tag_category_strength.py
+6 -2
View File
@@ -2,22 +2,26 @@ from . import raffle
from . import preview_history # Import the renamed module
from . import tag_category_strength # Import the new module
from . import curved_rescale_cfg # Import the curved rescale cfg module
from . import sort_tags_by_popularity # Import the sort tags by popularity module
from .raffle import Raffle
from .preview_history import PreviewHistory # Import the renamed class
from .tag_category_strength import TagCategoryStrength # Import the new class
from .curved_rescale_cfg import CurvedRescaleCFG # Import the curved rescale cfg class
from .sort_tags_by_popularity import SortTagsByPopularity # Import the sort tags by popularity class
NODE_CLASS_MAPPINGS = {
"Raffle": Raffle,
"PreviewHistory": PreviewHistory, # Add the renamed mapping
"TagCategoryStrength": TagCategoryStrength, # Add the new mapping
"CurvedRescaleCFG": CurvedRescaleCFG # Add the curved rescale cfg mapping
"CurvedRescaleCFG": CurvedRescaleCFG, # Add the curved rescale cfg mapping
"SortTagsByPopularity": SortTagsByPopularity # Add the sort tags by popularity mapping
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Raffle": "Raffle",
"PreviewHistory": "Preview History (Raffle)", # Add the renamed display name
"TagCategoryStrength": "Tag Category Strength (Raffle)", # Add the new display name
"CurvedRescaleCFG": "Curved Rescale CFG (Raffle)" # Add the curved rescale cfg display name
"CurvedRescaleCFG": "Curved Rescale CFG (Raffle)", # Add the curved rescale cfg display name
"SortTagsByPopularity": "Sort Tags By Popularity (Raffle)" # Add the sort tags by popularity display name
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
+146
View File
@@ -0,0 +1,146 @@
import os
import re
class SortTagsByPopularity:
_allowed_tags_cache = None
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input_tags": ("STRING", {
"multiline": True,
"forceInput": True,
"default": "",
"tooltip": "Input tags to sort by Raffle's categorized tag order (comma-separated)"
}),
},
"optional": {
"remove_duplicates": ("BOOLEAN", {
"default": False,
"tooltip": "Remove duplicate tags while sorting"
}),
}
}
CATEGORY = "Raffle"
RETURN_TYPES = ("STRING", "STRING")
RETURN_NAMES = ("sorted_tags", "unsorted_tags")
OUTPUT_TOOLTIPS = (
"Tags found in categorized_tags.txt, sorted by Raffle's categorized tag order",
"Tags not found in categorized_tags.txt, preserved separately"
)
FUNCTION = "sort_tags"
def _load_allowed_tags(self):
if SortTagsByPopularity._allowed_tags_cache is not None:
return SortTagsByPopularity._allowed_tags_cache
extension_path = os.path.normpath(os.path.dirname(__file__))
categorized_tags_file_path = os.path.join(extension_path, "lists", "categorized_tags.txt")
if not os.path.exists(categorized_tags_file_path):
raise ValueError(f"Categorized tags file not found at {categorized_tags_file_path}")
allowed_tags = []
try:
with open(categorized_tags_file_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split('] ', 1)
if len(parts) != 2:
continue
allowed_tags.append(parts[1])
except Exception as e:
raise ValueError(f"Error reading categorized tags file: {str(e)}")
SortTagsByPopularity._allowed_tags_cache = allowed_tags
return allowed_tags
def _normalize_tags(self, tag_string):
tag_string = tag_string.replace('\r\n', '\n')
tag_string = tag_string.replace('\n', ',')
while ' ' in tag_string:
tag_string = tag_string.replace(' ', ' ')
while ',,' in tag_string:
tag_string = tag_string.replace(',,', ',')
tags = tag_string.replace(', ', ',').split(',')
return [
tag.strip()
for tag in tags
if tag.strip()
]
def _canonicalize_tag_name(self, tag_name):
return tag_name.strip().replace(' ', '_')
def _extract_tag_name(self, tag):
weight_pattern = r'^\(([^:]+):([^)]+)\)$'
match = re.match(weight_pattern, tag)
if match:
return match.group(1).strip()
return tag
def _deduplicate_tags(self, tags):
seen = set()
deduplicated_tags = []
for tag in tags:
tag_name = self._canonicalize_tag_name(self._extract_tag_name(tag))
if tag_name in seen:
continue
seen.add(tag_name)
deduplicated_tags.append(tag)
return deduplicated_tags
def sort_tags(self, input_tags, remove_duplicates=False):
input_str = input_tags if isinstance(input_tags, str) else ""
lora_pattern = r'<lora:[^>]+>'
lora_tags = re.findall(lora_pattern, input_str)
input_without_lora = re.sub(lora_pattern, '', input_str)
regular_tags = self._normalize_tags(input_without_lora)
if remove_duplicates:
regular_tags = self._deduplicate_tags(regular_tags)
lora_tags = self._deduplicate_tags(lora_tags)
allowed_tags = self._load_allowed_tags()
allowed_tag_indexes = {
self._canonicalize_tag_name(tag): index
for index, tag in enumerate(allowed_tags)
}
sorted_tags = [
tag for tag in regular_tags
if self._canonicalize_tag_name(self._extract_tag_name(tag)) in allowed_tag_indexes
]
sorted_tags.sort(
key=lambda tag: allowed_tag_indexes[
self._canonicalize_tag_name(self._extract_tag_name(tag))
]
)
unsorted_tags = [
tag for tag in regular_tags
if self._canonicalize_tag_name(self._extract_tag_name(tag)) not in allowed_tag_indexes
]
unsorted_tags.extend(lora_tags)
if not sorted_tags and not unsorted_tags:
return "", ""
return ", ".join(sorted_tags), ", ".join(unsorted_tags)