feat(tagging): skipped tags hide matching suggestions (#431)

A Skipped tags list in System > Auto-tagging (D202) hides every suggested
tag whose words contain an entry's words, on every suggestion path
(Tag image, Auto-tag selected, the System batch, the legacy single and
batch routes), before the limit. Jobs snapshot the list at their start.
A read-only preview route counts what a list hides among the library's
tags and the downloaded WD14 label lists. The draft store compares list
and object drafts by value (sameDraft).
This commit is contained in:
Vito Sansevero
2026-10-31 16:43:15 -07:00
parent c3c75c3369
commit a20e59f674
32 changed files with 1837 additions and 58 deletions
+21 -5
View File
@@ -587,6 +587,7 @@ try:
MODEL_TYPES,
WD14_MODEL_TYPES,
validate_saved_threshold,
validate_skipped_tags,
validate_template,
validate_threshold,
)
@@ -600,6 +601,7 @@ except ImportError:
MODEL_TYPES,
WD14_MODEL_TYPES,
validate_saved_threshold,
validate_skipped_tags,
validate_template,
validate_threshold,
)
@@ -617,6 +619,20 @@ def _valid_existing(value: Any) -> str:
return value
def _valid_skipped_tags(value: Any) -> Tuple[str, ...]:
return tuple(validate_skipped_tags(value))
def _fallback_warning(key: str, error: ValueError, default: Any) -> str:
"""The one load warning of a saved tagging default that fails its check."""
if key == "template":
return f"autotag.defaults.template {error}; using the built-in one"
if key == "skipped_tags":
reason = str(error).removeprefix("Skipped tags").lstrip(": ").rstrip(".")
return f"autotag.defaults.skipped_tags {reason}; using no skipped tags"
return f"autotag.defaults.{key} {error}; using {default!r}"
def _valid_suggestion_limit(value: Any) -> int:
if type(value) is not int or not 1 <= value <= MAX_SUGGESTION_LIMIT:
raise ValueError(f"must be an integer from 1 to {MAX_SUGGESTION_LIMIT}")
@@ -639,6 +655,7 @@ class AutotagConfig:
CHARACTER_THRESHOLD = 0.85
TEMPLATE = DEFAULT_TAG_TEMPLATE
SUGGESTION_LIMIT = DEFAULT_SUGGESTION_LIMIT
SKIPPED_TAGS: Tuple[str, ...] = ()
# config.json key -> (attribute, validator, default)
_KEYS = {
@@ -660,6 +677,8 @@ class AutotagConfig:
_valid_suggestion_limit,
DEFAULT_SUGGESTION_LIMIT,
),
# #431: words whose suggested tags are never offered.
"skipped_tags": ("SKIPPED_TAGS", _valid_skipped_tags, ()),
}
@classmethod
@@ -681,6 +700,7 @@ class AutotagConfig:
}
if defaults["template"] == DEFAULT_TAG_TEMPLATE:
del defaults["template"]
defaults["skipped_tags"] = list(defaults["skipped_tags"])
return {"defaults": defaults}
@classmethod
@@ -698,11 +718,7 @@ class AutotagConfig:
try:
setattr(cls, attr, validate(defaults[key]))
except ValueError as error:
config_logger.warning(
f"autotag.defaults.{key} {error}; using {default!r}"
if key != "template"
else f"autotag.defaults.template {error}; using the built-in one"
)
config_logger.warning(_fallback_warning(key, error, default))
setattr(cls, attr, default)