mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-23 12:04:09 -03:00
fix(organize): stop keyword-dump tags from becoming folder names (#1119)
CivitAI tags are normally short single-concept labels, but some uploaders pack their entire keyword list into one tag. The model in #1119 carries "lora, character, rosie, irish, ... face" as a single 181-character tag. Priority resolution matches aliases by exact equality, so that tag matched nothing and resolve_priority_tag_for_model fell back to tags[0] -- the blob. With the default "{base_model}/{first_tag}" template the model was filed under "Krea 2/<181-character blob>/", and the full path plus the ".civitai.info" sidecar and the preview images next to it ran into the Windows MAX_PATH limit. Tags also bypassed sanitization on the way into a path: both calculate_relative_path_for_model and DownloadManager._calculate_relative_path sanitized model_name and version_name but interpolated {first_tag} verbatim, so a tag containing "/" or ":" silently produced nested or illegal folders. Two changes: - The fallback skips tags that cannot serve as a folder name. is_usable_path_tag rejects comma-separated keyword dumps and tags longer than MAX_PATH_TAG_LENGTH; the resolver returns "" when nothing usable is left, which callers already render as "no tags". Whole-tag priority matching is untouched, so existing priority configurations behave the same. - sanitize_folder_name gains an optional max_length, and every tag-derived segment now goes through it. Tags are capped at MAX_PATH_TAG_LENGTH, model and version names at MAX_FOLDER_NAME_LENGTH, and rendered filename stems at MAX_FILENAME_STEM_LENGTH. For the reported model the folder becomes "Krea 2/base model" instead of the blob, and the full path drops from 235 to 64 characters. Existing libraries are not migrated up front: a path is only recomputed on download, on an auto-organize run or when a filename template is applied, and values already inside the caps are left byte-identical. Models previously filed under a keyword-dump folder move on the next auto-organize run.
This commit is contained in:
@@ -238,6 +238,47 @@ async def test_successful_download_uses_defaults(
|
||||
assert captured["download_urls"] == ["https://example.invalid/file.safetensors"]
|
||||
|
||||
|
||||
def test_calculate_relative_path_ignores_keyword_dump_tag():
|
||||
"""The #1119 download flow: a keyword-dump tag must not become a folder."""
|
||||
keyword_dump = (
|
||||
"lora, character, rosie, irish, redhead, auburn, freckles, green eyes, "
|
||||
"curly hair, woman, female, photorealistic, realistic, krea2, dark beast, "
|
||||
"kreativity, nsfw, nude, portrait, face"
|
||||
)
|
||||
manager = DownloadManager()
|
||||
|
||||
relative_path = manager._calculate_relative_path(
|
||||
{
|
||||
"baseModel": "BaseModel",
|
||||
"creator": {"username": "mad_macs"},
|
||||
"name": "v1.2",
|
||||
"model": {"name": "Rosie", "tags": [keyword_dump, "base model"]},
|
||||
},
|
||||
"lora",
|
||||
)
|
||||
|
||||
assert relative_path == "MappedModel/base model"
|
||||
assert keyword_dump not in relative_path
|
||||
assert len(relative_path) < 50
|
||||
|
||||
|
||||
def test_calculate_relative_path_sanitizes_tag_segment():
|
||||
"""A tag with path separators must not create nested folders."""
|
||||
manager = DownloadManager()
|
||||
|
||||
relative_path = manager._calculate_relative_path(
|
||||
{
|
||||
"baseModel": "BaseModel",
|
||||
"creator": {"username": "author"},
|
||||
"name": "v1.2",
|
||||
"model": {"name": "Rosie", "tags": ["a/b:c"]},
|
||||
},
|
||||
"lora",
|
||||
)
|
||||
|
||||
assert relative_path == "MappedModel/a_b_c"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_accepts_enhancement_lora_primary_file(
|
||||
monkeypatch, scanners, metadata_provider, tmp_path
|
||||
|
||||
@@ -365,6 +365,53 @@ def test_download_path_template_unknown_type_is_flat(manager):
|
||||
assert manager.get_download_path_template("not-a-model-type") == ""
|
||||
|
||||
|
||||
# Real CivitAI data for the model reported in issue #1119: the uploader dumped
|
||||
# a whole keyword list into a single tag.
|
||||
KEYWORD_DUMP_TAG = (
|
||||
"lora, character, rosie, irish, redhead, auburn, freckles, green eyes, "
|
||||
"curly hair, woman, female, photorealistic, realistic, krea2, dark beast, "
|
||||
"kreativity, nsfw, nude, portrait, face"
|
||||
)
|
||||
|
||||
|
||||
def test_resolve_priority_tag_prefers_configured_priority(manager):
|
||||
# Priority order from CIVITAI_MODEL_TAGS: "character" precedes "anime".
|
||||
assert manager.resolve_priority_tag_for_model(["anime", "character"], "lora") == (
|
||||
"character"
|
||||
)
|
||||
|
||||
|
||||
def test_resolve_priority_tag_falls_back_to_first_usable_tag(manager):
|
||||
assert (
|
||||
manager.resolve_priority_tag_for_model(["portrait", "anime-ish"], "lora")
|
||||
== "portrait"
|
||||
)
|
||||
|
||||
|
||||
def test_resolve_priority_tag_skips_keyword_dump_tag(manager):
|
||||
"""A keyword-dump tag must not be used as a folder name (#1119)."""
|
||||
assert manager.resolve_priority_tag_for_model([KEYWORD_DUMP_TAG], "lora") == ""
|
||||
|
||||
|
||||
def test_resolve_priority_tag_skips_keyword_dump_and_uses_next_tag(manager):
|
||||
assert (
|
||||
manager.resolve_priority_tag_for_model([KEYWORD_DUMP_TAG, "portrait"], "lora")
|
||||
== "portrait"
|
||||
)
|
||||
|
||||
|
||||
def test_resolve_priority_tag_skips_unusable_tags(manager):
|
||||
overlong_tag = "x" * 51
|
||||
|
||||
assert manager.resolve_priority_tag_for_model([overlong_tag], "lora") == ""
|
||||
assert manager.resolve_priority_tag_for_model([overlong_tag, " "], "lora") == ""
|
||||
# Non-string entries never win the fallback.
|
||||
assert manager.resolve_priority_tag_for_model([None, 42], "lora") == ""
|
||||
# A tag at the length budget is still accepted and stripped.
|
||||
assert manager.resolve_priority_tag_for_model(["x" * 50], "lora") == "x" * 50
|
||||
assert manager.resolve_priority_tag_for_model([" portrait "], "lora") == "portrait"
|
||||
|
||||
|
||||
def test_auto_set_default_roots(manager):
|
||||
# Clear any previously auto-set values to test fresh behavior
|
||||
manager.settings["default_lora_root"] = ""
|
||||
|
||||
Reference in New Issue
Block a user