Spaces:
Build error
Build error
import requests | |
from dataclasses import dataclass | |
from typing import List | |
import manager_util | |
import toml | |
import os | |
import asyncio | |
import json | |
import time | |
base_url = "https://api.comfy.org" | |
lock = asyncio.Lock() | |
is_cache_loading = False | |
async def get_cnr_data(cache_mode=True, dont_wait=True): | |
try: | |
return await _get_cnr_data(cache_mode, dont_wait) | |
except asyncio.TimeoutError: | |
print("A timeout occurred during the fetch process from ComfyRegistry.") | |
return await _get_cnr_data(cache_mode=True, dont_wait=True) # timeout fallback | |
async def _get_cnr_data(cache_mode=True, dont_wait=True): | |
global is_cache_loading | |
uri = f'{base_url}/nodes' | |
async def fetch_all(): | |
remained = True | |
page = 1 | |
full_nodes = {} | |
while remained: | |
sub_uri = f'{base_url}/nodes?page={page}&limit=30' | |
sub_json_obj = await asyncio.wait_for(manager_util.get_data_with_cache(sub_uri, cache_mode=False, silent=True), timeout=30) | |
remained = page < sub_json_obj['totalPages'] | |
for x in sub_json_obj['nodes']: | |
full_nodes[x['id']] = x | |
if page % 5 == 0: | |
print(f"FETCH ComfyRegistry Data: {page}/{sub_json_obj['totalPages']}") | |
page += 1 | |
time.sleep(0.5) | |
print("FETCH ComfyRegistry Data [DONE]") | |
for v in full_nodes.values(): | |
if 'latest_version' not in v: | |
v['latest_version'] = dict(version='nightly') | |
return {'nodes': list(full_nodes.values())} | |
if cache_mode: | |
is_cache_loading = True | |
cache_state = manager_util.get_cache_state(uri) | |
if dont_wait: | |
if cache_state == 'not-cached': | |
return {} | |
else: | |
print("[ComfyUI-Manager] The ComfyRegistry cache update is still in progress, so an outdated cache is being used.") | |
with open(manager_util.get_cache_path(uri), 'r', encoding="UTF-8", errors="ignore") as json_file: | |
return json.load(json_file)['nodes'] | |
if cache_state == 'cached': | |
with open(manager_util.get_cache_path(uri), 'r', encoding="UTF-8", errors="ignore") as json_file: | |
return json.load(json_file)['nodes'] | |
try: | |
json_obj = await fetch_all() | |
manager_util.save_to_cache(uri, json_obj) | |
return json_obj['nodes'] | |
except: | |
res = {} | |
print("Cannot connect to comfyregistry.") | |
finally: | |
if cache_mode: | |
is_cache_loading = False | |
return res | |
class NodeVersion: | |
changelog: str | |
dependencies: List[str] | |
deprecated: bool | |
id: str | |
version: str | |
download_url: str | |
def map_node_version(api_node_version): | |
""" | |
Maps node version data from API response to NodeVersion dataclass. | |
Args: | |
api_data (dict): The 'node_version' part of the API response. | |
Returns: | |
NodeVersion: An instance of NodeVersion dataclass populated with data from the API. | |
""" | |
return NodeVersion( | |
changelog=api_node_version.get( | |
"changelog", "" | |
), # Provide a default value if 'changelog' is missing | |
dependencies=api_node_version.get( | |
"dependencies", [] | |
), # Provide a default empty list if 'dependencies' is missing | |
deprecated=api_node_version.get( | |
"deprecated", False | |
), # Assume False if 'deprecated' is not specified | |
id=api_node_version[ | |
"id" | |
], # 'id' should be mandatory; raise KeyError if missing | |
version=api_node_version[ | |
"version" | |
], # 'version' should be mandatory; raise KeyError if missing | |
download_url=api_node_version.get( | |
"downloadUrl", "" | |
), # Provide a default value if 'downloadUrl' is missing | |
) | |
def install_node(node_id, version=None): | |
""" | |
Retrieves the node version for installation. | |
Args: | |
node_id (str): The unique identifier of the node. | |
version (str, optional): Specific version of the node to retrieve. If omitted, the latest version is returned. | |
Returns: | |
NodeVersion: Node version data or error message. | |
""" | |
if version is None: | |
url = f"{base_url}/nodes/{node_id}/install" | |
else: | |
url = f"{base_url}/nodes/{node_id}/install?version={version}" | |
response = requests.get(url) | |
if response.status_code == 200: | |
# Convert the API response to a NodeVersion object | |
return map_node_version(response.json()) | |
else: | |
return None | |
def all_versions_of_node(node_id): | |
url = f"{base_url}/nodes/{node_id}/versions?statuses=NodeVersionStatusActive&statuses=NodeVersionStatusPending" | |
response = requests.get(url) | |
if response.status_code == 200: | |
return response.json() | |
else: | |
return None | |
def read_cnr_info(fullpath): | |
try: | |
toml_path = os.path.join(fullpath, 'pyproject.toml') | |
tracking_path = os.path.join(fullpath, '.tracking') | |
if not os.path.exists(toml_path) or not os.path.exists(tracking_path): | |
return None # not valid CNR node pack | |
with open(toml_path, "r", encoding="utf-8") as f: | |
data = toml.load(f) | |
project = data.get('project', {}) | |
name = project.get('name').strip().lower() | |
version = project.get('version') | |
urls = project.get('urls', {}) | |
repository = urls.get('Repository') | |
if name and version: # repository is optional | |
return { | |
"id": name, | |
"version": version, | |
"url": repository | |
} | |
return None | |
except Exception: | |
return None # not valid CNR node pack | |
def generate_cnr_id(fullpath, cnr_id): | |
cnr_id_path = os.path.join(fullpath, '.git', '.cnr-id') | |
try: | |
if not os.path.exists(cnr_id_path): | |
with open(cnr_id_path, "w") as f: | |
return f.write(cnr_id) | |
except: | |
print(f"[ComfyUI Manager] unable to create file: {cnr_id_path}") | |
def read_cnr_id(fullpath): | |
cnr_id_path = os.path.join(fullpath, '.git', '.cnr-id') | |
try: | |
if os.path.exists(cnr_id_path): | |
with open(cnr_id_path) as f: | |
return f.read().strip() | |
except: | |
pass | |
return None | |