Merge branch 'ltdrdata:main' into main

This commit is contained in:
smthemex 2024-04-24 10:03:38 +08:00 committed by GitHub
commit 938dbe7a76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 7786 additions and 4094 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ matrix_auth
channels.list channels.list
comfyworkflows_sharekey comfyworkflows_sharekey
github-stats-cache.json github-stats-cache.json
pip_overrides.json

View File

@ -5,10 +5,9 @@
![menu](misc/menu.jpg) ![menu](misc/menu.jpg)
## NOTICE ## NOTICE
* 🏆 Join us for the [ComfyUI Workflow Contest](https://contest.openart.ai/), hosted by OpenArt AI (11.27.2023 - 12.15.2023). Our esteemed judge panel includes Scott E. Detweiler, Olivio Sarikas, MERJIC麦橘, among others. We're also thrilled to have the authors of ComfyUI Manager and AnimateDiff as our special guests! * V2.21 [cm-cli](docs/en/cm-cli.md) tool is added.
* If you wish to hide the "Share" button, click "Manager" and choose "Share: None" option. * V2.18 to V2.18.3 is not functioning due to a severe bug. Users on these versions are advised to promptly update to V2.18.4. Please navigate to the `ComfyUI/custom_nodes/ComfyUI-Manager` directory and execute `git pull` to update.
* You can see whole nodes info on [ComfyUI Nodes Info](https://ltdrdata.github.io/) page. * You can see whole nodes info on [ComfyUI Nodes Info](https://ltdrdata.github.io/) page.
* Versions prior to V0.22.2 will no longer detect missing nodes unless using a local database. Please update ComfyUI-Manager to the latest version.
## Installation ## Installation
@ -35,7 +34,7 @@ To install ComfyUI-Manager in addition to an existing installation of ComfyUI, y
### Installation[method3] (Installation for linux+venv: ComfyUI + ComfyUI-Manager) ### Installation[method3] (Installation for linux+venv: ComfyUI + ComfyUI-Manager)
To install ComfyUI with ComfyUI-Manager on Linux using a venv environment, you can follow these steps: To install ComfyUI with ComfyUI-Manager on Linux using a venv environment, you can follow these steps:
prerequisite: python-is-python3, python3-venv * **prerequisite: python-is-python3, python3-venv**
1. Download [scripts/install-comfyui-venv-linux.sh](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-comfyui-venv-linux.sh) into empty install directory 1. Download [scripts/install-comfyui-venv-linux.sh](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-comfyui-venv-linux.sh) into empty install directory
- ComfyUI will be installed in the subdirectory of the specified directory, and the directory will contain the generated executable script. - ComfyUI will be installed in the subdirectory of the specified directory, and the directory will contain the generated executable script.
@ -63,6 +62,7 @@ This repository provides Colab notebooks that allow you to install and use Comfy
* Support for automatically installing dependencies of custom nodes upon restarting Colab notebooks. * Support for automatically installing dependencies of custom nodes upon restarting Colab notebooks.
## Changes ## Changes
* **2.21** [cm-cli](docs/en/cm-cli.md) tool is added.
* **2.4** Copy the connections of the nearest node by double-clicking. * **2.4** Copy the connections of the nearest node by double-clicking.
* **2.2.3** Support Components System * **2.2.3** Support Components System
* **0.29** Add `Update all` feature * **0.29** Add `Update all` feature
@ -157,6 +157,12 @@ This repository provides Colab notebooks that allow you to install and use Comfy
![model-install-dialog](misc/snapshot.jpg) ![model-install-dialog](misc/snapshot.jpg)
## cm-cli: command line tools for power user
* A tool is provided that allows you to use the features of ComfyUI-Manager without running ComfyUI.
* For more details, please refer to the [cm-cli documentation](docs/en/cm-cli.md).
## How to register your custom node into ComfyUI-Manager ## How to register your custom node into ComfyUI-Manager
* Add an entry to `custom-node-list.json` located in the root of ComfyUI-Manager and submit a Pull Request. * Add an entry to `custom-node-list.json` located in the root of ComfyUI-Manager and submit a Pull Request.
@ -279,6 +285,26 @@ NODE_CLASS_MAPPINGS.update({
downgrade_blacklist = diffusers, kornia downgrade_blacklist = diffusers, kornia
``` ```
* Custom pip mapping
* When you create the `pip_overrides.json` file, it changes the installation of specific pip packages to installations defined by the user.
* Please refer to the `pip_overrides.json.template` file.
## Scanner
When you run the `scan.sh` script:
* It updates the `extension-node-map.json`.
* To do this, it pulls or clones the custom nodes listed in `custom-node-list.json` into `~/.tmp/default`.
* To skip this step, add the `--skip-update` option.
* If you want to specify a different path instead of `~/.tmp/default`, run `python scanner.py [path]` directly instead of `scan.sh`.
* It updates the `github-stats.json`.
* This uses the GitHub API, so set your token with `export GITHUB_TOKEN=your_token_here` to avoid quickly reaching the rate limit and malfunctioning.
* To skip this step, add the `--skip-update-stat` option.
* The `--skip-all` option applies both `--skip-update` and `--skip-stat-update`.
## Troubleshooting ## Troubleshooting
* If your `git.exe` is installed in a specific location other than system git, please install ComfyUI-Manager and run ComfyUI. Then, specify the path including the file name in `git_exe = ` in the ComfyUI-Manager/config.ini file that is generated. * If your `git.exe` is installed in a specific location other than system git, please install ComfyUI-Manager and run ComfyUI. Then, specify the path including the file name in `git_exe = ` in the ComfyUI-Manager/config.ini file that is generated.
* If updating ComfyUI-Manager itself fails, please go to the **ComfyUI-Manager** directory and execute the command `git update-ref refs/remotes/origin/main a361cc1 && git fetch --all && git pull`. * If updating ComfyUI-Manager itself fails, please go to the **ComfyUI-Manager** directory and execute the command `git update-ref refs/remotes/origin/main a361cc1 && git fetch --all && git pull`.

File diff suppressed because it is too large Load Diff

508
cm-cli.py Normal file
View File

@ -0,0 +1,508 @@
import os
import sys
import traceback
import json
import asyncio
import subprocess
import shutil
sys.path.append(os.path.dirname(__file__))
sys.path.append(os.path.join(os.path.dirname(__file__), "glob"))
import manager_core as core
import cm_global
import git
print(f"\n-= ComfyUI-Manager CLI ({core.version_str}) =-\n")
if not (len(sys.argv) == 2 and sys.argv[1] in ['save-snapshot', 'restore-dependencies', 'clear']) and len(sys.argv) < 3:
print(f"\npython cm-cli.py [OPTIONS]\n\n"
f"OPTIONS:\n"
f" [install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel <channel name>] ?[--mode [remote|local|cache]]\n"
f" [update|disable|enable|fix] all ?[--channel <channel name>] ?[--mode [remote|local|cache]]\n"
f" [simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel <channel name>] ?[--mode [remote|local|cache]]\n"
f" save-snapshot\n"
f" restore-snapshot <snapshot>\n"
f" cli-only-mode [enable|disable]\n"
f" restore-dependencies\n"
f" clear\n")
exit(-1)
comfyui_manager_path = os.path.dirname(__file__)
comfy_path = os.environ.get('COMFYUI_PATH')
if comfy_path is None:
print(f"WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.\n", file=sys.stderr)
comfy_path = os.path.abspath(os.path.join(comfyui_manager_path, '..', '..'))
startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts")
custom_nodes_path = os.path.join(comfy_path, 'custom_nodes')
script_path = os.path.join(startup_script_path, "install-scripts.txt")
restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json")
pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json")
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
cm_global.pip_downgrade_blacklist = ['torch', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia']
cm_global.pip_overrides = {}
if os.path.exists(pip_overrides_path):
with open(pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
cm_global.pip_overrides = json.load(json_file)
processed_install = set()
def post_install(url):
try:
repository_name = url.split("/")[-1].strip()
repo_path = os.path.join(custom_nodes_path, repository_name)
repo_path = os.path.abspath(repo_path)
requirements_path = os.path.join(repo_path, 'requirements.txt')
install_script_path = os.path.join(repo_path, 'install.py')
if os.path.exists(requirements_path):
with (open(requirements_path, 'r', encoding="UTF-8", errors="ignore") as file):
for line in file:
package_name = core.remap_pip_package(line.strip())
if package_name and not core.is_installed(package_name):
install_cmd = [sys.executable, "-m", "pip", "install", package_name]
output = subprocess.check_output(install_cmd, cwd=repo_path, text=True)
for msg_line in output.split('\n'):
if 'Requirement already satisfied:' in msg_line:
print('.', end='')
else:
print(msg_line)
if os.path.exists(install_script_path) and f'{repo_path}/install.py' not in processed_install:
processed_install.add(f'{repo_path}/install.py')
install_cmd = [sys.executable, install_script_path]
output = subprocess.check_output(install_cmd, cwd=repo_path, text=True)
for msg_line in output.split('\n'):
if 'Requirement already satisfied:' in msg_line:
print('.', end='')
else:
print(msg_line)
except Exception:
print(f"ERROR: Restoring '{url}' is failed.")
def restore_dependencies():
node_paths = [os.path.join(custom_nodes_path, name) for name in os.listdir(custom_nodes_path)
if os.path.isdir(os.path.join(custom_nodes_path, name)) and not name.endswith('.disabled')]
total = len(node_paths)
i = 1
for x in node_paths:
print(f"----------------------------------------------------------------------------------------------------")
print(f"Restoring [{i}/{total}]: {x}")
post_install(x)
i += 1
def restore_snapshot(snapshot_name):
global processed_install
snapshot_path = os.path.join(core.comfyui_manager_path, 'snapshots', snapshot_name)
if not os.path.exists(snapshot_path):
print(f"ERROR: `{snapshot_path}` is not exists.")
exit(-1)
try:
cloned_repos = []
checkout_repos = []
skipped_repos = []
enabled_repos = []
disabled_repos = []
is_failed = False
def extract_infos(msg_lines):
nonlocal is_failed
for x in msg_lines:
if x.startswith("CLONE: "):
cloned_repos.append(x[7:])
elif x.startswith("CHECKOUT: "):
checkout_repos.append(x[10:])
elif x.startswith("SKIPPED: "):
skipped_repos.append(x[9:])
elif x.startswith("ENABLE: "):
enabled_repos.append(x[8:])
elif x.startswith("DISABLE: "):
disabled_repos.append(x[9:])
elif 'APPLY SNAPSHOT: False' in x:
is_failed = True
print(f"Restore snapshot.")
cmd_str = [sys.executable, git_script_path, '--apply-snapshot', snapshot_path]
output = subprocess.check_output(cmd_str, cwd=custom_nodes_path, text=True)
msg_lines = output.split('\n')
extract_infos(msg_lines)
for url in cloned_repos:
post_install(url)
# print summary
for x in cloned_repos:
print(f"[ INSTALLED ] {x}")
for x in checkout_repos:
print(f"[ CHECKOUT ] {x}")
for x in enabled_repos:
print(f"[ ENABLED ] {x}")
for x in disabled_repos:
print(f"[ DISABLED ] {x}")
if is_failed:
print("ERROR: Failed to restore snapshot.")
except Exception:
print("ERROR: Failed to restore snapshot.")
traceback.print_exc()
exit(-1)
def check_comfyui_hash():
repo = git.Repo(comfy_path)
core.comfy_ui_revision = len(list(repo.iter_commits('HEAD')))
comfy_ui_hash = repo.head.commit.hexsha
cm_global.variables['comfyui.revision'] = core.comfy_ui_revision
core.comfy_ui_commit_datetime = repo.head.commit.committed_datetime
check_comfyui_hash()
def read_downgrade_blacklist():
try:
import configparser
config_path = os.path.join(os.path.dirname(__file__), "config.ini")
config = configparser.ConfigParser()
config.read(config_path)
default_conf = config['default']
if 'downgrade_blacklist' in default_conf:
items = default_conf['downgrade_blacklist'].split(',')
items = [x.strip() for x in items if x != '']
cm_global.pip_downgrade_blacklist += items
cm_global.pip_downgrade_blacklist = list(set(cm_global.pip_downgrade_blacklist))
except:
pass
read_downgrade_blacklist()
channel = 'default'
mode = 'remote'
nodes = set()
def load_custom_nodes():
channel_dict = core.get_channel_dict()
if channel not in channel_dict:
print(f"ERROR: Invalid channel is specified `--channel {channel}`", file=sys.stderr)
exit(-1)
if mode not in ['remote', 'local', 'cache']:
print(f"ERROR: Invalid mode is specified `--mode {mode}`", file=sys.stderr)
exit(-1)
channel_url = channel_dict[channel]
res = {}
json_obj = asyncio.run(core.get_data_by_mode(mode, 'custom-node-list.json', channel_url=channel_url))
for x in json_obj['custom_nodes']:
for y in x['files']:
if 'github.com' in y and not (y.endswith('.py') or y.endswith('.js')):
repo_name = y.split('/')[-1]
res[repo_name] = x
return res
def process_args():
global channel
global mode
i = 2
while i < len(sys.argv):
if sys.argv[i] == '--channel':
if i+1 < len(sys.argv):
channel = sys.argv[i+1]
i += 1
elif sys.argv[i] == '--mode':
if i+1 < len(sys.argv):
mode = sys.argv[i+1]
i += 1
else:
nodes.add(sys.argv[i])
i += 1
process_args()
custom_node_map = load_custom_nodes()
def lookup_node_path(node_name):
# Currently, the node_name is used directly as the node_path, but in the future, I plan to allow nicknames.
if '..' in node_name:
print(f"ERROR: invalid node name '{node_name}'")
exit(-1)
if node_name in custom_node_map:
node_path = os.path.join(custom_nodes_path, node_name)
return node_path, custom_node_map[node_name]
print(f"ERROR: invalid node name '{node_name}'")
exit(-1)
def install_node(node_name, is_all=False, cnt_msg=''):
node_path, node_item = lookup_node_path(node_name)
if os.path.exists(node_path):
if not is_all:
print(f"{cnt_msg} [ SKIPPED ] {node_name:50} => Already installed")
elif os.path.exists(node_path+'.disabled'):
enable_node(node_name)
else:
res = core.gitclone_install(node_item['files'], instant_execution=True, msg_prefix=f"[{cnt_msg}] ")
if not res:
print(f"ERROR: An error occurred while installing '{node_name}'.")
else:
print(f"{cnt_msg} [INSTALLED] {node_name:50}")
def reinstall_node(node_name, is_all=False, cnt_msg=''):
node_path, node_item = lookup_node_path(node_name)
if os.path.exists(node_path):
shutil.rmtree(node_path)
if os.path.exists(node_path+'.disabled'):
shutil.rmtree(node_path+'.disabled')
install_node(node_name, is_all=is_all, cnt_msg=cnt_msg)
def fix_node(node_name, is_all=False, cnt_msg=''):
node_path, node_item = lookup_node_path(node_name)
if os.path.exists(node_path):
print(f"{cnt_msg} [ FIXING ]: {node_name:50} => Disabled")
res = core.gitclone_fix(node_item['files'], instant_execution=True)
if not res:
print(f"ERROR: An error occurred while fixing '{node_name}'.")
elif not is_all and os.path.exists(node_path+'.disabled'):
print(f"{cnt_msg} [ SKIPPED ]: {node_name:50} => Disabled")
elif not is_all:
print(f"{cnt_msg} [ SKIPPED ]: {node_name:50} => Not installed")
def uninstall_node(node_name, is_all=False, cnt_msg=''):
node_path, node_item = lookup_node_path(node_name)
if os.path.exists(node_path) or os.path.exists(node_path+'.disabled'):
res = core.gitclone_uninstall(node_item['files'])
if not res:
print(f"ERROR: An error occurred while uninstalling '{node_name}'.")
else:
print(f"{cnt_msg} [UNINSTALLED] {node_name:50}")
else:
print(f"{cnt_msg} [ SKIPPED ]: {node_name:50} => Not installed")
def update_node(node_name, is_all=False, cnt_msg=''):
node_path, node_item = lookup_node_path(node_name)
res = core.gitclone_update(node_item['files'], skip_script=True, msg_prefix=f"[{cnt_msg}] ")
post_install(node_path)
if not res:
print(f"ERROR: An error occurred while uninstalling '{node_name}'.")
def enable_node(node_name, is_all=False, cnt_msg=''):
if node_name == 'ComfyUI-Manager':
return
node_path, _ = lookup_node_path(node_name)
if os.path.exists(node_path+'.disabled'):
current_name = node_path+'.disabled'
os.rename(current_name, node_path)
print(f"{cnt_msg} [ENABLED] {node_name:50}")
elif os.path.exists(node_path):
print(f"{cnt_msg} [SKIPPED] {node_name:50} => Already enabled")
elif not is_all:
print(f"{cnt_msg} [SKIPPED] {node_name:50} => Not installed")
def disable_node(node_name, is_all=False, cnt_msg=''):
if node_name == 'ComfyUI-Manager':
return
node_path, _ = lookup_node_path(node_name)
if os.path.exists(node_path):
current_name = node_path
new_name = node_path+'.disabled'
os.rename(current_name, new_name)
print(f"{cnt_msg} [DISABLED] {node_name:50}")
elif os.path.exists(node_path+'.disabled'):
print(f"{cnt_msg} [ SKIPPED] {node_name:50} => Already disabled")
elif not is_all:
print(f"{cnt_msg} [ SKIPPED] {node_name:50} => Not installed")
def show_list(kind, simple=False):
for k, v in custom_node_map.items():
node_path = os.path.join(custom_nodes_path, k)
states = set()
if os.path.exists(node_path):
prefix = '[ ENABLED ] '
states.add('installed')
states.add('enabled')
states.add('all')
elif os.path.exists(node_path+'.disabled'):
prefix = '[ DISABLED ] '
states.add('installed')
states.add('disabled')
states.add('all')
else:
prefix = '[ NOT INSTALLED ] '
states.add('not-installed')
states.add('all')
if kind in states:
if simple:
print(f"{k:50}")
else:
print(f"{prefix} {k:50}(author: {v['author']})")
def show_snapshot(simple_mode=False):
json_obj = core.get_current_snapshot()
if simple_mode:
print(f"[{json_obj['comfyui']}] comfyui")
for k, v in json_obj['git_custom_nodes'].items():
print(f"[{v['hash']}] {k}")
for v in json_obj['file_custom_nodes']:
print(f"[ N/A ] {v['filename']}")
else:
formatted_json = json.dumps(json_obj, ensure_ascii=False, indent=4)
print(formatted_json)
def show_snapshot_list(simple_mode=False):
path = os.path.join(comfyui_manager_path, 'snapshots')
files = os.listdir(path)
json_files = [x for x in files if x.endswith('.json')]
for x in sorted(json_files):
print(x)
def cancel():
if os.path.exists(script_path):
os.remove(script_path)
if os.path.exists(restore_snapshot_path):
os.remove(restore_snapshot_path)
def for_each_nodes(act, allow_all=True):
global nodes
is_all = False
if allow_all and 'all' in nodes:
is_all = True
nodes = [x for x in custom_node_map.keys() if os.path.exists(os.path.join(custom_nodes_path, x)) or os.path.exists(os.path.join(custom_nodes_path, x)+'.disabled')]
total = len(nodes)
i = 1
for x in nodes:
try:
act(x, is_all=is_all, cnt_msg=f'{i}/{total}')
except Exception as e:
print(f"ERROR: {e}")
traceback.print_exc()
i+=1
op = sys.argv[1]
if op == 'install':
for_each_nodes(install_node)
elif op == 'reinstall':
for_each_nodes(reinstall_node)
elif op == 'uninstall':
for_each_nodes(uninstall_node)
elif op == 'update':
for_each_nodes(update_node, allow_all=True)
elif op == 'disable':
for_each_nodes(disable_node, allow_all=True)
elif op == 'enable':
for_each_nodes(enable_node, allow_all=True)
elif op == 'fix':
for_each_nodes(fix_node, allow_all=True)
elif op == 'show':
if sys.argv[2] == 'snapshot':
show_snapshot()
elif sys.argv[2] == 'snapshot-list':
show_snapshot_list()
else:
show_list(sys.argv[2])
elif op == 'simple-show':
if sys.argv[2] == 'snapshot':
show_snapshot(True)
elif sys.argv[2] == 'snapshot-list':
show_snapshot_list(True)
else:
show_list(sys.argv[2], True)
elif op == 'cli-only-mode':
cli_mode_flag = os.path.join(os.path.dirname(__file__), '.enable-cli-only-mode')
if sys.argv[2] == 'enable':
with open(cli_mode_flag, 'w') as file:
pass
print(f"\ncli-only-mode: enabled\n")
elif sys.argv[2] == 'disable':
if os.path.exists(cli_mode_flag):
os.remove(cli_mode_flag)
print(f"\ncli-only-mode: disabled\n")
else:
print(f"\ninvalid value for cli-only-mode: {sys.argv[2]}\n")
elif op == 'save-snapshot':
path = core.save_snapshot_with_postfix('snapshot')
print(f"Current snapshot is saved as `{path}`")
elif op == 'restore-snapshot':
restore_snapshot(sys.argv[2])
elif op == 'restore-dependencies':
restore_dependencies()
elif op == 'clear':
cancel()
else:
print(f"\nInvalid command `{op}`")
print(f"")

View File

@ -42,6 +42,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Nodes: ModelSamplerTonemapNoiseTest, TonemapNoiseWithRescaleCFG, ReferenceOnlySimple, RescaleClassifierFreeGuidanceTest, ModelMergeBlockNumber, ModelMergeSDXL, ModelMergeSDXLTransformers, ModelMergeSDXLDetailedTransformers.[w/NOTE: This is a consolidation of the previously separate custom nodes. Please delete the sampler_tonemap.py, sampler_rescalecfg.py, advanced_model_merging.py, sdxl_model_merging.py, and reference_only.py files installed in custom_nodes before.]" "description": "Nodes: ModelSamplerTonemapNoiseTest, TonemapNoiseWithRescaleCFG, ReferenceOnlySimple, RescaleClassifierFreeGuidanceTest, ModelMergeBlockNumber, ModelMergeSDXL, ModelMergeSDXLTransformers, ModelMergeSDXLDetailedTransformers.[w/NOTE: This is a consolidation of the previously separate custom nodes. Please delete the sampler_tonemap.py, sampler_rescalecfg.py, advanced_model_merging.py, sdxl_model_merging.py, and reference_only.py files installed in custom_nodes before.]"
}, },
{
"author": "Stability-AI",
"title": "Stability API nodes for ComfyUI",
"reference": "https://github.com/Stability-AI/ComfyUI-SAI_API",
"files": [
"https://github.com/Stability-AI/ComfyUI-SAI_API"
],
"install_type": "git-clone",
"description": "Nodes:Stability SD3, Stability Outpainting, Stability Search and Replace, Stability Image Core, Stability Inpainting, Stability Remove Background, Stability Creative Upscale.\nAdd API key to environment variable 'SAI_API_KEY'\nAlternatively you can write your API key to file 'sai_platform_key.txt'\nYou can also use and/or override the above by entering your API key in the 'api_key_override' field of each node."
},
{ {
"author": "Stability-AI", "author": "Stability-AI",
"title": "stability-ComfyUI-nodes", "title": "stability-ComfyUI-nodes",
@ -152,6 +162,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "A minimalistic implementation of [a/Robust Video Matting (RVM)](https://github.com/PeterL1n/RobustVideoMatting/) in ComfyUI" "description": "A minimalistic implementation of [a/Robust Video Matting (RVM)](https://github.com/PeterL1n/RobustVideoMatting/) in ComfyUI"
}, },
{
"author": "Fannovel16",
"title": "ComfyUI-MagickWand",
"reference": "https://github.com/Fannovel16/ComfyUI-MagickWand",
"files": [
"https://github.com/Fannovel16/ComfyUI-MagickWand"
],
"install_type": "git-clone",
"description": "Proper implementation of ImageMagick - the famous software suite for editing and manipulating digital images to ComfyUI using [a/wandpy](https://github.com/emcconville/wand).\nNOTE: You need to install ImageMagick, manually."
},
{ {
"author": "biegert", "author": "biegert",
"title": "CLIPSeg", "title": "CLIPSeg",
@ -224,7 +244,7 @@
}, },
{ {
"author": "jags111", "author": "jags111",
"title": "ComfyUI_Jags_VectorMagic", "title": "Jags_VectorMagic",
"reference": "https://github.com/jags111/ComfyUI_Jags_VectorMagic", "reference": "https://github.com/jags111/ComfyUI_Jags_VectorMagic",
"files": [ "files": [
"https://github.com/jags111/ComfyUI_Jags_VectorMagic" "https://github.com/jags111/ComfyUI_Jags_VectorMagic"
@ -234,7 +254,7 @@
}, },
{ {
"author": "jags111", "author": "jags111",
"title": "ComfyUI_Jags_Audiotools", "title": "Jags_Audiotools",
"reference": "https://github.com/jags111/ComfyUI_Jags_Audiotools", "reference": "https://github.com/jags111/ComfyUI_Jags_Audiotools",
"files": [ "files": [
"https://github.com/jags111/ComfyUI_Jags_Audiotools" "https://github.com/jags111/ComfyUI_Jags_Audiotools"
@ -836,7 +856,7 @@
}, },
{ {
"author": "Suzie1", "author": "Suzie1",
"title": "ComfyUI_Comfyroll_CustomNodes", "title": "Comfyroll Studio",
"reference": "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes", "reference": "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes",
"files": [ "files": [
"https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes" "https://github.com/Suzie1/ComfyUI_Comfyroll_CustomNodes"
@ -2260,7 +2280,7 @@
}, },
{ {
"author": "receyuki", "author": "receyuki",
"title": "comfyui-prompt-reader-node", "title": "SD Prompt Reader",
"reference": "https://github.com/receyuki/comfyui-prompt-reader-node", "reference": "https://github.com/receyuki/comfyui-prompt-reader-node",
"files": [ "files": [
"https://github.com/receyuki/comfyui-prompt-reader-node" "https://github.com/receyuki/comfyui-prompt-reader-node"
@ -2399,16 +2419,6 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Custom AI prompt generator node for ComfyUI." "description": "Custom AI prompt generator node for ComfyUI."
}, },
{
"author": "mlinmg",
"title": "LaMa Preprocessor [WIP]",
"reference": "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor",
"files": [
"https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor"
],
"install_type": "git-clone",
"description": "A LaMa prerocessor for ComfyUI. This preprocessor finally enable users to generate coherent inpaint and outpaint prompt-free. The best results are given on landscapes, not so much in drawings/animation."
},
{ {
"author": "kijai", "author": "kijai",
"title": "KJNodes for ComfyUI", "title": "KJNodes for ComfyUI",
@ -2522,12 +2532,12 @@
{ {
"author": "kijai", "author": "kijai",
"title": "ComfyUI-APISR", "title": "ComfyUI-APISR",
"reference": "https://github.com/kijai/ComfyUI-APISR", "reference": "https://github.com/kijai/ComfyUI-APISR-KJ",
"files": [ "files": [
"https://github.com/kijai/ComfyUI-APISR" "https://github.com/kijai/ComfyUI-APISR-KJ"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "Node to use [a/APISR](https://github.com/Kiteretsu77/APISR) upscale models in ComfyUI" "description": "Node to use [a/APISR](https://github.com/Kiteretsu77/APISR) upscale models in ComfyUI.[w/NOTE: repo name is changed from ComfyUI-APISR -> ComfyUI-APISR-KJ]"
}, },
{ {
"author": "kijai", "author": "kijai",
@ -2539,6 +2549,36 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "This is simplified implementation of the [a/DiffusionLight](https://github.com/DiffusionLight/DiffusionLight) method of creating light probes. You will need the included LoRA, place it in ComfyUI/loras folder like usual, it's converted from the original diffusers one." "description": "This is simplified implementation of the [a/DiffusionLight](https://github.com/DiffusionLight/DiffusionLight) method of creating light probes. You will need the included LoRA, place it in ComfyUI/loras folder like usual, it's converted from the original diffusers one."
}, },
{
"author": "kijai",
"title": "ComfyUI-ELLA-wrapper",
"reference": "https://github.com/kijai/ComfyUI-ELLA-wrapper",
"files": [
"https://github.com/kijai/ComfyUI-ELLA-wrapper"
],
"install_type": "git-clone",
"description": "ComfyUI wrapper nodes to use the Diffusers implementation of ELLA"
},
{
"author": "kijai",
"title": "ComfyUI-LaVi-Bridge-Wrapper",
"reference": "https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper",
"files": [
"https://github.com/kijai/ComfyUI-LaVi-Bridge-Wrapper"
],
"install_type": "git-clone",
"description": "ComfyUI wrapper node to test LaVi-Bridge using Diffusers"
},
{
"author": "kijai",
"title": "ComfyUI-BrushNet-Wrapper",
"reference": "https://github.com/kijai/ComfyUI-BrushNet-Wrapper",
"files": [
"https://github.com/kijai/ComfyUI-BrushNet-Wrapper"
],
"install_type": "git-clone",
"description": "ComfyUI wrapper nodes to use the Diffusers implementation of BrushNet"
},
{ {
"author": "hhhzzyang", "author": "hhhzzyang",
"title": "Comfyui-Lama", "title": "Comfyui-Lama",
@ -2581,7 +2621,7 @@
}, },
{ {
"author": "avatechai", "author": "avatechai",
"title": "avatar-graph-comfyui", "title": "Avatar Graph",
"reference": "https://github.com/avatechai/avatar-graph-comfyui", "reference": "https://github.com/avatechai/avatar-graph-comfyui",
"files": [ "files": [
"https://github.com/avatechai/avatar-graph-comfyui" "https://github.com/avatechai/avatar-graph-comfyui"
@ -3304,7 +3344,7 @@
}, },
{ {
"author": "Danand", "author": "Danand",
"title": "ComfyUI-ComfyCouple", "title": "Comfy Couple",
"reference": "https://github.com/Danand/ComfyUI-ComfyCouple", "reference": "https://github.com/Danand/ComfyUI-ComfyCouple",
"files": [ "files": [
"https://github.com/Danand/ComfyUI-ComfyCouple" "https://github.com/Danand/ComfyUI-ComfyCouple"
@ -4114,6 +4154,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "A suite of tools for prompt management. Combining nodes helps the user sequence strings for prompts, also creating logical groupings if necessary. Individual nodes can be chained together in any order." "description": "A suite of tools for prompt management. Combining nodes helps the user sequence strings for prompts, also creating logical groupings if necessary. Individual nodes can be chained together in any order."
}, },
{
"author": "florestefano1975",
"title": "ComfyUI StabilityAI Suite",
"reference": "https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite",
"files": [
"https://github.com/florestefano1975/ComfyUI-StabilityAI-Suite"
],
"install_type": "git-clone",
"description": "This fork of the official StabilityAI repository contains a number of enhancements and implementations."
},
{ {
"author": "mozman", "author": "mozman",
"title": "ComfyUI_mozman_nodes", "title": "ComfyUI_mozman_nodes",
@ -4266,7 +4316,7 @@
}, },
{ {
"author": "HarroweD and quadmoon", "author": "HarroweD and quadmoon",
"title": "Harronode", "title": "Harrlogos Prompt Builder Node",
"reference": "https://github.com/NotHarroweD/Harronode", "reference": "https://github.com/NotHarroweD/Harronode",
"nodename_pattern": "Harronode", "nodename_pattern": "Harronode",
"files": [ "files": [
@ -4557,6 +4607,26 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Nodes:3D Pose Editor" "description": "Nodes:3D Pose Editor"
}, },
{
"author": "chaojie",
"title": "ComfyUI-CameraCtrl-Wrapper",
"reference": "https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper",
"files": [
"https://github.com/chaojie/ComfyUI-CameraCtrl-Wrapper"
],
"install_type": "git-clone",
"description": "ComfyUI-CameraCtrl-Wrapper"
},
{
"author": "chaojie",
"title": "ComfyUI-EasyAnimate",
"reference": "https://github.com/chaojie/ComfyUI-EasyAnimate",
"files": [
"https://github.com/chaojie/ComfyUI-EasyAnimate"
],
"install_type": "git-clone",
"description": "ComfyUI-EasyAnimate"
},
{ {
"author": "chaojie", "author": "chaojie",
"title": "ComfyUI_StreamingT2V", "title": "ComfyUI_StreamingT2V",
@ -4787,6 +4857,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "This is an ComfyUI implementation of RAFT to generate motion brush" "description": "This is an ComfyUI implementation of RAFT to generate motion brush"
}, },
{
"author": "chaojie",
"title": "ComfyUI-LaVIT",
"reference": "https://github.com/chaojie/ComfyUI-LaVIT",
"files": [
"https://github.com/chaojie/ComfyUI-LaVIT"
],
"install_type": "git-clone",
"description": "Nodes:VideoLaVITLoader, VideoLaVITT2V, VideoLaVITI2V, VideoLaVITI2VLong, VideoLaVITT2VLong, VideoLaVITI2I"
},
{ {
"author": "alexopus", "author": "alexopus",
"title": "ComfyUI Image Saver", "title": "ComfyUI Image Saver",
@ -5321,7 +5401,7 @@
}, },
{ {
"author": "Hiero207", "author": "Hiero207",
"title": "ComfyUI-Hiero-Nodes", "title": "Hiero-Nodes",
"reference": "https://github.com/Hiero207/ComfyUI-Hiero-Nodes", "reference": "https://github.com/Hiero207/ComfyUI-Hiero-Nodes",
"files": [ "files": [
"https://github.com/Hiero207/ComfyUI-Hiero-Nodes" "https://github.com/Hiero207/ComfyUI-Hiero-Nodes"
@ -5411,7 +5491,7 @@
}, },
{ {
"author": "JerryOrbachJr", "author": "JerryOrbachJr",
"title": "ComfyUI-RandomSize", "title": "Random Size",
"reference": "https://github.com/JerryOrbachJr/ComfyUI-RandomSize", "reference": "https://github.com/JerryOrbachJr/ComfyUI-RandomSize",
"files": [ "files": [
"https://github.com/JerryOrbachJr/ComfyUI-RandomSize" "https://github.com/JerryOrbachJr/ComfyUI-RandomSize"
@ -5431,7 +5511,7 @@
}, },
{ {
"author": "mape", "author": "mape",
"title": "mape's ComfyUI Helpers", "title": "mape's helpers",
"reference": "https://github.com/mape/ComfyUI-mape-Helpers", "reference": "https://github.com/mape/ComfyUI-mape-Helpers",
"files": [ "files": [
"https://github.com/mape/ComfyUI-mape-Helpers" "https://github.com/mape/ComfyUI-mape-Helpers"
@ -5621,7 +5701,7 @@
}, },
{ {
"author": "dfl", "author": "dfl",
"title": "comfyui-clip-with-break", "title": "CLIP with BREAK syntax",
"reference": "https://github.com/dfl/comfyui-clip-with-break", "reference": "https://github.com/dfl/comfyui-clip-with-break",
"files": [ "files": [
"https://github.com/dfl/comfyui-clip-with-break" "https://github.com/dfl/comfyui-clip-with-break"
@ -5639,16 +5719,6 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "ComfyUI Custom Sampler nodes that implement Zheng et al.'s Trajectory Consistency Distillation based on [a/https://mhh0318.github.io/tcd](https://mhh0318.github.io/tcd)" "description": "ComfyUI Custom Sampler nodes that implement Zheng et al.'s Trajectory Consistency Distillation based on [a/https://mhh0318.github.io/tcd](https://mhh0318.github.io/tcd)"
}, },
{
"author": "MarkoCa1",
"title": "ComfyUI_Segment_Mask",
"reference": "https://github.com/MarkoCa1/ComfyUI_Segment_Mask",
"files": [
"https://github.com/MarkoCa1/ComfyUI_Segment_Mask"
],
"install_type": "git-clone",
"description": "Mask cutout based on Segment Anything."
},
{ {
"author": "antrobot", "author": "antrobot",
"title": "antrobots ComfyUI Nodepack", "title": "antrobots ComfyUI Nodepack",
@ -5920,14 +5990,24 @@
"description": "ComfyUI nodes to use [a/FLATTEN: optical FLow-guided ATTENtion for consistent text-to-video editing](https://github.com/yrcong/flatten)." "description": "ComfyUI nodes to use [a/FLATTEN: optical FLow-guided ATTENtion for consistent text-to-video editing](https://github.com/yrcong/flatten)."
}, },
{ {
"author": "Big-Idea-Technology", "author": "logtd",
"title": "ImageTextOverlay Node for ComfyUI", "title": "ComfyUI-RAVE Attention",
"reference": "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay", "reference": "https://github.com/logtd/ComfyUI-RAVE_ATTN",
"files": [ "files": [
"https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay" "https://github.com/logtd/ComfyUI-RAVE_ATTN"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "ImageTextOverlay is a customizable Node for ComfyUI that allows users to easily add text overlays to images within their ComfyUI projects. This Node leverages Python Imaging Library (PIL) and PyTorch to dynamically render text on images, supporting a wide range of customization options including font size, alignment, color, and padding." "description": "ComfyUI nodes to use RAVE attention as a temporal attention mechanism.\nThis differs from other implementations in that it does not concatenate the images together, but within the UNet's Self-Attention mechanism performs the RAVE technique. By not altering the images/latents throughout the UNet, this method does not affect other temporal techniques, style mechanisms, or other UNet modifications.\nFor example, it can be combined with AnimateDiff, ModelScope/ZeroScope, or FLATTEN."
},
{
"author": "Big-Idea-Technology",
"title": "ComfyUI-Book-Tools Nodes for ComfyUI",
"reference": "https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools",
"files": [
"https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools"
],
"install_type": "git-clone",
"description": "ComfyUI-Book-Tools is a set o new nodes for ComfyUI that allows users to easily add text overlays to images within their ComfyUI projects. This Node leverages Python Imaging Library (PIL) and PyTorch to dynamically render text on images, supporting a wide range of customization options including font size, alignment, color, and padding. Loop with any parameters (*), prompt batch schedule with prompt selector, end queue for automatic ending current queue."
}, },
{ {
"author": "Big Idea Technology", "author": "Big Idea Technology",
@ -5939,16 +6019,6 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "The LLM_Node enhances ComfyUI by integrating advanced language model capabilities, enabling a wide range of NLP tasks such as text generation, content summarization, question answering, and more. This flexibility is powered by various transformer model architectures from the transformers library, allowing for the deployment of models like T5, GPT-2, and others based on your project's needs." "description": "The LLM_Node enhances ComfyUI by integrating advanced language model capabilities, enabling a wide range of NLP tasks such as text generation, content summarization, question answering, and more. This flexibility is powered by various transformer model architectures from the transformers library, allowing for the deployment of models like T5, GPT-2, and others based on your project's needs."
}, },
{
"author": "Big Idea Technology",
"title": "Image Text Overlay Node for ComfyUI",
"reference": "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay",
"files": [
"https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay"
],
"install_type": "git-clone",
"description": "ImageTextOverlay is a customizable Node for ComfyUI that allows users to easily add text overlays to images within their ComfyUI projects. This Node leverages Python Imaging Library (PIL) and PyTorch to dynamically render text on images, supporting a wide range of customization options including font size, alignment, color, and padding."
},
{ {
"author": "Guillaume-Fgt", "author": "Guillaume-Fgt",
"title": "ComfyUI-ScenarioPrompt", "title": "ComfyUI-ScenarioPrompt",
@ -5981,7 +6051,7 @@
}, },
{ {
"author": "czcz1024", "author": "czcz1024",
"title": "Comfyui-FaceCompare", "title": "Face Compare",
"reference": "https://github.com/czcz1024/Comfyui-FaceCompare", "reference": "https://github.com/czcz1024/Comfyui-FaceCompare",
"files": [ "files": [
"https://github.com/czcz1024/Comfyui-FaceCompare" "https://github.com/czcz1024/Comfyui-FaceCompare"
@ -6399,6 +6469,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "ComfyUI Version of '[a/Visual Style Prompting with Swapping Self-Attention](https://github.com/naver-ai/Visual-Style-Prompting)'" "description": "ComfyUI Version of '[a/Visual Style Prompting with Swapping Self-Attention](https://github.com/naver-ai/Visual-Style-Prompting)'"
}, },
{
"author": "ExponentialML",
"title": "ComfyUI_ELLA",
"reference": "https://github.com/ExponentialML/ComfyUI_ELLA",
"files": [
"https://github.com/ExponentialML/ComfyUI_ELLA"
],
"install_type": "git-clone",
"description": "ComfyUI Implementaion of ELLA: Equip Diffusion Models with LLM for Enhanced Semantic Alignment"
},
{ {
"author": "angeloshredder", "author": "angeloshredder",
"title": "StableCascadeResizer", "title": "StableCascadeResizer",
@ -6489,6 +6569,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Various AI tools to use in Comfy UI. Starting with VL and prompt making tools using Ollma as backend will evolve as I find time." "description": "Various AI tools to use in Comfy UI. Starting with VL and prompt making tools using Ollma as backend will evolve as I find time."
}, },
{
"author": "if-ai",
"title": "ComfyUI-IF_AI_WishperSpeechNode",
"reference": "https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode",
"files": [
"https://github.com/if-ai/ComfyUI-IF_AI_WishperSpeechNode"
],
"install_type": "git-clone",
"description": "This repository hosts a Text-to-Speech (TTS) application that leverages Whisper Speech for voice synthesis, allowing users to train a voice model on-the-fly. It is built on ComfyUI and supports rapid training and inference processes."
},
{ {
"author": "dmMaze", "author": "dmMaze",
"title": "Sketch2Manga", "title": "Sketch2Manga",
@ -6549,6 +6639,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Text." "description": "Text."
}, },
{
"author": "MarkoCa1",
"title": "ComfyUI_Segment_Mask",
"reference": "https://github.com/MarkoCa1/ComfyUI_Segment_Mask",
"files": [
"https://github.com/MarkoCa1/ComfyUI_Segment_Mask"
],
"install_type": "git-clone",
"description": "Mask cutout based on Segment Anything."
},
{ {
"author": "Shadetail", "author": "Shadetail",
"title": "Eagleshadow Custom Nodes", "title": "Eagleshadow Custom Nodes",
@ -6647,7 +6747,7 @@
"https://github.com/chaosaiart/Chaosaiart-Nodes" "https://github.com/chaosaiart/Chaosaiart-Nodes"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "This extension provides various custom nodes to assist in configuring the workflow structure." "description": "LowVRAM Animation : txt2video - img2video - video2video , Frame by Frame, compatible with LowVRAM GPUs\nIncluded : Prompt Switch, Checkpoint Switch, Cache, Number Count by Frame, Ksampler txt2img & img2img ..."
}, },
{ {
"author": "viperyl", "author": "viperyl",
@ -6691,13 +6791,43 @@
}, },
{ {
"author": "hay86", "author": "hay86",
"title": "ComfyUI_AceNodes", "title": "ComfyUI OpenVoice",
"reference": "https://github.com/hay86/ComfyUI_OpenVoice",
"files": [
"https://github.com/hay86/ComfyUI_OpenVoice"
],
"install_type": "git-clone",
"description": "Unofficial implementation of [a/OpenVoice](https://github.com/myshell-ai/OpenVoice) for ComfyUI"
},
{
"author": "hay86",
"title": "ComfyUI DDColor",
"reference": "https://github.com/hay86/ComfyUI_DDColor",
"files": [
"https://github.com/hay86/ComfyUI_DDColor"
],
"install_type": "git-clone",
"description": "Unofficial implementation of [a/DDColor](https://github.com/piddnad/DDColor) for ComfyUI"
},
{
"author": "hay86",
"title": "ComfyUI MiniCPM-V",
"reference": "https://github.com/hay86/ComfyUI_MiniCPM-V",
"files": [
"https://github.com/hay86/ComfyUI_MiniCPM-V"
],
"install_type": "git-clone",
"description": "Unofficial implementation of [a/MiniCPM-V](https://github.com/OpenBMB/MiniCPM-V) for ComfyUI"
},
{
"author": "hay86",
"title": "ComfyUI AceNodes",
"reference": "https://github.com/hay86/ComfyUI_AceNodes", "reference": "https://github.com/hay86/ComfyUI_AceNodes",
"files": [ "files": [
"https://github.com/hay86/ComfyUI_AceNodes" "https://github.com/hay86/ComfyUI_AceNodes"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "Nodes:Integer, Float, Text, Seed, Text Concatenate, Text Input Switch (2/4/8 way), Text List, Text Preview, Text Selector, Text To Resolution. Some useful custom nodes that are not included in ComfyUI core yet." "description": "Some useful custom nodes that are not included in ComfyUI core yet."
}, },
{ {
"author": "shinich39", "author": "shinich39",
@ -6830,7 +6960,7 @@
"description": "Several utility nodes for use with ComfyUI." "description": "Several utility nodes for use with ComfyUI."
}, },
{ {
"author": "frankchieng", "author": "FrankChieng",
"title": "ComfyUI_Aniportrait", "title": "ComfyUI_Aniportrait",
"reference": "https://github.com/frankchieng/ComfyUI_Aniportrait", "reference": "https://github.com/frankchieng/ComfyUI_Aniportrait",
"files": [ "files": [
@ -6839,6 +6969,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "implementation of [a/AniPortrait](https://github.com/Zejun-Yang/AniPortrait) generating of videos, includes self driven, face reenacment and audio driven with a reference image" "description": "implementation of [a/AniPortrait](https://github.com/Zejun-Yang/AniPortrait) generating of videos, includes self driven, face reenacment and audio driven with a reference image"
}, },
{
"author": "FrankChieng",
"title": "ComfyUI_MagicClothing",
"reference": "https://github.com/frankchieng/ComfyUI_MagicClothing",
"files": [
"https://github.com/frankchieng/ComfyUI_MagicClothing"
],
"install_type": "git-clone",
"description": "implementation of MagicClothing with garment and prompt in ComfyUI"
},
{ {
"author": "BlakeOne", "author": "BlakeOne",
"title": "ComfyUI SchedulerMixer", "title": "ComfyUI SchedulerMixer",
@ -6859,6 +6999,26 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Simple node for setting the sigma values directly. Note, for a full denoise the last sigma should be zero." "description": "Simple node for setting the sigma values directly. Note, for a full denoise the last sigma should be zero."
}, },
{
"author": "BlakeOne",
"title": "ComfyUI NodePresets",
"reference": "https://github.com/BlakeOne/ComfyUI-NodePresets",
"files": [
"https://github.com/BlakeOne/ComfyUI-NodePresets"
],
"install_type": "git-clone",
"description": "An extension for ComyUI that enables saving and loading node presets using the node's context menu.\nRight click a node and choose 'Presets' from its context menu to access the node's presets."
},
{
"author": "BlakeOne",
"title": "ComfyUI NodeReset",
"reference": "https://github.com/BlakeOne/ComfyUI-NodeReset",
"files": [
"https://github.com/BlakeOne/ComfyUI-NodeReset"
],
"install_type": "git-clone",
"description": "An extension for ComyUI to allow resetting a node's inputs to their default values.\nNOTE:Right click any node and choose 'Reset' from the context menu."
},
{ {
"author": "kale4eat", "author": "kale4eat",
"title": "ComfyUI_demucus", "title": "ComfyUI_demucus",
@ -6889,6 +7049,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Text file utility for ComfyUI" "description": "Text file utility for ComfyUI"
}, },
{
"author": "kale4eat",
"title": "ComfyUI-speech-dataset-toolkit",
"reference": "https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit",
"files": [
"https://github.com/kale4eat/ComfyUI-speech-dataset-toolkit"
],
"install_type": "git-clone",
"description": "Basic audio tools using torchaudio for ComfyUI. It is assumed to assist in the speech dataset creation for ASR, TTS, etc."
},
{ {
"author": "DrMWeigand", "author": "DrMWeigand",
"title": "ComfyUI Color Detection Nodes", "title": "ComfyUI Color Detection Nodes",
@ -6959,6 +7129,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Attach a debug node to an output to obtain more detailed information. Uncover the details of your models in ComfyUI with ease." "description": "Attach a debug node to an output to obtain more detailed information. Uncover the details of your models in ComfyUI with ease."
}, },
{
"author": "Sida Liu",
"title": "ComfyUI-Login",
"reference": "https://github.com/liusida/ComfyUI-Login",
"files": [
"https://github.com/liusida/ComfyUI-Login"
],
"install_type": "git-clone",
"description": "A simple password to protect ComfyUI."
},
{ {
"author": "jtydhr88", "author": "jtydhr88",
"title": "ComfyUI-Workflow-Encrypt", "title": "ComfyUI-Workflow-Encrypt",
@ -6999,16 +7179,6 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "This repository simply caches the CLIP embeddings and subtly accelerates the inference process by bypassing unnecessary computations." "description": "This repository simply caches the CLIP embeddings and subtly accelerates the inference process by bypassing unnecessary computations."
}, },
{
"author": "abdozmantar",
"title": "InstaSwap Face Swap Node for ComfyUI",
"reference": "https://github.com/abdozmantar/ComfyUI-InstaSwap",
"files": [
"https://github.com/abdozmantar/ComfyUI-InstaSwap"
],
"install_type": "git-clone",
"description": "Fastest Face Swap Extension Node for ComfyUI, Single node and FastTrack: Lightning-Speed Facial Transformation for your projects."
},
{ {
"author": "AIFSH", "author": "AIFSH",
"title": "ComfyUI-UVR5", "title": "ComfyUI-UVR5",
@ -7020,14 +7190,54 @@
"description": "the custom code for [a/UVR5](https://github.com/Anjok07/ultimatevocalremovergui) to separate vocals and background music" "description": "the custom code for [a/UVR5](https://github.com/Anjok07/ultimatevocalremovergui) to separate vocals and background music"
}, },
{ {
"author": "CapsAdmin", "author": "AIFSH",
"title": "ComfyUI-Euler-Smea-Dyn-Sampler", "title": "ComfyUI-IP_LAP",
"reference": "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler", "reference": "https://github.com/AIFSH/ComfyUI-IP_LAP",
"files": [ "files": [
"https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler" "https://github.com/AIFSH/ComfyUI-IP_LAP"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "Just a comfyui version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds the sampler directly to existing samplers." "description": "Nodes:IP_LAP Node, Video Loader, PreView Video, Combine Audio Video. the comfyui custom node of [a/IP_LAP](https://github.com/Weizhi-Zhong/IP_LAP) to make audio driven videos!"
},
{
"author": "AIFSH",
"title": "ComfyUI-GPT_SoVITS",
"reference": "https://github.com/AIFSH/ComfyUI-GPT_SoVITS",
"files": [
"https://github.com/AIFSH/ComfyUI-GPT_SoVITS"
],
"install_type": "git-clone",
"description": "a comfyui custom node for [a/GPT-SoVITS](https://github.com/RVC-Boss/GPT-SoVITS)! you can voice cloning and tts in comfyui now\n[w/NOTE:make sure ffmpeg is worked in your commandline]"
},
{
"author": "AIFSH",
"title": "ComfyUI-MuseTalk_FSH",
"reference": "https://github.com/AIFSH/ComfyUI-MuseTalk_FSH",
"files": [
"https://github.com/AIFSH/ComfyUI-MuseTalk_FSH"
],
"install_type": "git-clone",
"description": "the comfyui custom node of [a/MuseTalk](https://github.com/TMElyralab/MuseTalk) to make audio driven videos!"
},
{
"author": "AIFSH",
"title": "ComfyUI-WhisperX",
"reference": "https://github.com/AIFSH/ComfyUI-WhisperX",
"files": [
"https://github.com/AIFSH/ComfyUI-WhisperX"
],
"install_type": "git-clone",
"description": "a comfyui cuatom node for audio subtitling based on [a/whisperX](https://github.com/m-bain/whisperX.git) and [a/translators](https://github.com/UlionTse/translators)"
},
{
"author": "Koishi-Star",
"title": "Euler-Smea-Dyn-Sampler",
"reference": "https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler",
"files": [
"https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler"
],
"install_type": "git-clone",
"description": "СomfyUI version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds samplers directly to KSampler nodes."
}, },
{ {
"author": "sdfxai", "author": "sdfxai",
@ -7039,7 +7249,376 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "SDFXBridgeForComfyUI is a custom node designed for seamless integration between ComfyUI and SDFX. This custom node allows users to make ComfyUI compatible with SDFX when running the ComfyUI instance on their local machines." "description": "SDFXBridgeForComfyUI is a custom node designed for seamless integration between ComfyUI and SDFX. This custom node allows users to make ComfyUI compatible with SDFX when running the ComfyUI instance on their local machines."
}, },
{
"author": "smthemex",
"title": "ComfyUI_ChatGLM_API",
"reference": "https://github.com/smthemex/ComfyUI_ChatGLM_API",
"files": [
"https://github.com/smthemex/ComfyUI_ChatGLM_API"
],
"install_type": "git-clone",
"description": "You can call Chatglm's API in comfyUI to translate and describe pictures, and the API similar to OpenAI."
},
{
"author": "smthemex",
"title": "ComfyUI_ParlerTTS",
"reference": "https://github.com/smthemex/ComfyUI_ParlerTTS",
"files": [
"https://github.com/smthemex/ComfyUI_ParlerTTS"
],
"install_type": "git-clone",
"description": "This is a simple ComfyUI custom TTS node based on [a/Parler_tts](https://huggingface.co/parler-tts)."
},
{
"author": "smthemex",
"title": "ComfyUI_Pic2Story",
"reference": "https://github.com/smthemex/ComfyUI_Pic2Story",
"files": [
"https://github.com/smthemex/ComfyUI_Pic2Story"
],
"install_type": "git-clone",
"description": "ComfyUI simple node based on BLIP method, with the function of 'Image to Txt'."
},
{
"author": "smthemex",
"title": "ComfyUI_Pic2Story",
"reference": "https://github.com/smthemex/ComfyUI_Pic2Story",
"files": [
"https://github.com/smthemex/ComfyUI_Pic2Story"
],
"install_type": "git-clone",
"description": "ComfyUI simple node based on BLIP method, with the function of 'Image to Txt'."
},
{
"author": "smthemex",
"title": "ComfyUI_Pipeline_Tool",
"reference": "https://github.com/smthemex/ComfyUI_Pipeline_Tool",
"files": [
"https://github.com/smthemex/ComfyUI_Pipeline_Tool"
],
"install_type": "git-clone",
"description": "Nodes:Pipeline_Tool"
},
{
"author": "choey",
"title": "Comfy-Topaz",
"reference": "https://github.com/choey/Comfy-Topaz",
"files": [
"https://github.com/choey/Comfy-Topaz"
],
"install_type": "git-clone",
"description": "Comfy-Topaz is a custom node for ComfyUI, which integrates with Topaz Photo AI to enhance (upscale, sharpen, denoise, etc.) images, allowing this traditionally asynchronous step to become a part of ComfyUI workflows.\nNOTE:Licensed installation of Topaz Photo AI"
},
{
"author": "ALatentPlace",
"title": "ComfyUI_yanc",
"reference": "https://github.com/ALatentPlace/ComfyUI_yanc",
"files": [
"https://github.com/ALatentPlace/ComfyUI_yanc"
],
"install_type": "git-clone",
"description": "Yet Another Node Collection. Adds some useful nodes, check out the GitHub page for more details."
},
{
"author": "Wicloz",
"title": "ComfyUI-Simply-Nodes",
"reference": "https://github.com/Wicloz/ComfyUI-Simply-Nodes",
"files": [
"https://github.com/Wicloz/ComfyUI-Simply-Nodes"
],
"install_type": "git-clone",
"description": "Nodes:Conditional LoRA Loader, Multiline Text, Text Flow Controller, Select SDXL Resolution, Random Style Prompt."
},
{
"author": "wandbrandon",
"title": "comfyui-pixel",
"reference": "https://github.com/wandbrandon/comfyui-pixel",
"files": [
"https://github.com/wandbrandon/comfyui-pixel"
],
"install_type": "git-clone",
"description": "pixel art workshop nodes for comfyui."
},
{
"author": "nullquant",
"title": "BrushNet",
"reference": "https://github.com/nullquant/ComfyUI-BrushNet",
"files": [
"https://github.com/nullquant/ComfyUI-BrushNet"
],
"install_type": "git-clone",
"description": "Custom nodes for ComfyUI allow to inpaint using Brushnet: '[a/BrushNet: A Plug-and-Play Image Inpainting Model with Decomposed Dual-Branch Diffusion](https://arxiv.org/abs/2403.06976)'."
},
{
"author": "pamparamm",
"title": "Perturbed-Attention Guidance",
"reference": "https://github.com/pamparamm/sd-perturbed-attention",
"files": [
"https://github.com/pamparamm/sd-perturbed-attention"
],
"install_type": "git-clone",
"description": "Perturbed-Attention Guidance node for ComfyUI."
},
{
"author": "unwdef",
"title": "unwdef-nodes",
"reference": "https://github.com/unwdef/unwdef-nodes-comfyui",
"files": [
"https://github.com/unwdef/unwdef-nodes-comfyui"
],
"install_type": "git-clone",
"description": "Custom nodes for ComfyUI by unwdef."
},
{
"author": "fevre27",
"title": "Self-Guidance nodes",
"reference": "https://github.com/forever22777/comfyui-self-guidance",
"files": [
"https://github.com/forever22777/comfyui-self-guidance"
],
"install_type": "git-clone",
"description": "Unofficial ComfyUI implementation of Self-Guidance."
},
{
"author": "aburahamu",
"title": "ComfyUI-RequestsPoster",
"reference": "https://github.com/aburahamu/ComfyUI-RequestsPoster",
"files": [
"https://github.com/aburahamu/ComfyUI-RequestsPoster"
],
"install_type": "git-clone",
"description": "This custom node is that simply posts HttpRequest from ComfyUI."
},
{
"author": "Sorcerio",
"title": "MBM's Music Visualizer",
"reference": "https://github.com/Sorcerio/MBM-Music-Visualizer",
"files": [
"https://github.com/Sorcerio/MBM-Music-Visualizer"
],
"install_type": "git-clone",
"description": "An image generation based music visualizer integrated into comfyanonymous/ComfyUI as custom nodes."
},
{
"author": "quadmoon",
"title": "quadmoon's ComfyUI nodes",
"reference": "https://github.com/traugdor/ComfyUI-quadMoons-nodes",
"files": [
"https://github.com/traugdor/ComfyUI-quadMoons-nodes"
],
"install_type": "git-clone",
"description": "These are just some nodes I wanted and couldn't find where anyone else had made them yet."
},
{
"author": "quadme7macoon",
"title": "ComfyUI-ShadertoyGL",
"reference": "https://github.com/e7mac/ComfyUI-ShadertoyGL",
"files": [
"https://github.com/e7mac/ComfyUI-ShadertoyGL"
],
"install_type": "git-clone",
"description": "Nodes:Shadertoy, Shader, ColorChannelOffset."
},
{
"author": "turkyden",
"title": "ComfyUI-Sticker",
"reference": "https://github.com/turkyden/ComfyUI-Sticker",
"files": [
"https://github.com/turkyden/ComfyUI-Sticker"
],
"install_type": "git-clone",
"description": "image to sticker"
},
{
"author": "turkyden",
"title": "ComfyUI-Comic",
"reference": "https://github.com/turkyden/ComfyUI-Comic",
"files": [
"https://github.com/turkyden/ComfyUI-Comic"
],
"install_type": "git-clone",
"description": "a comfyui plugin for image to comic"
},
{
"author": "royceschultz",
"title": "ComfyUI-TranscriptionTools",
"reference": "https://github.com/royceschultz/ComfyUI-TranscriptionTools",
"files": [
"https://github.com/royceschultz/ComfyUI-TranscriptionTools"
],
"install_type": "git-clone",
"description": "Transcribe audio and video files in ComfyUI."
},
{
"author": "kunieone",
"title": "ComfyUI_alkaid",
"reference": "https://github.com/kunieone/ComfyUI_alkaid",
"files": [
"https://github.com/kunieone/ComfyUI_alkaid"
],
"install_type": "git-clone",
"description": "Nodes:A_Face3DSwapper, A_FaceCrop, A_FacePaste, A_OpenPosePreprocessor, A_EmptyLatentImageLongside, A_GetImageSize, AlkaidLoader, AdapterFaceLoader, AdapterStyleLoader, ..."
},
{
"author": "jtydhr88",
"title": "ComfyUI-InstantMesh",
"reference": "https://github.com/jtydhr88/ComfyUI-InstantMesh",
"files": [
"https://github.com/jtydhr88/ComfyUI-InstantMesh"
],
"install_type": "git-clone",
"description": "ComfyUI InstantMesh is custom nodes that running TencentARC/InstantMesh into ComfyUI, this extension depends on ComfyUI-3D-Pack. Please refer to Readme carefully to install."
},
{
"author": "txt2any",
"title": "ComfyUI-PromptOrganizer",
"reference": "https://github.com/txt2any/ComfyUI-PromptOrganizer",
"files": [
"https://github.com/txt2any/ComfyUI-PromptOrganizer"
],
"install_type": "git-clone",
"description": "This is a custom node for ComfyUI that automatically saves your AI-generated images specifically to [a/www.txt2any.com](http://www.txt2any.com/)."
},
{
"author": "kealiu",
"title": "ComfyUI Load and Save file to S3",
"reference": "https://github.com/kealiu/ComfyUI-S3-Tools",
"files": [
"https://github.com/kealiu/ComfyUI-S3-Tools"
],
"install_type": "git-clone",
"description": "Nodes:Load From S3, Save To S3."
},
{
"author": "TashaSkyUp",
"title": "ComfyUI_LiteLLM",
"reference": "https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM",
"files": [
"https://github.com/Hopping-Mad-Games/ComfyUI_LiteLLM"
],
"install_type": "git-clone",
"description": "Nodes for interfacing with LiteLLM"
},
{
"author": "AonekoSS",
"title": "ComfyUI-SimpleCounter",
"reference": "https://github.com/AonekoSS/ComfyUI-SimpleCounter",
"files": [
"https://github.com/AonekoSS/ComfyUI-SimpleCounter"
],
"install_type": "git-clone",
"description": "Nodes:Simple Counter"
},
{
"author": "heshengtao",
"title": "comfyui_LLM_party",
"reference": "https://github.com/heshengtao/comfyui_LLM_party",
"files": [
"https://github.com/heshengtao/comfyui_LLM_party"
],
"install_type": "git-clone",
"description": "A set of block-based LLM agent node libraries designed for ComfyUI.This project aims to develop a complete set of nodes for LLM workflow construction based on comfyui. It allows users to quickly and conveniently build their own LLM workflows and easily integrate them into their existing SD workflows."
},
{
"author": "VAST-AI-Research",
"title": "Tripo for ComfyUI",
"reference": "https://github.com/VAST-AI-Research/ComfyUI-Tripo",
"files": [
"https://github.com/VAST-AI-Research/ComfyUI-Tripo"
],
"install_type": "git-clone",
"description": "Custom nodes for using [a/Tripo](https://www.tripo3d.ai/) in ComfyUI to create 3D from text and image prompts."
},
{
"author": "JettHu",
"title": "ComfyUI_TGate",
"reference": "https://github.com/JettHu/ComfyUI_TGate",
"files": [
"https://github.com/JettHu/ComfyUI_TGate"
],
"install_type": "git-clone",
"description": "ComfyUI reference implementation for [a/T-GATE](https://github.com/HaozheLiu-ST/T-GATE)."
},
{
"author": "sugarkwork",
"title": "comfyui_tag_filter",
"reference": "https://github.com/sugarkwork/comfyui_tag_fillter",
"files": [
"https://github.com/sugarkwork/comfyui_tag_fillter"
],
"install_type": "git-clone",
"description": "This is a custom node of ComfyUI that categorizes tags outputted by tools like WD14Tagger, filters them by each category, and returns the filtered results."
},
{
"author": "Intersection98",
"title": "ComfyUI-MX-post-processing-nodes",
"reference": "https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes",
"files": [
"https://github.com/Intersection98/ComfyUI_MX_post_processing-nodes"
],
"install_type": "git-clone",
"description": "A collection of post processing nodes for ComfyUI, dds image post-processing adjustment capabilities to the ComfyUI."
},
{
"author": "TencentQQGYLab",
"title": "ComfyUI-ELLA",
"reference": "https://github.com/TencentQQGYLab/ComfyUI-ELLA",
"files": [
"https://github.com/TencentQQGYLab/ComfyUI-ELLA"
],
"install_type": "git-clone",
"description": "ComfyUI implementation for [a/ELLA](https://github.com/TencentQQGYLab/ELLA)."
},
{
"author": "DarKDinDoN",
"title": "ComfyUI Checkpoint Automatic Config",
"reference": "https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config",
"files": [
"https://github.com/DarKDinDoN/comfyui-checkpoint-automatic-config"
],
"install_type": "git-clone",
"description": "This node was designed to help with checkpoint configuration."
},
{
"author": "aburahamu",
"title": "ComfyUI-RequestPoster",
"reference": "https://github.com/aburahamu/ComfyUI-RequestsPoster",
"files": [
"https://github.com/aburahamu/ComfyUI-RequestsPoster"
],
"install_type": "git-clone",
"description": "This extension can send HTTP Requests. You can request image generation to StableDiffusion3 and post images to X (Twitter) and Discord."
},
{
"author": "MinusZoneAI",
"title": "ComfyUI-Prompt-MZ",
"reference": "https://github.com/MinusZoneAI/ComfyUI-Prompt-MZ",
"files": [
"https://github.com/MinusZoneAI/ComfyUI-Prompt-MZ"
],
"install_type": "git-clone",
"description": "Use llama.cpp to help generate some nodes for prompt word related work"
},
{
"author": "blueraincoatli",
"title": "comfyUI_SillyNodes",
"reference": "https://github.com/blueraincoatli/comfyUI_SillyNodes",
"files": [
"https://github.com/blueraincoatli/comfyUI_SillyNodes"
],
"install_type": "git-clone",
"description": "Using rgthree's fast_group_muter and bookmark nodes, introduce the pyautogui library to simulate clicks and hotkeys, and run groups in sequence. screen manipulation is involved"
},
{
"author": "ty0x2333",
"title": "ComfyUI-Dev-Utils",
"reference": "https://github.com/ty0x2333/ComfyUI-Dev-Utils",
"files": [
"https://github.com/ty0x2333/ComfyUI-Dev-Utils"
],
"install_type": "git-clone",
"description": "Execution Time Analysis, Reroute Enhancement, Node collection for developers."
},
@ -7352,7 +7931,19 @@
], ],
"install_type": "copy", "install_type": "copy",
"description": "Extension to show random cat GIFs while queueing prompt." "description": "Extension to show random cat GIFs while queueing prompt."
}, },
{
"author": "xliry",
"title": "ComfyUI_SendDiscord",
"reference": "https://github.com/xliry/ComfyUI_SendDiscord",
"files": [
"https://github.com/xliry/ComfyUI_SendDiscord/raw/main/SendDiscord.py"
],
"install_type": "copy",
"description": "Nodes:Send Video to Discord"
},
{ {
"author": "theally", "author": "theally",
"title": "TheAlly's Custom Nodes", "title": "TheAlly's Custom Nodes",

140
docs/en/cm-cli.md Normal file
View File

@ -0,0 +1,140 @@
# `cm-cli`: ComfyUI-Manager CLI
`cm-cli` is a tool that allows you to use various functions of ComfyUI-Manager from the command line without launching ComfyUI.
```
-= ComfyUI-Manager CLI (V2.22) =-
python cm-cli.py [OPTIONS]
OPTIONS:
[install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel <channel name>] ?[--mode [remote|local|cache]]
[update|disable|enable|fix] all ?[--channel <channel name>] ?[--mode [remote|local|cache]]
[simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel <channel name>] ?[--mode [remote|local|cache]]
save-snapshot
restore-snapshot <snapshot>
cli-only-mode [enable|disable]
restore-dependencies
clear
```
## How To Use?
* You can execute it via `python cm-cli.py`.
* For example, if you want to update all custom nodes:
* In the ComfyUI-Manager directory, you can execute the command `python cm-cli.py update all`.
* If running from the ComfyUI directory, you can specify the path to cm-cli.py like this: `python custom_nodes/ComfyUI-Manager/cm-cli.py update all`.
## Prerequisite
* It must be run in the same Python environment as the one running ComfyUI.
* If using a venv, you must run it with the venv activated.
* If using a portable version, and you are in the directory with the run_nvidia_gpu.bat file, you should execute the command as follows:
`.\python_embeded\python.exe ComfyUI\custom_nodes\ComfyUI-Manager\cm-cli.py update all`
* The path for ComfyUI can be set with the COMFYUI_PATH environment variable. If omitted, a warning message will appear, and the path will be set relative to the installed location of ComfyUI-Manager:
```
WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.
```
## Features
### 1. --channel, --mode
* For viewing information and managing custom nodes, you can set the information database through --channel and --mode.
* For instance, executing the command `python cm-cli.py update all --channel recent --mode remote` will operate based on the latest information from remote rather than local data embedded in the current ComfyUI-Manager repo and will only target the list in the recent channel.
* --channel, --mode are only available with the commands `simple-show, show, install, uninstall, update, disable, enable, fix`.
### 2. Viewing Management Information
`[simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
* `[show|simple-show]` - `show` provides detailed information, while `simple-show` displays information more simply.
Executing a command like `python cm-cli.py show installed` will display detailed information about the installed custom nodes.
```
-= ComfyUI-Manager CLI (V2.21.1) =-
FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json
[ ENABLED ] ComfyUI-Manager (author: Dr.Lt.Data)
[ ENABLED ] ComfyUI-Impact-Pack (author: Dr.Lt.Data)
[ ENABLED ] ComfyUI-Inspire-Pack (author: Dr.Lt.Data)
[ ENABLED ] ComfyUI_experiments (author: comfyanonymous)
[ ENABLED ] ComfyUI-SAI_API (author: Stability-AI)
[ ENABLED ] stability-ComfyUI-nodes (author: Stability-AI)
[ ENABLED ] comfyui_controlnet_aux (author: Fannovel16)
[ ENABLED ] ComfyUI-Frame-Interpolation (author: Fannovel16)
[ DISABLED ] ComfyUI-Loopchain (author: Fannovel16)
```
Using a command like `python cm-cli.py simple-show installed` will simply display information about the installed custom nodes.
```
-= ComfyUI-Manager CLI (V2.21.1) =-
FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json
ComfyUI-Manager
ComfyUI-Impact-Pack
ComfyUI-Inspire-Pack
ComfyUI_experiments
ComfyUI-SAI_API
stability-ComfyUI-nodes
comfyui_controlnet_aux
ComfyUI-Frame-Interpolation
ComfyUI-Loopchain
```
`[installed|enabled|not-installed|disabled|all|snapshot|snapshot-list]`
* `enabled`, `disabled`: Shows nodes that have been enabled or disabled among the installed custom nodes.
* `installed`: Shows all nodes that have been installed, regardless of whether they are enabled or disabled.
* `not-installed`: Shows a list of custom nodes that have not been installed.
* `all`: Shows a list of all custom nodes.
* `snapshot`: Displays snapshot information of the currently installed custom nodes. When viewed with `show`, it is displayed in JSON format, and with `simple-show`, it is displayed simply, along with the commit hash.
* `snapshot-list`: Shows a list of snapshot files stored in ComfyUI-Manager/snapshots.
### 3. Managing Custom Nodes
`[install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
* You can apply management functions by listing the names of custom nodes, such as `python cm-cli.py install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack ComfyUI_experiments`.
* The names of the custom nodes are as shown by `show` and are the names of the git repositories.
(Plans are to update the use of nicknames in the future.)
`[update|disable|enable|fix] all ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
* The `update, disable, enable, fix` functions can be specified for all.
* Detailed Operations
* `install`: Installs the specified custom nodes.
* `reinstall`: Removes and then reinstalls the specified custom nodes.
* `uninstall`: Uninstalls the specified custom nodes.
* `update`: Updates the specified custom nodes.
* `disable`: Disables the specified custom nodes.
* `enable`: Enables the specified custom nodes.
* `fix`: Attempts to fix dependencies for the specified custom nodes.
### 4. Snapshot Management
* `python cm-cli.py save-snapshot`: Saves the current snapshot.
* `python cm-cli.py restore-snapshot <snapshot>`: Restores to the specified snapshot.
* It is assumed that the snapshot files are located in ComfyUI-Manager/snapshots.
(An update is planned to allow files from other paths in the future.)
### 5. CLI Only Mode
You can set whether to use ComfyUI-Manager solely via CLI.
`cli-only-mode [enable|disable]`
* This mode can be used if you want to restrict the use of ComfyUI-Manager through the GUI for security or policy reasons.
* When CLI only mode is enabled, ComfyUI-Manager is loaded in a very restricted state, the internal web API is disabled, and the Manager button is not displayed in the main menu.
### 6. Dependency Restoration
`restore-dependencies`
* This command can be used if custom nodes are installed under the `ComfyUI/custom_nodes` path but their dependencies are not installed.
* It is useful when starting a new cloud instance, like colab, where dependencies need to be reinstalled and installation scripts re-executed.
* It can also be utilized if ComfyUI is reinstalled and only the custom_nodes path has been backed up and restored.
### 7. Clear
In the GUI, installations, updates, or snapshot restorations are scheduled to execute the next time ComfyUI is launched. The `clear` command clears this scheduled state, ensuring no pre-execution actions are applied.

145
docs/ko/cm-cli.md Normal file
View File

@ -0,0 +1,145 @@
# `cm-cli`: ComfyUI-Manager CLI
`cm-cli` 는 ComfyUI를 실행시키지 않고 command line에서 ComfyUI-Manager의 여러가지 기능을 사용할 수 있도록 도와주는 도구입니다.
```
-= ComfyUI-Manager CLI (V2.21.1) =-
python cm-cli.py [OPTIONS]
OPTIONS:
[install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel <channel name>] ?[--mode [remote|local|cache]]
[update|disable|enable|fix] all ?[--channel <channel name>] ?[--mode [remote|local|cache]]
[simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel <channel name>] ?[--mode [remote|local|cache]]
save-snapshot
restore-snapshot <snapshot>
cli-only-mode [enable|disable]
restore-dependencies
clear
```
## How To Use?
* `python cm-cli.py` 를 통해서 실행 시킬 수 있습니다.
* 예를 들어 custom node를 모두 업데이트 하고 싶다면
* ComfyUI-Manager경로 에서 `python cm-cli.py update all` 를 command를 실행할 수 있습니다.
* ComfyUI 경로에서 실행한다면, `python custom_nodes/ComfyUI-Manager/cm-cli.py update all` 와 같이 cm-cli.py 의 경로를 지정할 수도 있습니다.
## Prerequisite
* ComfyUI 를 실행하는 python과 동일한 python 환경에서 실행해야 합니다.
* venv를 사용할 경우 해당 venv를 activate 한 상태에서 실행해야 합니다.
* portable 버전을 사용할 경우 run_nvidia_gpu.bat 파일이 있는 경로인 경우, 다음과 같은 방식으로 코맨드를 실행해야 합니다.
`.\python_embeded\python.exe ComfyUI\custom_nodes\ComfyUI-Manager\cm-cli.py update all`
* ComfyUI 의 경로는 COMFYUI_PATH 환경 변수로 설정할 수 있습니다. 만약 생략할 경우 다음과 같은 경고 메시지가 나타나며, ComfyUI-Manager가 설치된 경로를 기준으로 상대 경로로 설정됩니다.
```
WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.
```
## Features
### 1. --channel, --mode
* 정보 보기 기능과 커스텀 노드 관리 기능의 경우는 --channel과 --mode를 통해 정보 DB를 설정할 수 있습니다.
* 예들 들어 `python cm-cli.py update all --channel recent --mode remote`와 같은 command를 실행할 경우, 현재 ComfyUI-Manager repo에 내장된 로컬의 정보가 아닌 remote의 최신 정보를 기준으로 동작하며, recent channel에 있는 목록을 대상으로만 동작합니다.
* --channel, --mode 는 `simple-show, show, install, uninstall, update, disable, enable, fix` command에서만 사용 가능합니다.
### 2. 관리 정보 보기
`[simple-show|show] [installed|enabled|not-installed|disabled|all|snapshot|snapshot-list] ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
* `[show|simple-show]` - `show`는 상세하게 정보를 보여주며, `simple-show`는 간단하게 정보를 보여줍니다.
`python cm-cli.py show installed` 와 같은 코맨드를 실행하면 설치된 커스텀 노드의 정보를 상세하게 보여줍니다.
```
-= ComfyUI-Manager CLI (V2.21.1) =-
FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json
[ ENABLED ] ComfyUI-Manager (author: Dr.Lt.Data)
[ ENABLED ] ComfyUI-Impact-Pack (author: Dr.Lt.Data)
[ ENABLED ] ComfyUI-Inspire-Pack (author: Dr.Lt.Data)
[ ENABLED ] ComfyUI_experiments (author: comfyanonymous)
[ ENABLED ] ComfyUI-SAI_API (author: Stability-AI)
[ ENABLED ] stability-ComfyUI-nodes (author: Stability-AI)
[ ENABLED ] comfyui_controlnet_aux (author: Fannovel16)
[ ENABLED ] ComfyUI-Frame-Interpolation (author: Fannovel16)
[ DISABLED ] ComfyUI-Loopchain (author: Fannovel16)
```
`python cm-cli.py simple-show installed` 와 같은 코맨드를 이용해서 설치된 커스텀 노드의 정보를 간단하게 보여줍니다.
```
-= ComfyUI-Manager CLI (V2.21.1) =-
FETCH DATA from: https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main/custom-node-list.json
ComfyUI-Manager
ComfyUI-Impact-Pack
ComfyUI-Inspire-Pack
ComfyUI_experiments
ComfyUI-SAI_API
stability-ComfyUI-nodes
comfyui_controlnet_aux
ComfyUI-Frame-Interpolation
ComfyUI-Loopchain
```
* `[installed|enabled|not-installed|disabled|all|snapshot|snapshot-list]`
* `enabled`, `disabled`: 설치된 커스텀 노드들 중 enable 되었거나, disable된 노드들을 보여줍니다.
* `installed`: enable, disable 여부와 상관없이 설치된 모든 노드를 보여줍니다
* `not-installed`: 설치되지 않은 커스텀 노드의 목록을 보여줍니다.
* `all`: 모든 커스텀 노드의 목록을 보여줍니다.
* `snapshot`: 현재 설치된 커스텀 노드의 snapshot 정보를 보여줍니다. `show`롤 통해서 볼 경우는 json 출력 형태로 보여주며, `simple-show`를 통해서 볼 경우는 간단하게, 커밋 해시와 함께 보여줍니다.
* `snapshot-list`: ComfyUI-Manager/snapshots 에 저장된 snapshot 파일의 목록을 보여줍니다.
### 3. 커스텀 노드 관리 하기
`[install|reinstall|uninstall|update|disable|enable|fix] node_name ... ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
* `python cm-cli.py install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack ComfyUI_experiments` 와 같이 커스텀 노드의 이름을 나열해서 관리 기능을 적용할 수 있습니다.
* 커스텀 노드의 이름은 `show`를 했을 때 보여주는 이름이며, git repository의 이름입니다.
(추후 nickname 을 사용가능하돌고 업데이트 할 예정입니다.)
`[update|disable|enable|fix] all ?[--channel <channel name>] ?[--mode [remote|local|cache]]`
* `update, disable, enable, fix` 기능은 all 로 지정 가능합니다.
* 세부 동작
* `install`: 지정된 커스텀 노드들을 설치합니다
* `reinstall`: 지정된 커스텀 노드를 삭제하고 재설치 합니다.
* `uninstall`: 지정된 커스텀 노드들을 삭제합니다.
* `update`: 지정된 커스텀 노드들을 업데이트합니다.
* `disable`: 지정된 커스텀 노드들을 비활성화합니다.
* `enable`: 지정된 커스텀 노드들을 활성화합니다.
* `fix`: 지정된 커스텀 노드의 의존성을 고치기 위한 시도를 합니다.
### 4. 스냅샷 관리 기능
* `python cm-cli.py save-snapshot`: 현재의 snapshot을 저장합니다.
* `python cm-cli.py restore-snapshot <snapshot>`: 지정된 snapshot으로 복구합니다.
* snapshot 파일은 ComfyUI-Manager/snapshots 에 있다고 가정합니다.
(추후 다른 경로에 있는 파일을 허용 가능하도록 업데이트 예정입니다.)
### 5. CLI only mode
ComfyUI-Manager를 CLI로만 사용할 것인지를 설정할 수 있습니다.
`cli-only-mode [enable|disable]`
* security 혹은 policy 의 이유로 GUI 를 통한 ComfyUI-Manager 사용을 제한하고 싶은 경우 이 모드를 사용할 수 있습니다.
* CLI only mode를 적용할 경우 ComfyUI-Manager 가 매우 제한된 상태로 로드되어, 내부적으로 제공하는 web API가 비활성화 되며, 메인 메뉴에서도 Manager 버튼이 표시되지 않습니다.
### 6. 의존성 설치
`restore-dependencies`
* `ComfyUI/custom_nodes` 하위 경로에 커스텀 노드들이 설치되어 있긴 하지만, 의존성이 설치되지 않은 경우 사용할 수 있습니다.
* colab 과 같이 cloud instance를 새로 시작하는 경우 의존성 재설치 및 설치 스크립트가 재실행 되어야 하는 경우 사용합니다.
* ComfyUI을 재설치할 경우, custom_nodes 경로만 백업했다가 재설치 할 경우 활용 가능합니다.
### 7. clear
GUI에서 install, update를 하거나 snapshot 을 restore하는 경우 예약을 통해서 다음번 ComfyUI를 실행할 경우 실행되는 구조입니다. `clear` 는 이런 예약 상태를 clear해서, 아무런 사전 실행이 적용되지 않도록 합니다.

File diff suppressed because it is too large Load Diff

View File

@ -176,24 +176,32 @@ def checkout_custom_node_hash(git_custom_node_infos):
if repo_name.endswith('.disabled'): if repo_name.endswith('.disabled'):
repo_name = repo_name[:-9] repo_name = repo_name[:-9]
item = git_custom_node_infos[repo_name_to_url[repo_name]] if repo_name not in repo_name_to_url:
if item['disabled'] and is_disabled: if not is_disabled:
pass # should be disabled
elif item['disabled'] and not is_disabled: print(f"DISABLE: {repo_name}")
# disable new_path = fullpath + ".disabled"
print(f"DISABLE: {repo_name}") os.rename(fullpath, new_path)
new_path = fullpath + ".disabled" need_checkout = False
os.rename(fullpath, new_path)
pass
elif not item['disabled'] and is_disabled:
# enable
print(f"ENABLE: {repo_name}")
new_path = fullpath[:-9]
os.rename(fullpath, new_path)
fullpath = new_path
need_checkout = True
else: else:
need_checkout = True item = git_custom_node_infos[repo_name_to_url[repo_name]]
if item['disabled'] and is_disabled:
pass
elif item['disabled'] and not is_disabled:
# disable
print(f"DISABLE: {repo_name}")
new_path = fullpath + ".disabled"
os.rename(fullpath, new_path)
elif not item['disabled'] and is_disabled:
# enable
print(f"ENABLE: {repo_name}")
new_path = fullpath[:-9]
os.rename(fullpath, new_path)
fullpath = new_path
need_checkout = True
else:
need_checkout = True
if need_checkout: if need_checkout:
repo = git.Repo(fullpath) repo = git.Repo(fullpath)
@ -202,6 +210,7 @@ def checkout_custom_node_hash(git_custom_node_infos):
if commit_hash != item['hash']: if commit_hash != item['hash']:
print(f"CHECKOUT: {repo_name} [{item['hash']}]") print(f"CHECKOUT: {repo_name} [{item['hash']}]")
repo.git.checkout(item['hash']) repo.git.checkout(item['hash'])
except Exception: except Exception:
print(f"Failed to restore snapshots for the custom node '{path}'") print(f"Failed to restore snapshots for the custom node '{path}'")

File diff suppressed because it is too large Load Diff

951
glob/manager_core.py Normal file
View File

@ -0,0 +1,951 @@
import os
import sys
import subprocess
import re
import shutil
import configparser
import platform
from datetime import datetime
import git
from git.remote import RemoteProgress
from urllib.parse import urlparse
from tqdm.auto import tqdm
import aiohttp
import threading
import json
import time
glob_path = os.path.join(os.path.dirname(__file__)) # ComfyUI-Manager/glob
sys.path.append(glob_path)
import cm_global
from manager_util import *
version = [2, 22, 1]
version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '')
comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, '..'))
comfy_path = os.path.abspath(os.path.join(custom_nodes_path, '..'))
channel_list_path = os.path.join(comfyui_manager_path, 'channels.list')
config_path = os.path.join(comfyui_manager_path, "config.ini")
startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts")
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
cache_dir = os.path.join(comfyui_manager_path, '.cache')
cached_config = None
js_path = None
comfy_ui_required_revision = 1930
comfy_ui_required_commit_datetime = datetime(2024, 1, 24, 0, 0, 0)
comfy_ui_revision = "Unknown"
comfy_ui_commit_datetime = datetime(1900, 1, 1, 0, 0, 0)
cache_lock = threading.Lock()
channel_dict = None
channel_list = None
pip_map = None
def remap_pip_package(pkg):
if pkg in cm_global.pip_overrides:
res = cm_global.pip_overrides[pkg]
print(f"[ComfyUI-Manager] '{pkg}' is remapped to '{res}'")
return res
else:
return pkg
def get_installed_packages():
global pip_map
if pip_map is None:
try:
result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True)
pip_map = {}
for line in result.split('\n'):
x = line.strip()
if x:
y = line.split()
if y[0] == 'Package' or y[0].startswith('-'):
continue
pip_map[y[0]] = y[1]
except subprocess.CalledProcessError as e:
print(f"[ComfyUI-Manager] Failed to retrieve the information of installed pip packages.")
return set()
return pip_map
def clear_pip_cache():
global pip_map
pip_map = None
def is_blacklisted(name):
name = name.strip()
pattern = r'([^<>!=]+)([<>!=]=?)(.*)'
match = re.search(pattern, name)
if match:
name = match.group(1)
if name in cm_global.pip_downgrade_blacklist:
pips = get_installed_packages()
if match is None:
if name in pips:
return True
elif match.group(2) in ['<=', '==', '<']:
if name in pips:
if StrictVersion(pips[name]) >= StrictVersion(match.group(3)):
return True
return False
def is_installed(name):
name = name.strip()
if name.startswith('#'):
return True
pattern = r'([^<>!=]+)([<>!=]=?)(.*)'
match = re.search(pattern, name)
if match:
name = match.group(1)
if name in cm_global.pip_downgrade_blacklist:
pips = get_installed_packages()
if match is None:
if name in pips:
return True
elif match.group(2) in ['<=', '==', '<']:
if name in pips:
if StrictVersion(pips[name]) >= StrictVersion(match.group(3)):
print(f"[ComfyUI-Manager] skip black listed pip installation: '{name}'")
return True
return name.lower() in get_installed_packages()
def get_channel_dict():
global channel_dict
if channel_dict is None:
channel_dict = {}
if not os.path.exists(channel_list_path):
shutil.copy(channel_list_path+'.template', channel_list_path)
with open(os.path.join(comfyui_manager_path, 'channels.list'), 'r') as file:
channels = file.read()
for x in channels.split('\n'):
channel_info = x.split("::")
if len(channel_info) == 2:
channel_dict[channel_info[0]] = channel_info[1]
return channel_dict
def get_channel_list():
global channel_list
if channel_list is None:
channel_list = []
for k, v in get_channel_dict().items():
channel_list.append(f"{k}::{v}")
return channel_list
class ManagerFuncs:
def __init__(self):
pass
def get_current_preview_method(self):
return "none"
def run_script(self, cmd, cwd='.'):
if len(cmd) > 0 and cmd[0].startswith("#"):
print(f"[ComfyUI-Manager] Unexpected behavior: `{cmd}`")
return 0
out = subprocess.check_call(cmd, cwd=cwd)
print(out)
return 0
manager_funcs = ManagerFuncs()
def write_config():
config = configparser.ConfigParser()
config['default'] = {
'preview_method': manager_funcs.get_current_preview_method(),
'badge_mode': get_config()['badge_mode'],
'git_exe': get_config()['git_exe'],
'channel_url': get_config()['channel_url'],
'share_option': get_config()['share_option'],
'bypass_ssl': get_config()['bypass_ssl'],
"file_logging": get_config()['file_logging'],
'default_ui': get_config()['default_ui'],
'component_policy': get_config()['component_policy'],
'double_click_policy': get_config()['double_click_policy'],
'windows_selector_event_loop_policy': get_config()['windows_selector_event_loop_policy'],
'model_download_by_agent': get_config()['model_download_by_agent'],
'downgrade_blacklist': get_config()['downgrade_blacklist']
}
with open(config_path, 'w') as configfile:
config.write(configfile)
def read_config():
try:
config = configparser.ConfigParser()
config.read(config_path)
default_conf = config['default']
return {
'preview_method': default_conf['preview_method'] if 'preview_method' in default_conf else manager_funcs.get_current_preview_method(),
'badge_mode': default_conf['badge_mode'] if 'badge_mode' in default_conf else 'none',
'git_exe': default_conf['git_exe'] if 'git_exe' in default_conf else '',
'channel_url': default_conf['channel_url'] if 'channel_url' in default_conf else 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main',
'share_option': default_conf['share_option'] if 'share_option' in default_conf else 'all',
'bypass_ssl': default_conf['bypass_ssl'] if 'bypass_ssl' in default_conf else False,
'file_logging': default_conf['file_logging'] if 'file_logging' in default_conf else True,
'default_ui': default_conf['default_ui'] if 'default_ui' in default_conf else 'none',
'component_policy': default_conf['component_policy'] if 'component_policy' in default_conf else 'workflow',
'double_click_policy': default_conf['double_click_policy'] if 'double_click_policy' in default_conf else 'copy-all',
'windows_selector_event_loop_policy': default_conf['windows_selector_event_loop_policy'] if 'windows_selector_event_loop_policy' in default_conf else False,
'model_download_by_agent': default_conf['model_download_by_agent'] if 'model_download_by_agent' in default_conf else False,
'downgrade_blacklist': default_conf['downgrade_blacklist'] if 'downgrade_blacklist' in default_conf else '',
}
except Exception:
return {
'preview_method': manager_funcs.get_current_preview_method(),
'badge_mode': 'none',
'git_exe': '',
'channel_url': 'https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main',
'share_option': 'all',
'bypass_ssl': False,
'file_logging': True,
'default_ui': 'none',
'component_policy': 'workflow',
'double_click_policy': 'copy-all',
'windows_selector_event_loop_policy': False,
'model_download_by_agent': False,
'downgrade_blacklist': ''
}
def get_config():
global cached_config
if cached_config is None:
cached_config = read_config()
return cached_config
def switch_to_default_branch(repo):
show_result = repo.git.remote("show", "origin")
matches = re.search(r"\s*HEAD branch:\s*(.*)", show_result)
if matches:
default_branch = matches.group(1)
repo.git.checkout(default_branch)
def try_install_script(url, repo_path, install_cmd, instant_execution=False):
if not instant_execution and ((len(install_cmd) > 0 and install_cmd[0].startswith('#')) or (platform.system() == "Windows" and comfy_ui_commit_datetime.date() >= comfy_ui_required_commit_datetime.date())):
if not os.path.exists(startup_script_path):
os.makedirs(startup_script_path)
script_path = os.path.join(startup_script_path, "install-scripts.txt")
with open(script_path, "a") as file:
obj = [repo_path] + install_cmd
file.write(f"{obj}\n")
return True
else:
if len(install_cmd) == 5 and install_cmd[2:4] == ['pip', 'install']:
if is_blacklisted(install_cmd[4]):
print(f"[ComfyUI-Manager] skip black listed pip installation: '{install_cmd[4]}'")
return True
print(f"\n## ComfyUI-Manager: EXECUTE => {install_cmd}")
code = manager_funcs.run_script(install_cmd, cwd=repo_path)
if platform.system() != "Windows":
try:
if comfy_ui_commit_datetime.date() < comfy_ui_required_commit_datetime.date():
print("\n\n###################################################################")
print(f"[WARN] ComfyUI-Manager: Your ComfyUI version ({comfy_ui_revision})[{comfy_ui_commit_datetime.date()}] is too old. Please update to the latest version.")
print(f"[WARN] The extension installation feature may not work properly in the current installed ComfyUI version on Windows environment.")
print("###################################################################\n\n")
except:
pass
if code != 0:
if url is None:
url = os.path.dirname(repo_path)
print(f"install script failed: {url}")
return False
# use subprocess to avoid file system lock by git (Windows)
def __win_check_git_update(path, do_fetch=False, do_update=False):
if do_fetch:
command = [sys.executable, git_script_path, "--fetch", path]
elif do_update:
command = [sys.executable, git_script_path, "--pull", path]
else:
command = [sys.executable, git_script_path, "--check", path]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, _ = process.communicate()
output = output.decode('utf-8').strip()
if 'detected dubious' in output:
# fix and try again
safedir_path = path.replace('\\', '/')
try:
print(f"[ComfyUI-Manager] Try fixing 'dubious repository' error on '{safedir_path}' repo")
process = subprocess.Popen(['git', 'config', '--global', '--add', 'safe.directory', safedir_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, _ = process.communicate()
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, _ = process.communicate()
output = output.decode('utf-8').strip()
except Exception:
print(f'[ComfyUI-Manager] failed to fixing')
if 'detected dubious' in output:
print(f'\n[ComfyUI-Manager] Failed to fixing repository setup. Please execute this command on cmd: \n'
f'-----------------------------------------------------------------------------------------\n'
f'git config --global --add safe.directory "{safedir_path}"\n'
f'-----------------------------------------------------------------------------------------\n')
if do_update:
if "CUSTOM NODE PULL: Success" in output:
process.wait()
print(f"\rUpdated: {path}")
return True, True # updated
elif "CUSTOM NODE PULL: None" in output:
process.wait()
return False, True # there is no update
else:
print(f"\rUpdate error: {path}")
process.wait()
return False, False # update failed
else:
if "CUSTOM NODE CHECK: True" in output:
process.wait()
return True, True
elif "CUSTOM NODE CHECK: False" in output:
process.wait()
return False, True
else:
print(f"\rFetch error: {path}")
print(f"\n{output}\n")
process.wait()
return False, True
def __win_check_git_pull(path):
command = [sys.executable, git_script_path, "--pull", path]
process = subprocess.Popen(command)
process.wait()
def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=False):
install_script_path = os.path.join(repo_path, "install.py")
requirements_path = os.path.join(repo_path, "requirements.txt")
if lazy_mode:
install_cmd = ["#LAZY-INSTALL-SCRIPT", sys.executable]
try_install_script(url, repo_path, install_cmd)
else:
if os.path.exists(requirements_path):
print("Install: pip packages")
with open(requirements_path, "r") as requirements_file:
for line in requirements_file:
package_name = remap_pip_package(line.strip())
if package_name and not package_name.startswith('#'):
install_cmd = [sys.executable, "-m", "pip", "install", package_name]
if package_name.strip() != "":
try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution)
if os.path.exists(install_script_path):
print(f"Install: install script")
install_cmd = [sys.executable, "install.py"]
try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution)
return True
def git_repo_has_updates(path, do_fetch=False, do_update=False):
if do_fetch:
print(f"\x1b[2K\rFetching: {path}", end='')
elif do_update:
print(f"\x1b[2K\rUpdating: {path}", end='')
# Check if the path is a git repository
if not os.path.exists(os.path.join(path, '.git')):
raise ValueError('Not a git repository')
if platform.system() == "Windows":
updated, success = __win_check_git_update(path, do_fetch, do_update)
if updated and success:
execute_install_script(None, path, lazy_mode=True)
return updated, success
else:
# Fetch the latest commits from the remote repository
repo = git.Repo(path)
current_branch = repo.active_branch
branch_name = current_branch.name
remote_name = 'origin'
remote = repo.remote(name=remote_name)
# Get the current commit hash
commit_hash = repo.head.commit.hexsha
if do_fetch or do_update:
remote.fetch()
if do_update:
if repo.head.is_detached:
switch_to_default_branch(repo)
remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha
if commit_hash == remote_commit_hash:
repo.close()
return False, True
try:
remote.pull()
repo.git.submodule('update', '--init', '--recursive')
new_commit_hash = repo.head.commit.hexsha
if commit_hash != new_commit_hash:
execute_install_script(None, path)
print(f"\x1b[2K\rUpdated: {path}")
return True, True
else:
return False, False
except Exception as e:
print(f"\nUpdating failed: {path}\n{e}", file=sys.stderr)
return False, False
if repo.head.is_detached:
repo.close()
return True, True
# Get commit hash of the remote branch
current_branch = repo.active_branch
branch_name = current_branch.name
remote_commit_hash = repo.refs[f'{remote_name}/{branch_name}'].object.hexsha
# Compare the commit hashes to determine if the local repository is behind the remote repository
if commit_hash != remote_commit_hash:
# Get the commit dates
commit_date = repo.head.commit.committed_datetime
remote_commit_date = repo.refs[f'{remote_name}/{branch_name}'].object.committed_datetime
# Compare the commit dates to determine if the local repository is behind the remote repository
if commit_date < remote_commit_date:
repo.close()
return True, True
repo.close()
return False, True
class GitProgress(RemoteProgress):
def __init__(self):
super().__init__()
self.pbar = tqdm()
def update(self, op_code, cur_count, max_count=None, message=''):
self.pbar.total = max_count
self.pbar.n = cur_count
self.pbar.pos = 0
self.pbar.refresh()
def is_valid_url(url):
try:
result = urlparse(url)
return all([result.scheme, result.netloc])
except ValueError:
return False
def gitclone_install(files, instant_execution=False, msg_prefix=''):
print(f"{msg_prefix}Install: {files}")
for url in files:
if not is_valid_url(url):
print(f"Invalid git url: '{url}'")
return False
if url.endswith("/"):
url = url[:-1]
try:
print(f"Download: git clone '{url}'")
repo_name = os.path.splitext(os.path.basename(url))[0]
repo_path = os.path.join(custom_nodes_path, repo_name)
# Clone the repository from the remote URL
if not instant_execution and platform.system() == 'Windows':
res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", custom_nodes_path, url])
if res != 0:
return False
else:
repo = git.Repo.clone_from(url, repo_path, recursive=True, progress=GitProgress())
repo.git.clear_cache()
repo.close()
if not execute_install_script(url, repo_path, instant_execution=instant_execution):
return False
except Exception as e:
print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr)
return False
print("Installation was successful.")
return True
def git_pull(path):
# Check if the path is a git repository
if not os.path.exists(os.path.join(path, '.git')):
raise ValueError('Not a git repository')
# Pull the latest changes from the remote repository
if platform.system() == "Windows":
return __win_check_git_pull(path)
else:
repo = git.Repo(path)
if repo.is_dirty():
repo.git.stash()
if repo.head.is_detached:
switch_to_default_branch(repo)
current_branch = repo.active_branch
remote_name = current_branch.tracking_branch().remote_name
remote = repo.remote(name=remote_name)
remote.pull()
repo.git.submodule('update', '--init', '--recursive')
repo.close()
return True
async def get_data(uri, silent=False):
if not silent:
print(f"FETCH DATA from: {uri}")
if uri.startswith("http"):
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
async with session.get(uri) as resp:
json_text = await resp.text()
else:
with cache_lock:
with open(uri, "r", encoding="utf-8") as f:
json_text = f.read()
json_obj = json.loads(json_text)
return json_obj
def simple_hash(input_string):
hash_value = 0
for char in input_string:
hash_value = (hash_value * 31 + ord(char)) % (2**32)
return hash_value
def is_file_created_within_one_day(file_path):
if not os.path.exists(file_path):
return False
file_creation_time = os.path.getctime(file_path)
current_time = datetime.now().timestamp()
time_difference = current_time - file_creation_time
return time_difference <= 86400
async def get_data_by_mode(mode, filename, channel_url=None):
try:
if mode == "local":
uri = os.path.join(comfyui_manager_path, filename)
json_obj = await get_data(uri)
else:
if channel_url is None:
uri = get_config()['channel_url'] + '/' + filename
else:
uri = channel_url + '/' + filename
cache_uri = str(simple_hash(uri))+'_'+filename
cache_uri = os.path.join(cache_dir, cache_uri)
if mode == "cache":
if is_file_created_within_one_day(cache_uri):
json_obj = await get_data(cache_uri)
else:
json_obj = await get_data(uri)
with cache_lock:
with open(cache_uri, "w", encoding='utf-8') as file:
json.dump(json_obj, file, indent=4, sort_keys=True)
else:
json_obj = await get_data(uri)
with cache_lock:
with open(cache_uri, "w", encoding='utf-8') as file:
json.dump(json_obj, file, indent=4, sort_keys=True)
except Exception as e:
print(f"[ComfyUI-Manager] Due to a network error, switching to local mode.\n=> {filename}\n=> {e}")
uri = os.path.join(comfyui_manager_path, filename)
json_obj = await get_data(uri)
return json_obj
def gitclone_fix(files, instant_execution=False):
print(f"Try fixing: {files}")
for url in files:
if not is_valid_url(url):
print(f"Invalid git url: '{url}'")
return False
if url.endswith("/"):
url = url[:-1]
try:
repo_name = os.path.splitext(os.path.basename(url))[0]
repo_path = os.path.join(custom_nodes_path, repo_name)
if os.path.exists(repo_path+'.disabled'):
repo_path = repo_path+'.disabled'
if not execute_install_script(url, repo_path, instant_execution=instant_execution):
return False
except Exception as e:
print(f"Install(git-clone) error: {url} / {e}", file=sys.stderr)
return False
print(f"Attempt to fixing '{files}' is done.")
return True
def pip_install(packages):
install_cmd = ['#FORCE', sys.executable, "-m", "pip", "install", '-U'] + packages
try_install_script('pip install via manager', '..', install_cmd)
def rmtree(path):
retry_count = 3
while True:
try:
retry_count -= 1
if platform.system() == "Windows":
manager_funcs.run_script(['attrib', '-R', path + '\\*', '/S'])
shutil.rmtree(path)
return True
except Exception as ex:
print(f"ex: {ex}")
time.sleep(3)
if retry_count < 0:
raise ex
print(f"Uninstall retry({retry_count})")
def gitclone_uninstall(files):
import os
print(f"Uninstall: {files}")
for url in files:
if url.endswith("/"):
url = url[:-1]
try:
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name)
# safety check
if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '':
print(f"Uninstall(git-clone) error: invalid path '{dir_path}' for '{url}'")
return False
install_script_path = os.path.join(dir_path, "uninstall.py")
disable_script_path = os.path.join(dir_path, "disable.py")
if os.path.exists(install_script_path):
uninstall_cmd = [sys.executable, "uninstall.py"]
code = manager_funcs.run_script(uninstall_cmd, cwd=dir_path)
if code != 0:
print(f"An error occurred during the execution of the uninstall.py script. Only the '{dir_path}' will be deleted.")
elif os.path.exists(disable_script_path):
disable_script = [sys.executable, "disable.py"]
code = manager_funcs.run_script(disable_script, cwd=dir_path)
if code != 0:
print(f"An error occurred during the execution of the disable.py script. Only the '{dir_path}' will be deleted.")
if os.path.exists(dir_path):
rmtree(dir_path)
elif os.path.exists(dir_path + ".disabled"):
rmtree(dir_path + ".disabled")
except Exception as e:
print(f"Uninstall(git-clone) error: {url} / {e}", file=sys.stderr)
return False
print("Uninstallation was successful.")
return True
def gitclone_set_active(files, is_disable):
import os
if is_disable:
action_name = "Disable"
else:
action_name = "Enable"
print(f"{action_name}: {files}")
for url in files:
if url.endswith("/"):
url = url[:-1]
try:
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name)
# safety check
if dir_path == '/' or dir_path[1:] == ":/" or dir_path == '':
print(f"{action_name}(git-clone) error: invalid path '{dir_path}' for '{url}'")
return False
if is_disable:
current_path = dir_path
new_path = dir_path + ".disabled"
else:
current_path = dir_path + ".disabled"
new_path = dir_path
os.rename(current_path, new_path)
if is_disable:
if os.path.exists(os.path.join(new_path, "disable.py")):
disable_script = [sys.executable, "disable.py"]
try_install_script(url, new_path, disable_script)
else:
if os.path.exists(os.path.join(new_path, "enable.py")):
enable_script = [sys.executable, "enable.py"]
try_install_script(url, new_path, enable_script)
except Exception as e:
print(f"{action_name}(git-clone) error: {url} / {e}", file=sys.stderr)
return False
print(f"{action_name} was successful.")
return True
def gitclone_update(files, instant_execution=False, skip_script=False, msg_prefix=""):
import os
print(f"{msg_prefix}Update: {files}")
for url in files:
if url.endswith("/"):
url = url[:-1]
try:
repo_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
repo_path = os.path.join(custom_nodes_path, repo_name)
if os.path.exists(repo_path+'.disabled'):
repo_path = repo_path+'.disabled'
git_pull(repo_path)
if not skip_script:
if instant_execution:
if not execute_install_script(url, repo_path, lazy_mode=False, instant_execution=True):
return False
else:
if not execute_install_script(url, repo_path, lazy_mode=True):
return False
except Exception as e:
print(f"Update(git-clone) error: {url} / {e}", file=sys.stderr)
return False
if not skip_script:
print("Update was successful.")
return True
def lookup_customnode_by_url(data, target):
for x in data['custom_nodes']:
if target in x['files']:
dir_name = os.path.splitext(os.path.basename(target))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name)
if os.path.exists(dir_path):
x['installed'] = 'True'
elif os.path.exists(dir_path + ".disabled"):
x['installed'] = 'Disabled'
return x
return None
def check_a_custom_node_installed(item, do_fetch=False, do_update_check=True, do_update=False):
item['installed'] = 'None'
if item['install_type'] == 'git-clone' and len(item['files']) == 1:
url = item['files'][0]
if url.endswith("/"):
url = url[:-1]
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
dir_path = os.path.join(custom_nodes_path, dir_name)
if os.path.exists(dir_path):
try:
item['installed'] = 'True' # default
if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name):
item['installed'] = 'Fail'
if do_update_check:
update_state, success = git_repo_has_updates(dir_path, do_fetch, do_update)
if (do_update_check or do_update) and update_state:
item['installed'] = 'Update'
elif do_update and not success:
item['installed'] = 'Fail'
except:
if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name):
item['installed'] = 'Fail'
else:
item['installed'] = 'True'
elif os.path.exists(dir_path + ".disabled"):
item['installed'] = 'Disabled'
else:
item['installed'] = 'False'
elif item['install_type'] == 'copy' and len(item['files']) == 1:
dir_name = os.path.basename(item['files'][0])
if item['files'][0].endswith('.py'):
base_path = custom_nodes_path
elif 'js_path' in item:
base_path = os.path.join(js_path, item['js_path'])
else:
base_path = js_path
file_path = os.path.join(base_path, dir_name)
if os.path.exists(file_path):
if cm_global.try_call(api="cm.is_import_failed_extension", name=dir_name):
item['installed'] = 'Fail'
else:
item['installed'] = 'True'
elif os.path.exists(file_path + ".disabled"):
item['installed'] = 'Disabled'
else:
item['installed'] = 'False'
def get_current_snapshot():
# Get ComfyUI hash
repo_path = comfy_path
print(f"comfy_path: {comfy_path}")
if not os.path.exists(os.path.join(repo_path, '.git')):
print(f"ComfyUI update fail: The installed ComfyUI does not have a Git repository.")
return {}
repo = git.Repo(repo_path)
comfyui_commit_hash = repo.head.commit.hexsha
git_custom_nodes = {}
file_custom_nodes = []
# Get custom nodes hash
for path in os.listdir(custom_nodes_path):
fullpath = os.path.join(custom_nodes_path, path)
if os.path.isdir(fullpath):
is_disabled = path.endswith(".disabled")
try:
git_dir = os.path.join(fullpath, '.git')
if not os.path.exists(git_dir):
continue
repo = git.Repo(fullpath)
commit_hash = repo.head.commit.hexsha
url = repo.remotes.origin.url
git_custom_nodes[url] = {
'hash': commit_hash,
'disabled': is_disabled
}
except:
print(f"Failed to extract snapshots for the custom node '{path}'.")
elif path.endswith('.py'):
is_disabled = path.endswith(".py.disabled")
filename = os.path.basename(path)
item = {
'filename': filename,
'disabled': is_disabled
}
file_custom_nodes.append(item)
return {
'comfyui': comfyui_commit_hash,
'git_custom_nodes': git_custom_nodes,
'file_custom_nodes': file_custom_nodes,
}
def save_snapshot_with_postfix(postfix):
now = datetime.now()
date_time_format = now.strftime("%Y-%m-%d_%H-%M-%S")
file_name = f"{date_time_format}_{postfix}"
path = os.path.join(comfyui_manager_path, 'snapshots', f"{file_name}.json")
with open(path, "w") as json_file:
json.dump(get_current_snapshot(), json_file, indent=4)
return file_name+'.json'

1627
glob/manager_server.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -89,7 +89,10 @@ export async function install_pip(packages) {
if(packages.includes('&')) if(packages.includes('&'))
app.ui.dialog.show(`Invalid PIP package enumeration: '${packages}'`); app.ui.dialog.show(`Invalid PIP package enumeration: '${packages}'`);
const res = await api.fetchApi(`/customnode/install/pip?packages=${packages}`); const res = await api.fetchApi("/customnode/install/pip", {
method: "POST",
body: packages,
});
if(res.status == 200) { if(res.status == 200) {
app.ui.dialog.show(`PIP package installation is processed.<br>To apply the pip packages, please click the <button id='cm-reboot-button3'><font size='3px'>RESTART</font></button> button in ComfyUI.`); app.ui.dialog.show(`PIP package installation is processed.<br>To apply the pip packages, please click the <button id='cm-reboot-button3'><font size='3px'>RESTART</font></button> button in ComfyUI.`);
@ -121,7 +124,10 @@ export async function install_via_git_url(url, manager_dialog) {
app.ui.dialog.show(`Wait...<BR><BR>Installing '${url}'`); app.ui.dialog.show(`Wait...<BR><BR>Installing '${url}'`);
app.ui.dialog.element.style.zIndex = 10010; app.ui.dialog.element.style.zIndex = 10010;
const res = await api.fetchApi(`/customnode/install/git_url?url=${url}`); const res = await api.fetchApi("/customnode/install/git_url", {
method: "POST",
body: url,
});
if(res.status == 200) { if(res.status == 200) {
app.ui.dialog.show(`'${url}' is installed<BR>To apply the installed custom node, please <button id='cm-reboot-button4'><font size='3px'>RESTART</font></button> ComfyUI.`); app.ui.dialog.show(`'${url}' is installed<BR>To apply the installed custom node, please <button id='cm-reboot-button4'><font size='3px'>RESTART</font></button> ComfyUI.`);
@ -148,7 +154,7 @@ export async function free_models() {
let res = await api.fetchApi(`/free`, { let res = await api.fetchApi(`/free`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: '{}' body: '{"unload_models": true}'
}); });
if(res.status == 200) { if(res.status == 200) {

View File

@ -269,6 +269,7 @@ export class SnapshotManager extends ComfyDialog {
save_button.onclick = () => { save_current_snapshot(); } save_button.onclick = () => { save_current_snapshot(); }
save_button.style.display = "inline-block"; save_button.style.display = "inline-block";
save_button.style.horizontalAlign = "right"; save_button.style.horizontalAlign = "right";
save_button.style.width = "170px";
this.message_box = $el('div', {id:'custom-download-message'}, [$el('br'), '']); this.message_box = $el('div', {id:'custom-download-message'}, [$el('br'), '']);
this.message_box.style.height = '60px'; this.message_box.style.height = '60px';

View File

@ -2400,6 +2400,26 @@
"filename": "SUPIR-v0Q.ckpt", "filename": "SUPIR-v0Q.ckpt",
"url": "https://huggingface.co/camenduru/SUPIR/resolve/main/SUPIR-v0Q.ckpt" "url": "https://huggingface.co/camenduru/SUPIR/resolve/main/SUPIR-v0Q.ckpt"
}, },
{
"name": "Kijai/SUPIR-v0F_fp16.safetensors (pruned)",
"type": "checkpoints",
"base": "SUPIR",
"save_path": "checkpoints/SUPIR",
"description": "SUPIR checkpoint model",
"reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main",
"filename": "SUPIR-v0F_fp16.safetensors",
"url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0F_fp16.safetensors"
},
{
"name": "Kijai/SUPIR-v0Q_fp16.safetensors (pruned)",
"type": "checkpoints",
"base": "SUPIR",
"save_path": "checkpoints/SUPIR",
"description": "SUPIR checkpoint model",
"reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main",
"filename": "SUPIR-v0Q_fp16.safetensors",
"url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0Q_fp16.safetensors"
},
{ {
"name": "RAM", "name": "RAM",
"type": "RAM", "type": "RAM",

View File

@ -10,6 +10,77 @@
}, },
{
"author": "kijai",
"title": "ComfyUI nodes to use DeepSeek-VL",
"reference": "https://github.com/kijai/ComfyUI-DeepSeek-VL",
"files": [
"https://github.com/kijai/ComfyUI-DeepSeek-VL"
],
"install_type": "git-clone",
"description": "[a/https://huggingface.co/deepseek-ai](https://huggingface.co/deepseek-ai)"
},
{
"author": "GentlemanHu",
"title": "ComfyUI-Notifier",
"reference": "https://github.com/GentlemanHu/ComfyUI-Notifier",
"files": [
"https://github.com/GentlemanHu/ComfyUI-Notifier"
],
"install_type": "git-clone",
"description": "Nodes:GentlemanHu_Notifier"
},
{
"author": "nat-chan",
"title": "comfyui-in-memory-transceiver",
"reference": "https://github.com/nat-chan/comfyui-in-memory-transceiver",
"files": [
"https://github.com/nat-chan/comfyui-in-memory-transceiver"
],
"install_type": "git-clone",
"description": "Why? When processing a large number of requests, the SaveImage and LoadImage nodes may be IO-limited, and using shared memory improves performance by passing images only through memory access, not through IO."
},
{
"author": "DrMWeigand",
"title": "ComfyUI_LineBreakInserter",
"reference": "https://github.com/DrMWeigand/ComfyUI_LineBreakInserter",
"files": [
"https://github.com/DrMWeigand/ComfyUI_LineBreakInserter"
],
"install_type": "git-clone",
"description": "Nodes:Line Break Inserter"
},
{
"author": "WilliamStanford",
"title": "visuallabs_comfyui_nodes",
"reference": "https://github.com/WilliamStanford/visuallabs_comfyui_nodes",
"files": [
"https://github.com/WilliamStanford/visuallabs_comfyui_nodes"
],
"install_type": "git-clone",
"description": "Nodes:PointStringFromFloatArray"
},
{
"author": "bruce007lee",
"title": "comfyui-cleaner",
"reference": "https://github.com/bruce007lee/comfyui-cleaner",
"files": [
"https://github.com/bruce007lee/comfyui-cleaner"
],
"install_type": "git-clone",
"description": "Nodes:cleaner"
},
{
"author": "ExponentialML",
"title": "ComfyUI_LiveDirector (WIP)",
"reference": "https://github.com/ExponentialML/ComfyUI_LiveDirector",
"files": [
"https://github.com/ExponentialML/ComfyUI_LiveDirector"
],
"install_type": "git-clone",
"description": "Experimental method to use reference video to drive motion in generations without training in ComfyUI."
},
{ {
"author": "logtd", "author": "logtd",
"title": "ComfyUI-MotionThiefExperiment", "title": "ComfyUI-MotionThiefExperiment",
@ -30,16 +101,6 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Nodes:sound voice, text concat, latent to list, movie generate, movie batch, hy save image, generate story" "description": "Nodes:sound voice, text concat, latent to list, movie generate, movie batch, hy save image, generate story"
}, },
{
"author": "liusida",
"title": "ComfyUI-Login",
"reference": "https://github.com/liusida/ComfyUI-Login",
"files": [
"https://github.com/liusida/ComfyUI-Login"
],
"install_type": "git-clone",
"description": "This custom node serves as a proof-of-concept to explore the implementation of basic login functionality for ComfyUI.\nNOTE:In the future, if proven useful, this feature might be directly integrated into either ComfyUI or ComfyUI-Manager."
},
{ {
"author": "gameltb", "author": "gameltb",
"title": "io_comfyui", "title": "io_comfyui",

View File

@ -1,5 +1,25 @@
{ {
"custom_nodes": [ "custom_nodes": [
{
"author": "ZHO-ZHO-ZHO",
"title": "Dr.Lt.Data/ComfyUI-YoloWorld-EfficientSAM",
"reference": "https://github.com/ltdrdata/ComfyUI-YoloWorld-EfficientSAM",
"files": [
"https://github.com/ltdrdata/ComfyUI-YoloWorld-EfficientSAM"
],
"install_type": "git-clone",
"description": "This fork includes [a/PR32](https://github.com/ZHO-ZHO-ZHO/ComfyUI-YoloWorld-EfficientSAM/pull/32)"
},
{
"author": "ertu110",
"title": "sdxl_prompt_style",
"reference": "https://github.com/ertu110/sdxl_prompt_style",
"files": [
"https://github.com/ertu110/sdxl_prompt_style"
],
"install_type": "git-clone",
"description": "This project is a complete benchmark [a/https://github.com/twri/sdxl_prompt_styler](https://github.com/twri/sdxl_prompt_styler) A large amount of code inside comes from https://github.com/twri/sdxl_prompt_styler Project and [a/https://www.nodecafe.org/package/pythongosssss_ComfyUI-Custom-Scripts](https://www.nodecafe.org/package/pythongosssss_ComfyUI-Custom-Scripts) project\nThe functionality of this project is related to https://github.com/twri/sdxl_prompt_styler Highly overlapping, the only purpose of creating this project is because there are too many styles when selecting, resulting in a long and inconvenient dropdown box. Therefore, To address this issue, this project has added a secondary menu to the style."
},
{ {
"author": "gustproof", "author": "gustproof",
"title": "ComfyUI_IPAdapter_plus_Style_Components", "title": "ComfyUI_IPAdapter_plus_Style_Components",
@ -10,16 +30,6 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Style Components is an IP-Adapter model conditioned on anime styles. The style embeddings can either be extracted from images or created manually. This repo currently only supports the SDXL model trained on AutismmixPony." "description": "Style Components is an IP-Adapter model conditioned on anime styles. The style embeddings can either be extracted from images or created manually. This repo currently only supports the SDXL model trained on AutismmixPony."
}, },
{
"author": "BlenderNeko",
"title": "Dr.Lt.Data/Advanced CLIP Text Encode (PR21)",
"reference": "https://github.com/ltdrdata/ComfyUI_ADV_CLIP_emb",
"files": [
"https://github.com/ltdrdata/ComfyUI_ADV_CLIP_emb"
],
"install_type": "git-clone",
"description": "[a/PR21](https://github.com/BlenderNeko/ComfyUI_ADV_CLIP_emb/pull/21) is applied.\nmissing 'clip_layer' method fix."
},
{ {
"author": "gameltb", "author": "gameltb",
"title": "comfyui-stablsr", "title": "comfyui-stablsr",

View File

@ -8,7 +8,48 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "If you see this message, your ComfyUI-Manager is outdated.\nLegacy channel provides only the list of the deprecated nodes. If you want to find the complete node list, please go to the Default channel." "description": "If you see this message, your ComfyUI-Manager is outdated.\nLegacy channel provides only the list of the deprecated nodes. If you want to find the complete node list, please go to the Default channel."
}, },
{
"author": "Big Idea Technology",
"title": "Image Text Overlay Node for ComfyUI [DEPRECATED]",
"reference": "https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay",
"files": [
"https://github.com/Big-Idea-Technology/ComfyUI_Image_Text_Overlay"
],
"install_type": "git-clone",
"description": "Please note that the ImageTextOverlay project is no longer supported and has been moved to a new repository. For ongoing developments, contributions, and issues, please refer to the new repository at: [a/https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools](https://github.com/Big-Idea-Technology/ComfyUI-Book-Tools)"
},
{
"author": "meimeilook",
"title": "ComfyUI_IPAdapter_plus.old [backward compatbility]",
"reference": "https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old",
"files": [
"https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old"
],
"install_type": "git-clone",
"description": "This repo is created to provide backward compatibility for workflows configured with the old IPAdapter."
},
{
"author": "mlinmg",
"title": "LaMa Preprocessor [DEPRECATED]",
"reference": "https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor",
"files": [
"https://github.com/mlinmg/ComfyUI-LaMA-Preprocessor"
],
"install_type": "git-clone",
"description": "A LaMa prerocessor for ComfyUI. This preprocessor finally enable users to generate coherent inpaint and outpaint prompt-free. The best results are given on landscapes, not so much in drawings/animation."
},
{
"author": "CapsAdmin",
"title": "ComfyUI-Euler-Smea-Dyn-Sampler [DEPRECATED]",
"reference": "https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler",
"files": [
"https://github.com/CapsAdmin/ComfyUI-Euler-Smea-Dyn-Sampler"
],
"install_type": "git-clone",
"description": "Just a comfyui version of [a/Euler Smea Dyn Sampler](https://github.com/Koishi-Star/Euler-Smea-Dyn-Sampler). It adds the sampler directly to existing samplers."
},
{ {
"author": "BlakeOne", "author": "BlakeOne",
"title": "ComfyUI FastImageListToImageBatch [REMOVED]", "title": "ComfyUI FastImageListToImageBatch [REMOVED]",
@ -59,16 +100,6 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Proof of concent on how to use IPAdapter to control tiled upscaling. NOTE: You need to have 'ComfyUI_IPAdapter_plus' installed." "description": "Proof of concent on how to use IPAdapter to control tiled upscaling. NOTE: You need to have 'ComfyUI_IPAdapter_plus' installed."
}, },
{
"author": "meimeilook",
"title": "ComfyUI_IPAdapter_plus",
"reference": "https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old",
"files": [
"https://github.com/meimeilook/ComfyUI_IPAdapter_plus.old"
],
"install_type": "git-clone",
"description": "This repo is created to provide backward compatibility for workflows configured with the old IPAdapter."
},
{ {
"author": "XINZHANG-ops", "author": "XINZHANG-ops",
"title": "comfyui-xin-nodes [REMOVED]", "title": "comfyui-xin-nodes [REMOVED]",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,25 @@
{ {
"models": [ "models": [
{
"name": "Kijai/SUPIR-v0F_fp16.safetensors (pruned)",
"type": "checkpoints",
"base": "SUPIR",
"save_path": "checkpoints/SUPIR",
"description": "SUPIR checkpoint model",
"reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main",
"filename": "SUPIR-v0F_fp16.safetensors",
"url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0F_fp16.safetensors"
},
{
"name": "Kijai/SUPIR-v0Q_fp16.safetensors (pruned)",
"type": "checkpoints",
"base": "SUPIR",
"save_path": "checkpoints/SUPIR",
"description": "SUPIR checkpoint model",
"reference": "https://huggingface.co/Kijai/SUPIR_pruned/tree/main",
"filename": "SUPIR-v0Q_fp16.safetensors",
"url": "https://huggingface.co/Kijai/SUPIR_pruned/resolve/main/SUPIR-v0Q_fp16.safetensors"
},
{ {
"name": "SUPIR-v0F.ckpt", "name": "SUPIR-v0F.ckpt",
"type": "checkpoints", "type": "checkpoints",
@ -641,86 +661,6 @@
"reference": "https://huggingface.co/Lightricks/LongAnimateDiff", "reference": "https://huggingface.co/Lightricks/LongAnimateDiff",
"filename": "lt_long_mm_16_64_frames.ckpt", "filename": "lt_long_mm_16_64_frames.ckpt",
"url": "https://huggingface.co/Lightricks/LongAnimateDiff/resolve/main/lt_long_mm_16_64_frames.ckpt" "url": "https://huggingface.co/Lightricks/LongAnimateDiff/resolve/main/lt_long_mm_16_64_frames.ckpt"
},
{
"name": "ip-adapter_sd15.safetensors",
"type": "IP-Adapter",
"base": "SD1.5",
"save_path": "ipadapter",
"description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter_sd15.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15.safetensors"
},
{
"name": "ip-adapter_sd15_light.safetensors",
"type": "IP-Adapter",
"base": "SD1.5",
"save_path": "ipadapter",
"description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter_sd15_light.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15_light.safetensors"
},
{
"name": "ip-adapter_sd15_vit-G.safetensors",
"type": "IP-Adapter",
"base": "SD1.5",
"save_path": "ipadapter",
"description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter_sd15_vit-G.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter_sd15_vit-G.safetensors"
},
{
"name": "ip-adapter-plus_sd15.safetensors",
"type": "IP-Adapter",
"base": "SD1.5",
"save_path": "ipadapter",
"description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter-plus_sd15.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-plus_sd15.safetensors"
},
{
"name": "ip-adapter-plus-face_sd15.safetensors",
"type": "IP-Adapter",
"base": "SD1.5",
"save_path": "ipadapter",
"description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter-plus-face_sd15.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-plus-face_sd15.safetensors"
},
{
"name": "ip-adapter-full-face_sd15.safetensors",
"type": "IP-Adapter",
"base": "SD1.5",
"save_path": "ipadapter",
"description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter-full-face_sd15.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/models/ip-adapter-full-face_sd15.safetensors"
},
{
"name": "ip-adapter_sdxl.safetensors",
"type": "IP-Adapter",
"base": "SDXL",
"save_path": "ipadapter",
"description": "You can use this model in the [a/ComfyUI IPAdapter plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) extension.",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter_sdxl.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter_sdxl.safetensors"
},
{
"name": "ip-adapter_sdxl_vit-h.safetensors",
"type": "IP-Adapter",
"base": "SDXL",
"save_path": "ipadapter",
"description": "This model requires the use of the SD1.5 encoder despite being for SDXL checkpoints",
"reference": "https://huggingface.co/h94/IP-Adapter",
"filename": "ip-adapter_sdxl_vit-h.safetensors",
"url": "https://huggingface.co/h94/IP-Adapter/resolve/main/sdxl_models/ip-adapter_sdxl_vit-h.safetensors"
} }
] ]
} }

View File

@ -10,6 +10,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "There is a small node pack attached to this guide. This includes the init file and 3 nodes associated with the tutorials." "description": "There is a small node pack attached to this guide. This includes the init file and 3 nodes associated with the tutorials."
}, },
{
"author": "bamboodia",
"title": "BAM Nodes",
"reference": "https://github.com/bamboodia/BAM_Nodes",
"files": [
"https://github.com/bamboodia/BAM_Nodes"
],
"install_type": "git-clone",
"description": "A collection of comfyui nodes that I have made for nothing more than educational purposes."
},
{ {
"author": "BadCafeCode", "author": "BadCafeCode",
"title": "execution-inversion-demo-comfyui", "title": "execution-inversion-demo-comfyui",
@ -159,6 +169,16 @@
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "Nodes:Woman_in_a_dress" "description": "Nodes:Woman_in_a_dress"
},
{
"author": "shinich39",
"title": "comfyui-concat-text-39",
"reference": "https://github.com/shinich39/comfyui-concat-text-39",
"files": [
"https://github.com/shinich39/comfyui-concat-text-39"
],
"install_type": "git-clone",
"description": "Nodes:Concatenate multiple text nodes."
} }
] ]
} }

View File

@ -50,11 +50,21 @@
"\n", "\n",
"if OPTIONS['UPDATE_COMFY_UI']:\n", "if OPTIONS['UPDATE_COMFY_UI']:\n",
" !echo -= Updating ComfyUI =-\n", " !echo -= Updating ComfyUI =-\n",
"\n",
" # Correction of the issue of permissions being deleted on Google Drive.\n",
" ![ -f \".ci/nightly/update_windows/update_comfyui_and_python_dependencies.bat\" ] && chmod 755 .ci/nightly/update_windows/update_comfyui_and_python_dependencies.bat\n",
" ![ -f \".ci/nightly/windows_base_files/run_nvidia_gpu.bat\" ] && chmod 755 .ci/nightly/windows_base_files/run_nvidia_gpu.bat\n",
" ![ -f \".ci/update_windows/update_comfyui_and_python_dependencies.bat\" ] && chmod 755 .ci/update_windows/update_comfyui_and_python_dependencies.bat\n",
" ![ -f \".ci/update_windows_cu118/update_comfyui_and_python_dependencies.bat\" ] && chmod 755 .ci/update_windows_cu118/update_comfyui_and_python_dependencies.bat\n",
" ![ -f \".ci/update_windows/update.py\" ] && chmod 755 .ci/update_windows/update.py\n",
" ![ -f \".ci/update_windows/update_comfyui.bat\" ] && chmod 755 .ci/update_windows/update_comfyui.bat\n",
" ![ -f \".ci/update_windows/README_VERY_IMPORTANT.txt\" ] && chmod 755 .ci/update_windows/README_VERY_IMPORTANT.txt\n",
" ![ -f \".ci/update_windows/run_cpu.bat\" ] && chmod 755 .ci/update_windows/run_cpu.bat\n",
" ![ -f \".ci/update_windows/run_nvidia_gpu.bat\" ] && chmod 755 .ci/update_windows/run_nvidia_gpu.bat\n",
"\n",
" !git pull\n", " !git pull\n",
"\n", "\n",
"!echo -= Install dependencies =-\n", "!echo -= Install dependencies =-\n",
"#Remove cu121 as it causes issues in Colab.\n",
"#!pip install xformers!=0.0.18 -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu121 --extra-index-url https://download.pytorch.org/whl/cu118 --extra-index-url https://download.pytorch.org/whl/cu117\n",
"!pip3 install accelerate\n", "!pip3 install accelerate\n",
"!pip3 install einops transformers>=4.25.1 safetensors>=0.3.0 aiohttp pyyaml Pillow scipy tqdm psutil\n", "!pip3 install einops transformers>=4.25.1 safetensors>=0.3.0 aiohttp pyyaml Pillow scipy tqdm psutil\n",
"!pip3 install xformers!=0.0.18 torch==2.1.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121\n", "!pip3 install xformers!=0.0.18 torch==2.1.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121\n",
@ -62,6 +72,14 @@
"\n", "\n",
"if OPTIONS['USE_COMFYUI_MANAGER']:\n", "if OPTIONS['USE_COMFYUI_MANAGER']:\n",
" %cd custom_nodes\n", " %cd custom_nodes\n",
"\n",
" # Correction of the issue of permissions being deleted on Google Drive.\n",
" ![ -f \"ComfyUI-Manager/check.sh\" ] && chmod 755 ComfyUI-Manager/check.sh\n",
" ![ -f \"ComfyUI-Manager/scan.sh\" ] && chmod 755 ComfyUI-Manager/scan.sh\n",
" ![ -f \"ComfyUI-Manager/node_db/dev/scan.sh\" ] && chmod 755 ComfyUI-Manager/node_db/dev/scan.sh\n",
" ![ -f \"ComfyUI-Manager/scripts/install-comfyui-venv-linux.sh\" ] && chmod 755 ComfyUI-Manager/scripts/install-comfyui-venv-linux.sh\n",
" ![ -f \"ComfyUI-Manager/scripts/install-comfyui-venv-win.bat\" ] && chmod 755 ComfyUI-Manager/scripts/install-comfyui-venv-win.bat\n",
"\n",
" ![ ! -d ComfyUI-Manager ] && echo -= Initial setup ComfyUI-Manager =- && git clone https://github.com/ltdrdata/ComfyUI-Manager\n", " ![ ! -d ComfyUI-Manager ] && echo -= Initial setup ComfyUI-Manager =- && git clone https://github.com/ltdrdata/ComfyUI-Manager\n",
" %cd ComfyUI-Manager\n", " %cd ComfyUI-Manager\n",
" !git pull\n", " !git pull\n",
@ -69,9 +87,9 @@
"%cd $WORKSPACE\n", "%cd $WORKSPACE\n",
"\n", "\n",
"if OPTIONS['INSTALL_CUSTOM_NODES_DEPENDENCIES']:\n", "if OPTIONS['INSTALL_CUSTOM_NODES_DEPENDENCIES']:\n",
" !pwd\n",
" !echo -= Install custom nodes dependencies =-\n", " !echo -= Install custom nodes dependencies =-\n",
" ![ -f \"custom_nodes/ComfyUI-Manager/scripts/colab-dependencies.py\" ] && python \"custom_nodes/ComfyUI-Manager/scripts/colab-dependencies.py\"\n" " !pip install GitPython\n",
" !python custom_nodes/ComfyUI-Manager/cm-cli.py restore-dependencies\n"
] ]
}, },
{ {
@ -350,4 +368,4 @@
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 0 "nbformat_minor": 0
} }

View File

@ -0,0 +1,21 @@
{
"imageio-ffmpeg": "imageio",
"imageio[ffmpeg]": "imageio",
"imageio_ffmpeg": "imageio",
"diffusers~=0.21.4": "diffusers",
"huggingface_hub": "huggingface-hub",
"numpy<1.24>=1.18": "numpy",
"numpy>=1.18.5, <1.25.0": "numpy",
"opencv-contrib-python": "opencv-contrib-python-headless",
"opencv-python": "opencv-contrib-python-headless",
"opencv-python-headless": "opencv-contrib-python-headless",
"opencv-python-headless[ffmpeg]<=4.7.0.72": "opencv-contrib-python-headless",
"opencv-python>=4.7.0.72": "opencv-contrib-python-headless",
"pandas<=1.5.1": "pandas",
"scikit-image==0.20.0": "scikit-image",
"scipy>=1.11.4": "scipy",
"segment_anything": "segment-anything",
"timm==0.6.5": "timm",
"timm>=0.4.12": "timm",
"transformers==4.26.1": "transformers"
}

View File

@ -7,13 +7,13 @@ import threading
import re import re
import locale import locale
import platform import platform
import json
glob_path = os.path.join(os.path.dirname(__file__), "glob") glob_path = os.path.join(os.path.dirname(__file__), "glob")
sys.path.append(glob_path) sys.path.append(glob_path)
from manager_util import * from manager_util import *
import cm_global import cm_global
@ -69,6 +69,23 @@ custom_nodes_path = os.path.abspath(os.path.join(comfyui_manager_path, ".."))
startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts") startup_script_path = os.path.join(comfyui_manager_path, "startup-scripts")
restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json") restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json")
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py") git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json")
cm_global.pip_overrides = {}
if os.path.exists(pip_overrides_path):
with open(pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
cm_global.pip_overrides = json.load(json_file)
def remap_pip_package(pkg):
if pkg in cm_global.pip_overrides:
res = cm_global.pip_overrides[pkg]
print(f"[ComfyUI-Manager] '{pkg}' is remapped to '{res}'")
return res
else:
return pkg
std_log_lock = threading.Lock() std_log_lock = threading.Lock()
@ -283,6 +300,30 @@ except Exception as e:
print(f"[ComfyUI-Manager] Logging failed: {e}") print(f"[ComfyUI-Manager] Logging failed: {e}")
try:
import git
except:
my_path = os.path.dirname(__file__)
requirements_path = os.path.join(my_path, "requirements.txt")
print(f"## ComfyUI-Manager: installing dependencies. (GitPython)")
result = subprocess.check_output([sys.executable, '-s', '-m', 'pip', 'install', '-r', requirements_path])
try:
import git
except:
print(f"## [ERROR] ComfyUI-Manager: Attempting to reinstall dependencies using an alternative method.")
result = subprocess.check_output([sys.executable, '-s', '-m', 'pip', 'install', '--user', '-r', requirements_path])
try:
import git
except:
print(f"## [ERROR] ComfyUI-Manager: Failed to install the GitPython package in the correct Python environment. Please install it manually in the appropriate environment. (You can seek help at https://app.element.io/#/room/%23comfyui_space%3Amatrix.org)")
print(f"## ComfyUI-Manager: installing dependencies done.")
print("** ComfyUI startup time:", datetime.datetime.now()) print("** ComfyUI startup time:", datetime.datetime.now())
print("** Platform:", platform.system()) print("** Platform:", platform.system())
print("** Python version:", sys.version) print("** Python version:", sys.version)
@ -391,8 +432,6 @@ def is_installed(name):
if os.path.exists(restore_snapshot_path): if os.path.exists(restore_snapshot_path):
try: try:
import json
cloned_repos = [] cloned_repos = []
def msg_capture(stream, prefix): def msg_capture(stream, prefix):
@ -420,40 +459,39 @@ if os.path.exists(restore_snapshot_path):
cmd_str = [sys.executable, git_script_path, '--apply-snapshot', restore_snapshot_path] cmd_str = [sys.executable, git_script_path, '--apply-snapshot', restore_snapshot_path]
exit_code = process_wrap(cmd_str, custom_nodes_path, handler=msg_capture) exit_code = process_wrap(cmd_str, custom_nodes_path, handler=msg_capture)
with open(restore_snapshot_path, 'r', encoding="UTF-8", errors="ignore") as json_file: repository_name = ''
info = json.load(json_file) for url in cloned_repos:
for url in cloned_repos: try:
try: repository_name = url.split("/")[-1].strip()
repository_name = url.split("/")[-1].strip() repo_path = os.path.join(custom_nodes_path, repository_name)
repo_path = os.path.join(custom_nodes_path, repository_name) repo_path = os.path.abspath(repo_path)
repo_path = os.path.abspath(repo_path)
requirements_path = os.path.join(repo_path, 'requirements.txt') requirements_path = os.path.join(repo_path, 'requirements.txt')
install_script_path = os.path.join(repo_path, 'install.py') install_script_path = os.path.join(repo_path, 'install.py')
this_exit_code = 0 this_exit_code = 0
if os.path.exists(requirements_path): if os.path.exists(requirements_path):
with open(requirements_path, 'r', encoding="UTF-8", errors="ignore") as file: with open(requirements_path, 'r', encoding="UTF-8", errors="ignore") as file:
for line in file: for line in file:
package_name = line.strip() package_name = remap_pip_package(line.strip())
if package_name and not is_installed(package_name): if package_name and not is_installed(package_name):
install_cmd = [sys.executable, "-m", "pip", "install", package_name] install_cmd = [sys.executable, "-m", "pip", "install", package_name]
this_exit_code += process_wrap(install_cmd, repo_path) this_exit_code += process_wrap(install_cmd, repo_path)
if os.path.exists(install_script_path) and f'{repo_path}/install.py' not in processed_install: if os.path.exists(install_script_path) and f'{repo_path}/install.py' not in processed_install:
processed_install.add(f'{repo_path}/install.py') processed_install.add(f'{repo_path}/install.py')
install_cmd = [sys.executable, install_script_path] install_cmd = [sys.executable, install_script_path]
print(f">>> {install_cmd} / {repo_path}") print(f">>> {install_cmd} / {repo_path}")
this_exit_code += process_wrap(install_cmd, repo_path) this_exit_code += process_wrap(install_cmd, repo_path)
if this_exit_code != 0: if this_exit_code != 0:
print(f"[ComfyUI-Manager] Restoring '{repository_name}' is failed.")
except Exception as e:
print(e)
print(f"[ComfyUI-Manager] Restoring '{repository_name}' is failed.") print(f"[ComfyUI-Manager] Restoring '{repository_name}' is failed.")
except Exception as e:
print(e)
print(f"[ComfyUI-Manager] Restoring '{repository_name}' is failed.")
if exit_code != 0: if exit_code != 0:
print(f"[ComfyUI-Manager] Restore snapshot failed.") print(f"[ComfyUI-Manager] Restore snapshot failed.")
else: else:
@ -476,7 +514,7 @@ def execute_lazy_install_script(repo_path, executable):
print(f"Install: pip packages for '{repo_path}'") print(f"Install: pip packages for '{repo_path}'")
with open(requirements_path, "r") as requirements_file: with open(requirements_path, "r") as requirements_file:
for line in requirements_file: for line in requirements_file:
package_name = line.strip() package_name = remap_pip_package(line.strip())
if package_name and not is_installed(package_name): if package_name and not is_installed(package_name):
install_cmd = [executable, "-m", "pip", "install", package_name] install_cmd = [executable, "-m", "pip", "install", package_name]
process_wrap(install_cmd, repo_path) process_wrap(install_cmd, repo_path)

View File

@ -14,7 +14,6 @@ import sys
from urllib.parse import urlparse from urllib.parse import urlparse
from github import Github from github import Github
g = Github(os.environ.get('GITHUB_TOKEN'))
# prepare temp dir # prepare temp dir
if len(sys.argv) > 1: if len(sys.argv) > 1:
@ -25,7 +24,15 @@ else:
if not os.path.exists(temp_dir): if not os.path.exists(temp_dir):
os.makedirs(temp_dir) os.makedirs(temp_dir)
skip_update = '--skip-update' in sys.argv
skip_update = '--skip-update' in sys.argv or '--skip-all' in sys.argv
skip_stat_update = '--skip-stat-update' in sys.argv or '--skip-all' in sys.argv
if not skip_stat_update:
g = Github(os.environ.get('GITHUB_TOKEN'))
else:
g = None
print(f"TEMP DIR: {temp_dir}") print(f"TEMP DIR: {temp_dir}")
@ -301,7 +308,9 @@ def update_custom_nodes():
# pass # pass
with concurrent.futures.ThreadPoolExecutor(11) as executor: with concurrent.futures.ThreadPoolExecutor(11) as executor:
executor.submit(process_git_stats, git_url_titles_preemptions) # One single thread for `process_git_stats()`. Runs concurrently with `process_git_url_title()`. if not skip_stat_update:
executor.submit(process_git_stats, git_url_titles_preemptions) # One single thread for `process_git_stats()`. Runs concurrently with `process_git_url_title()`.
for url, title, preemptions, node_pattern in git_url_titles_preemptions: for url, title, preemptions, node_pattern in git_url_titles_preemptions:
executor.submit(process_git_url_title, url, title, preemptions, node_pattern) executor.submit(process_git_url_title, url, title, preemptions, node_pattern)