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:
+93
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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/"
|
||||
Reference in New Issue
Block a user