fix(import): request withMeta=true from CivitAI API, fix checkpoint type guard and CivArchive version lookup

- Add &withMeta=true to image info URL so API returns full generation
  metadata (resources with hash/type) instead of null meta
- Fix checkpoint assignment guard: check modelId instead of id so non-
  checkpoint types (upscaler) are not wrongly set as recipe checkpoint
- Skip modelVersionIds loop when resources/civitaiResources already
  provided LoRAs, preventing hash-resolved duplicates
- Fix int/str type comparison in CivArchive get_model_version so
  version ID matching works correctly
This commit is contained in:
Will Miao
2026-06-27 22:22:48 +08:00
parent 283730cf38
commit 703a6a4ea0
4 changed files with 21 additions and 10 deletions

View File

@@ -514,11 +514,21 @@ class CivitaiApiMetadataParser(RecipeMetadataParser):
result["loras"].append(lora_entry) result["loras"].append(lora_entry)
# Process modelVersionIds from Civitai image API # Process modelVersionIds from Civitai image API.
# These are model version IDs returned at root level when meta doesn't contain resources # These are version IDs returned at root level of the API response.
if "modelVersionIds" in metadata and isinstance( # When resources or civitaiResources are already present in metadata
metadata["modelVersionIds"], list # (which they are when ?withMeta=true is passed), those sections have
# complete hash/type information — modelVersionIds is a fallback for
# when meta is null and only the flat ID list is available. Skipping
# it here avoids duplicates: the same file hash often resolves to
# different version IDs via hash lookup (resources) vs the original
# version ID in modelVersionIds, and both paths would create entries.
if (
"modelVersionIds" in metadata
and isinstance(metadata["modelVersionIds"], list)
and not result.get("loras")
): ):
for version_id in metadata["modelVersionIds"]: for version_id in metadata["modelVersionIds"]:
version_id_str = str(version_id) version_id_str = str(version_id)
@@ -594,11 +604,12 @@ class CivitaiApiMetadataParser(RecipeMetadataParser):
checkpoint_entry, civitai_info checkpoint_entry, civitai_info
) )
) )
if cp_populated.get("id"): if cp_populated.get("modelId"):
result["model"] = cp_populated result["model"] = cp_populated
continue # Not a LoRA, don't add to loras continue # Not a LoRA, don't add to loras
lora_entry = populated_entry lora_entry = populated_entry
except Exception as e: except Exception as e:
logger.error( logger.error(
f"Error fetching Civitai info for model version {version_id}: {e}" f"Error fetching Civitai info for model version {version_id}: {e}"

View File

@@ -417,7 +417,7 @@ class CivArchiveClient:
if version_id is not None: if version_id is not None:
raw_id = version_data.get("id") raw_id = version_data.get("id")
if raw_id != version_id: if raw_id is not None and str(raw_id) != str(version_id):
logger.warning( logger.warning(
"Requested version %s doesn't match default version %s for model %s", "Requested version %s doesn't match default version %s for model %s",
version_id, version_id,

View File

@@ -56,7 +56,7 @@ class CivitaiClient:
self._MAX_CACHE_ENTRIES = 500 self._MAX_CACHE_ENTRIES = 500
def _build_image_info_url(self, image_id: str) -> str: def _build_image_info_url(self, image_id: str) -> str:
return f"{self.base_url}/images?imageId={image_id}&nsfw=X" return f"{self.base_url}/images?imageId={image_id}&nsfw=X&withMeta=true"
async def _make_request( async def _make_request(
self, self,

View File

@@ -568,7 +568,7 @@ async def test_get_image_info_prefers_red_host_for_red_source(monkeypatch, downl
assert result == {"id": 124950237, "name": "target"} assert result == {"id": 124950237, "name": "target"}
assert requested_urls == [ assert requested_urls == [
"https://civitai.red/api/v1/images?imageId=124950237&nsfw=X" "https://civitai.red/api/v1/images?imageId=124950237&nsfw=X&withMeta=true"
] ]
@@ -589,7 +589,7 @@ async def test_get_image_info_uses_red_host_even_for_red_source(monkeypatch, dow
assert result == {"id": 124950237, "name": "target"} assert result == {"id": 124950237, "name": "target"}
assert requested_urls == [ assert requested_urls == [
"https://civitai.red/api/v1/images?imageId=124950237&nsfw=X", "https://civitai.red/api/v1/images?imageId=124950237&nsfw=X&withMeta=true",
] ]
@@ -610,7 +610,7 @@ async def test_get_image_info_does_not_fall_back_after_request_failure(monkeypat
assert result is None assert result is None
assert requested_urls == [ assert requested_urls == [
"https://civitai.red/api/v1/images?imageId=124950237&nsfw=X", "https://civitai.red/api/v1/images?imageId=124950237&nsfw=X&withMeta=true",
] ]