mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-20 12:31:27 -03:00
Fix recipe parsing for metadata-free local LoRAs (#1065)
* fix(recipes): resolve metadata-free local LoRAs * fix(recipes): prioritize LoRA hashes over names
This commit is contained in:
@@ -2,6 +2,38 @@ import pytest
|
||||
import json
|
||||
from py.recipes.parsers.comfy import ComfyMetadataParser
|
||||
|
||||
|
||||
class LocalRecipeScanner:
|
||||
class LoraScanner:
|
||||
@staticmethod
|
||||
def has_hash(model_hash):
|
||||
return False
|
||||
|
||||
def __init__(self, models):
|
||||
self.models = models
|
||||
self.queries = []
|
||||
self.base_models = []
|
||||
self._lora_scanner = self.LoraScanner()
|
||||
|
||||
async def get_local_lora(self, name, base_model=None):
|
||||
self.queries.append(name)
|
||||
self.base_models.append(base_model)
|
||||
return self.models.get(name)
|
||||
|
||||
|
||||
def local_lora(file_name):
|
||||
return {
|
||||
"file_path": f"/models/loras/{file_name}.safetensors",
|
||||
"file_name": file_name.rsplit("/", 1)[-1],
|
||||
"model_name": file_name.rsplit("/", 1)[-1],
|
||||
"sha256": file_name[0] * 64,
|
||||
"size": 4096,
|
||||
"base_model": "SDXL 1.0",
|
||||
"preview_url": "",
|
||||
"civitai": None,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_metadata_without_loras(monkeypatch):
|
||||
checkpoint_info = {
|
||||
@@ -84,6 +116,140 @@ async def test_parse_metadata_without_loras(monkeypatch):
|
||||
assert result["gen_params"]["size"] == "1024x1024"
|
||||
assert result["from_comfy_metadata"] is True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_metadata_resolves_standard_and_manager_local_loras(monkeypatch):
|
||||
async def fake_metadata_provider():
|
||||
class Provider:
|
||||
async def get_model_version_info(self, version_id):
|
||||
raise AssertionError("Local LoRAs must not query Civitai")
|
||||
|
||||
return Provider()
|
||||
|
||||
monkeypatch.setattr(
|
||||
"py.recipes.parsers.comfy.get_default_metadata_provider",
|
||||
fake_metadata_provider,
|
||||
)
|
||||
scanner = LocalRecipeScanner({
|
||||
"styles/standard.safetensors": local_lora("standard"),
|
||||
"manager": local_lora("manager"),
|
||||
})
|
||||
metadata_json = {
|
||||
"1": {
|
||||
"class_type": "LoraLoader",
|
||||
"inputs": {
|
||||
"lora_name": "styles/standard.safetensors",
|
||||
"strength_model": 0.55,
|
||||
},
|
||||
},
|
||||
"2": {
|
||||
"class_type": "LoraLoaderLM",
|
||||
"inputs": {
|
||||
"loras": {
|
||||
"__value__": [
|
||||
{"name": "manager", "strength": "0.80", "active": True},
|
||||
{"name": "disabled", "strength": 1.0, "active": False},
|
||||
{"name": "dummy", "strength": 1.0, "active": True, "_isDummy": True},
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result = await ComfyMetadataParser().parse_metadata(json.dumps(metadata_json), scanner)
|
||||
|
||||
assert [entry["file_name"] for entry in result["loras"]] == ["standard", "manager"]
|
||||
assert [entry["weight"] for entry in result["loras"]] == [0.55, 0.8]
|
||||
assert all(isinstance(entry["weight"], float) for entry in result["loras"])
|
||||
assert all(entry["existsLocally"] is True for entry in result["loras"])
|
||||
assert all(entry["isDeleted"] is False for entry in result["loras"])
|
||||
assert scanner.queries == ["styles/standard.safetensors", "manager"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_metadata_defaults_malformed_weight_and_passes_checkpoint_base_model(monkeypatch):
|
||||
checkpoint_info = {
|
||||
"id": 456,
|
||||
"modelId": 123,
|
||||
"model": {"name": "Checkpoint", "type": "checkpoint"},
|
||||
"name": "v1",
|
||||
"baseModel": "SDXL 1.0",
|
||||
}
|
||||
|
||||
async def fake_metadata_provider():
|
||||
class Provider:
|
||||
async def get_model_version_info(self, version_id):
|
||||
return checkpoint_info, None
|
||||
|
||||
return Provider()
|
||||
|
||||
monkeypatch.setattr(
|
||||
"py.recipes.parsers.comfy.get_default_metadata_provider",
|
||||
fake_metadata_provider,
|
||||
)
|
||||
scanner = LocalRecipeScanner({"style": local_lora("style")})
|
||||
metadata_json = {
|
||||
"1": {"class_type": "LoraLoader", "inputs": {"lora_name": "style", "strength_model": "invalid"}},
|
||||
"2": {"class_type": "CheckpointLoaderSimple", "inputs": {"ckpt_name": "civitai:123@456"}},
|
||||
}
|
||||
|
||||
result = await ComfyMetadataParser().parse_metadata(json.dumps(metadata_json), scanner)
|
||||
|
||||
assert result["loras"][0]["weight"] == 1.0
|
||||
assert scanner.base_models == ["SDXL 1.0"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_metadata_keeps_civitai_urn_with_local_lora(monkeypatch):
|
||||
remote_info = {
|
||||
"id": 456,
|
||||
"modelId": 123,
|
||||
"model": {"name": "Remote LoRA", "type": "LORA"},
|
||||
"name": "v1",
|
||||
"files": [
|
||||
{
|
||||
"type": "Model",
|
||||
"primary": True,
|
||||
"name": "remote.safetensors",
|
||||
"hashes": {"SHA256": "c" * 64},
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
async def fake_metadata_provider():
|
||||
class Provider:
|
||||
async def get_model_version_info(self, version_id):
|
||||
assert version_id == "456"
|
||||
return remote_info, None
|
||||
|
||||
return Provider()
|
||||
|
||||
monkeypatch.setattr(
|
||||
"py.recipes.parsers.comfy.get_default_metadata_provider",
|
||||
fake_metadata_provider,
|
||||
)
|
||||
scanner = LocalRecipeScanner({"local": local_lora("local")})
|
||||
metadata_json = {
|
||||
"1": {
|
||||
"class_type": "LoraLoader",
|
||||
"inputs": {"lora_name": "local", "strength_model": 0.4},
|
||||
},
|
||||
"2": {
|
||||
"class_type": "LoraLoader",
|
||||
"inputs": {
|
||||
"lora_name": "urn:air:sdxl:lora:civitai:123@456",
|
||||
"strength_model": 0.9,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
result = await ComfyMetadataParser().parse_metadata(json.dumps(metadata_json), scanner)
|
||||
|
||||
assert [entry["name"] for entry in result["loras"]] == ["local", "Remote LoRA"]
|
||||
assert [entry["weight"] for entry in result["loras"]] == [0.4, 0.9]
|
||||
assert result["loras"][0]["existsLocally"] is True
|
||||
assert result["loras"][1]["id"] == 456
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_metadata_without_extra_metadata(monkeypatch):
|
||||
async def fake_metadata_provider():
|
||||
|
||||
Reference in New Issue
Block a user