mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-26 21:44:09 -03:00
fix: stop grouping HF/ModelScope models by repository
A repository is not a model identity: collection repos on Hugging Face and ModelScope host many unrelated models, which were wrongly shown as versions of each other. - Hugging Face models no longer auto-group (the Hub exposes no site-native model id) - ModelScope models group by the site's native published-model id (MuseInfo modelVersion.modelId), extracted during enrichment and persisted on the sidecar as source_model_id/source_version_id; unenriched models stay standalone instead of collapsing a whole repo into one group - TensorArt grouping unchanged (its URL id is already model-level) - Frontend group-key derivation mirrors the new backend semantics
This commit is contained in:
@@ -1263,39 +1263,8 @@ async def test_get_model_civitai_url_falls_back_when_host_setting_is_not_a_strin
|
||||
}
|
||||
|
||||
|
||||
class TestHfGroupKey:
|
||||
"""Tests for _extract_hf_group_key and _extract_group_key."""
|
||||
|
||||
# --- _extract_hf_group_key ---
|
||||
|
||||
def test_hf_group_key_valid_url(self):
|
||||
"""Standard HF URL returns hf:user/repo."""
|
||||
item = {"hf_url": "https://huggingface.co/unsloth/qwen-edit"}
|
||||
assert BaseModelService._extract_hf_group_key(item) == "hf:unsloth/qwen-edit"
|
||||
|
||||
def test_hf_group_key_url_with_subpath(self):
|
||||
"""URL with subpath still extracts just owner/repo."""
|
||||
item = {"hf_url": "https://huggingface.co/user/repo/resolve/main/file.safetensors"}
|
||||
assert BaseModelService._extract_hf_group_key(item) == "hf:user/repo"
|
||||
|
||||
def test_hf_group_key_empty_url(self):
|
||||
"""Empty hf_url returns None."""
|
||||
assert BaseModelService._extract_hf_group_key({"hf_url": ""}) is None
|
||||
|
||||
def test_hf_group_key_no_url(self):
|
||||
"""Missing hf_url key returns None."""
|
||||
assert BaseModelService._extract_hf_group_key({}) is None
|
||||
|
||||
def test_hf_group_key_none_url(self):
|
||||
"""None hf_url returns None."""
|
||||
assert BaseModelService._extract_hf_group_key({"hf_url": None}) is None
|
||||
|
||||
def test_hf_group_key_invalid_url(self):
|
||||
"""Malformed HF URL returns None."""
|
||||
assert BaseModelService._extract_hf_group_key({"hf_url": "not-a-url"}) is None
|
||||
assert BaseModelService._extract_hf_group_key({"hf_url": "https://example.com"}) is None
|
||||
|
||||
# --- _extract_group_key ---
|
||||
class TestSourceGroupKey:
|
||||
"""Tests for _extract_group_key (CivitAI id, then site-native source identity)."""
|
||||
|
||||
def test_group_key_civitai_only(self):
|
||||
"""CivitAI modelId returned as int."""
|
||||
@@ -1303,30 +1272,64 @@ class TestHfGroupKey:
|
||||
assert BaseModelService._extract_group_key(item) == 123
|
||||
|
||||
def test_group_key_hf_only(self):
|
||||
"""HF-only item returns hf:user/repo string."""
|
||||
"""HF-linked items never group: a repository is not a model identity."""
|
||||
item = {"hf_url": "https://huggingface.co/user/repo"}
|
||||
assert BaseModelService._extract_group_key(item) == "hf:user/repo"
|
||||
assert BaseModelService._extract_group_key(item) is None
|
||||
|
||||
def test_group_key_civitai_preferred(self):
|
||||
"""CivitAI modelId takes precedence over hf_url."""
|
||||
"""CivitAI modelId takes precedence over any source identity."""
|
||||
item = {
|
||||
"civitai": {"modelId": 456},
|
||||
"hf_url": "https://huggingface.co/other/repo",
|
||||
"source_url": "https://tensor.art/models/789",
|
||||
}
|
||||
assert BaseModelService._extract_group_key(item) == 456
|
||||
|
||||
def test_group_key_neither(self):
|
||||
"""No CivitAI or HF returns None."""
|
||||
"""No CivitAI or groupable source returns None."""
|
||||
assert BaseModelService._extract_group_key({}) is None
|
||||
assert BaseModelService._extract_group_key({"some": "data"}) is None
|
||||
|
||||
def test_group_key_civitai_none_model_id(self):
|
||||
"""civitai.modelId=None falls through to HF."""
|
||||
"""civitai.modelId=None falls through to the source identity."""
|
||||
item = {
|
||||
"civitai": {"modelId": None},
|
||||
"hf_url": "https://huggingface.co/user/repo",
|
||||
"source_url": "https://tensor.art/models/789",
|
||||
}
|
||||
assert BaseModelService._extract_group_key(item) == "hf:user/repo"
|
||||
assert BaseModelService._extract_group_key(item) == "ta:789"
|
||||
|
||||
def test_group_key_modelscope_uses_published_model_id(self):
|
||||
"""ModelScope groups under ms:<modelId> once enrichment recorded it."""
|
||||
item = {
|
||||
"source_platform": "modelscope",
|
||||
"source_url": "https://modelscope.cn/models/u/r",
|
||||
"source_model_id": "555",
|
||||
}
|
||||
assert BaseModelService._extract_group_key(item) == "ms:555"
|
||||
|
||||
def test_group_key_modelscope_unenriched_stays_standalone(self):
|
||||
"""Without source_model_id there is no key — never repo-level grouping."""
|
||||
item = {
|
||||
"source_platform": "modelscope",
|
||||
"source_url": "https://modelscope.cn/models/u/r",
|
||||
}
|
||||
assert BaseModelService._extract_group_key(item) is None
|
||||
|
||||
def test_group_key_modelscope_identity_crosses_repos(self):
|
||||
"""Same published-model id groups across repos; same repo does not."""
|
||||
|
||||
def ms_item(repo, model_id):
|
||||
return {
|
||||
"source_platform": "modelscope",
|
||||
"source_url": f"https://modelscope.cn/models/{repo}",
|
||||
"source_model_id": model_id,
|
||||
}
|
||||
|
||||
assert BaseModelService._extract_group_key(
|
||||
ms_item("alice/collection", "555")
|
||||
) == BaseModelService._extract_group_key(ms_item("bob/mirror", "555"))
|
||||
assert BaseModelService._extract_group_key(
|
||||
ms_item("alice/collection", "555")
|
||||
) != BaseModelService._extract_group_key(ms_item("alice/collection", "777"))
|
||||
|
||||
|
||||
class TestApplyHashFilters:
|
||||
|
||||
Reference in New Issue
Block a user