mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-09 20:39:25 -03:00
feat(ui): merge user tags into auto-tag badges and refresh on tag edit (#918)
- Layer 2 fallback: user tags overlapping with auto-tag categories (HIGH/LOW/I2V/T2V/TI2V/Lightning/Turbo) are merged into auto_tags, providing manual override when filename-based detection fails. Matching is case-insensitive so "high"/"High"/"HIGH" all work. - Refresh on tag edit: save_metadata and add_tags handlers now return recalculated auto_tags in the response; the frontend passes them to VirtualScroller.updateSingleItem so badges update immediately without requiring a page reload. - 8 new test cases for Layer 2 fallback and case-insensitive matching.
This commit is contained in:
@@ -255,7 +255,7 @@ def test_tag_update_service_adds_unique_tags(tmp_path: Path) -> None:
|
||||
cache_updates.append(metadata)
|
||||
return True
|
||||
|
||||
tags = asyncio.run(
|
||||
tags, auto_tags = asyncio.run(
|
||||
service.add_tags(
|
||||
file_path=str(tmp_path / "model.safetensors"),
|
||||
new_tags=["new", "existing"],
|
||||
@@ -265,5 +265,6 @@ def test_tag_update_service_adds_unique_tags(tmp_path: Path) -> None:
|
||||
)
|
||||
|
||||
assert tags == ["existing", "new"]
|
||||
assert auto_tags == []
|
||||
assert manager.saved
|
||||
assert cache_updates
|
||||
|
||||
@@ -43,7 +43,7 @@ async def test_tag_update_service_handles_case_insensitive_tags(tmp_path: Path)
|
||||
return True
|
||||
|
||||
# Try to add "Test" (different case) - should not be added since "test" already exists
|
||||
tags = await service.add_tags(
|
||||
tags, auto_tags = await service.add_tags(
|
||||
file_path=str(tmp_path / "model.safetensors"),
|
||||
new_tags=["Test"],
|
||||
metadata_loader=loader,
|
||||
@@ -52,6 +52,7 @@ async def test_tag_update_service_handles_case_insensitive_tags(tmp_path: Path)
|
||||
|
||||
# Should still only have "test" (lowercase) in the tags
|
||||
assert tags == ["test"]
|
||||
assert auto_tags == [] # no file_name/base_model in metadata, so no auto-detection
|
||||
assert len(manager.saved) == 1
|
||||
saved_metadata = manager.saved[0][1]
|
||||
assert saved_metadata["tags"] == ["test"]
|
||||
@@ -76,7 +77,7 @@ async def test_tag_update_service_adds_new_tags_in_lowercase(tmp_path: Path) ->
|
||||
return True
|
||||
|
||||
# Add new tags with mixed case
|
||||
tags = await service.add_tags(
|
||||
tags, auto_tags = await service.add_tags(
|
||||
file_path=str(tmp_path / "model.safetensors"),
|
||||
new_tags=["NewTag", "ANOTHER_TAG"],
|
||||
metadata_loader=loader,
|
||||
@@ -87,6 +88,7 @@ async def test_tag_update_service_adds_new_tags_in_lowercase(tmp_path: Path) ->
|
||||
assert "existing" in tags
|
||||
assert "newtag" in tags
|
||||
assert "another_tag" in tags
|
||||
assert auto_tags == []
|
||||
assert len(manager.saved) == 1
|
||||
saved_metadata = manager.saved[0][1]
|
||||
assert "newtag" in saved_metadata["tags"]
|
||||
|
||||
@@ -126,6 +126,80 @@ class TestExtractAutoTags:
|
||||
})
|
||||
assert set(result) == {"HIGH", "I2V"}
|
||||
|
||||
# ── Layer 2: user-defined tags as manual fallback ───────────
|
||||
|
||||
def test_user_tags_fallback_when_detection_fails(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "BOTH-v1.0",
|
||||
"base_model": "Wan 2.2",
|
||||
"civitai": {},
|
||||
"tags": ["HIGH", "I2V", "T2V"],
|
||||
})
|
||||
assert set(result) == {"HIGH", "I2V", "T2V"}
|
||||
|
||||
def test_user_tags_augment_partial_detection(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "wan_i2v_hn_v2",
|
||||
"base_model": "Wan 2.2 I2V",
|
||||
"civitai": {},
|
||||
"tags": ["HIGH"],
|
||||
})
|
||||
assert set(result) == {"HIGH", "I2V"}
|
||||
|
||||
def test_user_tags_non_auto_tag_ignored(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "model_v1",
|
||||
"base_model": "Wan 2.2",
|
||||
"civitai": {},
|
||||
"tags": ["HIGH", "character", "style", "nsfw"],
|
||||
})
|
||||
assert set(result) == {"HIGH"}
|
||||
|
||||
def test_user_tags_overrides_non_wan_gate(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "flux_model_v1",
|
||||
"base_model": "Flux.1 D",
|
||||
"civitai": {},
|
||||
"tags": ["HIGH", "LOW", "Turbo"],
|
||||
})
|
||||
assert set(result) == {"HIGH", "LOW", "Turbo"}
|
||||
|
||||
def test_user_tags_no_duplication(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "wan_i2v_high_v3",
|
||||
"base_model": "Wan 2.2",
|
||||
"civitai": {},
|
||||
"tags": ["HIGH", "I2V"],
|
||||
})
|
||||
assert set(result) == {"HIGH", "I2V"}
|
||||
|
||||
def test_user_tags_lightning_turbo_manual(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "sdxl_model_v1",
|
||||
"base_model": "SDXL",
|
||||
"civitai": {},
|
||||
"tags": ["Lightning"],
|
||||
})
|
||||
assert set(result) == {"Lightning"}
|
||||
|
||||
def test_user_tags_case_insensitive_lowercase(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "wan_masterpieces_v2",
|
||||
"base_model": "Wan Video 14B t2v",
|
||||
"civitai": {},
|
||||
"tags": ["high"],
|
||||
})
|
||||
assert set(result) == {"HIGH", "T2V"}
|
||||
|
||||
def test_user_tags_case_insensitive_mixed(self):
|
||||
result = extract_auto_tags({
|
||||
"file_name": "model_v1",
|
||||
"base_model": "SDXL",
|
||||
"civitai": {},
|
||||
"tags": ["lightning", "turbo", "i2v"],
|
||||
})
|
||||
assert set(result) == {"Lightning", "Turbo", "I2V"}
|
||||
|
||||
|
||||
class TestAutoTagCategories:
|
||||
def test_all_patterns_compile(self):
|
||||
|
||||
Reference in New Issue
Block a user