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:
tomasz-syn-grzegorza
2026-07-05 18:45:17 +00:00
parent 359afb3a59
commit 73e4fc005e
33 changed files with 3604 additions and 307 deletions
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env bash
# Shared helpers for comfyui-models.catalog.yaml (simple parser, no PyYAML required).
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SERVER_UI_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
CATALOG_FILE="${CATALOG_FILE:-${SERVER_UI_DIR}/comfyui-models.catalog.yaml}"
catalog_list_ids() {
grep '^ - id:' "${CATALOG_FILE}" | awk '{print $3}'
}
catalog_get_field() {
local model_id="$1"
local field="$2"
awk -v id="${model_id}" -v key="${field}:" '
$0 ~ "^ - id: " id "$" { found=1; next }
found && $0 ~ "^ - id:" { exit }
found && index($0, key) == 5 { sub(/^ [^:]+: /, ""); print; exit }
' "${CATALOG_FILE}"
}
catalog_category_dir() {
local category="$1"
case "${category}" in
checkpoint) echo "checkpoints" ;;
lora) echo "loras" ;;
vae) echo "vae" ;;
controlnet) echo "controlnet" ;;
upscale) echo "upscale_models" ;;
latent_upscale) echo "latent_upscale_models" ;;
text_encoder) echo "text_encoders" ;;
diffusion_models) echo "diffusion_models" ;;
clip) echo "clip" ;;
unet) echo "unet" ;;
*) echo "${category}" ;;
esac
}
catalog_dest_path() {
local model_id="$1"
local data_root="${2:-${DATA_ROOT:-/data}}"
local local_path category filename subdir
local_path="$(catalog_get_field "${model_id}" local_path)"
if [[ -n "${local_path}" ]]; then
echo "${local_path}"
return
fi
category="$(catalog_get_field "${model_id}" category)"
filename="$(catalog_get_field "${model_id}" filename)"
subdir="$(catalog_category_dir "${category}")"
echo "${data_root}/apps/comfyui/models/${subdir}/${filename}"
}
catalog_ensure_dirs() {
local data_root="${1:-/data}"
mkdir -p \
"${data_root}/apps/comfyui/storage" \
"${data_root}/apps/comfyui/models/checkpoints" \
"${data_root}/apps/comfyui/models/loras" \
"${data_root}/apps/comfyui/models/vae" \
"${data_root}/apps/comfyui/models/controlnet" \
"${data_root}/apps/comfyui/models/upscale_models" \
"${data_root}/apps/comfyui/models/latent_upscale_models" \
"${data_root}/apps/comfyui/models/text_encoders" \
"${data_root}/apps/comfyui/models/diffusion_models" \
"${data_root}/apps/comfyui/models/clip" \
"${data_root}/apps/comfyui/models/unet" \
"${data_root}/apps/comfyui/cache/hf-hub" \
"${data_root}/apps/comfyui/cache/torch-hub" \
"${data_root}/apps/comfyui/input" \
"${data_root}/apps/comfyui/output" \
"${data_root}/apps/comfyui/custom_nodes" \
"${data_root}/apps/comfyui/workflows"
}
catalog_model_downloaded() {
local model_id="$1"
local dest
dest="$(catalog_dest_path "${model_id}")"
[[ -f "${dest}" ]]
}
load_comfyui_stack_env() {
local repo_root
repo_root="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
local env_file="${repo_root}/stacks/comfyui/.env"
if [[ -f "${env_file}" ]]; then
set -a
# shellcheck disable=SC1090
source "${env_file}"
set +a
fi
}
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/catalog-lib.sh"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/download-http-lib.sh"
URL=""
DEST=""
while [[ $# -gt 0 ]]; do
case "$1" in
--url)
URL="${2:-}"
shift 2
;;
--dest)
DEST="${2:-}"
shift 2
;;
*)
echo "Usage: $0 --url URL --dest /absolute/path/to/file"
exit 1
;;
esac
done
if [[ -z "${URL}" || -z "${DEST}" ]]; then
echo "Usage: $0 --url URL --dest /absolute/path/to/file"
exit 1
fi
load_comfyui_stack_env
DATA_ROOT="${DATA_ROOT:-/data}"
MODELS_ROOT="${DATA_ROOT}/apps/comfyui/models"
if [[ "${DEST}" != "${MODELS_ROOT}"/* ]]; then
echo "ERROR: Destination must be under ${MODELS_ROOT}"
exit 1
fi
if [[ -f "${DEST}" ]]; then
echo "Already exists: ${DEST}"
echo ""
echo "Done."
exit 0
fi
mkdir -p "$(dirname "${DEST}")"
download_http_file "${URL}" "${DEST}"
if [[ ! -f "${DEST}" ]]; then
echo "ERROR: Download finished but file missing: ${DEST}"
exit 1
fi
echo ""
echo "Done."
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# Shared HTTP download helpers for ComfyUI model scripts.
# shellcheck disable=SC2034
download_http_file() {
local url="$1"
local dest="$2"
local data_root="${DATA_ROOT:-/data}"
local dest_dir
dest_dir="$(dirname "${dest}")"
echo "Downloading ${url} ..."
echo "Target: ${dest}"
if [[ -w "${dest_dir}" ]]; then
if [[ -n "${HF_TOKEN:-}" ]]; then
if command -v wget >/dev/null 2>&1; then
wget -c --progress=dot:giga \
--header="Authorization: Bearer ${HF_TOKEN}" \
-O "${dest}" "${url}"
else
curl -fL -C - \
-H "Authorization: Bearer ${HF_TOKEN}" \
-o "${dest}" "${url}"
fi
else
if command -v wget >/dev/null 2>&1; then
wget -c --progress=dot:giga -O "${dest}" "${url}"
else
curl -fL -C - -o "${dest}" "${url}"
fi
fi
return
fi
if docker ps --format '{{.Names}}' 2>/dev/null | grep -qx 'comfyui'; then
local container_dest="/root/ComfyUI/models${dest#"${data_root}/apps/comfyui/models"}"
echo "Host directory not writable — using comfyui container: ${container_dest}"
if [[ -n "${HF_TOKEN:-}" ]]; then
docker exec comfyui wget -c --progress=dot:giga \
--header="Authorization: Bearer ${HF_TOKEN}" \
-O "${container_dest}" "${url}"
else
docker exec comfyui wget -c --progress=dot:giga \
-O "${container_dest}" "${url}"
fi
return
fi
echo "ERROR: Cannot write to ${dest_dir}"
echo "Fix: sudo chown -R \$USER:\$USER ${data_root}/apps/comfyui/models"
echo "Or start ComfyUI: cd stacks/comfyui && ./scripts/start.sh"
exit 1
}
+105
View File
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/catalog-lib.sh"
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <catalog-model-id>"
echo ""
echo "Available models:"
catalog_list_ids | sed 's/^/ /'
exit 1
fi
MODEL_ID="$1"
if ! catalog_list_ids | grep -qx "${MODEL_ID}"; then
echo "ERROR: Unknown model id: ${MODEL_ID}"
echo "Run: ${SCRIPT_DIR}/list-models.sh"
exit 1
fi
load_comfyui_stack_env
DATA_ROOT="${DATA_ROOT:-/data}"
catalog_ensure_dirs "${DATA_ROOT}"
SOURCE="$(catalog_get_field "${MODEL_ID}" source)"
NAME="$(catalog_get_field "${MODEL_ID}" name)"
DEST="$(catalog_dest_path "${MODEL_ID}" "${DATA_ROOT}")"
echo "=== Download: ${NAME} (${MODEL_ID}) ==="
echo "Source: ${SOURCE}"
echo "Target: ${DEST}"
echo ""
if [[ -f "${DEST}" ]]; then
echo "Already exists: ${DEST}"
echo ""
echo "Done."
exit 0
fi
mkdir -p "$(dirname "${DEST}")"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/download-http-lib.sh"
case "${SOURCE}" in
huggingface)
HF_REPO="$(catalog_get_field "${MODEL_ID}" hf_repo)"
FILENAME="$(catalog_get_field "${MODEL_ID}" filename)"
DOWNLOAD_URL="$(catalog_get_field "${MODEL_ID}" download_url)"
HF_REVISION="$(catalog_get_field "${MODEL_ID}" hf_revision)"
REVISION="${HF_REVISION:-main}"
if [[ -n "${DOWNLOAD_URL}" ]]; then
URL="${DOWNLOAD_URL}"
elif [[ -n "${HF_REPO}" && -n "${FILENAME}" ]]; then
URL="https://huggingface.co/${HF_REPO}/resolve/${REVISION}/${FILENAME}"
else
echo "ERROR: Catalog entry missing download_url or hf_repo/filename"
exit 1
fi
download_http_file "${URL}" "${DEST}"
;;
url)
DOWNLOAD_URL="$(catalog_get_field "${MODEL_ID}" download_url)"
if [[ -z "${DOWNLOAD_URL}" ]]; then
echo "ERROR: Catalog entry missing download_url"
exit 1
fi
download_http_file "${DOWNLOAD_URL}" "${DEST}"
;;
civitai)
CIVITAI_MODEL_ID="$(catalog_get_field "${MODEL_ID}" civitai_model_id)"
if [[ -z "${CIVITAI_MODEL_ID}" ]]; then
echo "ERROR: Catalog entry missing civitai_model_id"
exit 1
fi
if [[ -z "${CIVITAI_TOKEN:-}" ]]; then
echo "ERROR: CIVITAI_TOKEN not set in stacks/comfyui/.env"
exit 1
fi
curl -fL \
-H "Authorization: Bearer ${CIVITAI_TOKEN}" \
-o "${DEST}" \
"https://civitai.com/api/download/models/${CIVITAI_MODEL_ID}"
;;
*)
echo "ERROR: Unknown source: ${SOURCE}"
exit 1
;;
esac
if [[ ! -f "${DEST}" ]]; then
echo "ERROR: Download finished but file missing: ${DEST}"
exit 1
fi
echo ""
echo "Done."
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
source "${SCRIPT_DIR}/catalog-lib.sh"
load_comfyui_stack_env
DATA_ROOT="${DATA_ROOT:-/data}"
catalog_ensure_dirs "${DATA_ROOT}"
echo "=== ComfyUI model catalog ==="
echo "Catalog: ${CATALOG_FILE}"
echo "Data: ${DATA_ROOT}"
echo ""
printf "%-24s %-12s %-8s %s\n" "ID" "CATEGORY" "ON DISK" "NAME"
printf "%-24s %-12s %-8s %s\n" "----" "--------" "-------" "----"
while IFS= read -r model_id; do
name="$(catalog_get_field "${model_id}" name)"
category="$(catalog_get_field "${model_id}" category)"
if catalog_model_downloaded "${model_id}"; then
on_disk="yes"
else
on_disk="no"
fi
printf "%-24s %-12s %-8s %s\n" "${model_id}" "${category}" "${on_disk}" "${name}"
done < <(catalog_list_ids)
echo ""
echo "Download on demand: ${SCRIPT_DIR}/download-model.sh <id>"
echo "Target root: ${DATA_ROOT}/apps/comfyui/models/"