1. Fix Make Image Grid `from torchvision import transforms as TF` -> `import torchvision.transforms.functional as TF` issue. 2. Upgrade Split Image Grid node: ① Reasonable default values: Ensure at least 1 row/column to avoid division by zero errors. ② Better error messages: Provide specific resolution suggestions. ③ Boundary checks: Ensure cropping does not exceed the image area. ④ Empty list protection: Ensure a valid image tensor is always returned. ⑤ Exception handling: Gracefully handle errors in crop mode. 3. Separated the `install.py` file for ComfyUI and the `install_manual.py` file for the `install.bat` file. It should work fine now. 4. Zip IPAdapterPlus.py to IPAdapterPlus.zip to avoid node-conflict attention in ComfyUI Manager. 5. Random Prompter supports both string dictionaries, lists or txt format for YAML files. 6. Add more choices to Random Prompter.
296 lines
10 KiB
Python
296 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
JakeUpgrade Nodes Auto-Install Script
|
|
JakeUpgrade 节点自动安装脚本
|
|
用于安装 ComfyUI 自定义节点所需的依赖包
|
|
For installing dependencies required by ComfyUI custom nodes
|
|
"""
|
|
|
|
import sys
|
|
import subprocess
|
|
import os
|
|
import platform
|
|
import re
|
|
from pathlib import Path
|
|
|
|
def get_comfyui_path():
|
|
"""获取 ComfyUI 根目录路径 / Get ComfyUI root path"""
|
|
current_dir = Path(__file__).parent
|
|
|
|
# 尝试多种可能的目录结构
|
|
possible_paths = [
|
|
current_dir.parent.parent, # root\ComfyUI\custom_nodes\
|
|
current_dir.parent.parent.parent, # root\ComfyUI\custom_nodes\node_name
|
|
current_dir.parent.parent.parent.parent, # root\ComfyUI\custom_nodes\node_name\subfolder
|
|
]
|
|
|
|
for comfy_path in possible_paths:
|
|
# 检查是否是 ComfyUI 目录
|
|
if (comfy_path / "ComfyUI").exists():
|
|
return comfy_path
|
|
|
|
# 如果找不到,返回当前目录的父目录的父目录
|
|
return current_dir.parent.parent
|
|
|
|
def get_python_executable():
|
|
"""获取 Python 可执行文件路径 / Get Python executable path"""
|
|
comfy_path = get_comfyui_path()
|
|
|
|
# 优先使用嵌入式 Python / Prefer embedded Python
|
|
embedded_python = comfy_path / "python_embeded" / "python.exe"
|
|
if embedded_python.exists():
|
|
print(f"✅ Using embedded Python: {embedded_python}")
|
|
return str(embedded_python)
|
|
|
|
# 检查 ComfyUI 目录下的嵌入式 Python
|
|
embedded_python2 = comfy_path / "ComfyUI" / "python_embeded" / "python.exe"
|
|
if embedded_python2.exists():
|
|
print(f"✅ Using embedded Python: {embedded_python2}")
|
|
return str(embedded_python2)
|
|
|
|
# 使用系统 Python / Use system Python
|
|
system_python = sys.executable
|
|
print(f"✅ Using system Python: {system_python}")
|
|
return system_python
|
|
|
|
def check_python_version(python_exec):
|
|
"""检查 Python 版本 / Check Python version"""
|
|
print("🔍 Checking Python version...")
|
|
try:
|
|
result = subprocess.run(
|
|
[python_exec, "--version"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
if result.returncode == 0:
|
|
version_output = result.stdout.strip()
|
|
print(f"✅ Python version: {version_output}")
|
|
|
|
# 解析版本号 / Parse version number
|
|
version_match = re.search(r"Python (\d+)\.(\d+)", version_output)
|
|
if version_match:
|
|
major, minor = int(version_match.group(1)), int(version_match.group(2))
|
|
if major < 3 or (major == 3 and minor < 8):
|
|
print(f"❌ Unsupported Python version: {version_output}")
|
|
print("✅ Requires Python 3.8 or higher")
|
|
return False
|
|
return True
|
|
except Exception as e:
|
|
print(f"❌ Failed to check Python version: {e}")
|
|
return False
|
|
|
|
return True
|
|
|
|
def check_existing_dependencies(python_exec):
|
|
"""检查已安装的依赖 / Check existing dependencies"""
|
|
print("\n🔍 Checking existing dependencies...")
|
|
|
|
try:
|
|
# 获取已安装的包列表
|
|
result = subprocess.run(
|
|
[python_exec, "-s", "-m", "pip", "list", "--format=freeze"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
installed_packages = set()
|
|
for line in result.stdout.strip().split('\n'):
|
|
if line and '==' in line:
|
|
pkg = line.split('==', 1)[0].strip().lower()
|
|
installed_packages.add(pkg)
|
|
|
|
# 读取 requirements.txt
|
|
current_dir = Path(__file__).parent
|
|
requirements_file = current_dir / "requirements.txt"
|
|
|
|
with open(requirements_file, 'r', encoding='utf-8') as f:
|
|
requirements = f.readlines()
|
|
|
|
missing_packages = []
|
|
for req in requirements:
|
|
req = req.strip()
|
|
if not req or req.startswith('#'):
|
|
continue
|
|
|
|
# 只检查包名,不考虑版本
|
|
pkg_name = req.strip().lower()
|
|
|
|
if pkg_name not in installed_packages:
|
|
missing_packages.append(req)
|
|
print(f"❌ {req} - Not installed")
|
|
else:
|
|
print(f"✅ {req} - Already installed")
|
|
|
|
return missing_packages
|
|
else:
|
|
print(f"❌ Cannot get installed packages: {result.stderr}")
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"❌ Error checking dependencies: {e}")
|
|
return None
|
|
|
|
def install_missing_only(python_exec, missing_packages):
|
|
"""只安装缺失的包 / Install only missing packages"""
|
|
if not missing_packages:
|
|
print("✅ All dependencies already installed")
|
|
return True
|
|
|
|
print(f"\n📦 Packages to install: {', '.join(missing_packages)}")
|
|
|
|
try:
|
|
# 为所有缺失的包一次性安装
|
|
print("⏳ Installing missing dependencies...")
|
|
result = subprocess.run(
|
|
[python_exec, "-s", "-m", "pip", "install"] + missing_packages,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print("✅ Missing dependencies installed")
|
|
return True
|
|
else:
|
|
print(f"❌ Installation failed: {result.stderr}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"❌ Exception during installation: {e}")
|
|
return False
|
|
|
|
def install_requirements(python_exec):
|
|
"""安装 requirements.txt 中的依赖 / Install dependencies from requirements.txt"""
|
|
print("\n📦 Starting dependency check...")
|
|
|
|
current_dir = Path(__file__).parent
|
|
requirements_file = current_dir / "requirements.txt"
|
|
|
|
if not requirements_file.exists():
|
|
print(f"❌ requirements.txt not found: {requirements_file}")
|
|
return False
|
|
|
|
try:
|
|
# 首先检查已安装的依赖
|
|
missing_packages = check_existing_dependencies(python_exec)
|
|
|
|
if missing_packages is None:
|
|
# 如果检查失败,回退到传统安装方式
|
|
print("⚠️ Dependency check failed, using traditional installation")
|
|
return install_traditional(python_exec, requirements_file)
|
|
|
|
# 只安装缺失的包
|
|
return install_missing_only(python_exec, missing_packages)
|
|
|
|
except Exception as e:
|
|
print(f"❌ Exception during installation: {e}")
|
|
return install_traditional(python_exec, requirements_file)
|
|
|
|
def install_traditional(python_exec, requirements_file):
|
|
"""传统安装方式(备用) / Traditional installation (fallback)"""
|
|
print("🔄 Using traditional installation method")
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
[python_exec, "-s", "-m", "pip", "install", "-r", str(requirements_file)],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print("✅ Dependencies installation completed!")
|
|
return True
|
|
else:
|
|
print(f"❌ Error during installation:")
|
|
if result.stdout:
|
|
print(f"Stdout: {result.stdout}")
|
|
if result.stderr:
|
|
print(f"Stderr: {result.stderr}")
|
|
return False
|
|
|
|
except subprocess.TimeoutExpired:
|
|
print("❌ Installation timeout, check network connection or install manually")
|
|
return False
|
|
|
|
def check_installation(python_exec):
|
|
"""检查安装结果 / Check installation results"""
|
|
print("\n🔍 Checking installation results...")
|
|
|
|
packages_to_check = [
|
|
("cv2", "opencv-python"),
|
|
("piexif", "piexif"),
|
|
("torch", "torch"),
|
|
("torchvision", "torchvision"),
|
|
("numpy", "numpy"),
|
|
("PIL", "pillow"),
|
|
("simpleeval", "simpleeval"),
|
|
("functools", "functools"),
|
|
("yaml", "PyYAML"),
|
|
("toml", "toml"),
|
|
|
|
]
|
|
|
|
all_installed = True
|
|
for import_name, package_name in packages_to_check:
|
|
try:
|
|
# 使用指定的 Python 执行器检查
|
|
check_script = f"import {import_name}" if import_name != "PIL" else "import PIL"
|
|
result = subprocess.run(
|
|
[python_exec, "-c", check_script],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10
|
|
)
|
|
if result.returncode == 0:
|
|
print(f"✅ {package_name} installed correctly")
|
|
else:
|
|
print(f"❌ {package_name} installation failed: {result.stderr}")
|
|
all_installed = False
|
|
except Exception as e:
|
|
print(f"❌ Error checking {package_name}: {e}")
|
|
all_installed = False
|
|
|
|
return all_installed
|
|
|
|
def main():
|
|
"""主函数 / Main function"""
|
|
print("=" * 60)
|
|
print("🛠️ JakeUpgrade Nodes Installer")
|
|
print("=" * 60)
|
|
|
|
# 检查系统信息
|
|
print(f"💻 OS: {platform.system()} {platform.release()}")
|
|
print(f"📁 Working directory: {Path(__file__).parent}")
|
|
|
|
# 获取 Python 执行器
|
|
python_exec = get_python_executable()
|
|
|
|
# 执行安装步骤
|
|
if not check_python_version(python_exec):
|
|
sys.exit(1)
|
|
|
|
if not install_requirements(python_exec):
|
|
print("\n❌ Dependency installation failed, try manual installation:")
|
|
print(" 1. Open command prompt or terminal")
|
|
print(" 2. Change to current directory")
|
|
print(f" 3. Run: {python_exec} -m pip install -r requirements.txt")
|
|
sys.exit(1)
|
|
|
|
# 验证安装
|
|
if check_installation(python_exec):
|
|
print("\n🎉 Installation complete! JakeUpgrade Nodes ready!")
|
|
print("🔧 You can now start ComfyUI and use JakeUpgrade nodes")
|
|
else:
|
|
print("\n⚠️ Some dependencies may not be installed correctly")
|
|
print("💡 Recommended to restart ComfyUI and check if nodes work properly")
|
|
|
|
print("\nPress Enter to exit...")
|
|
input()
|
|
|
|
if __name__ == "__main__":
|
|
import re
|
|
main() |