refactor: Handle invalid tag names gracefully

- Change Tag.get_or_create to return None for invalid tag names
- Add None checks at all call sites to prevent AttributeError
- Protects against invalid Chinese names (>16 chars) and other language names (>8 words)
- Ensures system stability when encountering problematic tag data
pref/tag
zanllp 2026-01-22 22:41:28 +08:00
parent 323b2485e6
commit e1dad21286
5 changed files with 28 additions and 16 deletions

0
1.json Normal file
View File

View File

@ -1177,6 +1177,9 @@ def infinite_image_browsing_api(app: FastAPI, **kwargs):
async def add_custom_tag(req: AddCustomTagReq):
conn = DataBase.get_conn()
tag = Tag.get_or_create(conn, name=req.tag_name, type="custom")
if tag is None:
conn.rollback()
return None
conn.commit()
return tag

View File

@ -96,6 +96,7 @@ class AutoTagMatcher:
tag_name = rule.get("tag")
if tag_name:
tag = Tag.get_or_create(self.conn, tag_name, "custom")
ImageTag(img_id, tag.id).save_or_ignore(self.conn)
if tag is not None:
ImageTag(img_id, tag.id).save_or_ignore(self.conn)
except Exception as e:
logger.error(f"Error applying auto tag rule {rule}: {e}")

View File

@ -720,9 +720,9 @@ class Tag:
if len(name) > 12:
return "INVALID_TAG_NAME_TOO_LONG"
else:
# Other languages: max 6 words
# Other languages: max 6 words and 40 characters
words = name.split()
if len(words) > 6:
if len(words) > 6 and len(name) > 40:
return "INVALID_TAG_TOO_MANY_WORDS"
return None
@ -798,8 +798,8 @@ class Tag:
# Validate tag name
error_name = cls.validate_tag_name(name)
if error_name:
# Use get_or_create recursively to ensure error tag has an id
return cls.get_or_create(conn, error_name, "error")
# Return None for invalid tag names
return None
with closing(conn.cursor()) as cur:
cur.execute(

View File

@ -189,7 +189,8 @@ def build_single_img_idx(conn, file_path, is_rebuild, safe_save_img_tag):
size_str,
type="size",
)
safe_save_img_tag(ImageTag(img.id, size_tag.id))
if size_tag is not None:
safe_save_img_tag(ImageTag(img.id, size_tag.id))
# 确定媒体类型Image / Video / Audio / Unknown
if is_image_file(file_path):
media_type_name = "Image"
@ -200,7 +201,8 @@ def build_single_img_idx(conn, file_path, is_rebuild, safe_save_img_tag):
else:
media_type_name = "Unknown"
media_type_tag = Tag.get_or_create(conn, media_type_name, 'Media Type')
safe_save_img_tag(ImageTag(img.id, media_type_tag.id))
if media_type_tag is not None:
safe_save_img_tag(ImageTag(img.id, media_type_tag.id))
keys = [
"Model",
"Sampler",
@ -218,21 +220,27 @@ def build_single_img_idx(conn, file_path, is_rebuild, safe_save_img_tag):
continue
tag = Tag.get_or_create(conn, str(v), k)
safe_save_img_tag(ImageTag(img.id, tag.id))
if "Hires upscaler" == k:
tag = Tag.get_or_create(conn, 'Hires All', k)
safe_save_img_tag(ImageTag(img.id, tag.id))
elif "Refiner" == k:
tag = Tag.get_or_create(conn, 'Refiner All', k)
if tag is not None:
safe_save_img_tag(ImageTag(img.id, tag.id))
if "Hires upscaler" == k:
tag = Tag.get_or_create(conn, 'Hires All', k)
if tag is not None:
safe_save_img_tag(ImageTag(img.id, tag.id))
elif "Refiner" == k:
tag = Tag.get_or_create(conn, 'Refiner All', k)
if tag is not None:
safe_save_img_tag(ImageTag(img.id, tag.id))
for i in lora:
tag = Tag.get_or_create(conn, i["name"], "lora")
safe_save_img_tag(ImageTag(img.id, tag.id))
if tag is not None:
safe_save_img_tag(ImageTag(img.id, tag.id))
for i in lyco:
tag = Tag.get_or_create(conn, i["name"], "lyco")
safe_save_img_tag(ImageTag(img.id, tag.id))
if tag is not None:
safe_save_img_tag(ImageTag(img.id, tag.id))
for k in pos:
tag = Tag.get_or_create(conn, k, "pos")
safe_save_img_tag(ImageTag(img.id, tag.id))
if tag is not None:
safe_save_img_tag(ImageTag(img.id, tag.id))
AutoTagMatcher.get_instance(conn).apply(img.id, parsed_params)