Add custom nodes, Civitai loras (LFS), and vast.ai setup script
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
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
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>
This commit is contained in:
135
custom_nodes/comfyui-image-saver/civitai_nodes.py
Normal file
135
custom_nodes/comfyui-image-saver/civitai_nodes.py
Normal file
@@ -0,0 +1,135 @@
|
||||
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}",)
|
||||
Reference in New Issue
Block a user