From c43905f8064451784b4d965b73c6812a3ad1cce1 Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Sat, 27 Dec 2025 16:21:59 +0800 Subject: [PATCH 01/10] feat: add comfyui model downloader Change-Id: I42aade4e2cd49744d7810404be34c0041700cef9 Co-developed-by: Cursor --- src/code/agent/services/model/__init__.py | 1 + src/code/comfyui/models/README.md | 282 ++++ src/code/comfyui/models/cal_checksum.py | 384 +++++ src/code/comfyui/models/download_models.sh | 376 +++++ src/code/comfyui/models/extract_models.py | 273 ++++ src/code/comfyui/models/models_20251220.json | 1491 ++++++++++++++++++ src/code/comfyui/models/models_nunchaku.json | 86 + 7 files changed, 2893 insertions(+) create mode 100644 src/code/comfyui/models/README.md create mode 100755 src/code/comfyui/models/cal_checksum.py create mode 100755 src/code/comfyui/models/download_models.sh create mode 100755 src/code/comfyui/models/extract_models.py create mode 100644 src/code/comfyui/models/models_20251220.json create mode 100644 src/code/comfyui/models/models_nunchaku.json diff --git a/src/code/agent/services/model/__init__.py b/src/code/agent/services/model/__init__.py index ba0dd75e..710e7d52 100644 --- a/src/code/agent/services/model/__init__.py +++ b/src/code/agent/services/model/__init__.py @@ -3,3 +3,4 @@ 提供模型链接和监听功能 """ + diff --git a/src/code/comfyui/models/README.md b/src/code/comfyui/models/README.md new file mode 100644 index 00000000..a7d2d733 --- /dev/null +++ b/src/code/comfyui/models/README.md @@ -0,0 +1,282 @@ +# ComfyUI 模型下载工具 + +从 ComfyUI 模板中提取模型信息,批量下载并验证文件完整性的工具集。 + +## 📁 工具脚本 + +| 脚本 | 功能 | +|------|------| +| `extract_models.py` | 从模板中提取模型信息 | +| `download_models.sh` | 批量下载模型文件 | +| `cal_checksum.py` | 验证文件 SHA256 完整性 | + +## 🚀 使用流程 + +### 准备工作 + +安装依赖: +```bash +pip install huggingface_hub +``` + +### 第 1 步:提取模型信息 + +从 `templates` 目录提取所有模板使用的模型信息: + +```bash +cd models +python3 extract_models.py +``` + +**输出**:`models_20251225.json`(自动生成当前日期) + +### 第 2 步:下载模型 + +根据提取的配置文件下载模型: + +```bash +# 下载所有模型(使用国内镜像加速) +./download_models.sh models_20251220.json /root/ComfyUI/models --use-mirror + +# 只下载指定目录的模型(推荐) +./download_models.sh models_20251220.json /root/ComfyUI/models --use-mirror --dirs vae loras + +# 支持多个目录 +./download_models.sh models_20251220.json /root/ComfyUI/models --use-mirror --dirs unet clip vae loras +``` + +**参数说明**: +- `models_*.json`:第 1 步生成的配置文件 +- `/root/ComfyUI/models`:下载目标目录 +- `--use-mirror`:使用国内镜像(https://hf-mirror.com) +- `--dirs <目录...>`:只下载指定目录的模型 + +**功能特性**: +- ✅ 自动创建目录结构 +- ✅ 跳过已存在的文件 +- ✅ 失败自动重试 3 次 +- ✅ 显示详细的下载进度和统计 + +### 第 3 步:验证完整性 + +验证下载的文件是否完整: + +```bash +# 验证所有模型 +python3 cal_checksum.py /root/ComfyUI/models models_20251220.json + +# 只验证指定目录 +python3 cal_checksum.py /root/ComfyUI/models models_20251220.json --dir vae + +# 使用国内镜像获取 SHA256(推荐) +export HF_ENDPOINT="https://hf-mirror.com" +python3 cal_checksum.py /root/ComfyUI/models models_20251220.json +``` + +**验证结果**: +- ✅ **一致**:文件完整 +- ❌ **不一致**:需要重新下载 +- ⚠️ **错误**:无法验证(非 HF 链接或缺少 URL) + +如有不一致的文件,删除后重新运行第 2 步: +```bash +rm /root/ComfyUI/models/loras/problematic_model.safetensors +./download_models.sh models_20251225.json /root/ComfyUI/models --use-mirror --dirs loras +``` + +## 💡 使用技巧 + +### 按需下载,节省时间和空间 + +根据实际需要,先下载关键模型: + +```bash +# 先下载小文件 +./download_models.sh models_20251225.json /root/models --use-mirror --dirs vae loras clip + +# 网络稳定时再下载大模型 +./download_models.sh models_20251225.json /root/models --use-mirror --dirs unet checkpoints +``` + +### 查看可用目录 + +查看配置文件中包含哪些目录: + +```bash +python3 -c " +import json +from collections import Counter +with open('models_20251225.json') as f: + data = json.load(f) +dirs = Counter(info.get('directory', 'unknown') for info in data.values()) +for dir_name, count in sorted(dirs.items()): + print(f'{dir_name}: {count} 个模型') +" +``` + +常见目录: +- `unet`:UNET 模型(通常较大) +- `vae`:VAE 编码器 +- `clip`:CLIP 文本编码器 +- `loras`:LoRA 微调模型 +- `checkpoints`:完整检查点 +- `controlnet`:ControlNet 控制模型 +- `clip_vision`:CLIP 视觉编码器 + +## 📊 输出示例 + +### 提取模型信息 + +``` +============================== +提取 ComfyUI 模板中的模型信息 +============================== +模板目录: ../templates + +正在分析模板文件... +找到 206 个模板文件 +✓ 找到 130 个独特的模型文件 +✓ 已生成: models_20251220.json + +按目录分布: + unet : 46 个 + loras : 18 个 + checkpoints: 19 个 + vae : 10 个 + ... +``` + +### 下载模型 + +``` +====================================== +开始下载 ComfyUI 模型 +====================================== +模型配置: models_20251220.json +目标目录: /root/ComfyUI/models +筛选目录: vae loras + +可用目录: audio checkpoints clip controlnet loras unet vae +要下载 28 个模型 + +[1/28] vae-ft-mse-840000-ema-pruned.safetensors + 目录: vae + 下载中... + ✓ 下载完成 + +[2/28] flux1-depth-dev-lora.safetensors + 目录: loras + ✓ 已存在,跳过 +... + +====================================== +下载完成! +====================================== +成功: 22 +跳过: 5 +失败: 1 +总计: 28 +====================================== +``` + +### 验证完整性 + +``` +================================================================================ +🔍 ComfyUI 模型 SHA256 验证工具 +================================================================================ +✓ 找到 28 个模型文件 + +[1/28] 验证: vae/vae-ft-mse.safetensors + 计算本地 SHA256... + 从 Hugging Face 获取 SHA256... +✅ 状态: 一致 +... + +================================================================================ +📊 验证总结 +================================================================================ +总文件数: 28 +✅ 一致: 27 +❌ 不一致: 1 + +⚠️ 以下模型 SHA256 不一致,建议重新下载: + • loras/problematic_model.safetensors +================================================================================ +``` + +## ⚠️ 常见问题 + +### 1. 下载速度慢 + +**解决方案**:使用 `--use-mirror` 启用国内镜像加速 + +```bash +./download_models.sh models_20251225.json /root/models --use-mirror +``` + +### 2. 找不到 hf 命令 + +**解决方案**: +```bash +pip install -U huggingface_hub +``` + +### 3. 下载失败 + +**解决方案**: +1. 检查网络连接 +2. 使用镜像加速(`--use-mirror`) +3. 检查磁盘空间:`df -h` +4. 脚本会自动重试 3 次,失败后可手动重新运行 + +### 4. SHA256 不一致 + +**原因**:文件下载不完整或损坏 + +**解决方案**:删除文件后重新下载 +```bash +rm /path/to/problematic_model.safetensors +./download_models.sh models_20251225.json /root/models --use-mirror +``` + +## 🌐 永久配置国内镜像 + +在 `~/.bashrc` 或 `~/.zshrc` 中添加: + +```bash +export HF_ENDPOINT="https://hf-mirror.com" +``` + +然后重新加载: +```bash +source ~/.bashrc # 或 source ~/.zshrc +``` + +配置后,无需每次都加 `--use-mirror` 参数。 + +## 📖 工作原理 + +### extract_models.py +1. 扫描 `templates` 目录的所有 JSON 文件 +2. 解析节点中的模型文件名和下载链接 +3. 根据节点类型推断存储目录 +4. 生成 `models_{日期}.json` 配置文件 + +### download_models.sh +1. 读取配置文件中的模型信息 +2. 根据 `--dirs` 参数筛选目录(可选) +3. 检查文件是否已存在,存在则跳过 +4. 使用 `hf download` 命令下载 +5. 失败自动重试,最多 3 次 +6. 生成下载统计报告 + +### cal_checksum.py +1. 扫描指定目录的模型文件 +2. 计算本地文件的 SHA256 +3. 从 Hugging Face API 获取远程 SHA256 +4. 比对并生成验证报告 + +--- + +**提示**:建议使用 `--dirs` 参数按需下载,避免下载不需要的大模型,节省时间和磁盘空间。 diff --git a/src/code/comfyui/models/cal_checksum.py b/src/code/comfyui/models/cal_checksum.py new file mode 100755 index 00000000..10cc6dc7 --- /dev/null +++ b/src/code/comfyui/models/cal_checksum.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python3 +""" +计算并验证模型文件的 SHA256 完整性 + +功能: +- 扫描指定目录下的所有模型文件 +- 计算本地文件的 SHA256 +- 从 Hugging Face 获取远程文件的 SHA256 +- 比较并报告不一致的文件 + +依赖: + pip install huggingface_hub + +使用方法: + python3 cal_checksum.py /path/to/models models_20251225.json + python3 cal_checksum.py /path/to/models models_20251225.json --dir unet +""" + +import argparse +import hashlib +import json +import os +import re +import sys +from pathlib import Path +from typing import Dict, List, Optional, Tuple + +try: + from huggingface_hub import HfApi +except ImportError: + print("❌ 错误: 请先安装 huggingface_hub") + print("运行: pip install huggingface_hub") + sys.exit(1) + + +def calculate_sha256(filepath: str) -> str: + """计算本地文件的 SHA256""" + sha256_hash = hashlib.sha256() + file_size = os.path.getsize(filepath) + + print(f" 计算中... (文件大小: {file_size / (1024**3):.2f} GB)") + + with open(filepath, "rb") as f: + # 使用较大的缓冲区以提高性能 + for byte_block in iter(lambda: f.read(8192 * 1024), b""): + sha256_hash.update(byte_block) + + return sha256_hash.hexdigest() + + +def parse_hf_url(url: str) -> Optional[Dict[str, str]]: + """ + 解析 Hugging Face URL,提取 repo_id 和 file_path + + URL 格式: + - https://huggingface.co/{repo_id}/resolve/{revision}/{file_path} + - https://huggingface.co/{repo_id}/blob/{revision}/{file_path} + """ + if not url or not url.startswith('https://huggingface.co/'): + return None + + # 移除 query string + url = url.split('?')[0] + + # 匹配模式 + pattern = r'https://huggingface\.co/([^/]+/[^/]+)/(resolve|blob)/([^/]+)/(.+)' + match = re.match(pattern, url) + + if match: + repo_id = match.group(1) + revision = match.group(3) + file_path = match.group(4) + return { + 'repo_id': repo_id, + 'revision': revision, + 'file_path': file_path + } + + return None + + +def get_hf_file_sha256(repo_id: str, filename: str, revision: str = "main") -> Optional[str]: + """通过 HuggingFace Hub SDK 获取文件的 SHA256""" + try: + # 使用 HfApi,会自动使用 HF_ENDPOINT 环境变量 + api = HfApi() + + # 获取仓库文件树 + repo_files = api.list_repo_tree( + repo_id=repo_id, + revision=revision, + recursive=True + ) + + # 查找目标文件 + for file_info in repo_files: + # 跳过目录 + if not hasattr(file_info, 'path'): + continue + + file_path = file_info.path + + # 匹配文件路径 + if file_path == filename or file_path.endswith('/' + filename): + # 检查是否有 LFS 信息 + if hasattr(file_info, 'lfs') and file_info.lfs: + if hasattr(file_info.lfs, 'sha256'): + return file_info.lfs.sha256.lower() + # 有些文件可能在 oid 中 + if hasattr(file_info.lfs, 'oid') and file_info.lfs.oid.startswith('sha256:'): + return file_info.lfs.oid.replace('sha256:', '').lower() + + return None + + except Exception as e: + print(f" ⚠️ 获取远程 SHA256 失败: {e}") + return None + + +def find_model_files(base_dir: str, target_subdir: Optional[str] = None) -> List[Tuple[str, str, str]]: + """ + 查找所有模型文件 + + 返回: [(完整路径, 相对目录, 文件名), ...] + """ + base_path = Path(base_dir) + if not base_path.exists(): + print(f"❌ 错误: 目录不存在: {base_dir}") + sys.exit(1) + + model_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'} + found_files = [] + + # 如果指定了子目录 + if target_subdir: + search_path = base_path / target_subdir + if not search_path.exists(): + print(f"❌ 错误: 子目录不存在: {search_path}") + sys.exit(1) + search_paths = [search_path] + else: + # 搜索所有子目录 + search_paths = [base_path] + + for search_path in search_paths: + for root, dirs, files in os.walk(search_path): + for filename in files: + if any(filename.endswith(ext) for ext in model_extensions): + full_path = os.path.join(root, filename) + # 计算相对于 base_dir 的目录 + rel_dir = os.path.relpath(root, base_path) + found_files.append((full_path, rel_dir, filename)) + + return sorted(found_files) + + +def load_models_mapping(json_file: str) -> Dict[str, Dict]: + """从 models_*.json 加载模型映射""" + json_path = Path(json_file) + + if not json_path.exists(): + print(f"❌ 错误: 文件不存在: {json_file}") + sys.exit(1) + + try: + with open(json_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + print(f"❌ 错误: 读取 {json_file} 失败: {e}") + sys.exit(1) + + +def verify_model_file( + file_path: str, + rel_dir: str, + filename: str, + models_mapping: Dict +) -> Dict: + """ + 验证单个模型文件 + + 返回验证结果字典 + """ + result = { + 'path': file_path, + 'dir': rel_dir, + 'filename': filename, + 'local_sha256': None, + 'remote_sha256': None, + 'match': None, + 'error': None + } + + # 计算本地 SHA256 + try: + print(f" 计算本地 SHA256...") + result['local_sha256'] = calculate_sha256(file_path) + except Exception as e: + result['error'] = f"计算 SHA256 失败: {e}" + return result + + # 查找对应的远程 URL + model_info = models_mapping.get(filename) + + if not model_info or not model_info.get('url'): + result['error'] = "未找到下载 URL" + return result + + url = model_info['url'] + + # 解析 URL + parsed = parse_hf_url(url) + if not parsed: + result['error'] = f"无法解析 URL (非 Hugging Face 链接)" + return result + + # 从 Hugging Face 获取 SHA256 + print(f" 从 Hugging Face 获取 SHA256...") + print(f" Repo: {parsed['repo_id']}") + print(f" File: {parsed['file_path']}") + + remote_sha256 = get_hf_file_sha256( + parsed['repo_id'], + parsed['file_path'], + parsed['revision'] + ) + + if not remote_sha256: + result['error'] = "无法从 Hugging Face 获取 SHA256" + return result + + result['remote_sha256'] = remote_sha256 + result['match'] = (result['local_sha256'].lower() == remote_sha256.lower()) + + return result + + +def print_result(result: Dict): + """打印单个文件的验证结果""" + print("=" * 80) + print(f"📁 目录: {result['dir']}") + print(f"📄 文件: {result['filename']}") + print("-" * 80) + + if result['error']: + print(f"❌ 错误: {result['error']}") + print("=" * 80) + return + + print(f"本地 SHA256: {result['local_sha256']}") + print(f"远程 SHA256: {result['remote_sha256']}") + + if result['match']: + print(f"✅ 状态: 一致") + else: + print(f"❌ 状态: 不一致") + + print("=" * 80) + + +def print_summary(results: List[Dict]): + """打印验证总结""" + total = len(results) + matched = sum(1 for r in results if r['match'] is True) + mismatched = sum(1 for r in results if r['match'] is False) + errors = sum(1 for r in results if r['error'] is not None) + + print() + print("=" * 80) + print("📊 验证总结") + print("=" * 80) + print(f"总文件数: {total}") + print(f"✅ 一致: {matched}") + print(f"❌ 不一致: {mismatched}") + print(f"⚠️ 错误: {errors}") + print() + + if mismatched > 0: + print("⚠️ 以下模型 SHA256 不一致,建议重新下载:") + print("-" * 80) + for result in results: + if result['match'] is False: + print(f" • {result['dir']}/{result['filename']}") + print() + + if errors > 0: + print("⚠️ 以下模型验证时出错:") + print("-" * 80) + for result in results: + if result['error']: + print(f" • {result['dir']}/{result['filename']}") + print(f" 原因: {result['error']}") + print() + + print("=" * 80) + + +def main(): + parser = argparse.ArgumentParser( + description='计算并验证本地模型文件的 SHA256 完整性', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +示例: + %(prog)s /root/models models_20251225.json + %(prog)s /root/models models_20251225.json --dir unet + %(prog)s ~/ComfyUI/models models_20251225.json --dir loras + """ + ) + + parser.add_argument( + 'base_dir', + help='模型文件所在的基础目录' + ) + + parser.add_argument( + 'models_json', + help='models_*.json 文件路径' + ) + + parser.add_argument( + '--dir', '-d', + dest='subdir', + help='只验证指定子目录(如 unet, loras, vae 等)' + ) + + args = parser.parse_args() + + print("=" * 80) + print("🔍 ComfyUI 模型 SHA256 验证工具") + print("=" * 80) + + # 显示是否使用镜像 + hf_endpoint = os.environ.get('HF_ENDPOINT') + if hf_endpoint: + print(f"✓ 使用 Hugging Face 镜像: {hf_endpoint}") + else: + print("ℹ️ 使用官方 Hugging Face API (huggingface.co)") + print(" 提示: 如需使用镜像,请设置环境变量: export HF_ENDPOINT=\"https://hf-mirror.com\"") + print() + + # 加载模型映射 + print(f"📋 加载模型映射: {args.models_json}") + models_mapping = load_models_mapping(args.models_json) + print(f"✓ 找到 {len(models_mapping)} 个模型的信息") + print() + + # 查找模型文件 + print(f"🔎 扫描目录: {args.base_dir}") + if args.subdir: + print(f" 子目录: {args.subdir}") + + model_files = find_model_files(args.base_dir, args.subdir) + + if not model_files: + print("⚠️ 未找到任何模型文件") + return + + print(f"✓ 找到 {len(model_files)} 个模型文件") + print() + + # 验证每个文件 + results = [] + + for i, (file_path, rel_dir, filename) in enumerate(model_files, 1): + print(f"[{i}/{len(model_files)}] 验证: {rel_dir}/{filename}") + + result = verify_model_file( + file_path, + rel_dir, + filename, + models_mapping + ) + + results.append(result) + print_result(result) + print() + + # 打印总结 + print_summary(results) + + +if __name__ == "__main__": + main() + diff --git a/src/code/comfyui/models/download_models.sh b/src/code/comfyui/models/download_models.sh new file mode 100755 index 00000000..d2b9c151 --- /dev/null +++ b/src/code/comfyui/models/download_models.sh @@ -0,0 +1,376 @@ +#!/bin/bash +# +# 使用 hf download 批量下载 ComfyUI 模型 +# +# 依赖: +# pip install huggingface_hub +# +# 使用方法: +# ./download_models.sh models_20251225.json /path/to/target_dir +# ./download_models.sh models_20251225.json /path/to/target_dir --use-mirror +# ./download_models.sh models_20251225.json /path/to/target_dir --dirs vae loras +# +# 参数: +# $1: models_*.json 文件路径 +# $2: 下载目标目录 +# --use-mirror: 使用国内镜像 (可选) +# --dirs <目录...>: 只下载指定目录的模型 (可选) +# + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 参数检查 +if [ $# -lt 2 ]; then + echo -e "${RED}错误: 参数不足${NC}" + echo "" + echo "使用方法:" + echo " $0 [选项]" + echo "" + echo "选项:" + echo " --use-mirror 使用国内镜像加速" + echo " --dirs <目录...> 只下载指定目录的模型" + echo " -h, --help 显示此帮助信息" + echo "" + echo "示例:" + echo " $0 models_20251225.json /root/models" + echo " $0 models_20251225.json /root/models --use-mirror" + echo " $0 models_20251225.json /root/models --dirs vae" + echo " $0 models_20251225.json /root/models --dirs vae loras unet" + echo " $0 models_20251225.json /root/models --use-mirror --dirs vae" + echo "" + exit 1 +fi + +MODELS_JSON="$1" +TARGET_DIR="$2" +shift 2 + +USE_MIRROR=false +FILTER_DIRS=() + +# 解析可选参数 +while [[ $# -gt 0 ]]; do + case $1 in + --use-mirror) + USE_MIRROR=true + export HF_ENDPOINT="https://hf-mirror.com" + shift + ;; + --dirs|-d) + shift + while [[ $# -gt 0 && ! "$1" =~ ^-- ]]; do + FILTER_DIRS+=("$1") + shift + done + ;; + -h|--help) + echo "使用方法: $0 [选项]" + echo "" + echo "选项:" + echo " --use-mirror 使用国内镜像加速" + echo " --dirs <目录...> 只下载指定目录的模型" + echo " -h, --help 显示此帮助信息" + echo "" + echo "示例:" + echo " $0 models_20251225.json /root/models" + echo " $0 models_20251225.json /root/models --use-mirror" + echo " $0 models_20251225.json /root/models --dirs vae" + echo " $0 models_20251225.json /root/models --dirs vae loras unet --use-mirror" + echo "" + exit 0 + ;; + *) + echo -e "${RED}错误: 未知参数 $1${NC}" + echo "运行 $0 --help 查看帮助" + exit 1 + ;; + esac +done + +if [ "$USE_MIRROR" = true ]; then + echo -e "${BLUE}✓ 使用 Hugging Face 镜像: $HF_ENDPOINT${NC}" +fi + +# 检查文件是否存在 +if [ ! -f "$MODELS_JSON" ]; then + echo -e "${RED}错误: 文件不存在: $MODELS_JSON${NC}" + exit 1 +fi + +# 检查 hf 命令 +if ! command -v hf &> /dev/null; then + echo -e "${RED}错误: 未找到 hf 命令${NC}" + echo "请运行: pip install huggingface_hub" + exit 1 +fi + +# 创建目标目录 +mkdir -p "$TARGET_DIR" + +echo "======================================" +echo "开始下载 ComfyUI 模型" +echo "======================================" +echo -e "${BLUE}模型配置: ${MODELS_JSON}${NC}" +echo -e "${BLUE}目标目录: ${TARGET_DIR}${NC}" +if [ ${#FILTER_DIRS[@]} -gt 0 ]; then + echo -e "${BLUE}筛选目录: ${FILTER_DIRS[*]}${NC}" +fi +echo "" + +# 统计变量 +declare -a SUCCESS_MODELS +declare -a FAILED_MODELS +declare -a SKIPPED_MODELS +SUCCESS=0 +FAILED=0 +SKIPPED=0 + +# 解析 Hugging Face URL +parse_hf_url() { + local url="$1" + + # 移除查询参数(如 ?download=true) + url="${url%%\?*}" + + # 检查是否是 HF URL + if [[ ! "$url" =~ ^https://huggingface\.co/ ]]; then + echo "" + return 1 + fi + + # 提取 repo_id, revision, file_path + # 格式: https://huggingface.co/{repo_id}/resolve/{revision}/{file_path} + if [[ "$url" =~ https://huggingface\.co/([^/]+/[^/]+)/(resolve|blob)/([^/]+)/(.+) ]]; then + REPO_ID="${BASH_REMATCH[1]}" + REVISION="${BASH_REMATCH[3]}" + FILE_PATH="${BASH_REMATCH[4]}" + echo "${REPO_ID}|${REVISION}|${FILE_PATH}" + return 0 + fi + + echo "" + return 1 +} + +# 下载单个模型 +download_model() { + local model_name="$1" + local url="$2" + local directory="$3" + local target_path="$TARGET_DIR/$directory" + + # 创建目录 + mkdir -p "$target_path" + + # 检查文件是否已存在 + if [ -f "$target_path/$model_name" ]; then + echo -e " ${GREEN}✓ 已存在,跳过${NC}" + SKIPPED=$((SKIPPED + 1)) + SKIPPED_MODELS+=("$model_name ($directory)") + return 0 + fi + + # 检查是否有下载地址 + if [ -z "$url" ] || [ "$url" = "null" ]; then + echo -e " ${YELLOW}⚠ 没有下载地址,跳过${NC}" + SKIPPED=$((SKIPPED + 1)) + SKIPPED_MODELS+=("$model_name ($directory) - 无下载地址") + return 0 + fi + + # 解析 URL + local parsed=$(parse_hf_url "$url") + if [ -z "$parsed" ]; then + echo -e " ${YELLOW}⚠ 非 Hugging Face 链接,跳过${NC}" + echo -e " ${YELLOW} URL: $url${NC}" + SKIPPED=$((SKIPPED + 1)) + SKIPPED_MODELS+=("$model_name ($directory) - 非HF链接") + return 0 + fi + + # 提取信息 + IFS='|' read -r REPO_ID REVISION FILE_PATH <<< "$parsed" + + echo -e " ${BLUE}下载中...${NC}" + echo -e " Repo: $REPO_ID" + echo -e " File: $FILE_PATH" + + # 执行下载(最多重试3次) + local max_retries=3 + local retry_delay=5 + + for ((attempt=1; attempt<=max_retries; attempt++)); do + if [ $attempt -gt 1 ]; then + echo -e " ${YELLOW}🔄 重试 $attempt/$max_retries...${NC}" + sleep $retry_delay + fi + + # 显示执行的命令 + if [ $attempt -eq 1 ]; then + echo -e " ${CYAN}执行命令:${NC}" + echo -e " ${CYAN}hf download \"$REPO_ID\" \"$FILE_PATH\" --local-dir \"$target_path\" --revision \"$REVISION\"${NC}" + fi + + # 下载命令 + if hf download "$REPO_ID" "$FILE_PATH" \ + --local-dir "$target_path" \ + --revision "$REVISION" 2>&1; then + + # 检查文件是否在子目录中 + SOURCE_FILE="$target_path/$FILE_PATH" + TARGET_FILE="$target_path/$model_name" + + if [ "$SOURCE_FILE" != "$TARGET_FILE" ] && [ -f "$SOURCE_FILE" ]; then + mv "$SOURCE_FILE" "$TARGET_FILE" 2>/dev/null || true + # 清理空目录 + rmdir "$(dirname "$SOURCE_FILE")" 2>/dev/null || true + fi + + echo -e " ${GREEN}✓ 下载完成${NC}" + SUCCESS=$((SUCCESS + 1)) + SUCCESS_MODELS+=("$model_name ($directory)") + return 0 + fi + done + + # 所有重试都失败 + echo -e " ${RED}✗ 下载失败(已重试 $max_retries 次)${NC}" + FAILED=$((FAILED + 1)) + FAILED_MODELS+=("$model_name ($directory)") + return 1 +} + +# 读取 JSON 并下载 +echo "正在解析模型列表..." + +# 获取可用目录列表 +available_dirs=$(python3 -c " +import json +dirs = set() +with open('$MODELS_JSON', 'r', encoding='utf-8') as f: + data = json.load(f) + for info in data.values(): + dirs.add(info.get('directory', 'unknown')) +print(' '.join(sorted(dirs))) +") + +echo -e "${BLUE}可用目录: $available_dirs${NC}" + +# 验证筛选的目录是否有效 +if [ ${#FILTER_DIRS[@]} -gt 0 ]; then + for filter_dir in "${FILTER_DIRS[@]}"; do + if [[ ! " $available_dirs " =~ " $filter_dir " ]]; then + echo -e "${YELLOW}⚠️ 警告: 目录 '$filter_dir' 在配置文件中不存在${NC}" + fi + done +fi + +# 计算要下载的模型数量 +if [ ${#FILTER_DIRS[@]} -gt 0 ]; then + model_count=$(python3 -c " +import json +with open('$MODELS_JSON', 'r', encoding='utf-8') as f: + data = json.load(f) +filter_dirs = set('${FILTER_DIRS[*]}'.split()) +count = sum(1 for info in data.values() if info.get('directory', 'unknown') in filter_dirs) +print(count) +") +else + model_count=$(python3 -c "import json; data=json.load(open('$MODELS_JSON')); print(len(data))") +fi + +echo -e "${BLUE}要下载 $model_count 个模型${NC}" +echo "" + +current=0 +total_count=0 + +# 使用 Python 解析 JSON 并逐个下载 +python3 -c " +import json +import sys + +with open('$MODELS_JSON', 'r', encoding='utf-8') as f: + data = json.load(f) + +filter_dirs = set('${FILTER_DIRS[*]}'.split()) if '${FILTER_DIRS[*]}' else None + +for model_name, info in data.items(): + url = info.get('url', '') + directory = info.get('directory', 'unknown') + + # 如果指定了目录筛选,只输出匹配的模型 + if filter_dirs and directory not in filter_dirs: + continue + + # 使用特殊分隔符 + sep = '###SEP###' + print(f'{model_name}{sep}{url}{sep}{directory}') +" | while IFS= read -r line; do + # 手动分割,避免空字段问题 + model_name=$(echo "$line" | awk -F'###SEP###' '{print $1}') + url=$(echo "$line" | awk -F'###SEP###' '{print $2}') + directory=$(echo "$line" | awk -F'###SEP###' '{print $3}') + current=$((current + 1)) + echo "[$current/$model_count] $model_name" + echo -e " 目录: ${BLUE}$directory${NC}" + + download_model "$model_name" "$url" "$directory" + echo "" +done + +# 显示总结 +echo "" +echo "======================================" +echo "下载完成!" +echo "======================================" +echo -e "${GREEN}成功: $SUCCESS${NC}" +echo -e "${YELLOW}跳过: $SKIPPED${NC}" +echo -e "${RED}失败: $FAILED${NC}" +echo "总计: $((SUCCESS + SKIPPED + FAILED))" +echo "======================================" + +# 显示成功的模型 +if [ $SUCCESS -gt 0 ]; then + echo "" + echo -e "${GREEN}✓ 成功下载的模型:${NC}" + for model in "${SUCCESS_MODELS[@]}"; do + echo -e " ${GREEN}✓${NC} $model" + done +fi + +# 显示失败的模型 +if [ $FAILED -gt 0 ]; then + echo "" + echo -e "${RED}✗ 失败的模型(建议重新下载):${NC}" + for model in "${FAILED_MODELS[@]}"; do + echo -e " ${RED}✗${NC} $model" + done +fi + +# 显示跳过的模型 +if [ $SKIPPED -gt 0 ] && [ ${#SKIPPED_MODELS[@]} -lt 20 ]; then + echo "" + echo -e "${YELLOW}⚠ 跳过的模型:${NC}" + for model in "${SKIPPED_MODELS[@]}"; do + echo -e " ${YELLOW}⚠${NC} $model" + done +fi + +echo "" +echo "======================================" + +# 如果有失败,返回非零退出码 +if [ $FAILED -gt 0 ]; then + exit 1 +fi + +exit 0 + diff --git a/src/code/comfyui/models/extract_models.py b/src/code/comfyui/models/extract_models.py new file mode 100755 index 00000000..527f99af --- /dev/null +++ b/src/code/comfyui/models/extract_models.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python3 +""" +从 templates 目录的 ComfyUI JSON 文件中提取模型信息 + +功能: +- 扫描 templates 目录下所有 JSON 文件 +- 提取模型名称、下载地址、存储目录 +- 输出为 models_{date}.json 格式 + +使用方法: + python3 extract_models.py + python3 extract_models.py --templates-dir ../workflow_templates/templates +""" + +import json +import os +import re +from datetime import datetime +from collections import defaultdict +from pathlib import Path +from typing import Dict, List, Tuple +import argparse + + +def extract_url_with_balanced_parens(text: str, start_pos: int) -> Tuple[str, int]: + """提取URL,处理平衡的括号""" + depth = 1 + pos = start_pos + while pos < len(text) and depth > 0: + char = text[pos] + if char == '(': + depth += 1 + elif char == ')': + depth -= 1 + if depth == 0: + break + elif char in ' \t\n\r': + break + pos += 1 + return text[start_pos:pos], pos + + +def find_markdown_links(obj, links_list): + """递归查找所有markdown链接""" + if isinstance(obj, dict): + for v in obj.values(): + find_markdown_links(v, links_list) + elif isinstance(obj, list): + for v in obj: + find_markdown_links(v, links_list) + elif isinstance(obj, str): + # Markdown链接格式: [filename.safetensors](url) + pattern = r'\[([^\]]+?\.(?:safetensors|ckpt|pt|pth|bin))\]\(' + for match in re.finditer(pattern, obj): + text_name = match.group(1) + start_pos = match.end() + url, _ = extract_url_with_balanced_parens(obj, start_pos) + links_list.append({ + 'name': text_name, + 'url': url + }) + + +def get_model_directory(node_type: str, file_name: str = '') -> str: + """根据节点类型和文件名确定模型存储目录""" + node_type_lower = node_type.lower() + file_name_lower = file_name.lower() + + # 基于节点类型的映射 + if 'unet' in node_type_lower: + return 'unet' + elif 'vae' in node_type_lower: + return 'vae' + elif 'clip' in node_type_lower: + if 'vision' in node_type_lower: + return 'clip_vision' + return 'clip' + elif 'lora' in node_type_lower: + return 'loras' + elif 'checkpoint' in node_type_lower: + return 'checkpoints' + elif 'controlnet' in node_type_lower: + return 'controlnet' + elif 'upscale' in node_type_lower or 'upscaler' in node_type_lower: + return 'upscale_models' + elif 'audio' in node_type_lower: + return 'audio' + elif 'sam' in node_type_lower or 'sam2' in node_type_lower: + return 'sams' + elif 'style' in node_type_lower: + return 'style_models' + + # 基于文件名的推断 + if 'lora' in file_name_lower: + return 'loras' + elif 'vae' in file_name_lower: + return 'vae' + elif 'controlnet' in file_name_lower or 'control' in file_name_lower: + return 'controlnet' + elif 'upscale' in file_name_lower: + return 'upscale_models' + + return 'unknown' + + +def analyze_template_file(file_path: str) -> Dict: + """分析单个模板文件""" + try: + with open(file_path, 'r', encoding='utf-8') as f: + data = json.load(f) + except Exception as e: + return {'error': str(e)} + + result = { + 'file': os.path.basename(file_path), + 'models': [] + } + + # 提取所有markdown链接 + markdown_links = [] + find_markdown_links(data, markdown_links) + + # 创建URL查找字典 + url_map = {link['name']: link['url'] for link in markdown_links} + + # 分析节点 + nodes = data.get('nodes', []) + for node in nodes: + node_type = node.get('type', '') + node_id = node.get('id', '') + widgets_values = node.get('widgets_values', []) + + # 跳过 MarkdownNote 节点(它们只是文档说明) + if node_type.lower() in ['markdownnote', 'note']: + continue + + # 查找所有包含模型文件的widgets_values + for widget_value in widgets_values: + if isinstance(widget_value, str) and any(ext in widget_value for ext in ['.safetensors', '.ckpt', '.pt', '.pth', '.bin']): + model_dir = get_model_directory(node_type, widget_value) + url = url_map.get(widget_value, '') + + result['models'].append({ + 'name': widget_value, + 'url': url, + 'directory': model_dir, + 'node_type': node_type + }) + + return result + + +def analyze_all_templates(templates_dir: str) -> Dict: + """分析所有模板文件""" + all_models = defaultdict(lambda: { + 'url': '', + 'directory': '', + 'node_types': set(), + 'used_in_templates': [] + }) + + template_files = [] + for filename in sorted(os.listdir(templates_dir)): + if filename.endswith('.json') and not filename.startswith('index.'): + template_files.append(filename) + + print(f"找到 {len(template_files)} 个模板文件") + + for filename in template_files: + file_path = os.path.join(templates_dir, filename) + result = analyze_template_file(file_path) + + if 'error' in result: + print(f"⚠️ 处理 {filename} 时出错: {result['error']}") + continue + + for model in result['models']: + model_name = model['name'] + if not all_models[model_name]['url'] and model['url']: + all_models[model_name]['url'] = model['url'] + if not all_models[model_name]['directory'] and model['directory']: + all_models[model_name]['directory'] = model['directory'] + all_models[model_name]['node_types'].add(model['node_type']) + if filename not in all_models[model_name]['used_in_templates']: + all_models[model_name]['used_in_templates'].append(filename) + + # 转换为最终格式 + output = {} + for model_name, info in all_models.items(): + output[model_name] = { + 'url': info['url'], + 'directory': info['directory'], + 'node_types': sorted(list(info['node_types'])), + 'used_in_templates': info['used_in_templates'] + } + + return output + + +def main(): + parser = argparse.ArgumentParser( + description='从 ComfyUI 模板文件中提取模型信息', + formatter_class=argparse.RawDescriptionHelpFormatter + ) + + parser.add_argument( + '--templates-dir', + default='../workflow_templates/templates', + help='模板文件所在目录(默认: ../workflow_templates/templates)' + ) + + args = parser.parse_args() + + templates_dir = Path(__file__).parent / args.templates_dir + + if not templates_dir.exists(): + print(f"❌ 错误: 目录不存在: {templates_dir}") + return + + print("=" * 60) + print("提取 ComfyUI 模板中的模型信息") + print("=" * 60) + print(f"模板目录: {templates_dir}") + print() + + print("正在分析模板文件...") + models_data = analyze_all_templates(str(templates_dir)) + + print(f"✓ 找到 {len(models_data)} 个独特的模型文件") + + # 生成输出文件名 + date_str = datetime.now().strftime("%Y%m%d") + output_file = f"models_{date_str}.json" + + # 保存JSON + with open(output_file, 'w', encoding='utf-8') as f: + json.dump(models_data, f, indent=2, ensure_ascii=False) + + print(f"✓ 已生成: {output_file}") + + # 打印统计信息 + print() + print("=" * 60) + print("统计信息") + print("=" * 60) + + # 按目录统计 + by_dir = defaultdict(int) + models_with_url = 0 + models_without_url = 0 + + for model_name, info in models_data.items(): + by_dir[info['directory']] += 1 + if info['url']: + models_with_url += 1 + else: + models_without_url += 1 + + print(f"总模型数: {len(models_data)}") + print(f" 有下载地址: {models_with_url}") + print(f" 无下载地址: {models_without_url}") + print() + print("按目录分布:") + for directory in sorted(by_dir.keys()): + print(f" {directory:20s}: {by_dir[directory]:3d} 个") + + print() + print("=" * 60) + + +if __name__ == "__main__": + main() + diff --git a/src/code/comfyui/models/models_20251220.json b/src/code/comfyui/models/models_20251220.json new file mode 100644 index 00000000..95788402 --- /dev/null +++ b/src/code/comfyui/models/models_20251220.json @@ -0,0 +1,1491 @@ +{ + "qwen_image_edit_2509_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_2509_fp8_e4m3fn.safetensors", + "directory": "unknown", + "node_types": [ + "33e101ba-5dc4-4252-b3eb-2a67387cb931", + "UNETLoader" + ], + "used_in_templates": [ + "02_qwen_Image_edit_subgraphed.json", + "image_qwen_image_edit_2509.json" + ] + }, + "Qwen-Image-Edit-2509-Lightning-4steps-V1.0-bf16.safetensors": { + "url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Edit-2509/Qwen-Image-Edit-2509-Lightning-4steps-V1.0-bf16.safetensors", + "directory": "unknown", + "node_types": [ + "33e101ba-5dc4-4252-b3eb-2a67387cb931", + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "02_qwen_Image_edit_subgraphed.json", + "image_qwen_image_edit_2509.json" + ] + }, + "hunyuan_3d_v2.1.safetensors": { + "url": "https://huggingface.co/Comfy-Org/hunyuan3D_2.1_repackaged/resolve/main/hunyuan_3d_v2.1.safetensors", + "directory": "unknown", + "node_types": [ + "ImageOnlyCheckpointLoader", + "d7344a5a-fd0d-4b8a-b5e1-1237e5b21937" + ], + "used_in_templates": [ + "04_hunyuan_3d_2.1_subgraphed.json", + "3d_hunyuan3d-v2.1.json" + ] + }, + "hunyuan3d-dit-v2_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/hunyuan3D_2.0_repackaged/resolve/main/split_files/hunyuan3d-dit-v2_fp16.safetensors", + "directory": "checkpoints", + "node_types": [ + "ImageOnlyCheckpointLoader" + ], + "used_in_templates": [ + "3d_hunyuan3d_image_to_model.json" + ] + }, + "hunyuan3d-dit-v2-mv_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/hunyuan3D_2.0_repackaged/resolve/main/split_files/hunyuan3d-dit-v2-mv_fp16.safetensors", + "directory": "checkpoints", + "node_types": [ + "ImageOnlyCheckpointLoader" + ], + "used_in_templates": [ + "3d_hunyuan3d_multiview_to_model.json" + ] + }, + "hunyuan3d-dit-v2-mv-turbo_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/hunyuan3D_2.0_repackaged/resolve/main/split_files/hunyuan3d-dit-v2-mv-turbo_fp16.safetensors", + "directory": "checkpoints", + "node_types": [ + "ImageOnlyCheckpointLoader" + ], + "used_in_templates": [ + "3d_hunyuan3d_multiview_to_model_turbo.json" + ] + }, + "ace_step_v1_3.5b.safetensors": { + "url": "https://huggingface.co/Comfy-Org/ACE-Step_ComfyUI_repackaged/blob/main/all_in_one/ace_step_v1_3.5b.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "audio_ace_step_1_m2m_editing.json", + "audio_ace_step_1_t2a_instrumentals.json", + "audio_ace_step_1_t2a_song.json" + ] + }, + "stable-audio-open-1.0.safetensors": { + "url": "https://huggingface.co/Comfy-Org/stable-audio-open-1.0_repackaged/resolve/main/stable-audio-open-1.0.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "audio_stable_audio_example.json" + ] + }, + "t5-base.safetensors": { + "url": "https://huggingface.co/ComfyUI-Wiki/t5-base/resolve/main/t5-base.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader" + ], + "used_in_templates": [ + "audio_stable_audio_example.json" + ] + }, + "DreamShaper_8_pruned.safetensors": { + "url": "https://huggingface.co/Lykon/DreamShaper/resolve/main/DreamShaper_8_pruned.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "controlnet_example.json" + ] + }, + "vae-ft-mse-840000-ema-pruned.safetensors": { + "url": "https://huggingface.co/stabilityai/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.safetensors?download=true", + "directory": "vae", + "node_types": [ + "6b0ed7ac-f476-44c9-9dad-b3f23ef985f8", + "VAELoader", + "d4b3d2cf-e436-4abb-84b8-47133c37745a" + ], + "used_in_templates": [ + "controlnet_example.json", + "flux_depth_lora_example.json", + "sd3.5_large_depth.json" + ] + }, + "control_v11p_sd15_scribble_fp16.safetensors": { + "url": "https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_scribble_fp16.safetensors?download=true", + "directory": "controlnet", + "node_types": [ + "ControlNetLoader" + ], + "used_in_templates": [ + "controlnet_example.json" + ] + }, + "v1-5-pruned-emaonly-fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/stable-diffusion-v1-5-archive/resolve/main/v1-5-pruned-emaonly-fp16.safetensors?download=true", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "default.json", + "image2image.json" + ] + }, + "architecturerealmix_v11.safetensors": { + "url": "https://civitai.com/api/download/models/431755?type=Model&format=SafeTensor&size=full&fp=fp16", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "depth_controlnet.json" + ] + }, + "control_v11f1p_sd15_depth_fp16.safetensors": { + "url": "https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11f1p_sd15_depth_fp16.safetensors", + "directory": "controlnet", + "node_types": [ + "ControlNetLoader" + ], + "used_in_templates": [ + "depth_controlnet.json" + ] + }, + "clip_l.safetensors": { + "url": "https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/clip_l.safetensors?download=true", + "directory": "clip", + "node_types": [ + "DualCLIPLoader" + ], + "used_in_templates": [ + "flux_canny_model_example.json", + "flux_depth_lora_example.json", + "flux_dev_full_text_to_image.json", + "flux_fill_outpaint_example.json", + "flux_redux_model_example.json", + "flux_schnell_full_text_to_image.json", + "hunyuan_video_text_to_video.json" + ] + }, + "t5xxl_fp16.safetensors": { + "url": "https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/t5xxl_fp16.safetensors?download=true", + "directory": "clip", + "node_types": [ + "CLIPLoader", + "DualCLIPLoader" + ], + "used_in_templates": [ + "flux_canny_model_example.json", + "flux_depth_lora_example.json", + "flux_dev_full_text_to_image.json", + "flux_fill_outpaint_example.json", + "flux_redux_model_example.json", + "flux_schnell_full_text_to_image.json", + "ltxv_image_to_video.json", + "ltxv_text_to_video.json" + ] + }, + "flux1-canny-dev.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux1-dev/resolve/main/split_files/diffusion_models/flux1-canny-dev.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "flux_canny_model_example.json" + ] + }, + "ae.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Lumina_Image_2.0_Repackaged/resolve/main/split_files/vae/ae.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "flux_canny_model_example.json", + "flux_depth_lora_example.json", + "flux_dev_full_text_to_image.json", + "flux_fill_outpaint_example.json", + "flux_redux_model_example.json", + "flux_schnell_full_text_to_image.json", + "hidream_e1_full.json", + "hidream_i1_dev.json", + "hidream_i1_fast.json", + "hidream_i1_full.json", + "image_chroma_text_to_image.json", + "image_omnigen2_image_edit.json", + "image_z_image_turbo.json" + ] + }, + "flux1-depth-dev-lora.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux1-dev/resolve/main/split_files/loras/flux1-depth-dev-lora.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "flux_depth_lora_example.json" + ] + }, + "flux1-dev-fp8.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux1-dev/resolve/main/flux1-dev-fp8.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "flux_depth_lora_example.json" + ] + }, + "lotus-depth-d-v1-1.safetensors": { + "url": "https://huggingface.co/Comfy-Org/lotus/resolve/main/lotus-depth-d-v1-1.safetensors", + "directory": "unknown", + "node_types": [ + "6b0ed7ac-f476-44c9-9dad-b3f23ef985f8", + "d4b3d2cf-e436-4abb-84b8-47133c37745a" + ], + "used_in_templates": [ + "flux_depth_lora_example.json", + "sd3.5_large_depth.json" + ] + }, + "flux1-dev.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux1-dev/resolve/main/flux1-dev.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "flux_dev_full_text_to_image.json", + "flux_redux_model_example.json" + ] + }, + "flux1-fill-dev.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux1-dev/resolve/main/split_files/diffusion_models/flux1-fill-dev.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "flux_fill_outpaint_example.json" + ] + }, + "flux1-redux-dev.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Flux1-Redux-Dev/resolve/main/flux1-redux-dev.safetensors", + "directory": "style_models", + "node_types": [ + "StyleModelLoader" + ], + "used_in_templates": [ + "flux_redux_model_example.json" + ] + }, + "sigclip_vision_patch14_384.safetensors": { + "url": "https://huggingface.co/Comfy-Org/sigclip_vision_384/resolve/main/sigclip_vision_patch14_384.safetensors", + "directory": "clip_vision", + "node_types": [ + "CLIPVisionLoader" + ], + "used_in_templates": [ + "flux_redux_model_example.json", + "video_hunyuan_video_1.5_720p_i2v.json" + ] + }, + "flux1-schnell-fp8.safetensors": { + "url": "", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "flux_schnell.json" + ] + }, + "flux1-schnell.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux1-schnell/resolve/main/flux1-schnell.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "flux_schnell_full_text_to_image.json" + ] + }, + "hidream_e1_full_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HiDream-I1_ComfyUI/resolve/main/split_files/diffusion_models/hidream_e1_full_bf16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "hidream_e1_full.json" + ] + }, + "clip_g_hidream.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HiDream-I1_ComfyUI/blob/main/split_files/text_encoders/clip_g_hidream.safetensors", + "directory": "clip", + "node_types": [ + "QuadrupleCLIPLoader" + ], + "used_in_templates": [ + "hidream_e1_full.json", + "hidream_i1_dev.json", + "hidream_i1_fast.json", + "hidream_i1_full.json" + ] + }, + "clip_l_hidream.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HiDream-I1_ComfyUI/blob/main/split_files/text_encoders/clip_l_hidream.safetensors", + "directory": "clip", + "node_types": [ + "QuadrupleCLIPLoader" + ], + "used_in_templates": [ + "hidream_e1_full.json", + "hidream_i1_dev.json", + "hidream_i1_fast.json", + "hidream_i1_full.json" + ] + }, + "t5xxl_fp8_e4m3fn_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HiDream-I1_ComfyUI/blob/main/split_files/text_encoders/t5xxl_fp8_e4m3fn_scaled.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader", + "QuadrupleCLIPLoader" + ], + "used_in_templates": [ + "hidream_e1_full.json", + "hidream_i1_dev.json", + "hidream_i1_fast.json", + "hidream_i1_full.json", + "image_chroma_text_to_image.json" + ] + }, + "llama_3.1_8b_instruct_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HiDream-I1_ComfyUI/blob/main/split_files/text_encoders/llama_3.1_8b_instruct_fp8_scaled.safetensors", + "directory": "clip", + "node_types": [ + "QuadrupleCLIPLoader" + ], + "used_in_templates": [ + "hidream_e1_full.json", + "hidream_i1_dev.json", + "hidream_i1_fast.json", + "hidream_i1_full.json" + ] + }, + "hidream_i1_dev_fp8.safetensors": { + "url": "", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "hidream_i1_dev.json" + ] + }, + "hidream_i1_fast_fp8.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HiDream-I1_ComfyUI/resolve/main/split_files/diffusion_models/hidream_i1_fast_fp8.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "hidream_i1_fast.json" + ] + }, + "hidream_i1_full_fp8.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HiDream-I1_ComfyUI/resolve/main/split_files/diffusion_models/hidream_i1_full_fp8.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "hidream_i1_full.json" + ] + }, + "llava_llama3_fp8_scaled.safetensors": { + "url": "", + "directory": "clip", + "node_types": [ + "DualCLIPLoader" + ], + "used_in_templates": [ + "hunyuan_video_text_to_video.json" + ] + }, + "hunyuan_video_t2v_720p_bf16.safetensors": { + "url": "", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "hunyuan_video_text_to_video.json" + ] + }, + "hunyuan_video_vae_bf16.safetensors": { + "url": "", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "hunyuan_video_text_to_video.json" + ] + }, + "Chroma1-HD-fp8_scaled_rev2.safetensors": { + "url": "https://huggingface.co/silveroxides/Chroma1-HD-fp8-scaled/resolve/main/Chroma1-HD-fp8_scaled_rev2.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "image_chroma_text_to_image.json" + ] + }, + "flux2-vae.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux2-dev/resolve/main/split_files/vae/flux2-vae.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "image_flux2.json", + "image_flux2_fp8.json" + ] + }, + "mistral_3_small_flux2_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux2-dev/resolve/main/split_files/text_encoders/mistral_3_small_flux2_bf16.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader" + ], + "used_in_templates": [ + "image_flux2.json" + ] + }, + "flux2_dev_fp8mixed.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux2-dev/resolve/main/split_files/diffusion_models/flux2_dev_fp8mixed.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "image_flux2.json", + "image_flux2_fp8.json" + ] + }, + "flux2_berthe_morisot.safetensors": { + "url": "https://huggingface.co/ostris/flux2_berthe_morisot/resolve/main/flux2_berthe_morisot.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "image_flux2.json" + ] + }, + "mistral_3_small_flux2_fp8.safetensors": { + "url": "https://huggingface.co/Comfy-Org/flux2-dev/resolve/main/split_files/text_encoders/mistral_3_small_flux2_fp8.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader" + ], + "used_in_templates": [ + "image_flux2_fp8.json" + ] + }, + "NetaYumev35_pretrained_all_in_one.safetensors": { + "url": "https://huggingface.co/duongve/NetaYume-Lumina-Image-2.0/resolve/main/NetaYumev35_pretrained_all_in_one.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "image_netayume_lumina_t2i.json" + ] + }, + "qwen_2.5_vl_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged/resolve/main/split_files/text_encoders/qwen_2.5_vl_fp16.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader" + ], + "used_in_templates": [ + "image_omnigen2_image_edit.json" + ] + }, + "omnigen2_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Omnigen2_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/omnigen2_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "image_omnigen2_image_edit.json" + ] + }, + "qwen_image_vae.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/vae/qwen_image_vae.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "image_qwen_image.json", + "image_qwen_image_controlnet_patch.json", + "image_qwen_image_edit_2509.json", + "image_qwen_image_instantx_inpainting_controlnet.json", + "image_qwen_image_union_control_lora.json" + ] + }, + "qwen_2.5_vl_7b_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader", + "DualCLIPLoader" + ], + "used_in_templates": [ + "image_qwen_image.json", + "image_qwen_image_controlnet_patch.json", + "image_qwen_image_edit_2509.json", + "image_qwen_image_instantx_inpainting_controlnet.json", + "image_qwen_image_union_control_lora.json", + "video_hunyuan_video_1.5_720p_i2v.json", + "video_hunyuan_video_1.5_720p_t2v.json" + ] + }, + "Qwen-Image-Lightning-8steps-V1.0.safetensors": { + "url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-8steps-V1.0.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "image_qwen_image.json" + ] + }, + "qwen_image_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_fp8_e4m3fn.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "image_qwen_image.json", + "image_qwen_image_controlnet_patch.json", + "image_qwen_image_instantx_inpainting_controlnet.json", + "image_qwen_image_union_control_lora.json" + ] + }, + "qwen_image_canny_diffsynth_controlnet.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image-DiffSynth-ControlNets/resolve/main/split_files/model_patches/qwen_image_canny_diffsynth_controlnet.safetensors", + "directory": "controlnet", + "node_types": [ + "ModelPatchLoader" + ], + "used_in_templates": [ + "image_qwen_image_controlnet_patch.json" + ] + }, + "Qwen-Image-Lightning-4steps-V1.0.safetensors": { + "url": "https://huggingface.co/lightx2v/Qwen-Image-Lightning/resolve/main/Qwen-Image-Lightning-4steps-V1.0.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "image_qwen_image_controlnet_patch.json", + "image_qwen_image_instantx_inpainting_controlnet.json", + "image_qwen_image_union_control_lora.json" + ] + }, + "Qwen-Image-Edit-2509-Relight.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/loras/Qwen-Image-Edit-2509-Relight.safetensors", + "directory": "unknown", + "node_types": [ + "3a756f48-801b-48eb-80dd-279f32d09b12" + ], + "used_in_templates": [ + "image_qwen_image_edit_2509_relight.json" + ] + }, + "Qwen-Image-InstantX-ControlNet-Inpainting.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image-InstantX-ControlNets/resolve/main/split_files/controlnet/Qwen-Image-InstantX-ControlNet-Inpainting.safetensors", + "directory": "controlnet", + "node_types": [ + "ControlNetLoader" + ], + "used_in_templates": [ + "image_qwen_image_instantx_inpainting_controlnet.json" + ] + }, + "qwen_image_union_diffsynth_lora.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image-DiffSynth-ControlNets/resolve/main/split_files/loras/qwen_image_union_diffsynth_lora.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "image_qwen_image_union_control_lora.json" + ] + }, + "wan2.1_i2v_480p_14B_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_i2v_480p_14B_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "image_to_video_wan.json" + ] + }, + "umt5_xxl_fp8_e4m3fn_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/text_encoders/umt5_xxl_fp8_e4m3fn_scaled.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader" + ], + "used_in_templates": [ + "image_to_video_wan.json", + "text_to_video_wan.json", + "video_humo.json", + "video_wan2.1_alpha_t2v_14B.json", + "video_wan2.1_fun_camera_v1.1_1.3B.json", + "video_wan2.1_fun_camera_v1.1_14B.json", + "video_wan2_2_14B_animate.json", + "video_wan2_2_14B_flf2v.json", + "video_wan2_2_14B_fun_camera.json", + "video_wan2_2_14B_fun_control.json", + "video_wan2_2_14B_fun_inpaint.json", + "video_wan2_2_14B_i2v.json", + "video_wan2_2_14B_s2v.json", + "video_wan2_2_14B_t2v.json", + "video_wan2_2_5B_fun_control.json", + "video_wan2_2_5B_fun_inpaint.json", + "video_wan2_2_5B_ti2v.json", + "video_wan_ati.json", + "video_wan_vace_14B_ref2v.json", + "video_wan_vace_14B_t2v.json", + "video_wan_vace_14B_v2v.json", + "video_wan_vace_flf2v.json", + "video_wan_vace_inpainting.json", + "video_wan_vace_outpainting.json", + "video_wanmove_480p.json", + "wan2.1_flf2v_720_f16.json", + "wan2.1_fun_control.json", + "wan2.1_fun_inp.json" + ] + }, + "wan_2.1_vae.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/vae/wan_2.1_vae.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "image_to_video_wan.json", + "text_to_video_wan.json", + "video_humo.json", + "video_wan2.1_fun_camera_v1.1_1.3B.json", + "video_wan2.1_fun_camera_v1.1_14B.json", + "video_wan2_2_14B_animate.json", + "video_wan2_2_14B_flf2v.json", + "video_wan2_2_14B_fun_camera.json", + "video_wan2_2_14B_fun_control.json", + "video_wan2_2_14B_fun_inpaint.json", + "video_wan2_2_14B_i2v.json", + "video_wan2_2_14B_s2v.json", + "video_wan2_2_14B_t2v.json", + "video_wan_ati.json", + "video_wan_vace_14B_ref2v.json", + "video_wan_vace_14B_t2v.json", + "video_wan_vace_14B_v2v.json", + "video_wan_vace_flf2v.json", + "video_wan_vace_inpainting.json", + "video_wan_vace_outpainting.json", + "video_wanmove_480p.json", + "wan2.1_flf2v_720_f16.json", + "wan2.1_fun_control.json", + "wan2.1_fun_inp.json" + ] + }, + "clip_vision_h.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/clip_vision/clip_vision_h.safetensors", + "directory": "clip_vision", + "node_types": [ + "CLIPVisionLoader" + ], + "used_in_templates": [ + "image_to_video_wan.json", + "video_wan2.1_fun_camera_v1.1_1.3B.json", + "video_wan2.1_fun_camera_v1.1_14B.json", + "video_wan2_2_14B_animate.json", + "video_wan_ati.json", + "video_wanmove_480p.json", + "wan2.1_flf2v_720_f16.json", + "wan2.1_fun_control.json", + "wan2.1_fun_inp.json" + ] + }, + "qwen_3_4b.safetensors": { + "url": "https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/text_encoders/qwen_3_4b.safetensors", + "directory": "clip", + "node_types": [ + "CLIPLoader" + ], + "used_in_templates": [ + "image_z_image_turbo.json" + ] + }, + "z_image_turbo_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/diffusion_models/z_image_turbo_bf16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "image_z_image_turbo.json" + ] + }, + "pixel_art_style_z_image_turbo.safetensors": { + "url": "https://huggingface.co/tarn59/pixel_art_style_lora_z_image_turbo/resolve/main/pixel_art_style_z_image_turbo.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "image_z_image_turbo.json" + ] + }, + "512-inpainting-ema.safetensors": { + "url": "https://huggingface.co/Comfy-Org/stable_diffusion_2.1_repackaged/resolve/main/512-inpainting-ema.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "inpaint_example.json", + "inpaint_model_outpainting.json" + ] + }, + "dreamshaper_8.safetensors": { + "url": "https://civitai.com/api/download/models/128713?type=Model&format=SafeTensor&size=pruned&fp=fp16", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "lora.json", + "lora_multiple.json" + ] + }, + "blindbox_v1_mix.safetensors": { + "url": "https://civitai.com/api/download/models/32988?type=Model&format=SafeTensor&size=full&fp=fp16", + "directory": "loras", + "node_types": [ + "LoraLoader" + ], + "used_in_templates": [ + "lora.json", + "lora_multiple.json" + ] + }, + "MoXinV1.safetensors": { + "url": "https://civitai.com/api/download/models/14856?type=Model&format=SafeTensor&size=full&fp=fp16", + "directory": "loras", + "node_types": [ + "LoraLoader" + ], + "used_in_templates": [ + "lora.json", + "lora_multiple.json" + ] + }, + "ltx-video-2b-v0.9.5.safetensors": { + "url": "https://huggingface.co/Lightricks/LTX-Video/resolve/main/ltx-video-2b-v0.9.5.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "ltxv_image_to_video.json" + ] + }, + "ltx-video-2b-v0.9.safetensors": { + "url": "", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "ltxv_text_to_video.json" + ] + }, + "sd3.5_large_controlnet_blur.safetensors": { + "url": "https://huggingface.co/Comfy-Org/stable-diffusion-3.5-controlnets_ComfyUI_repackaged/resolve/main/split_files/controlnet/sd3.5_large_controlnet_blur.safetensors", + "directory": "controlnet", + "node_types": [ + "ControlNetLoader" + ], + "used_in_templates": [ + "sd3.5_large_blur.json" + ] + }, + "sd3.5_large_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/stable-diffusion-3.5-fp8/resolve/main/sd3.5_large_fp8_scaled.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "sd3.5_large_blur.json", + "sd3.5_large_canny_controlnet_example.json", + "sd3.5_large_depth.json", + "sd3.5_simple_example.json" + ] + }, + "sd3.5_large_controlnet_canny.safetensors": { + "url": "https://huggingface.co/Comfy-Org/stable-diffusion-3.5-controlnets_ComfyUI_repackaged/resolve/main/split_files/controlnet/sd3.5_large_controlnet_canny.safetensors", + "directory": "controlnet", + "node_types": [ + "ControlNetLoader" + ], + "used_in_templates": [ + "sd3.5_large_canny_controlnet_example.json" + ] + }, + "sd3.5_large_controlnet_depth.safetensors": { + "url": "https://huggingface.co/Comfy-Org/stable-diffusion-3.5-controlnets_ComfyUI_repackaged/resolve/main/split_files/controlnet/sd3.5_large_controlnet_depth.safetensors", + "directory": "controlnet", + "node_types": [ + "ControlNetLoader" + ], + "used_in_templates": [ + "sd3.5_large_depth.json" + ] + }, + "sd_xl_refiner_1.0.safetensors": { + "url": "", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "sdxl_refiner_prompt_example.json", + "sdxl_simple_example.json" + ] + }, + "sd_xl_base_1.0.safetensors": { + "url": "https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "sdxl_refiner_prompt_example.json", + "sdxl_revision_text_prompts.json", + "sdxl_simple_example.json", + "txt_to_image_to_video.json" + ] + }, + "clip_vision_g.safetensors": { + "url": "https://huggingface.co/comfyanonymous/clip_vision_g/resolve/main/clip_vision_g.safetensors", + "directory": "clip_vision", + "node_types": [ + "CLIPVisionLoader" + ], + "used_in_templates": [ + "sdxl_revision_text_prompts.json" + ] + }, + "sd_xl_turbo_1.0_fp16.safetensors": { + "url": "", + "directory": "checkpoints", + "node_types": [ + "CheckpointLoaderSimple" + ], + "used_in_templates": [ + "sdxlturbo_example.json" + ] + }, + "wan2.1_t2v_1.3B_fp16.safetensors": { + "url": "", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "text_to_video_wan.json" + ] + }, + "svd_xt.safetensors": { + "url": "", + "directory": "checkpoints", + "node_types": [ + "ImageOnlyCheckpointLoader" + ], + "used_in_templates": [ + "txt_to_image_to_video.json" + ] + }, + "lightx2v_I2V_14B_480p_cfg_step_distill_rank64_bf16.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/Lightx2v/lightx2v_I2V_14B_480p_cfg_step_distill_rank64_bf16.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_humo.json", + "video_wan2_2_14B_animate.json", + "video_wanmove_480p.json" + ] + }, + "humo_17B_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HuMo_ComfyUI/resolve/main/split_files/diffusion_models/humo_17B_fp8_e4m3fn.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_humo.json" + ] + }, + "whisper_large_v3_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HuMo_ComfyUI/resolve/main/split_files/audio_encoders/whisper_large_v3_fp16.safetensors", + "directory": "audio", + "node_types": [ + "AudioEncoderLoader" + ], + "used_in_templates": [ + "video_humo.json" + ] + }, + "byt5_small_glyphxl_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/resolve/main/split_files/text_encoders/byt5_small_glyphxl_fp16.safetensors", + "directory": "clip", + "node_types": [ + "DualCLIPLoader" + ], + "used_in_templates": [ + "video_hunyuan_video_1.5_720p_i2v.json", + "video_hunyuan_video_1.5_720p_t2v.json" + ] + }, + "hunyuanvideo15_latent_upsampler_1080p.safetensors": { + "url": "", + "directory": "upscale_models", + "node_types": [ + "LatentUpscaleModelLoader" + ], + "used_in_templates": [ + "video_hunyuan_video_1.5_720p_i2v.json", + "video_hunyuan_video_1.5_720p_t2v.json" + ] + }, + "hunyuanvideo1.5_1080p_sr_distilled_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/resolve/main/split_files/diffusion_models/hunyuanvideo1.5_1080p_sr_distilled_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_hunyuan_video_1.5_720p_i2v.json", + "video_hunyuan_video_1.5_720p_t2v.json" + ] + }, + "hunyuanvideo15_vae_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/resolve/main/split_files/vae/hunyuanvideo15_vae_fp16.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "video_hunyuan_video_1.5_720p_i2v.json", + "video_hunyuan_video_1.5_720p_t2v.json" + ] + }, + "hunyuanvideo1.5_720p_i2v_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/resolve/main/split_files/diffusion_models/hunyuanvideo1.5_720p_i2v_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_hunyuan_video_1.5_720p_i2v.json" + ] + }, + "hunyuanvideo1.5_720p_t2v_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/HunyuanVideo_1.5_repackaged/resolve/main/split_files/diffusion_models/hunyuanvideo1.5_720p_t2v_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_hunyuan_video_1.5_720p_t2v.json" + ] + }, + "wan2.1_t2v_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_t2v_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2.1_alpha_t2v_14B.json" + ] + }, + "wan_alpha_2.1_rgba_lora.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/loras/wan_alpha_2.1_rgba_lora.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan2.1_alpha_t2v_14B.json" + ] + }, + "wan_alpha_2.1_vae_rgb_channel.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/vae/wan_alpha_2.1_vae_rgb_channel.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "video_wan2.1_alpha_t2v_14B.json" + ] + }, + "wan_alpha_2.1_vae_alpha_channel.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/vae/wan_alpha_2.1_vae_alpha_channel.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "video_wan2.1_alpha_t2v_14B.json" + ] + }, + "lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/Lightx2v/lightx2v_T2V_14B_cfg_step_distill_v2_lora_rank64_bf16.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan2.1_alpha_t2v_14B.json" + ] + }, + "wan2.1_fun_camera_v1.1_1.3B_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_fun_camera_v1.1_1.3B_bf16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2.1_fun_camera_v1.1_1.3B.json" + ] + }, + "wan2.1_fun_camera_v1.1_14B_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_fun_camera_v1.1_14B_bf16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2.1_fun_camera_v1.1_14B.json" + ] + }, + "sam2_hiera_base_plus.safetensors": { + "url": "", + "directory": "sams", + "node_types": [ + "DownloadAndLoadSAM2Model" + ], + "used_in_templates": [ + "video_wan2_2_14B_animate.json" + ] + }, + "dw-ll_ucoco_384_bs5.torchscript.pt": { + "url": "", + "directory": "unknown", + "node_types": [ + "DWPreprocessor" + ], + "used_in_templates": [ + "video_wan2_2_14B_animate.json" + ] + }, + "WanAnimate_relight_lora_fp16.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/LoRAs/Wan22_relight/WanAnimate_relight_lora_fp16.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan2_2_14B_animate.json" + ] + }, + "Wan2_2-Animate-14B_fp8_e4m3fn_scaled_KJ.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/resolve/main/Wan22Animate/Wan2_2-Animate-14B_fp8_e4m3fn_scaled_KJ.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_animate.json" + ] + }, + "wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_flf2v.json", + "video_wan2_2_14B_i2v.json" + ] + }, + "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_flf2v.json", + "video_wan2_2_14B_i2v.json" + ] + }, + "wan2.2_i2v_lightx2v_4steps_lora_v1_low_noise.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/loras/wan2.2_i2v_lightx2v_4steps_lora_v1_low_noise.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan2_2_14B_flf2v.json", + "video_wan2_2_14B_fun_camera.json", + "video_wan2_2_14B_fun_control.json", + "video_wan2_2_14B_fun_inpaint.json", + "video_wan2_2_14B_i2v.json" + ] + }, + "wan2.2_i2v_lightx2v_4steps_lora_v1_high_noise.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/loras/wan2.2_i2v_lightx2v_4steps_lora_v1_high_noise.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan2_2_14B_flf2v.json", + "video_wan2_2_14B_fun_camera.json", + "video_wan2_2_14B_fun_control.json", + "video_wan2_2_14B_fun_inpaint.json", + "video_wan2_2_14B_i2v.json" + ] + }, + "wan2.2_fun_camera_high_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_camera_high_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_fun_camera.json" + ] + }, + "wan2.2_fun_camera_low_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_camera_low_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_fun_camera.json" + ] + }, + "wan2.2_fun_control_high_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_control_high_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_fun_control.json" + ] + }, + "wan2.2_fun_control_low_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_control_low_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_fun_control.json" + ] + }, + "wan2.2_fun_inpaint_high_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_inpaint_high_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_fun_inpaint.json" + ] + }, + "wan2.2_fun_inpaint_low_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_inpaint_low_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_fun_inpaint.json" + ] + }, + "wav2vec2_large_english_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/audio_encoders/wav2vec2_large_english_fp16.safetensors", + "directory": "audio", + "node_types": [ + "AudioEncoderLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_s2v.json" + ] + }, + "wan2.2_t2v_lightx2v_4steps_lora_v1.1_high_noise.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/loras/wan2.2_t2v_lightx2v_4steps_lora_v1.1_high_noise.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan2_2_14B_s2v.json", + "video_wan2_2_14B_t2v.json" + ] + }, + "wan2.2_s2v_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_s2v_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_s2v.json" + ] + }, + "wan2.2_t2v_low_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_low_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_t2v.json" + ] + }, + "wan2.2_t2v_high_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_t2v_high_noise_14B_fp8_scaled.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_14B_t2v.json" + ] + }, + "wan2.2_t2v_lightx2v_4steps_lora_v1.1_low_noise.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/loras/wan2.2_t2v_lightx2v_4steps_lora_v1.1_low_noise.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan2_2_14B_t2v.json" + ] + }, + "wan2.2_vae.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/vae/wan2.2_vae.safetensors", + "directory": "vae", + "node_types": [ + "VAELoader" + ], + "used_in_templates": [ + "video_wan2_2_5B_fun_control.json", + "video_wan2_2_5B_fun_inpaint.json", + "video_wan2_2_5B_ti2v.json" + ] + }, + "wan2.2_fun_control_5B_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_control_5B_bf16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_5B_fun_control.json" + ] + }, + "wan2.2_fun_inpaint_5B_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_fun_inpaint_5B_bf16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_5B_fun_inpaint.json" + ] + }, + "wan2.2_ti2v_5B_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_ti2v_5B_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan2_2_5B_ti2v.json" + ] + }, + "Wan2_1-I2V-ATI-14B_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy/resolve/main/Wan2_1-I2V-ATI-14B_fp8_e4m3fn.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan_ati.json" + ] + }, + "wan2.1_vace_1.3B_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_vace_1.3B_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan_vace_14B_ref2v.json", + "video_wan_vace_14B_t2v.json", + "video_wan_vace_14B_v2v.json", + "video_wan_vace_flf2v.json", + "video_wan_vace_inpainting.json", + "video_wan_vace_outpainting.json" + ] + }, + "Wan21_CausVid_bidirect2_T2V_1_3B_lora_rank32.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy/blob/main/Wan21_CausVid_bidirect2_T2V_1_3B_lora_rank32.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoader" + ], + "used_in_templates": [ + "video_wan_vace_14B_ref2v.json", + "video_wan_vace_14B_t2v.json", + "video_wan_vace_14B_v2v.json", + "video_wan_vace_flf2v.json", + "video_wan_vace_inpainting.json", + "video_wan_vace_outpainting.json" + ] + }, + "umt5_xxl_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/text_encoders/umt5_xxl_fp16.safetensors?download=true", + "directory": "clip", + "node_types": [ + "CLIPLoader" + ], + "used_in_templates": [ + "video_wan_vace_14B_ref2v.json", + "video_wan_vace_14B_t2v.json", + "video_wan_vace_14B_v2v.json", + "video_wan_vace_flf2v.json", + "video_wan_vace_inpainting.json", + "video_wan_vace_outpainting.json" + ] + }, + "wan2.1_vace_14B_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_vace_14B_fp16.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wan_vace_14B_ref2v.json", + "video_wan_vace_14B_t2v.json", + "video_wan_vace_14B_v2v.json", + "video_wan_vace_flf2v.json", + "video_wan_vace_inpainting.json", + "video_wan_vace_outpainting.json" + ] + }, + "Wan21_CausVid_14B_T2V_lora_rank32.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy/blob/main/Wan21_CausVid_14B_T2V_lora_rank32.safetensors", + "directory": "loras", + "node_types": [ + "LoraLoader", + "LoraLoaderModelOnly" + ], + "used_in_templates": [ + "video_wan_vace_14B_ref2v.json", + "video_wan_vace_14B_t2v.json", + "video_wan_vace_14B_v2v.json", + "video_wan_vace_flf2v.json", + "video_wan_vace_inpainting.json", + "video_wan_vace_outpainting.json" + ] + }, + "Wan21-WanMove_fp8_scaled_e4m3fn_KJ.safetensors": { + "url": "https://huggingface.co/Kijai/WanVideo_comfy_fp8_scaled/resolve/main/WanMove/Wan21-WanMove_fp8_scaled_e4m3fn_KJ.safetensors", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "video_wanmove_480p.json" + ] + }, + "wan2.1_flf2v_720p_14B_fp16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_flf2v_720p_14B_fp16.safetensors?download=true", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "wan2.1_flf2v_720_f16.json" + ] + }, + "wan2.1_fun_control_1.3B_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_fun_control_1.3B_bf16.safetensors?download=true", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "wan2.1_fun_control.json" + ] + }, + "wan2.1_fun_inp_1.3B_bf16.safetensors": { + "url": "", + "directory": "unet", + "node_types": [ + "UNETLoader" + ], + "used_in_templates": [ + "wan2.1_fun_inp.json" + ] + } +} \ No newline at end of file diff --git a/src/code/comfyui/models/models_nunchaku.json b/src/code/comfyui/models/models_nunchaku.json new file mode 100644 index 00000000..2cac0477 --- /dev/null +++ b/src/code/comfyui/models/models_nunchaku.json @@ -0,0 +1,86 @@ +{ + "svdq-int4_r32-flux.1-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-dev/resolve/main/svdq-int4_r32-flux.1-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-flux.1-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-dev/resolve/main/svdq-fp4_r32-flux.1-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-flux.1-kontext-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev/resolve/main/svdq-fp4_r32-flux.1-kontext-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-flux.1-kontext-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev/resolve/main/svdq-int4_r32-flux.1-kontext-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-fp4_r128-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-fp4_r32-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r128-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r256-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r256-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r32-z-image-turbo.safetensors", + "directory": "diffusion_models" + } +} \ No newline at end of file From ce32c6a2a2da4b15483bf365fe15c4dd9ea4b532 Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Sat, 27 Dec 2025 17:20:38 +0800 Subject: [PATCH 02/10] add more models Change-Id: If1398a1eeefe98238af7ed4a960c916369d42c27 Co-developed-by: Cursor --- src/code/comfyui/models/models_nunchaku.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/code/comfyui/models/models_nunchaku.json b/src/code/comfyui/models/models_nunchaku.json index 2cac0477..21e797c9 100644 --- a/src/code/comfyui/models/models_nunchaku.json +++ b/src/code/comfyui/models/models_nunchaku.json @@ -7,6 +7,19 @@ "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-dev/resolve/main/svdq-fp4_r32-flux.1-dev.safetensors", "directory": "diffusion_models" }, + "svdq-fp4_r32-flux.1-schnell.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-schnell/resolve/main/svdq-fp4_r32-flux.1-schnell.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-flux.1-schnell.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-schnell/resolve/main/svdq-int4_r32-flux.1-schnell.safetensors", + "directory": "diffusion_models" + }, + + "awq-int4-flux.1-t5xxl.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-t5/resolve/main/awq-int4-flux.1-t5xxl.safetensors", + "directory": "text_encoders" + }, "svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors": { "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors", "directory": "diffusion_models" From 581f129cb69f1a61e3dc63dc277838cde8b1a3a8 Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Mon, 9 Mar 2026 11:01:57 +0800 Subject: [PATCH 03/10] add more models Change-Id: I43e84c07045d0ae81067ddaee974bfa6b898f2e6 Co-developed-by: Cursor --- src/code/comfyui/models/models_20260308.json | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/code/comfyui/models/models_20260308.json diff --git a/src/code/comfyui/models/models_20260308.json b/src/code/comfyui/models/models_20260308.json new file mode 100644 index 00000000..6f699ed3 --- /dev/null +++ b/src/code/comfyui/models/models_20260308.json @@ -0,0 +1,22 @@ +{ + "qwen_image_edit_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_fp8_e4m3fn.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit-2509-lightning-4steps-251115.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/lightning-251115/svdq-int4_r32-qwen-image-edit-2509-lightning-4steps-251115.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit-2509-lightning-4steps-251115.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/lightning-251115/svdq-int4_r128-qwen-image-edit-2509-lightning-4steps-251115.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-qwen-image-edit-2509-lightningv2.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/svdq-fp4_r128-qwen-image-edit-2509-lightningv2.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors", + "directory": "diffusion_models" + } +} From 514ca1e47e39ded946b1c13f9bc05b01e30e133a Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Mon, 9 Mar 2026 14:08:06 +0800 Subject: [PATCH 04/10] add script Change-Id: Ida8e2a006411adf59335f3880b6c0c9c206a1ef9 Co-developed-by: Cursor --- src/code/comfyui/Makefile | 36 +++- src/code/comfyui/models/sync_dev_to_prod.sh | 225 ++++++++++++++++++++ 2 files changed, 260 insertions(+), 1 deletion(-) create mode 100755 src/code/comfyui/models/sync_dev_to_prod.sh diff --git a/src/code/comfyui/Makefile b/src/code/comfyui/Makefile index 8e552fa6..c8dff62b 100644 --- a/src/code/comfyui/Makefile +++ b/src/code/comfyui/Makefile @@ -4,6 +4,12 @@ COMFYUI_IMAGE = registry.$(REGION).aliyuncs.com/ohyee/fc-demo:cap-comfyui OSS_BUCKET ?= dipper-cache-$(REGION) OSS_COMFYUI_BASE_DIR = base/comfyui/v0.3.10-beta +# 模型同步:dev OSS <-> prod OSS +DEV_MOUNT ?= /mnt/funart-dev/models +PROD_MOUNT ?= /mnt/funart/models +DEV_OSS_BUCKET ?= dipper-cache-$(REGION)-dev +PROD_OSS_BUCKET ?= dipper-cache-$(REGION) + .PHONY: upgrade upgrade: build upload-base @@ -94,4 +100,32 @@ build-from-snapshot: -t $(COMFYUI_IMAGE_PROD) . @rm -rf tmp - @echo "Build completed successfully" \ No newline at end of file + @echo "Build completed successfully" + +# ===== 模型管理 ===== + +# 列出 dev 有但 prod 没有的模型,生成 diff_YYYYMMDD.json +# 输出文件位于 models/ 目录下 +.PHONY: diff-models +diff-models: + @DEV_MOUNT=$(DEV_MOUNT) \ + PROD_MOUNT=$(PROD_MOUNT) \ + bash models/sync_dev_to_prod.sh --diff-only + +# 将 dev 有但 prod 没有的模型同步到 prod OSS +.PHONY: sync-models-to-prod +sync-models-to-prod: + @DEV_MOUNT=$(DEV_MOUNT) \ + PROD_MOUNT=$(PROD_MOUNT) \ + DEV_OSS_BUCKET=$(DEV_OSS_BUCKET) \ + PROD_OSS_BUCKET=$(PROD_OSS_BUCKET) \ + bash models/sync_dev_to_prod.sh + +# 打印将要执行的 ossutil 同步命令(不实际执行) +.PHONY: sync-models-to-prod-dry-run +sync-models-to-prod-dry-run: + @DEV_MOUNT=$(DEV_MOUNT) \ + PROD_MOUNT=$(PROD_MOUNT) \ + DEV_OSS_BUCKET=$(DEV_OSS_BUCKET) \ + PROD_OSS_BUCKET=$(PROD_OSS_BUCKET) \ + bash models/sync_dev_to_prod.sh --dry-run \ No newline at end of file diff --git a/src/code/comfyui/models/sync_dev_to_prod.sh b/src/code/comfyui/models/sync_dev_to_prod.sh new file mode 100755 index 00000000..faf63b77 --- /dev/null +++ b/src/code/comfyui/models/sync_dev_to_prod.sh @@ -0,0 +1,225 @@ +#!/bin/bash +# +# sync_dev_to_prod.sh - 对比 dev/prod 挂载目录,将差异模型从 dev OSS 同步到 prod OSS +# +# 依赖: +# ossutil (已配置 AK/SK) +# python3 +# +# 使用方法: +# ./sync_dev_to_prod.sh # 生成 diff JSON 并同步到 prod +# ./sync_dev_to_prod.sh --diff-only # 只生成 diff JSON,不执行同步 +# ./sync_dev_to_prod.sh --dry-run # 打印 ossutil 命令但不实际执行 +# +# 环境变量(可覆盖默认值): +# DEV_MOUNT dev OSS 挂载目录 (默认 /mnt/funart-dev/models) +# PROD_MOUNT prod OSS 挂载目录 (默认 /mnt/funart/models) +# DEV_OSS_BUCKET dev OSS bucket (默认 dipper-cache-cn-hangzhou-dev) +# PROD_OSS_BUCKET prod OSS bucket (默认 dipper-cache-cn-hangzhou) +# OUTPUT_JSON diff JSON 输出路径 (默认 diff_YYYYMMDD.json,放在脚本同目录) +# + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# 脚本所在目录,用于默认输出路径 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# 可通过环境变量覆盖的配置 +DEV_MOUNT="${DEV_MOUNT:-/mnt/funart-dev/models}" +PROD_MOUNT="${PROD_MOUNT:-/mnt/funart/models}" +DEV_OSS_BUCKET="${DEV_OSS_BUCKET:-dipper-cache-cn-hangzhou-dev}" +PROD_OSS_BUCKET="${PROD_OSS_BUCKET:-dipper-cache-cn-hangzhou}" +OUTPUT_JSON="${OUTPUT_JSON:-$SCRIPT_DIR/diff_$(date +%Y%m%d).json}" + +# 固定路径前缀(不对外暴露) +DEV_OSS_PREFIX="funart/models" +PROD_OSS_PREFIX="function-art/comfyui/models" + +# 参数解析 +DIFF_ONLY=false +DRY_RUN=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --diff-only) + DIFF_ONLY=true + shift + ;; + --dry-run) + DRY_RUN=true + shift + ;; + -h|--help) + echo "使用方法: $0 [选项]" + echo "" + echo "选项:" + echo " --diff-only 只生成 diff JSON,不执行 OSS 同步" + echo " --dry-run 打印 ossutil 命令,不实际执行" + echo " -h, --help 显示此帮助信息" + echo "" + echo "环境变量:" + echo " DEV_MOUNT dev 挂载目录 (默认: /mnt/funart-dev/models)" + echo " PROD_MOUNT prod 挂载目录 (默认: /mnt/funart/models)" + echo " DEV_OSS_BUCKET dev bucket (默认: dipper-cache-cn-hangzhou-dev)" + echo " PROD_OSS_BUCKET prod bucket (默认: dipper-cache-cn-hangzhou)" + echo " OUTPUT_JSON 输出路径 (默认: diff_YYYYMMDD.json)" + exit 0 + ;; + *) + echo -e "${RED}错误: 未知参数 $1${NC}" + echo "运行 $0 --help 查看帮助" + exit 1 + ;; + esac +done + +echo "======================================" +echo "Dev/Prod 模型差异对比 & 同步" +echo "======================================" +echo -e "${BLUE}Dev 目录: $DEV_MOUNT${NC}" +echo -e "${BLUE}Prod 目录: $PROD_MOUNT${NC}" +echo -e "${BLUE}输出 JSON: $OUTPUT_JSON${NC}" +echo "" + +# ────────────────────────────────────────── +# 步骤 1: 扫描目录差异,生成 diff JSON +# ────────────────────────────────────────── +echo -e "${BLUE}[1/2] 扫描目录差异...${NC}" + +if [ ! -d "$DEV_MOUNT" ]; then + echo -e "${RED}错误: dev 挂载目录不存在: $DEV_MOUNT${NC}" + exit 1 +fi + +if [ ! -d "$PROD_MOUNT" ]; then + echo -e "${YELLOW}警告: prod 挂载目录不存在: $PROD_MOUNT(将视为空目录)${NC}" +fi + +python3 - </dev/null; then + echo -e "${RED}错误: 未找到 ossutil 命令${NC}" + echo "安装: sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash" + exit 1 +fi + +SUCCESS=0 +FAILED=0 +FAILED_MODELS=() + +# 使用进程替换避免子 shell 导致计数器失效 +while IFS='###SEP###' read -r filename directory; do + src="oss://${DEV_OSS_BUCKET}/${DEV_OSS_PREFIX}/${directory}/${filename}" + dst="oss://${PROD_OSS_BUCKET}/${PROD_OSS_PREFIX}/${directory}/${filename}" + + if [ "$DRY_RUN" = true ]; then + echo -e " ${BLUE}ossutil cp --ignore-existing \"$src\" \"$dst\"${NC}" + else + echo -n " 同步 $directory/$filename ... " + if ossutil cp --ignore-existing "$src" "$dst" 2>&1 | tail -1; then + echo -e " ${GREEN}✓ 完成${NC}" + SUCCESS=$((SUCCESS + 1)) + else + echo -e " ${RED}✗ 失败${NC}" + FAILED=$((FAILED + 1)) + FAILED_MODELS+=("$directory/$filename") + fi + fi +done < <(python3 -c " +import json +with open('${OUTPUT_JSON}', 'r') as f: + data = json.load(f) +for filename, info in data.items(): + directory = info.get('directory', 'unknown') + print(f'{filename}###SEP###{directory}') +") + +if [ "$DRY_RUN" = false ]; then + echo "" + echo "======================================" + echo -e "${GREEN}成功: $SUCCESS${NC}" + echo -e "${RED}失败: $FAILED${NC}" + echo "======================================" + + if [ "${#FAILED_MODELS[@]}" -gt 0 ]; then + echo "" + echo -e "${RED}以下模型同步失败:${NC}" + for m in "${FAILED_MODELS[@]}"; do + echo -e " ${RED}✗${NC} $m" + done + exit 1 + fi +fi + +exit 0 From a4b806a1684a02da2e859a5d726d846965f315c0 Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Mon, 9 Mar 2026 14:12:19 +0800 Subject: [PATCH 05/10] debug Change-Id: I97a0f2c68e22695bf2208fd71dca6726d0d097bc Co-developed-by: Cursor --- src/code/comfyui/Makefile | 2 +- src/code/comfyui/models/sync_dev_to_prod.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/code/comfyui/Makefile b/src/code/comfyui/Makefile index c8dff62b..97ea8757 100644 --- a/src/code/comfyui/Makefile +++ b/src/code/comfyui/Makefile @@ -6,7 +6,7 @@ OSS_COMFYUI_BASE_DIR = base/comfyui/v0.3.10-beta # 模型同步:dev OSS <-> prod OSS DEV_MOUNT ?= /mnt/funart-dev/models -PROD_MOUNT ?= /mnt/funart/models +PROD_MOUNT ?= /mnt/funart-prod/models DEV_OSS_BUCKET ?= dipper-cache-$(REGION)-dev PROD_OSS_BUCKET ?= dipper-cache-$(REGION) diff --git a/src/code/comfyui/models/sync_dev_to_prod.sh b/src/code/comfyui/models/sync_dev_to_prod.sh index faf63b77..8830f7ea 100755 --- a/src/code/comfyui/models/sync_dev_to_prod.sh +++ b/src/code/comfyui/models/sync_dev_to_prod.sh @@ -13,7 +13,7 @@ # # 环境变量(可覆盖默认值): # DEV_MOUNT dev OSS 挂载目录 (默认 /mnt/funart-dev/models) -# PROD_MOUNT prod OSS 挂载目录 (默认 /mnt/funart/models) +# PROD_MOUNT prod OSS 挂载目录 (默认 /mnt/funart-prod/models) # DEV_OSS_BUCKET dev OSS bucket (默认 dipper-cache-cn-hangzhou-dev) # PROD_OSS_BUCKET prod OSS bucket (默认 dipper-cache-cn-hangzhou) # OUTPUT_JSON diff JSON 输出路径 (默认 diff_YYYYMMDD.json,放在脚本同目录) @@ -32,7 +32,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # 可通过环境变量覆盖的配置 DEV_MOUNT="${DEV_MOUNT:-/mnt/funart-dev/models}" -PROD_MOUNT="${PROD_MOUNT:-/mnt/funart/models}" +PROD_MOUNT="${PROD_MOUNT:-/mnt/funart-prod/models}" DEV_OSS_BUCKET="${DEV_OSS_BUCKET:-dipper-cache-cn-hangzhou-dev}" PROD_OSS_BUCKET="${PROD_OSS_BUCKET:-dipper-cache-cn-hangzhou}" OUTPUT_JSON="${OUTPUT_JSON:-$SCRIPT_DIR/diff_$(date +%Y%m%d).json}" @@ -65,7 +65,7 @@ while [[ $# -gt 0 ]]; do echo "" echo "环境变量:" echo " DEV_MOUNT dev 挂载目录 (默认: /mnt/funart-dev/models)" - echo " PROD_MOUNT prod 挂载目录 (默认: /mnt/funart/models)" + echo " PROD_MOUNT prod 挂载目录 (默认: /mnt/funart-prod/models)" echo " DEV_OSS_BUCKET dev bucket (默认: dipper-cache-cn-hangzhou-dev)" echo " PROD_OSS_BUCKET prod bucket (默认: dipper-cache-cn-hangzhou)" echo " OUTPUT_JSON 输出路径 (默认: diff_YYYYMMDD.json)" From 37cf2898bf6afbbc10998cc02b5af86ee0bc96ae Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Mon, 9 Mar 2026 15:47:48 +0800 Subject: [PATCH 06/10] debug Change-Id: I5ed2b520ad22bc0fad50fa1bda8609c4e1eda04f Co-developed-by: Cursor --- .gitignore | 1 + src/code/comfyui/Makefile | 12 +++ src/code/comfyui/models/merge_models.py | 78 +++++++++++++++++++ .../{models_20251220.json => models.json} | 20 +++++ src/code/comfyui/models/sync_dev_to_prod.sh | 4 +- 5 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/code/comfyui/models/merge_models.py rename src/code/comfyui/models/{models_20251220.json => models.json} (97%) diff --git a/.gitignore b/.gitignore index f363988e..114e20b2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ **/dist .DS_Store .vscode/settings.json +reference \ No newline at end of file diff --git a/src/code/comfyui/Makefile b/src/code/comfyui/Makefile index 97ea8757..96e1227e 100644 --- a/src/code/comfyui/Makefile +++ b/src/code/comfyui/Makefile @@ -104,6 +104,18 @@ build-from-snapshot: # ===== 模型管理 ===== +# 将 models_xxx.json 融入 models.json(主模型列表),已存在的模型不覆盖 +# 用法: make merge-models MODELS_JSON=models/models_20260308.json +MODELS_JSON ?= +.PHONY: merge-models +merge-models: + @if [ -z "$(MODELS_JSON)" ]; then \ + echo "错误: 请指定 MODELS_JSON"; \ + echo "用法: make merge-models MODELS_JSON=models/models_20260308.json"; \ + exit 1; \ + fi + @python3 models/merge_models.py $(MODELS_JSON) models/models.json + # 列出 dev 有但 prod 没有的模型,生成 diff_YYYYMMDD.json # 输出文件位于 models/ 目录下 .PHONY: diff-models diff --git a/src/code/comfyui/models/merge_models.py b/src/code/comfyui/models/merge_models.py new file mode 100644 index 00000000..983d96af --- /dev/null +++ b/src/code/comfyui/models/merge_models.py @@ -0,0 +1,78 @@ +""" +将 models_xxx.json 融入 models.json(主模型列表) + +规则: + - 新模型直接追加到 models.json + - 已存在的模型跳过(不覆盖) + +用法: + python3 merge_models.py [models.json] +""" + +import json +import sys +import os + + +def merge(source_path: str, target_path: str) -> None: + if not os.path.exists(source_path): + print(f"错误: 源文件不存在: {source_path}") + sys.exit(1) + + if not os.path.exists(target_path): + print(f"错误: 目标文件不存在: {target_path}") + sys.exit(1) + + with open(source_path, "r", encoding="utf-8") as f: + source: dict = json.load(f) + + with open(target_path, "r", encoding="utf-8") as f: + target: dict = json.load(f) + + added = [] + skipped = [] + + for name, info in source.items(): + if name in target: + skipped.append(name) + else: + target[name] = info + added.append(name) + + with open(target_path, "w", encoding="utf-8") as f: + json.dump(target, f, indent=2, ensure_ascii=False) + + print(f"源文件: {source_path} ({len(source)} 个模型)") + print(f"目标文件: {target_path}") + print() + + if added: + print(f"新增 {len(added)} 个模型:") + for name in added: + print(f" + {name}") + else: + print("无新增模型") + + if skipped: + print(f"\n跳过 {len(skipped)} 个已存在的模型:") + for name in skipped: + print(f" ~ {name}") + + print(f"\n完成。models.json 现有 {len(target)} 个模型。") + + +if __name__ == "__main__": + if len(sys.argv) < 2 or len(sys.argv) > 3: + print(f"用法: python3 {sys.argv[0]} [models.json]") + print() + print("示例:") + print(f" python3 {sys.argv[0]} models_20260308.json") + print(f" python3 {sys.argv[0]} models_nunchaku.json models.json") + sys.exit(1) + + source_path = sys.argv[1] + # 默认目标为同目录下的 models.json + default_target = os.path.join(os.path.dirname(os.path.abspath(source_path)), "models.json") + target_path = sys.argv[2] if len(sys.argv) == 3 else default_target + + merge(source_path, target_path) diff --git a/src/code/comfyui/models/models_20251220.json b/src/code/comfyui/models/models.json similarity index 97% rename from src/code/comfyui/models/models_20251220.json rename to src/code/comfyui/models/models.json index 95788402..00ba52f3 100644 --- a/src/code/comfyui/models/models_20251220.json +++ b/src/code/comfyui/models/models.json @@ -1487,5 +1487,25 @@ "used_in_templates": [ "wan2.1_fun_inp.json" ] + }, + "qwen_image_edit_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_fp8_e4m3fn.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit-2509-lightning-4steps-251115.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/lightning-251115/svdq-int4_r32-qwen-image-edit-2509-lightning-4steps-251115.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit-2509-lightning-4steps-251115.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/lightning-251115/svdq-int4_r128-qwen-image-edit-2509-lightning-4steps-251115.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-qwen-image-edit-2509-lightningv2.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/svdq-fp4_r128-qwen-image-edit-2509-lightningv2.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors", + "directory": "diffusion_models" } } \ No newline at end of file diff --git a/src/code/comfyui/models/sync_dev_to_prod.sh b/src/code/comfyui/models/sync_dev_to_prod.sh index 8830f7ea..9f9f6e0d 100755 --- a/src/code/comfyui/models/sync_dev_to_prod.sh +++ b/src/code/comfyui/models/sync_dev_to_prod.sh @@ -179,7 +179,7 @@ FAILED=0 FAILED_MODELS=() # 使用进程替换避免子 shell 导致计数器失效 -while IFS='###SEP###' read -r filename directory; do +while IFS=$'\t' read -r filename directory; do src="oss://${DEV_OSS_BUCKET}/${DEV_OSS_PREFIX}/${directory}/${filename}" dst="oss://${PROD_OSS_BUCKET}/${PROD_OSS_PREFIX}/${directory}/${filename}" @@ -202,7 +202,7 @@ with open('${OUTPUT_JSON}', 'r') as f: data = json.load(f) for filename, info in data.items(): directory = info.get('directory', 'unknown') - print(f'{filename}###SEP###{directory}') + print(f'{filename}\t{directory}') ") if [ "$DRY_RUN" = false ]; then From 605ddeb38089b2e2bd964cef9580ed64388ed932 Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Mon, 9 Mar 2026 17:34:06 +0800 Subject: [PATCH 07/10] debug Change-Id: I3b06e144da0c91a846588f5c6fc9b200c45287c3 Co-developed-by: Cursor --- src/code/comfyui/Makefile | 8 +- src/code/comfyui/models/README.md | 354 ++++++++---------- src/code/comfyui/models/models.json | 96 +++++ .../models/{ => scripts}/cal_checksum.py | 0 .../models/{ => scripts}/download_models.sh | 0 .../models/{ => scripts}/extract_models.py | 0 .../models/{ => scripts}/merge_models.py | 3 + .../models/{ => scripts}/sync_dev_to_prod.sh | 0 8 files changed, 268 insertions(+), 193 deletions(-) rename src/code/comfyui/models/{ => scripts}/cal_checksum.py (100%) rename src/code/comfyui/models/{ => scripts}/download_models.sh (100%) rename src/code/comfyui/models/{ => scripts}/extract_models.py (100%) rename src/code/comfyui/models/{ => scripts}/merge_models.py (96%) rename src/code/comfyui/models/{ => scripts}/sync_dev_to_prod.sh (100%) diff --git a/src/code/comfyui/Makefile b/src/code/comfyui/Makefile index 96e1227e..6770610c 100644 --- a/src/code/comfyui/Makefile +++ b/src/code/comfyui/Makefile @@ -114,7 +114,7 @@ merge-models: echo "用法: make merge-models MODELS_JSON=models/models_20260308.json"; \ exit 1; \ fi - @python3 models/merge_models.py $(MODELS_JSON) models/models.json + @python3 models/scripts/merge_models.py $(MODELS_JSON) models/models.json # 列出 dev 有但 prod 没有的模型,生成 diff_YYYYMMDD.json # 输出文件位于 models/ 目录下 @@ -122,7 +122,7 @@ merge-models: diff-models: @DEV_MOUNT=$(DEV_MOUNT) \ PROD_MOUNT=$(PROD_MOUNT) \ - bash models/sync_dev_to_prod.sh --diff-only + bash models/scripts/sync_dev_to_prod.sh --diff-only # 将 dev 有但 prod 没有的模型同步到 prod OSS .PHONY: sync-models-to-prod @@ -131,7 +131,7 @@ sync-models-to-prod: PROD_MOUNT=$(PROD_MOUNT) \ DEV_OSS_BUCKET=$(DEV_OSS_BUCKET) \ PROD_OSS_BUCKET=$(PROD_OSS_BUCKET) \ - bash models/sync_dev_to_prod.sh + bash models/scripts/sync_dev_to_prod.sh # 打印将要执行的 ossutil 同步命令(不实际执行) .PHONY: sync-models-to-prod-dry-run @@ -140,4 +140,4 @@ sync-models-to-prod-dry-run: PROD_MOUNT=$(PROD_MOUNT) \ DEV_OSS_BUCKET=$(DEV_OSS_BUCKET) \ PROD_OSS_BUCKET=$(PROD_OSS_BUCKET) \ - bash models/sync_dev_to_prod.sh --dry-run \ No newline at end of file + bash models/scripts/sync_dev_to_prod.sh --dry-run \ No newline at end of file diff --git a/src/code/comfyui/models/README.md b/src/code/comfyui/models/README.md index a7d2d733..0d627526 100644 --- a/src/code/comfyui/models/README.md +++ b/src/code/comfyui/models/README.md @@ -1,246 +1,219 @@ -# ComfyUI 模型下载工具 +# ComfyUI 模型管理工具 -从 ComfyUI 模板中提取模型信息,批量下载并验证文件完整性的工具集。 +批量下载、验证、同步 ComfyUI 模型的工具集。 -## 📁 工具脚本 +## 📁 目录结构 -| 脚本 | 功能 | -|------|------| -| `extract_models.py` | 从模板中提取模型信息 | -| `download_models.sh` | 批量下载模型文件 | -| `cal_checksum.py` | 验证文件 SHA256 完整性 | +``` +models/ +├── models.json # 主模型列表(全量,长期维护) +├── models_xxx.json # 增量模型列表(按批次,合并前暂存) +├── scripts/ +│ ├── extract_models.py # 从模板中提取模型信息 +│ ├── download_models.sh # 批量下载模型文件 +│ ├── cal_checksum.py # 验证文件 SHA256 完整性 +│ ├── merge_models.py # 将增量列表合并到 models.json +│ └── sync_dev_to_prod.sh # 将 dev OSS 模型同步到 prod OSS +└── README.md +``` -## 🚀 使用流程 +**OSS 挂载说明**: + +| 环境 | 挂载路径 | OSS Bucket | +|------|----------|------------| +| Dev | `/mnt/funart-dev/models` | `dipper-cache-cn-hangzhou-dev` | +| Prod | `/mnt/funart-prod/models` | `dipper-cache-cn-hangzhou` | + +--- + +## 🚀 完整工作流 ### 准备工作 -安装依赖: ```bash pip install huggingface_hub ``` -### 第 1 步:提取模型信息 +--- + +### 第 1 步:准备增量模型列表 -从 `templates` 目录提取所有模板使用的模型信息: +**方式 A:从模板自动提取**(提取工作流广场模板中引用的模型) ```bash cd models -python3 extract_models.py +python3 scripts/extract_models.py +# 输出: models_YYYYMMDD.json ``` -**输出**:`models_20251225.json`(自动生成当前日期) +**方式 B:手动维护** -### 第 2 步:下载模型 +直接创建或编辑 `models_xxx.json`,格式如下: -根据提取的配置文件下载模型: +```json +{ + "wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.2_ComfyUI_Repackaged/resolve/main/split_files/diffusion_models/wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors", + "directory": "diffusion_models" + } +} +``` + +--- + +### 第 2 步:下载模型到 dev ```bash # 下载所有模型(使用国内镜像加速) -./download_models.sh models_20251220.json /root/ComfyUI/models --use-mirror - -# 只下载指定目录的模型(推荐) -./download_models.sh models_20251220.json /root/ComfyUI/models --use-mirror --dirs vae loras +export HF_ENDPOINT="https://hf-mirror.com" +./scripts/download_models.sh models_20260308.json /mnt/funart-dev/models --use-mirror -# 支持多个目录 -./download_models.sh models_20251220.json /root/ComfyUI/models --use-mirror --dirs unet clip vae loras +# 只下载指定目录的模型(推荐,按需下载) +./scripts/download_models.sh models_20260308.json /mnt/funart-dev/models --use-mirror --dirs diffusion_models loras ``` **参数说明**: -- `models_*.json`:第 1 步生成的配置文件 -- `/root/ComfyUI/models`:下载目标目录 -- `--use-mirror`:使用国内镜像(https://hf-mirror.com) -- `--dirs <目录...>`:只下载指定目录的模型 -**功能特性**: -- ✅ 自动创建目录结构 -- ✅ 跳过已存在的文件 -- ✅ 失败自动重试 3 次 -- ✅ 显示详细的下载进度和统计 +| 参数 | 说明 | +|------|------| +| `models_xxx.json` | 增量模型列表 | +| `/mnt/funart-dev/models` | 下载目标目录(dev 挂载路径) | +| `--use-mirror` | 使用国内镜像(https://hf-mirror.com) | +| `--dirs <目录...>` | 只下载指定目录的模型 | -### 第 3 步:验证完整性 +--- -验证下载的文件是否完整: +### 第 3 步:验证 checksum ```bash -# 验证所有模型 -python3 cal_checksum.py /root/ComfyUI/models models_20251220.json +# 验证所有下载的模型 +python3 scripts/cal_checksum.py /mnt/funart-dev/models models_20260308.json # 只验证指定目录 -python3 cal_checksum.py /root/ComfyUI/models models_20251220.json --dir vae - -# 使用国内镜像获取 SHA256(推荐) -export HF_ENDPOINT="https://hf-mirror.com" -python3 cal_checksum.py /root/ComfyUI/models models_20251220.json +python3 scripts/cal_checksum.py /mnt/funart-dev/models models_20260308.json --dir diffusion_models ``` -**验证结果**: +验证结果: - ✅ **一致**:文件完整 -- ❌ **不一致**:需要重新下载 -- ⚠️ **错误**:无法验证(非 HF 链接或缺少 URL) +- ❌ **不一致**:删除后重新下载 -如有不一致的文件,删除后重新运行第 2 步: ```bash -rm /root/ComfyUI/models/loras/problematic_model.safetensors -./download_models.sh models_20251225.json /root/ComfyUI/models --use-mirror --dirs loras +# 重新下载不一致的模型 +rm /mnt/funart-dev/models/diffusion_models/problematic_model.safetensors +./scripts/download_models.sh models_20260308.json /mnt/funart-dev/models --use-mirror --dirs diffusion_models ``` -## 💡 使用技巧 +--- -### 按需下载,节省时间和空间 +### 第 4 步:同步到 prod OSS + +确认 dev 下载无误后,将新模型同步到 prod。 -根据实际需要,先下载关键模型: +**先 dry-run,确认将执行的 ossutil 命令**: ```bash -# 先下载小文件 -./download_models.sh models_20251225.json /root/models --use-mirror --dirs vae loras clip +make sync-models-to-prod-dry-run +``` -# 网络稳定时再下载大模型 -./download_models.sh models_20251225.json /root/models --use-mirror --dirs unet checkpoints +输出示例: + +``` +[Dry Run] 将执行以下 ossutil 命令: + ossutil cp --ignore-existing "oss://dipper-cache-cn-hangzhou-dev/funart/models/diffusion_models/wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors" "oss://dipper-cache-cn-hangzhou/function-art/comfyui/models/diffusion_models/wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors" + ... +``` + +**确认无误后,正式同步**: + +```bash +make sync-models-to-prod ``` -### 查看可用目录 +> 同步使用 `--ignore-existing`,不会覆盖 prod 中已存在的模型。 -查看配置文件中包含哪些目录: +**只查看 diff,不执行同步**: ```bash -python3 -c " -import json -from collections import Counter -with open('models_20251225.json') as f: - data = json.load(f) -dirs = Counter(info.get('directory', 'unknown') for info in data.values()) -for dir_name, count in sorted(dirs.items()): - print(f'{dir_name}: {count} 个模型') -" +make diff-models +# 生成 models/diff_YYYYMMDD.json ``` -常见目录: -- `unet`:UNET 模型(通常较大) -- `vae`:VAE 编码器 -- `clip`:CLIP 文本编码器 -- `loras`:LoRA 微调模型 -- `checkpoints`:完整检查点 -- `controlnet`:ControlNet 控制模型 -- `clip_vision`:CLIP 视觉编码器 +--- -## 📊 输出示例 +### 第 5 步:合并到主模型列表 -### 提取模型信息 +同步完成后,将增量列表合并到 `models.json`: -``` -============================== -提取 ComfyUI 模板中的模型信息 -============================== -模板目录: ../templates - -正在分析模板文件... -找到 206 个模板文件 -✓ 找到 130 个独特的模型文件 -✓ 已生成: models_20251220.json - -按目录分布: - unet : 46 个 - loras : 18 个 - checkpoints: 19 个 - vae : 10 个 - ... +```bash +make merge-models MODELS_JSON=models/models_20260308.json ``` -### 下载模型 +输出示例: ``` -====================================== -开始下载 ComfyUI 模型 -====================================== -模型配置: models_20251220.json -目标目录: /root/ComfyUI/models -筛选目录: vae loras - -可用目录: audio checkpoints clip controlnet loras unet vae -要下载 28 个模型 - -[1/28] vae-ft-mse-840000-ema-pruned.safetensors - 目录: vae - 下载中... - ✓ 下载完成 - -[2/28] flux1-depth-dev-lora.safetensors - 目录: loras - ✓ 已存在,跳过 -... - -====================================== -下载完成! -====================================== -成功: 22 -跳过: 5 -失败: 1 -总计: 28 -====================================== -``` +源文件: models/models_20260308.json (5 个模型) +目标文件: models/models.json -### 验证完整性 +新增 5 个模型: + + wan2.2_i2v_low_noise_14B_fp8_scaled.safetensors + + wan2.2_i2v_high_noise_14B_fp8_scaled.safetensors + ... -``` -================================================================================ -🔍 ComfyUI 模型 SHA256 验证工具 -================================================================================ -✓ 找到 28 个模型文件 - -[1/28] 验证: vae/vae-ft-mse.safetensors - 计算本地 SHA256... - 从 Hugging Face 获取 SHA256... -✅ 状态: 一致 -... - -================================================================================ -📊 验证总结 -================================================================================ -总文件数: 28 -✅ 一致: 27 -❌ 不一致: 1 - -⚠️ 以下模型 SHA256 不一致,建议重新下载: - • loras/problematic_model.safetensors -================================================================================ +完成。models.json 现有 140 个模型。 ``` -## ⚠️ 常见问题 +> 合并规则:新模型追加,已存在的跳过,不会覆盖 `models.json` 中已有条目。 -### 1. 下载速度慢 +--- -**解决方案**:使用 `--use-mirror` 启用国内镜像加速 +## 📋 Make 命令速查 -```bash -./download_models.sh models_20251225.json /root/models --use-mirror -``` +| 命令 | 说明 | +|------|------| +| `make diff-models` | 列出 dev 有但 prod 没有的模型,生成 `diff_YYYYMMDD.json` | +| `make sync-models-to-prod-dry-run` | 预览将执行的 ossutil 命令(不实际执行) | +| `make sync-models-to-prod` | 将 dev 新模型同步到 prod OSS | +| `make merge-models MODELS_JSON=models/models_xxx.json` | 将增量列表合并到 `models.json` | -### 2. 找不到 hf 命令 +**覆盖默认变量**(如挂载路径或 bucket 不同时): -**解决方案**: ```bash -pip install -U huggingface_hub +make sync-models-to-prod \ + DEV_MOUNT=/custom/dev/path \ + PROD_MOUNT=/custom/prod/path \ + DEV_OSS_BUCKET=my-dev-bucket \ + PROD_OSS_BUCKET=my-prod-bucket ``` -### 3. 下载失败 +--- + +## 💡 使用技巧 + +### 按需下载,节省时间和空间 -**解决方案**: -1. 检查网络连接 -2. 使用镜像加速(`--use-mirror`) -3. 检查磁盘空间:`df -h` -4. 脚本会自动重试 3 次,失败后可手动重新运行 +```bash +# 先下载小文件 +./scripts/download_models.sh models_xxx.json /mnt/funart-dev/models --use-mirror --dirs vae loras clip -### 4. SHA256 不一致 +# 网络稳定时再下载大模型 +./scripts/download_models.sh models_xxx.json /mnt/funart-dev/models --use-mirror --dirs diffusion_models unet checkpoints +``` -**原因**:文件下载不完整或损坏 +### 查看模型按目录分布 -**解决方案**:删除文件后重新下载 ```bash -rm /path/to/problematic_model.safetensors -./download_models.sh models_20251225.json /root/models --use-mirror +python3 -c " +import json +from collections import Counter +with open('models/models.json') as f: + data = json.load(f) +dirs = Counter(info.get('directory', 'unknown') for info in data.values()) +for d, count in sorted(dirs.items()): + print(f'{d}: {count} 个模型') +" ``` -## 🌐 永久配置国内镜像 +### 永久配置国内镜像 在 `~/.bashrc` 或 `~/.zshrc` 中添加: @@ -248,35 +221,38 @@ rm /path/to/problematic_model.safetensors export HF_ENDPOINT="https://hf-mirror.com" ``` -然后重新加载: +配置后无需每次都加 `--use-mirror` 参数。 + +--- + +## ⚠️ 常见问题 + +### 下载速度慢 + +使用 `--use-mirror` 或预先设置 `HF_ENDPOINT` 环境变量。 + +### 找不到 hf 命令 + ```bash -source ~/.bashrc # 或 source ~/.zshrc +pip install -U huggingface_hub ``` -配置后,无需每次都加 `--use-mirror` 参数。 - -## 📖 工作原理 +### SHA256 不一致 -### extract_models.py -1. 扫描 `templates` 目录的所有 JSON 文件 -2. 解析节点中的模型文件名和下载链接 -3. 根据节点类型推断存储目录 -4. 生成 `models_{日期}.json` 配置文件 +文件下载不完整或损坏,删除后重新下载: -### download_models.sh -1. 读取配置文件中的模型信息 -2. 根据 `--dirs` 参数筛选目录(可选) -3. 检查文件是否已存在,存在则跳过 -4. 使用 `hf download` 命令下载 -5. 失败自动重试,最多 3 次 -6. 生成下载统计报告 +```bash +rm /mnt/funart-dev/models/diffusion_models/problematic_model.safetensors +./scripts/download_models.sh models_xxx.json /mnt/funart-dev/models --use-mirror --dirs diffusion_models +``` -### cal_checksum.py -1. 扫描指定目录的模型文件 -2. 计算本地文件的 SHA256 -3. 从 Hugging Face API 获取远程 SHA256 -4. 比对并生成验证报告 +### ossutil 未配置 ---- +```bash +# 安装 +sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash -**提示**:建议使用 `--dirs` 参数按需下载,避免下载不需要的大模型,节省时间和磁盘空间。 +# 配置(需要有 OSS 写权限的 AK/SK,可联系 zijian) +ossutil config +# endpoint: oss-cn-hangzhou-internal.aliyuncs.com(内网)或 oss-cn-hangzhou.aliyuncs.com(公网) +``` diff --git a/src/code/comfyui/models/models.json b/src/code/comfyui/models/models.json index 00ba52f3..0152ffc8 100644 --- a/src/code/comfyui/models/models.json +++ b/src/code/comfyui/models/models.json @@ -1507,5 +1507,101 @@ "svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors": { "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors", "directory": "diffusion_models" + }, + "svdq-int4_r32-flux.1-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-dev/resolve/main/svdq-int4_r32-flux.1-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-flux.1-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-dev/resolve/main/svdq-fp4_r32-flux.1-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-flux.1-schnell.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-schnell/resolve/main/svdq-fp4_r32-flux.1-schnell.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-flux.1-schnell.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-schnell/resolve/main/svdq-int4_r32-flux.1-schnell.safetensors", + "directory": "diffusion_models" + }, + "awq-int4-flux.1-t5xxl.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-t5/resolve/main/awq-int4-flux.1-t5xxl.safetensors", + "directory": "text_encoders" + }, + "svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-flux.1-kontext-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev/resolve/main/svdq-fp4_r32-flux.1-kontext-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-flux.1-kontext-dev.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev/resolve/main/svdq-int4_r32-flux.1-kontext-dev.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r128-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-fp4_r128-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-fp4_r32-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-fp4_r32-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r128-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r256-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r256-z-image-turbo.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r32-z-image-turbo.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r32-z-image-turbo.safetensors", + "directory": "diffusion_models" } } \ No newline at end of file diff --git a/src/code/comfyui/models/cal_checksum.py b/src/code/comfyui/models/scripts/cal_checksum.py similarity index 100% rename from src/code/comfyui/models/cal_checksum.py rename to src/code/comfyui/models/scripts/cal_checksum.py diff --git a/src/code/comfyui/models/download_models.sh b/src/code/comfyui/models/scripts/download_models.sh similarity index 100% rename from src/code/comfyui/models/download_models.sh rename to src/code/comfyui/models/scripts/download_models.sh diff --git a/src/code/comfyui/models/extract_models.py b/src/code/comfyui/models/scripts/extract_models.py similarity index 100% rename from src/code/comfyui/models/extract_models.py rename to src/code/comfyui/models/scripts/extract_models.py diff --git a/src/code/comfyui/models/merge_models.py b/src/code/comfyui/models/scripts/merge_models.py similarity index 96% rename from src/code/comfyui/models/merge_models.py rename to src/code/comfyui/models/scripts/merge_models.py index 983d96af..0a02ff7c 100644 --- a/src/code/comfyui/models/merge_models.py +++ b/src/code/comfyui/models/scripts/merge_models.py @@ -42,6 +42,8 @@ def merge(source_path: str, target_path: str) -> None: with open(target_path, "w", encoding="utf-8") as f: json.dump(target, f, indent=2, ensure_ascii=False) + os.remove(source_path) + print(f"源文件: {source_path} ({len(source)} 个模型)") print(f"目标文件: {target_path}") print() @@ -59,6 +61,7 @@ def merge(source_path: str, target_path: str) -> None: print(f" ~ {name}") print(f"\n完成。models.json 现有 {len(target)} 个模型。") + print(f"已删除源文件: {source_path}") if __name__ == "__main__": diff --git a/src/code/comfyui/models/sync_dev_to_prod.sh b/src/code/comfyui/models/scripts/sync_dev_to_prod.sh similarity index 100% rename from src/code/comfyui/models/sync_dev_to_prod.sh rename to src/code/comfyui/models/scripts/sync_dev_to_prod.sh From 4d52d90dfbeaf9e692f3b7defb20d8d24c9acb5c Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Mon, 9 Mar 2026 19:54:59 +0800 Subject: [PATCH 08/10] debug Change-Id: I62412655746440b931a73229606f4010529d63fa Co-developed-by: Cursor --- src/code/comfyui/models/models_20260308.json | 22 ----- src/code/comfyui/models/models_nunchaku.json | 99 -------------------- 2 files changed, 121 deletions(-) delete mode 100644 src/code/comfyui/models/models_20260308.json delete mode 100644 src/code/comfyui/models/models_nunchaku.json diff --git a/src/code/comfyui/models/models_20260308.json b/src/code/comfyui/models/models_20260308.json deleted file mode 100644 index 6f699ed3..00000000 --- a/src/code/comfyui/models/models_20260308.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "qwen_image_edit_fp8_e4m3fn.safetensors": { - "url": "https://huggingface.co/Comfy-Org/Qwen-Image-Edit_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_edit_fp8_e4m3fn.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r32-qwen-image-edit-2509-lightning-4steps-251115.safetensors": { - "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/lightning-251115/svdq-int4_r32-qwen-image-edit-2509-lightning-4steps-251115.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r128-qwen-image-edit-2509-lightning-4steps-251115.safetensors": { - "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/lightning-251115/svdq-int4_r128-qwen-image-edit-2509-lightning-4steps-251115.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r128-qwen-image-edit-2509-lightningv2.0-4steps.safetensors": { - "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/svdq-fp4_r128-qwen-image-edit-2509-lightningv2.0-4steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors": { - "url": "https://huggingface.co/nunchaku-ai/nunchaku-qwen-image-edit-2509/resolve/main/svdq-fp4_r32-qwen-image-edit-2509-lightningv2.0-4steps.safetensors", - "directory": "diffusion_models" - } -} diff --git a/src/code/comfyui/models/models_nunchaku.json b/src/code/comfyui/models/models_nunchaku.json deleted file mode 100644 index 21e797c9..00000000 --- a/src/code/comfyui/models/models_nunchaku.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "svdq-int4_r32-flux.1-dev.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-dev/resolve/main/svdq-int4_r32-flux.1-dev.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-flux.1-dev.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-dev/resolve/main/svdq-fp4_r32-flux.1-dev.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-flux.1-schnell.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-schnell/resolve/main/svdq-fp4_r32-flux.1-schnell.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r32-flux.1-schnell.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-schnell/resolve/main/svdq-int4_r32-flux.1-schnell.safetensors", - "directory": "diffusion_models" - }, - - "awq-int4-flux.1-t5xxl.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-t5/resolve/main/awq-int4-flux.1-t5xxl.safetensors", - "directory": "text_encoders" - }, - "svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r128-qwen-image-edit.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r128-qwen-image-edit.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-qwen-image-edit.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-fp4_r32-qwen-image-edit.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit-lightningv1.0-4steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit-lightningv1.0-8steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r128-qwen-image-edit.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r128-qwen-image-edit.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit-lightningv1.0-4steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit-lightningv1.0-8steps.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r32-qwen-image-edit.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit/resolve/main/svdq-int4_r32-qwen-image-edit.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-flux.1-kontext-dev.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev/resolve/main/svdq-fp4_r32-flux.1-kontext-dev.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r32-flux.1-kontext-dev.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-flux.1-kontext-dev/resolve/main/svdq-int4_r32-flux.1-kontext-dev.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r128-z-image-turbo.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-fp4_r128-z-image-turbo.safetensors", - "directory": "diffusion_models" - }, - "svdq-fp4_r32-z-image-turbo.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-fp4_r32-z-image-turbo.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r128-z-image-turbo.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r128-z-image-turbo.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r256-z-image-turbo.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r256-z-image-turbo.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r32-z-image-turbo.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r32-z-image-turbo.safetensors", - "directory": "diffusion_models" - } -} \ No newline at end of file From 415f5f5401411a10bf3c4945d78d49d3d68bd9e7 Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Wed, 11 Mar 2026 21:33:22 +0800 Subject: [PATCH 09/10] dbg Change-Id: Iec3f540cc933adb3606461d0026bc21282e35c4e Co-developed-by: Cursor --- src/code/comfyui/models/models-0311.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/code/comfyui/models/models-0311.json diff --git a/src/code/comfyui/models/models-0311.json b/src/code/comfyui/models/models-0311.json new file mode 100644 index 00000000..86f20437 --- /dev/null +++ b/src/code/comfyui/models/models-0311.json @@ -0,0 +1,17 @@ +{ +"svdq-int4_r32-qwen-image-edit-2509.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit-2509/resolve/main/svdq-int4_r32-qwen-image-edit-2509.safetensors", + "directory": "diffusion_models" + }, + "qwen_image_2512_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_2512_fp8_e4m3fn.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image/resolve/main/svdq-int4_r128-qwen-image.safetensors", + "directory": "diffusion_models" + }, + "wan2.1_t2v_1.3B_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_t2v_1.3B_bf16.safetensors", + "directory": "unet" + }} \ No newline at end of file From 4d1b015d341d7553c30a08e85c952e9de33eff3d Mon Sep 17 00:00:00 2001 From: "dehui.kdh" Date: Thu, 12 Mar 2026 11:08:27 +0800 Subject: [PATCH 10/10] debug Change-Id: I398289a3ac17d5afb32c4237a81d49a1d4362fb9 Co-developed-by: Cursor --- src/code/comfyui/models/models-0311.json | 17 ----------------- src/code/comfyui/models/models.json | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 17 deletions(-) delete mode 100644 src/code/comfyui/models/models-0311.json diff --git a/src/code/comfyui/models/models-0311.json b/src/code/comfyui/models/models-0311.json deleted file mode 100644 index 86f20437..00000000 --- a/src/code/comfyui/models/models-0311.json +++ /dev/null @@ -1,17 +0,0 @@ -{ -"svdq-int4_r32-qwen-image-edit-2509.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit-2509/resolve/main/svdq-int4_r32-qwen-image-edit-2509.safetensors", - "directory": "diffusion_models" - }, - "qwen_image_2512_fp8_e4m3fn.safetensors": { - "url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_2512_fp8_e4m3fn.safetensors", - "directory": "diffusion_models" - }, - "svdq-int4_r128-qwen-image.safetensors": { - "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image/resolve/main/svdq-int4_r128-qwen-image.safetensors", - "directory": "diffusion_models" - }, - "wan2.1_t2v_1.3B_bf16.safetensors": { - "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_t2v_1.3B_bf16.safetensors", - "directory": "unet" - }} \ No newline at end of file diff --git a/src/code/comfyui/models/models.json b/src/code/comfyui/models/models.json index 0152ffc8..13fa9794 100644 --- a/src/code/comfyui/models/models.json +++ b/src/code/comfyui/models/models.json @@ -1603,5 +1603,21 @@ "svdq-int4_r32-z-image-turbo.safetensors": { "url": "https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo/resolve/main/svdq-int4_r32-z-image-turbo.safetensors", "directory": "diffusion_models" + }, + "svdq-int4_r32-qwen-image-edit-2509.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image-edit-2509/resolve/main/svdq-int4_r32-qwen-image-edit-2509.safetensors", + "directory": "diffusion_models" + }, + "qwen_image_2512_fp8_e4m3fn.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Qwen-Image_ComfyUI/resolve/main/split_files/diffusion_models/qwen_image_2512_fp8_e4m3fn.safetensors", + "directory": "diffusion_models" + }, + "svdq-int4_r128-qwen-image.safetensors": { + "url": "https://huggingface.co/nunchaku-tech/nunchaku-qwen-image/resolve/main/svdq-int4_r128-qwen-image.safetensors", + "directory": "diffusion_models" + }, + "wan2.1_t2v_1.3B_bf16.safetensors": { + "url": "https://huggingface.co/Comfy-Org/Wan_2.1_ComfyUI_repackaged/resolve/main/split_files/diffusion_models/wan2.1_t2v_1.3B_bf16.safetensors", + "directory": "unet" } } \ No newline at end of file