Files
ComfyUI/custom_nodes/comfyui-image-saver/civitai_nodes.py
jaidaken f09734b0ee
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Includes 30 custom nodes committed directly, 7 Civitai-exclusive
loras stored via Git LFS, and a setup script that installs all
dependencies and downloads HuggingFace-hosted models on vast.ai.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 00:56:42 +00:00

136 lines
5.6 KiB
Python

import requests
class CivitaiHashFetcher:
"""
A ComfyUI custom node that fetches the AutoV3 hash of a model from Civitai
based on the provided username and model name.
"""
def __init__(self):
self.last_username = None
self.last_model_name = None
self.last_version = None
self.last_hash = None # Store the last fetched hash
RETURN_TYPES = ("STRING",) # The node outputs a string (AutoV3 hash)
FUNCTION = "get_autov3_hash"
CATEGORY = "CivitaiAPI"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"username": ("STRING", {"default": "", "multiline": False}),
"model_name": ("STRING", {"default": "", "multiline": False}),
},
"optional": {
"version": ("STRING", {"default": "", "multiline": False, "tooltip": "Specify version keyword to fetch a particular model version (optional)"}),
}
}
def get_autov3_hash(self, username, model_name, version=""):
"""
Fetches the latest model version from Civitai and extracts its AutoV3 hash.
Uses caching to avoid redundant API calls.
"""
# Check if inputs are the same as last time
if (self.last_username is not None and self.last_model_name is not None and self.last_version is not None and
username == self.last_username and model_name == self.last_model_name and version == self.last_version):
return self.last_hash
base_url = "https://civitai.com/api/v1/models"
params = {
"username": username,
"query": model_name,
"limit": 20, # Fetch more results due to API ranking issues
"nsfw": "true" # Include NSFW models in search results
}
try:
# Fetch models by username and model name
response = requests.get(base_url, params=params, timeout=10)
if response.status_code != 200:
return (f"Error: API request failed with status {response.status_code}",)
data = response.json()
items = data.get("items", [])
# If no results with query, try without query (fallback for API search issues)
if not items and params.get("query"):
print("ComfyUI-Image-Saver: No results with query, trying without query parameter...")
params_no_query = {
"username": username,
"limit": 100,
"nsfw": "true"
}
response = requests.get(base_url, params=params_no_query, timeout=10)
if response.status_code == 200:
data = response.json()
items = data.get("items", [])
if not items:
return (f"No models found for user '{username}' with name '{model_name}'",)
# Find best matching model (prefer exact/partial matches)
model_name_lower = model_name.lower()
best_match = None
# Try exact match first
for item in items:
if item.get("name", "").lower() == model_name_lower:
best_match = item
break
# If no exact match, try partial match
if not best_match:
for item in items:
item_name_lower = item.get("name", "").lower()
if model_name_lower in item_name_lower or item_name_lower.startswith(model_name_lower):
best_match = item
break
# Fall back to first result if no good match
if not best_match:
best_match = items[0]
model = best_match
model_versions = model.get("modelVersions", [])
if not model_versions:
return ("No model versions found.",)
# If a version keyword is provided, search for a model version whose name contains it (case-insensitive).
chosen_version = None
if version:
for v in model_versions:
if version.lower() in v.get("name", "").lower():
chosen_version = v
break
# If no version is provided or no match was found, use the first (latest) version.
if chosen_version is None:
chosen_version = model_versions[0]
version_id = chosen_version.get("id")
# Fetch detailed version info
version_url = f"https://civitai.com/api/v1/model-versions/{version_id}"
version_response = requests.get(version_url, timeout=10)
if version_response.status_code != 200:
return (f"Error: Version API request failed with status {version_response.status_code}",)
version_data = version_response.json()
# Extract the AutoV3 hash from the model version files
for file_info in version_data.get("files", []):
autov3_hash = file_info.get("hashes", {}).get("AutoV3")
if autov3_hash:
# Cache the result before returning
self.last_username = username
self.last_model_name = model_name
self.last_version = version # Store version to track changes
self.last_hash = autov3_hash
return (autov3_hash,) # Return the first found hash
return ("No AutoV3 hash found in version files.",)
except Exception as e:
return (f"Error: {e}",)