mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-05-07 00:46:44 -03:00
fix(civitai): fallback image info hosts on request failure
This commit is contained in:
@@ -530,6 +530,97 @@ async def test_get_image_info_handles_missing(monkeypatch, downloader):
|
||||
assert result is None
|
||||
|
||||
|
||||
async def test_get_image_info_prefers_red_host_for_red_source(monkeypatch, downloader):
|
||||
requested_urls = []
|
||||
|
||||
async def fake_make_request(method, url, use_auth=True, **kwargs):
|
||||
requested_urls.append(url)
|
||||
return True, {"items": [{"id": 124950237, "name": "target"}]}
|
||||
|
||||
downloader.make_request = fake_make_request
|
||||
|
||||
client = await CivitaiClient.get_instance()
|
||||
|
||||
result = await client.get_image_info(
|
||||
"124950237", source_url="https://civitai.red/images/124950237"
|
||||
)
|
||||
|
||||
assert result == {"id": 124950237, "name": "target"}
|
||||
assert requested_urls == [
|
||||
"https://civitai.red/api/v1/images?imageId=124950237&nsfw=X"
|
||||
]
|
||||
|
||||
|
||||
async def test_get_image_info_falls_back_from_com_to_red(monkeypatch, downloader):
|
||||
requested_urls = []
|
||||
|
||||
async def fake_make_request(method, url, use_auth=True, **kwargs):
|
||||
requested_urls.append(url)
|
||||
if url.startswith("https://civitai.com/"):
|
||||
return True, {"items": []}
|
||||
return True, {"items": [{"id": 124950237, "name": "fallback"}]}
|
||||
|
||||
downloader.make_request = fake_make_request
|
||||
|
||||
client = await CivitaiClient.get_instance()
|
||||
|
||||
result = await client.get_image_info("124950237")
|
||||
|
||||
assert result == {"id": 124950237, "name": "fallback"}
|
||||
assert requested_urls == [
|
||||
"https://civitai.com/api/v1/images?imageId=124950237&nsfw=X",
|
||||
"https://civitai.red/api/v1/images?imageId=124950237&nsfw=X",
|
||||
]
|
||||
|
||||
|
||||
async def test_get_image_info_falls_back_from_red_to_com(monkeypatch, downloader):
|
||||
requested_urls = []
|
||||
|
||||
async def fake_make_request(method, url, use_auth=True, **kwargs):
|
||||
requested_urls.append(url)
|
||||
if url.startswith("https://civitai.red/"):
|
||||
return True, {"items": []}
|
||||
return True, {"items": [{"id": 124950237, "name": "fallback"}]}
|
||||
|
||||
downloader.make_request = fake_make_request
|
||||
|
||||
client = await CivitaiClient.get_instance()
|
||||
|
||||
result = await client.get_image_info(
|
||||
"124950237", source_url="https://civitai.red/images/124950237"
|
||||
)
|
||||
|
||||
assert result == {"id": 124950237, "name": "fallback"}
|
||||
assert requested_urls == [
|
||||
"https://civitai.red/api/v1/images?imageId=124950237&nsfw=X",
|
||||
"https://civitai.com/api/v1/images?imageId=124950237&nsfw=X",
|
||||
]
|
||||
|
||||
|
||||
async def test_get_image_info_falls_back_after_request_failure(monkeypatch, downloader):
|
||||
requested_urls = []
|
||||
|
||||
async def fake_make_request(method, url, use_auth=True, **kwargs):
|
||||
requested_urls.append(url)
|
||||
if url.startswith("https://civitai.red/"):
|
||||
return False, "403 forbidden"
|
||||
return True, {"items": [{"id": 124950237, "name": "fallback"}]}
|
||||
|
||||
downloader.make_request = fake_make_request
|
||||
|
||||
client = await CivitaiClient.get_instance()
|
||||
|
||||
result = await client.get_image_info(
|
||||
"124950237", source_url="https://civitai.red/images/124950237"
|
||||
)
|
||||
|
||||
assert result == {"id": 124950237, "name": "fallback"}
|
||||
assert requested_urls == [
|
||||
"https://civitai.red/api/v1/images?imageId=124950237&nsfw=X",
|
||||
"https://civitai.com/api/v1/images?imageId=124950237&nsfw=X",
|
||||
]
|
||||
|
||||
|
||||
async def test_get_image_info_handles_invalid_id(monkeypatch, downloader, caplog):
|
||||
"""When given a non-numeric image ID, return None and log error."""
|
||||
client = await CivitaiClient.get_instance()
|
||||
|
||||
@@ -6,7 +6,7 @@ from types import SimpleNamespace
|
||||
|
||||
# We define these here to help with spec= if needed
|
||||
class MockCivitaiClient:
|
||||
async def get_image_info(self, image_id):
|
||||
async def get_image_info(self, image_id, source_url=None):
|
||||
pass
|
||||
|
||||
class MockPersistenceService:
|
||||
@@ -119,6 +119,50 @@ async def test_repair_all_recipes_with_enriched_checkpoint_id(setup_scanner):
|
||||
assert "hash" not in checkpoint
|
||||
assert "file_name" not in checkpoint
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_repair_all_recipes_supports_civitai_red_source_url(setup_scanner):
|
||||
recipe_scanner, mock_civitai_client, mock_metadata_provider = setup_scanner
|
||||
|
||||
recipe = {
|
||||
"id": "r1",
|
||||
"title": "Red Recipe",
|
||||
"source_url": "https://civitai.red/images/12345",
|
||||
"checkpoint": None,
|
||||
"gen_params": {"prompt": ""},
|
||||
}
|
||||
recipe_scanner._cache = SimpleNamespace(raw_data=[recipe])
|
||||
|
||||
mock_civitai_client.get_image_info.return_value = {
|
||||
"modelVersionId": 5678,
|
||||
"meta": {"prompt": "from red"},
|
||||
}
|
||||
mock_metadata_provider.get_model_version_info.return_value = (
|
||||
{
|
||||
"id": 5678,
|
||||
"modelId": 1234,
|
||||
"name": "v1.0",
|
||||
"model": {"name": "Full Model Name"},
|
||||
"baseModel": "SDXL 1.0",
|
||||
"images": [{"url": "https://image.url/thumb.jpg"}],
|
||||
"files": [
|
||||
{
|
||||
"type": "Model",
|
||||
"hashes": {"SHA256": "ABCDEF"},
|
||||
"name": "full_filename.safetensors",
|
||||
}
|
||||
],
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
results = await recipe_scanner.repair_all_recipes()
|
||||
|
||||
assert results["repaired"] == 1
|
||||
mock_civitai_client.get_image_info.assert_called_with(
|
||||
"12345", source_url="https://civitai.red/images/12345"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_repair_all_recipes_with_enriched_checkpoint_hash(setup_scanner):
|
||||
recipe_scanner, mock_civitai_client, mock_metadata_provider = setup_scanner
|
||||
|
||||
@@ -678,7 +678,7 @@ async def test_analyze_remote_video(tmp_path):
|
||||
)
|
||||
|
||||
class DummyClient:
|
||||
async def get_image_info(self, image_id):
|
||||
async def get_image_info(self, image_id, source_url=None):
|
||||
return {
|
||||
"url": "https://civitai.com/video.mp4",
|
||||
"type": "video",
|
||||
@@ -698,3 +698,60 @@ async def test_analyze_remote_video(tmp_path):
|
||||
assert result.payload["is_video"] is True
|
||||
assert result.payload["extension"] == ".mp4"
|
||||
assert result.payload["image_base64"] is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_analyze_remote_image_supports_civitai_red():
|
||||
exif_utils = DummyExifUtils()
|
||||
|
||||
class DummyFactory:
|
||||
def create_parser(self, metadata):
|
||||
async def parse_metadata(m, recipe_scanner=None, civitai_client=None):
|
||||
return {"loras": [], "gen_params": {"prompt": "red prompt"}}
|
||||
|
||||
return SimpleNamespace(parse_metadata=parse_metadata)
|
||||
|
||||
async def downloader_factory():
|
||||
class Downloader:
|
||||
async def download_file(self, url, path, use_auth=False):
|
||||
Path(path).write_bytes(b"fake-image")
|
||||
return True, "success"
|
||||
|
||||
return Downloader()
|
||||
|
||||
service = RecipeAnalysisService(
|
||||
exif_utils=exif_utils,
|
||||
recipe_parser_factory=DummyFactory(),
|
||||
downloader_factory=downloader_factory,
|
||||
metadata_collector=None,
|
||||
metadata_processor_cls=None,
|
||||
metadata_registry_cls=None,
|
||||
standalone_mode=False,
|
||||
logger=logging.getLogger("test"),
|
||||
)
|
||||
|
||||
class DummyClient:
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
async def get_image_info(self, image_id, source_url=None):
|
||||
self.calls.append((image_id, source_url))
|
||||
return {
|
||||
"url": "https://image.civitai.com/x/y/original=true/sample.jpeg",
|
||||
"type": "image",
|
||||
"meta": {"prompt": "red prompt"},
|
||||
}
|
||||
|
||||
class DummyScanner:
|
||||
async def find_recipes_by_fingerprint(self, fingerprint):
|
||||
return []
|
||||
|
||||
client = DummyClient()
|
||||
result = await service.analyze_remote_image(
|
||||
url="https://civitai.red/images/123",
|
||||
recipe_scanner=DummyScanner(),
|
||||
civitai_client=client,
|
||||
)
|
||||
|
||||
assert client.calls == [("123", "https://civitai.red/images/123")]
|
||||
assert result.payload["loras"] == []
|
||||
|
||||
Reference in New Issue
Block a user