Add stack Update, ComfyUI model manager, and slim ComfyUI stack.
Server UI gains Update on stack cards, ComfyUI Models tab with workflow scan and downloads, and centralized comfyui_config. Model catalog and download scripts move from stacks/comfyui to server-ui so ComfyUI stays a minimal Docker wrapper for easier image updates.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
"""Index ComfyUI-Manager model-list.json for filename → download URL lookup."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from comfyui_config import host_custom_nodes_dir
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
MANAGER_REL_PATHS = (
|
||||
"custom_nodes/ComfyUI-Manager/model-list.json",
|
||||
"custom_nodes/ComfyUI-Manager/node_db/new/model-list.json",
|
||||
)
|
||||
|
||||
|
||||
def _manager_list_paths(data_root: Path) -> list[Path]:
|
||||
base = host_custom_nodes_dir(data_root).parent
|
||||
paths: list[Path] = []
|
||||
for rel in MANAGER_REL_PATHS:
|
||||
path = base / rel
|
||||
if path.is_file():
|
||||
paths.append(path)
|
||||
return paths
|
||||
|
||||
|
||||
def _score_entry(entry: dict[str, Any]) -> tuple[int, int]:
|
||||
"""Prefer entries with URL and shorter save_path."""
|
||||
has_url = 0 if entry.get("url") else 1
|
||||
save_path = str(entry.get("save_path") or "")
|
||||
return (has_url, len(save_path))
|
||||
|
||||
|
||||
def load_manager_index(data_root: Path) -> dict[str, dict[str, Any]]:
|
||||
"""Build filename → best matching ComfyUI-Manager entry."""
|
||||
index: dict[str, dict[str, Any]] = {}
|
||||
for list_path in _manager_list_paths(data_root):
|
||||
try:
|
||||
with list_path.open(encoding="utf-8") as fh:
|
||||
data = json.load(fh)
|
||||
except (OSError, json.JSONDecodeError) as exc:
|
||||
log.warning("Failed to read ComfyUI-Manager list %s: %s", list_path, exc)
|
||||
continue
|
||||
models = data.get("models") if isinstance(data, dict) else None
|
||||
if not isinstance(models, list):
|
||||
continue
|
||||
for entry in models:
|
||||
if not isinstance(entry, dict):
|
||||
continue
|
||||
filename = entry.get("filename")
|
||||
if not isinstance(filename, str) or not filename:
|
||||
continue
|
||||
existing = index.get(filename)
|
||||
if existing is None or _score_entry(entry) < _score_entry(existing):
|
||||
index[filename] = entry
|
||||
return index
|
||||
|
||||
|
||||
def lookup_manager_entry(
|
||||
data_root: Path, filename: str
|
||||
) -> dict[str, Any] | None:
|
||||
return load_manager_index(data_root).get(filename)
|
||||
Reference in New Issue
Block a user