diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml new file mode 100644 index 000000000..10b97e597 --- /dev/null +++ b/.github/workflows/publish-to-pypi.yml @@ -0,0 +1,58 @@ +name: Publish to PyPI + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - "pyproject.toml" + +jobs: + build-and-publish: + runs-on: ubuntu-latest + if: ${{ github.repository_owner == 'ltdrdata' || github.repository_owner == 'Comfy-Org' }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.9' + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + python -m pip install build twine + + - name: Get current version + id: current_version + run: | + CURRENT_VERSION=$(grep -oP 'version = "\K[^"]+' pyproject.toml) + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "Current version: $CURRENT_VERSION" + + - name: Build package + run: python -m build + + - name: Create GitHub Release + id: create_release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + files: dist/* + tag_name: v${{ steps.current_version.outputs.version }} + draft: false + prerelease: false + generate_release_notes: true + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_TOKEN }} + skip-existing: true + verbose: true \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 463ecca9e..e47764afd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,7 +14,7 @@ jobs: publish-node: name: Publish Custom Node to registry runs-on: ubuntu-latest - if: ${{ github.repository_owner == 'ltdrdata' }} + if: ${{ github.repository_owner == 'ltdrdata' || github.repository_owner == 'Comfy-Org' }} steps: - name: Check out code uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 33ee743b7..5bf40b47a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,6 @@ github-stats-cache.json pip_overrides.json *.json check2.sh -/venv/ \ No newline at end of file +/venv/ +build +*.egg-info \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..8af7bc576 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +include comfyui_manager/js/* +include comfyui_manager/*.json +include comfyui_manager/glob/* +include LICENSE.txt +include README.md +include requirements.txt +include pyproject.toml \ No newline at end of file diff --git a/README.md b/README.md index 7c3e6644b..cafdae902 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ![menu](https://raw.githubusercontent.com/ltdrdata/ComfyUI-extension-tutorials/refs/heads/Main/ComfyUI-Manager/images/dialog.jpg) ## NOTICE +* V4.0: Modify the structure to be installable via pip instead of using git clone. * V3.16: Support for `uv` has been added. Set `use_uv` in `config.ini`. * V3.10: `double-click feature` is removed * This feature has been moved to https://github.com/ltdrdata/comfyui-connection-helper @@ -13,78 +14,26 @@ ## Installation -### Installation[method1] (General installation method: ComfyUI-Manager only) +* When installing the latest ComfyUI, it will be automatically installed as a dependency, so manual installation is no longer necessary. -To install ComfyUI-Manager in addition to an existing installation of ComfyUI, you can follow the following steps: +* Manual installation of the nightly version: + * Clone to a temporary directory (**Note:** Do **not** clone into `ComfyUI/custom_nodes`.) + ``` + git clone https://github.com/Comfy-Org/ComfyUI-Manager + ``` + * Install via pip + ``` + cd ComfyUI-Manager + pip install . + ``` -1. goto `ComfyUI/custom_nodes` dir in terminal(cmd) -2. `git clone https://github.com/ltdrdata/ComfyUI-Manager comfyui-manager` -3. Restart ComfyUI - - -### Installation[method2] (Installation for portable ComfyUI version: ComfyUI-Manager only) -1. install git -- https://git-scm.com/download/win -- standalone version -- select option: use windows default console window -2. Download [scripts/install-manager-for-portable-version.bat](https://github.com/ltdrdata/ComfyUI-Manager/raw/main/scripts/install-manager-for-portable-version.bat) into installed `"ComfyUI_windows_portable"` directory -- Don't click. Right click the link and use save as... -3. double click `install-manager-for-portable-version.bat` batch file - -![portable-install](https://raw.githubusercontent.com/ltdrdata/ComfyUI-extension-tutorials/Main/ComfyUI-Manager/images/portable-install.jpg) - - -### Installation[method3] (Installation through comfy-cli: install ComfyUI and ComfyUI-Manager at once.) -> RECOMMENDED: comfy-cli provides various features to manage ComfyUI from the CLI. - -* **prerequisite: python 3, git** - -Windows: -```commandline -python -m venv venv -venv\Scripts\activate -pip install comfy-cli -comfy install -``` - -Linux/OSX: -```commandline -python -m venv venv -. venv/bin/activate -pip install comfy-cli -comfy install -``` * See also: https://github.com/Comfy-Org/comfy-cli -### Installation[method4] (Installation for linux+venv: ComfyUI + ComfyUI-Manager) - -To install ComfyUI with ComfyUI-Manager on Linux using a venv environment, you can follow these steps: -* **prerequisite: python-is-python3, python3-venv, git** - -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 -- Don't click. Right click the link and use save as... -- ComfyUI will be installed in the subdirectory of the specified directory, and the directory will contain the generated executable script. -2. `chmod +x install-comfyui-venv-linux.sh` -3. `./install-comfyui-venv-linux.sh` - -### Installation Precautions -* **DO**: `ComfyUI-Manager` files must be accurately located in the path `ComfyUI/custom_nodes/comfyui-manager` - * Installing in a compressed file format is not recommended. -* **DON'T**: Decompress directly into the `ComfyUI/custom_nodes` location, resulting in the Manager contents like `__init__.py` being placed directly in that directory. - * You have to remove all ComfyUI-Manager files from `ComfyUI/custom_nodes` -* **DON'T**: In a form where decompression occurs in a path such as `ComfyUI/custom_nodes/ComfyUI-Manager/ComfyUI-Manager`. -* **DON'T**: In a form where decompression occurs in a path such as `ComfyUI/custom_nodes/ComfyUI-Manager-main`. - * In such cases, `ComfyUI-Manager` may operate, but it won't be recognized within `ComfyUI-Manager`, and updates cannot be performed. It also poses the risk of duplicate installations. Remove it and install properly via `git clone` method. - - -You can execute ComfyUI by running either `./run_gpu.sh` or `./run_cpu.sh` depending on your system configuration. +## Front-end -## Colab Notebook -This repository provides Colab notebooks that allow you to install and use ComfyUI, including ComfyUI-Manager. To use ComfyUI, [click on this link](https://colab.research.google.com/github/ltdrdata/ComfyUI-Manager/blob/main/notebooks/comfyui_colab_with_manager.ipynb). -* Support for installing ComfyUI -* Support for basic installation of ComfyUI-Manager -* Support for automatically installing dependencies of custom nodes upon restarting Colab notebooks. +* The built-in front-end of ComfyUI-Manager is the legacy front-end. The front-end for ComfyUI-Manager is now provided via [ComfyUI Frontend](https://github.com/Comfy-Org/ComfyUI_frontend). +* To enable the legacy front-end, set the environment variable `ENABLE_LEGACY_COMFYUI_MANAGER_FRONT` to `true` before running. ## How To Use diff --git a/__init__.py b/__init__.py deleted file mode 100644 index f966524b3..000000000 --- a/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import sys - -cli_mode_flag = os.path.join(os.path.dirname(__file__), '.enable-cli-only-mode') - -if not os.path.exists(cli_mode_flag): - sys.path.append(os.path.join(os.path.dirname(__file__), "glob")) - import manager_server # noqa: F401 - import share_3rdparty # noqa: F401 - import cm_global - - if not cm_global.disable_front and not 'DISABLE_COMFYUI_MANAGER_FRONT' in os.environ: - WEB_DIRECTORY = "js" -else: - print("\n[ComfyUI-Manager] !! cli-only-mode is enabled !!\n") - -NODE_CLASS_MAPPINGS = {} -__all__ = ['NODE_CLASS_MAPPINGS'] - - - diff --git a/cm-cli.sh b/cm-cli.sh index b1a21ca55..1afaf9269 100755 --- a/cm-cli.sh +++ b/cm-cli.sh @@ -1,2 +1,2 @@ #!/bin/bash -python cm-cli.py $* +python ./comfyui_manager/cm-cli.py $* diff --git a/comfyui_manager/__init__.py b/comfyui_manager/__init__.py new file mode 100644 index 000000000..3fe040e05 --- /dev/null +++ b/comfyui_manager/__init__.py @@ -0,0 +1,24 @@ +import os +import logging +from comfy.cli_args import args + +ENABLE_LEGACY_COMFYUI_MANAGER_FRONT_DEFAULT = True # Enable legacy ComfyUI Manager frontend while new UI is in beta phase + +def prestartup(): + from . import prestartup_script # noqa: F401 + logging.info('[PRE] ComfyUI-Manager') + + +def start(): + logging.info('[START] ComfyUI-Manager') + from .glob import manager_server # noqa: F401 + from .glob import share_3rdparty # noqa: F401 + from .glob import cm_global # noqa: F401 + + should_show_legacy_manager_front = os.environ.get('ENABLE_LEGACY_COMFYUI_MANAGER_FRONT', 'false') == 'true' or ENABLE_LEGACY_COMFYUI_MANAGER_FRONT_DEFAULT + if not args.disable_manager and should_show_legacy_manager_front: + try: + import nodes + nodes.EXTENSION_WEB_DIRS['comfyui-manager-legacy'] = os.path.join(os.path.dirname(__file__), 'js') + except Exception as e: + print("Error enabling legacy ComfyUI Manager frontend:", e) diff --git a/cm-cli.py b/comfyui_manager/cm-cli.py similarity index 98% rename from cm-cli.py rename to comfyui_manager/cm-cli.py index ad00a1085..e589e58e9 100644 --- a/cm-cli.py +++ b/comfyui_manager/cm-cli.py @@ -15,31 +15,30 @@ import importlib -sys.path.append(os.path.dirname(__file__)) -sys.path.append(os.path.join(os.path.dirname(__file__), "glob")) - import manager_util # read env vars # COMFYUI_FOLDERS_BASE_PATH is not required in cm-cli.py # `comfy_path` should be resolved before importing manager_core + comfy_path = os.environ.get('COMFYUI_PATH') + if comfy_path is None: - try: - import folder_paths - comfy_path = os.path.join(os.path.dirname(folder_paths.__file__)) - except: - print("\n[bold yellow]WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.[/bold yellow]", file=sys.stderr) - comfy_path = os.path.abspath(os.path.join(manager_util.comfyui_manager_path, '..', '..')) + print("[bold red]cm-cli: environment variable 'COMFYUI_PATH' is not specified.[/bold red]") + exit(-1) -# This should be placed here sys.path.append(comfy_path) +if not os.path.exists(os.path.join(comfy_path, 'folder_paths.py')): + print("[bold red]cm-cli: '{comfy_path}' is not a valid 'COMFYUI_PATH' location.[/bold red]") + exit(-1) + + import utils.extra_config -import cm_global -import manager_core as core -from manager_core import unified_manager -import cnr_utils +from .glob import cm_global +from .glob import manager_core as core +from .glob.manager_core import unified_manager +from .glob import cnr_utils comfyui_manager_path = os.path.abspath(os.path.dirname(__file__)) diff --git a/glob/cm_global.py b/comfyui_manager/glob/cm_global.py similarity index 100% rename from glob/cm_global.py rename to comfyui_manager/glob/cm_global.py diff --git a/glob/cnr_utils.py b/comfyui_manager/glob/cnr_utils.py similarity index 99% rename from glob/cnr_utils.py rename to comfyui_manager/glob/cnr_utils.py index 6a61aaa35..bb4845a3e 100644 --- a/glob/cnr_utils.py +++ b/comfyui_manager/glob/cnr_utils.py @@ -6,8 +6,9 @@ from dataclasses import dataclass from typing import List -import manager_core -import manager_util +from . import manager_core +from . import manager_util + import requests import toml diff --git a/comfyui_manager/glob/enums.py b/comfyui_manager/glob/enums.py new file mode 100644 index 000000000..bd4a57f1c --- /dev/null +++ b/comfyui_manager/glob/enums.py @@ -0,0 +1,17 @@ +import enum + +class NetworkMode(enum.Enum): + PUBLIC = "public" + PRIVATE = "private" + OFFLINE = "offline" + +class SecurityLevel(enum.Enum): + STRONG = "strong" + NORMAL = "normal" + NORMAL_MINUS = "normal-minus" + WEAK = "weak" + +class DBMode(enum.Enum): + LOCAL = "local" + CACHE = "cache" + REMOTE = "remote" \ No newline at end of file diff --git a/git_helper.py b/comfyui_manager/glob/git_helper.py similarity index 98% rename from git_helper.py rename to comfyui_manager/glob/git_helper.py index e79b43a60..54031dd14 100644 --- a/git_helper.py +++ b/comfyui_manager/glob/git_helper.py @@ -15,9 +15,12 @@ git_exe_path = os.environ.get('GIT_EXE_PATH') if comfy_path is None: - print("\nWARN: The `COMFYUI_PATH` environment variable is not set. Assuming `custom_nodes/ComfyUI-Manager/../../` as the ComfyUI path.", file=sys.stderr) - comfy_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) + print("git_helper: environment variable 'COMFYUI_PATH' is not specified.") + exit(-1) +if not os.path.exists(os.path.join(comfy_path, 'folder_paths.py')): + print("git_helper: '{comfy_path}' is not a valid 'COMFYUI_PATH' location.") + exit(-1) def download_url(url, dest_folder, filename=None): # Ensure the destination folder exists diff --git a/glob/git_utils.py b/comfyui_manager/glob/git_utils.py similarity index 100% rename from glob/git_utils.py rename to comfyui_manager/glob/git_utils.py diff --git a/glob/manager_core.py b/comfyui_manager/glob/manager_core.py similarity index 98% rename from glob/manager_core.py rename to comfyui_manager/glob/manager_core.py index e9af16bc4..a839e51ec 100644 --- a/glob/manager_core.py +++ b/comfyui_manager/glob/manager_core.py @@ -32,18 +32,15 @@ import uuid -glob_path = os.path.join(os.path.dirname(__file__)) # ComfyUI-Manager/glob -sys.path.append(glob_path) - -import cm_global -import cnr_utils -import manager_util -import git_utils -import manager_downloader -from node_package import InstalledNodePackage - - -version_code = [3, 31, 9] +from . import cm_global +from . import cnr_utils +from . import manager_util +from . import git_utils +from . import manager_downloader +from .node_package import InstalledNodePackage +from .enums import NetworkMode, SecurityLevel, DBMode + +version_code = [4, 0] version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') @@ -58,6 +55,7 @@ def __init__(self, channel): self.channel = channel super().__init__(channel) + def get_default_custom_nodes_path(): global default_custom_nodes_path if default_custom_nodes_path is None: @@ -183,10 +181,11 @@ def check(root): if comfy_path is None: try: - import folder_paths - comfy_path = os.path.join(os.path.dirname(folder_paths.__file__)) + comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__)) + os.environ['COMFYUI_PATH'] = comfy_path except: - comfy_path = os.path.abspath(os.path.join(manager_util.comfyui_manager_path, '..', '..')) + logging.error("[ComfyUI-Manager] environment variable 'COMFYUI_PATH' is not specified.") + exit(-1) if comfy_base_path is None: comfy_base_path = comfy_path @@ -553,7 +552,7 @@ def resolve_from_path(self, fullpath): ver = str(manager_util.StrictVersion(info['version'])) return {'id': cnr['id'], 'cnr': cnr, 'ver': ver} else: - return None + return {'id': info['id'], 'ver': info['version']} else: return None @@ -729,7 +728,7 @@ def get_from_cnr_inactive_nodes(self, node_id, ver=None): return latest - async def reload(self, cache_mode, dont_wait=True): + async def reload(self, cache_mode, dont_wait=True, update_cnr_map=True): self.custom_node_map_cache = {} self.cnr_inactive_nodes = {} # node_id -> node_version -> fullpath self.nightly_inactive_nodes = {} # node_id -> fullpath @@ -737,17 +736,18 @@ async def reload(self, cache_mode, dont_wait=True): self.unknown_active_nodes = {} # node_id -> repo url * fullpath self.active_nodes = {} # node_id -> node_version * fullpath - if get_config()['network_mode'] != 'public': + if get_config()['network_mode'] != 'public' or manager_util.is_manager_pip_package(): dont_wait = True - # reload 'cnr_map' and 'repo_cnr_map' - cnrs = await cnr_utils.get_cnr_data(cache_mode=cache_mode=='cache', dont_wait=dont_wait) + if update_cnr_map: + # reload 'cnr_map' and 'repo_cnr_map' + cnrs = await cnr_utils.get_cnr_data(cache_mode=cache_mode=='cache', dont_wait=dont_wait) - for x in cnrs: - self.cnr_map[x['id']] = x - if 'repository' in x: - normalized_url = git_utils.normalize_url(x['repository']) - self.repo_cnr_map[normalized_url] = x + for x in cnrs: + self.cnr_map[x['id']] = x + if 'repository' in x: + normalized_url = git_utils.normalize_url(x['repository']) + self.repo_cnr_map[normalized_url] = x # reload node status info from custom_nodes/* for custom_nodes_path in folder_paths.get_folder_paths('custom_nodes'): @@ -1442,12 +1442,20 @@ async def install_by_id(self, node_id: str, version_spec=None, channel=None, mod return self.unified_enable(node_id, version_spec) elif version_spec == 'unknown' or version_spec == 'nightly': + to_path = os.path.abspath(os.path.join(get_default_custom_nodes_path(), node_id)) + if version_spec == 'nightly': # disable cnr nodes if self.is_enabled(node_id, 'cnr'): self.unified_disable(node_id, False) - to_path = os.path.abspath(os.path.join(get_default_custom_nodes_path(), node_id)) + # use `repo name` as a dir name instead of `cnr id` if system added nodepack (i.e. publisher is null) + cnr = self.cnr_map.get(node_id) + + if cnr is not None and cnr.get('publisher') is None: + repo_name = os.path.basename(git_utils.normalize_url(repo_url)) + to_path = os.path.abspath(os.path.join(get_default_custom_nodes_path(), repo_name)) + res = self.repo_install(repo_url, to_path, instant_execution=instant_execution, no_deps=no_deps, return_postinstall=return_postinstall) if res.result: if version_spec == 'unknown': @@ -1664,9 +1672,9 @@ def get_bool(key, default_value): 'model_download_by_agent': get_bool('model_download_by_agent', False), 'downgrade_blacklist': default_conf.get('downgrade_blacklist', '').lower(), 'always_lazy_install': get_bool('always_lazy_install', False), - 'network_mode': default_conf.get('network_mode', 'public').lower(), - 'security_level': default_conf.get('security_level', 'normal').lower(), - 'db_mode': default_conf.get('db_mode', 'cache').lower(), + 'network_mode': default_conf.get('network_mode', NetworkMode.PUBLIC.value).lower(), + 'security_level': default_conf.get('security_level', SecurityLevel.NORMAL.value).lower(), + 'db_mode': default_conf.get('db_mode', DBMode.CACHE.value).lower(), } except Exception: @@ -1687,9 +1695,9 @@ def get_bool(key, default_value): 'model_download_by_agent': False, 'downgrade_blacklist': '', 'always_lazy_install': False, - 'network_mode': 'public', # public | private | offline - 'security_level': 'normal', # strong | normal | normal- | weak - 'db_mode': 'cache', # local | cache | remote + 'network_mode': NetworkMode.OFFLINE.value, + 'security_level': SecurityLevel.NORMAL.value, + 'db_mode': DBMode.CACHE.value, } @@ -2186,7 +2194,7 @@ async def get_data_by_mode(mode, filename, channel_url=None): cache_uri = str(manager_util.simple_hash(uri))+'_'+filename cache_uri = os.path.join(manager_util.cache_dir, cache_uri) - if get_config()['network_mode'] == 'offline': + if get_config()['network_mode'] == 'offline' or manager_util.is_manager_pip_package(): # offline network mode if os.path.exists(cache_uri): json_obj = await manager_util.get_data(cache_uri) @@ -2206,7 +2214,7 @@ async def get_data_by_mode(mode, filename, channel_url=None): 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}") + print(f"[ComfyUI-Manager] Due to a network error, switching to local mode.\n=> {filename} @ {channel_url}/{mode}\n=> {e}") uri = os.path.join(manager_util.comfyui_manager_path, filename) json_obj = await manager_util.get_data(uri) diff --git a/glob/manager_downloader.py b/comfyui_manager/glob/manager_downloader.py similarity index 100% rename from glob/manager_downloader.py rename to comfyui_manager/glob/manager_downloader.py diff --git a/glob/manager_server.py b/comfyui_manager/glob/manager_server.py similarity index 93% rename from glob/manager_server.py rename to comfyui_manager/glob/manager_server.py index 979498325..b70f7bb54 100644 --- a/glob/manager_server.py +++ b/comfyui_manager/glob/manager_server.py @@ -14,18 +14,23 @@ from datetime import datetime from server import PromptServer -import manager_core as core -import manager_util -import cm_global import logging import asyncio import queue -import manager_downloader +from . import manager_core as core +from . import manager_util +from . import cm_global +from . import manager_downloader logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})") -logging.info("[ComfyUI-Manager] network_mode: " + core.get_config()['network_mode']) + +if not manager_util.is_manager_pip_package(): + network_mode_description = "offline" +else: + network_mode_description = core.get_config()['network_mode'] +logging.info("[ComfyUI-Manager] network_mode: " + network_mode_description) comfy_ui_hash = "-" comfyui_tag = None @@ -155,9 +160,7 @@ def run_script(self, cmd, cwd='.'): core.manager_funcs = ManagerFuncsInComfyUI() -sys.path.append('../..') - -from manager_downloader import download_url, download_url_with_agent +from .manager_downloader import download_url, download_url_with_agent core.comfy_path = os.path.dirname(folder_paths.__file__) core.js_path = os.path.join(core.comfy_path, "web", "extensions") @@ -659,7 +662,7 @@ async def do_install_model(item) -> str: 'total_count': total_count, 'done_count': done_count}) -@routes.get("/customnode/getmappings") +@routes.get("/v2/customnode/getmappings") async def fetch_customnode_mappings(request): """ provide unified (node -> node pack) mapping list @@ -695,7 +698,7 @@ async def fetch_customnode_mappings(request): return web.json_response(json_obj, content_type='application/json') -@routes.get("/customnode/fetch_updates") +@routes.get("/v2/customnode/fetch_updates") async def fetch_updates(request): try: if request.rel_url.query["mode"] == "local": @@ -722,7 +725,7 @@ async def fetch_updates(request): return web.Response(status=400) -@routes.get("/manager/queue/update_all") +@routes.get("/v2/manager/queue/update_all") async def update_all(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) @@ -810,7 +813,7 @@ def populate_markdown(x): # freeze imported version startup_time_installed_node_packs = core.get_installed_node_packs() -@routes.get("/customnode/installed") +@routes.get("/v2/customnode/installed") async def installed_list(request): mode = request.query.get('mode', 'default') @@ -822,7 +825,7 @@ async def installed_list(request): return web.json_response(res, content_type='application/json') -@routes.get("/customnode/getlist") +@routes.get("/v2/customnode/getlist") async def fetch_customnode_list(request): """ provide unified custom node list @@ -935,7 +938,7 @@ def process_model_phase(item): executor.submit(process_model_phase, item) -@routes.get("/externalmodel/getlist") +@routes.get("/v2/externalmodel/getlist") async def fetch_externalmodel_list(request): # The model list is only allowed in the default channel, yet. json_obj = await core.get_data_by_mode(request.rel_url.query["mode"], 'model-list.json') @@ -948,14 +951,14 @@ async def fetch_externalmodel_list(request): return web.json_response(json_obj, content_type='application/json') -@PromptServer.instance.routes.get("/snapshot/getlist") +@PromptServer.instance.routes.get("/v2/snapshot/getlist") async def get_snapshot_list(request): items = [f[:-5] for f in os.listdir(core.manager_snapshot_path) if f.endswith('.json')] items.sort(reverse=True) return web.json_response({'items': items}, content_type='application/json') -@routes.get("/snapshot/remove") +@routes.get("/v2/snapshot/remove") async def remove_snapshot(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) @@ -973,7 +976,7 @@ async def remove_snapshot(request): return web.Response(status=400) -@routes.get("/snapshot/restore") +@routes.get("/v2/snapshot/restore") async def restore_snapshot(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) @@ -999,7 +1002,7 @@ async def restore_snapshot(request): return web.Response(status=400) -@routes.get("/snapshot/get_current") +@routes.get("/v2/snapshot/get_current") async def get_current_snapshot_api(request): try: return web.json_response(await core.get_current_snapshot(), content_type='application/json') @@ -1007,7 +1010,7 @@ async def get_current_snapshot_api(request): return web.Response(status=400) -@routes.get("/snapshot/save") +@routes.get("/v2/snapshot/save") async def save_snapshot(request): try: await core.save_snapshot_with_postfix('snapshot') @@ -1044,82 +1047,7 @@ def unzip_install(files): return True -def copy_install(files, js_path_name=None): - for url in files: - if url.endswith("/"): - url = url[:-1] - try: - filename = os.path.basename(url) - if url.endswith(".py"): - download_url(url, core.get_default_custom_nodes_path(), filename) - else: - path = os.path.join(core.js_path, js_path_name) if js_path_name is not None else core.js_path - if not os.path.exists(path): - os.makedirs(path) - download_url(url, path, filename) - - except Exception as e: - logging.error(f"Install(copy) error: {url} / {e}", file=sys.stderr) - return False - - logging.info("Installation was successful.") - return True - - -def copy_uninstall(files, js_path_name='.'): - for url in files: - if url.endswith("/"): - url = url[:-1] - dir_name = os.path.basename(url) - base_path = core.get_default_custom_nodes_path() if url.endswith('.py') else os.path.join(core.js_path, js_path_name) - file_path = os.path.join(base_path, dir_name) - - try: - if os.path.exists(file_path): - os.remove(file_path) - elif os.path.exists(file_path + ".disabled"): - os.remove(file_path + ".disabled") - except Exception as e: - logging.error(f"Uninstall(copy) error: {url} / {e}", file=sys.stderr) - return False - - logging.info("Uninstallation was successful.") - return True - - -def copy_set_active(files, is_disable, js_path_name='.'): - if is_disable: - action_name = "Disable" - else: - action_name = "Enable" - - for url in files: - if url.endswith("/"): - url = url[:-1] - dir_name = os.path.basename(url) - base_path = core.get_default_custom_nodes_path() if url.endswith('.py') else os.path.join(core.js_path, js_path_name) - file_path = os.path.join(base_path, dir_name) - - try: - if is_disable: - current_name = file_path - new_name = file_path + ".disabled" - else: - current_name = file_path + ".disabled" - new_name = file_path - - os.rename(current_name, new_name) - - except Exception as e: - logging.error(f"{action_name}(copy) error: {url} / {e}", file=sys.stderr) - - return False - - logging.info(f"{action_name} was successful.") - return True - - -@routes.get("/customnode/versions/{node_name}") +@routes.get("/v2/customnode/versions/{node_name}") async def get_cnr_versions(request): node_name = request.match_info.get("node_name", None) versions = core.cnr_utils.all_versions_of_node(node_name) @@ -1130,7 +1058,7 @@ async def get_cnr_versions(request): return web.Response(status=400) -@routes.get("/customnode/disabled_versions/{node_name}") +@routes.get("/v2/customnode/disabled_versions/{node_name}") async def get_disabled_versions(request): node_name = request.match_info.get("node_name", None) versions = [] @@ -1146,7 +1074,7 @@ async def get_disabled_versions(request): return web.Response(status=400) -@routes.post("/customnode/import_fail_info") +@routes.post("/v2/customnode/import_fail_info") async def import_fail_info(request): json_data = await request.json() @@ -1163,20 +1091,20 @@ async def import_fail_info(request): return web.Response(status=400) -@routes.post("/manager/queue/reinstall") +@routes.post("/v2/manager/queue/reinstall") async def reinstall_custom_node(request): await uninstall_custom_node(request) await install_custom_node(request) -@routes.get("/manager/queue/reset") +@routes.get("/v2/manager/queue/reset") async def reset_queue(request): global task_queue task_queue = queue.Queue() return web.Response(status=200) -@routes.get("/manager/queue/status") +@routes.get("/v2/manager/queue/status") async def queue_count(request): global task_queue @@ -1191,7 +1119,7 @@ async def queue_count(request): 'is_processing': is_processing}) -@routes.post("/manager/queue/install") +@routes.post("/v2/manager/queue/install") async def install_custom_node(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) @@ -1252,7 +1180,7 @@ async def install_custom_node(request): task_worker_thread:threading.Thread = None -@routes.get("/manager/queue/start") +@routes.get("/v2/manager/queue/start") async def queue_start(request): global nodepack_result global model_result @@ -1270,7 +1198,7 @@ async def queue_start(request): return web.Response(status=200) -@routes.post("/manager/queue/fix") +@routes.post("/v2/manager/queue/fix") async def fix_custom_node(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_GENERAL) @@ -1292,7 +1220,7 @@ async def fix_custom_node(request): return web.Response(status=200) -@routes.post("/customnode/install/git_url") +@routes.post("/v2/customnode/install/git_url") async def install_custom_node_git_url(request): if not is_allowed_security_level('high'): logging.error(SECURITY_MESSAGE_NORMAL_MINUS) @@ -1312,7 +1240,7 @@ async def install_custom_node_git_url(request): return web.Response(status=400) -@routes.post("/customnode/install/pip") +@routes.post("/v2/customnode/install/pip") async def install_custom_node_pip(request): if not is_allowed_security_level('high'): logging.error(SECURITY_MESSAGE_NORMAL_MINUS) @@ -1324,7 +1252,7 @@ async def install_custom_node_pip(request): return web.Response(status=200) -@routes.post("/manager/queue/uninstall") +@routes.post("/v2/manager/queue/uninstall") async def uninstall_custom_node(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) @@ -1347,7 +1275,7 @@ async def uninstall_custom_node(request): return web.Response(status=200) -@routes.post("/manager/queue/update") +@routes.post("/v2/manager/queue/update") async def update_custom_node(request): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) @@ -1368,14 +1296,14 @@ async def update_custom_node(request): return web.Response(status=200) -@routes.get("/manager/queue/update_comfyui") +@routes.get("/v2/manager/queue/update_comfyui") async def update_comfyui(request): is_stable = core.get_config()['update_policy'] != 'nightly-comfyui' task_queue.put(("update-comfyui", ('comfyui', is_stable))) return web.Response(status=200) -@routes.get("/comfyui_manager/comfyui_versions") +@routes.get("/v2/comfyui_manager/comfyui_versions") async def comfyui_versions(request): try: res, current, latest = core.get_comfyui_versions() @@ -1386,7 +1314,7 @@ async def comfyui_versions(request): return web.Response(status=400) -@routes.get("/comfyui_manager/comfyui_switch_version") +@routes.get("/v2/comfyui_manager/comfyui_switch_version") async def comfyui_switch_version(request): try: if "ver" in request.rel_url.query: @@ -1399,7 +1327,7 @@ async def comfyui_switch_version(request): return web.Response(status=400) -@routes.post("/manager/queue/disable") +@routes.post("/v2/manager/queue/disable") async def disable_node(request): json_data = await request.json() @@ -1434,7 +1362,7 @@ async def check_whitelist_for_model(item): return False -@routes.post("/manager/queue/install_model") +@routes.post("/v2/manager/queue/install_model") async def install_model(request): json_data = await request.json() @@ -1466,7 +1394,7 @@ async def install_model(request): return web.Response(status=200) -@routes.get("/manager/preview_method") +@routes.get("/v2/manager/preview_method") async def preview_method(request): if "value" in request.rel_url.query: set_preview_method(request.rel_url.query['value']) @@ -1477,7 +1405,7 @@ async def preview_method(request): return web.Response(status=200) -@routes.get("/manager/db_mode") +@routes.get("/v2/manager/db_mode") async def db_mode(request): if "value" in request.rel_url.query: set_db_mode(request.rel_url.query['value']) @@ -1489,7 +1417,7 @@ async def db_mode(request): -@routes.get("/manager/policy/component") +@routes.get("/v2/manager/policy/component") async def component_policy(request): if "value" in request.rel_url.query: set_component_policy(request.rel_url.query['value']) @@ -1500,7 +1428,7 @@ async def component_policy(request): return web.Response(status=200) -@routes.get("/manager/policy/update") +@routes.get("/v2/manager/policy/update") async def update_policy(request): if "value" in request.rel_url.query: set_update_policy(request.rel_url.query['value']) @@ -1511,7 +1439,7 @@ async def update_policy(request): return web.Response(status=200) -@routes.get("/manager/channel_url_list") +@routes.get("/v2/manager/channel_url_list") async def channel_url_list(request): channels = core.get_channel_dict() if "value" in request.rel_url.query: @@ -1548,7 +1476,7 @@ def add_target(match): return modified_html -@routes.get("/manager/notice") +@routes.get("/v2/manager/notice") async def get_notice(request): url = "github.com" path = "/ltdrdata/ltdrdata.github.io/wiki/News" @@ -1595,7 +1523,13 @@ async def get_notice(request): return web.Response(text="Unable to retrieve Notice", status=200) -@routes.get("/manager/reboot") +# legacy /manager/notice +@routes.get("/manager/notice") +async def get_notice_legacy(request): + return web.Response(text="""Starting from ComfyUI-Manager V4.0+, it should be installed via pip.

Please remove the ComfyUI-Manager installed in the 'custom_nodes' directory.
""", status=200) + + +@routes.get("/v2/manager/reboot") def restart(self): if not is_allowed_security_level('middle'): logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) @@ -1632,7 +1566,7 @@ def restart(self): return os.execv(sys.executable, cmds) -@routes.post("/manager/component/save") +@routes.post("/v2/manager/component/save") async def save_component(request): try: data = await request.json() @@ -1662,7 +1596,7 @@ async def save_component(request): return web.Response(status=400) -@routes.post("/manager/component/loads") +@routes.post("/v2/manager/component/loads") async def load_components(request): if os.path.exists(core.manager_components_path): try: @@ -1687,7 +1621,7 @@ async def load_components(request): return web.json_response({}) -@routes.get("/manager/version") +@routes.get("/v2/manager/version") async def get_version(request): return web.Response(text=core.version_str, status=200) @@ -1736,7 +1670,7 @@ async def get_cache(filename): logging.error(f"[ComfyUI-Manager] Failed to perform initial fetching '{filename}': {e}") traceback.print_exc() - if core.get_config()['network_mode'] != 'offline': + if core.get_config()['network_mode'] != 'offline' and not manager_util.is_manager_pip_package(): a = get_cache("custom-node-list.json") b = get_cache("extension-node-map.json") c = get_cache("model-list.json") @@ -1751,6 +1685,8 @@ async def get_cache(filename): # load at least once await core.unified_manager.reload('remote', dont_wait=False) await core.unified_manager.get_custom_nodes(channel_url, 'remote') + else: + await core.unified_manager.reload('remote', dont_wait=False, update_cnr_map=False) logging.info("[ComfyUI-Manager] All startup tasks have been completed.") @@ -1768,4 +1704,3 @@ async def get_cache(filename): 'nodes': {}, 'description': 'This extension provides the ability to manage custom nodes in ComfyUI.', }) - diff --git a/glob/manager_util.py b/comfyui_manager/glob/manager_util.py similarity index 99% rename from glob/manager_util.py rename to comfyui_manager/glob/manager_util.py index cb65cc5bc..ae63bdd86 100644 --- a/glob/manager_util.py +++ b/comfyui_manager/glob/manager_util.py @@ -18,12 +18,15 @@ cache_lock = threading.Lock() +session_lock = threading.Lock() comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) cache_dir = os.path.join(comfyui_manager_path, '.cache') # This path is also updated together in **manager_core.update_user_directory**. use_uv = False +def is_manager_pip_package(): + return not os.path.exists(os.path.join(comfyui_manager_path, '..', 'custom_nodes')) def add_python_path_to_env(): if platform.system() != "Windows": diff --git a/glob/node_package.py b/comfyui_manager/glob/node_package.py similarity index 97% rename from glob/node_package.py rename to comfyui_manager/glob/node_package.py index d199fa308..6ec53a9ad 100644 --- a/glob/node_package.py +++ b/comfyui_manager/glob/node_package.py @@ -3,7 +3,7 @@ from dataclasses import dataclass import os -from git_utils import get_commit_hash +from .git_utils import get_commit_hash @dataclass diff --git a/glob/security_check.py b/comfyui_manager/glob/security_check.py similarity index 100% rename from glob/security_check.py rename to comfyui_manager/glob/security_check.py diff --git a/glob/share_3rdparty.py b/comfyui_manager/glob/share_3rdparty.py similarity index 95% rename from glob/share_3rdparty.py rename to comfyui_manager/glob/share_3rdparty.py index c6cfcb1e7..e6d31ba44 100644 --- a/glob/share_3rdparty.py +++ b/comfyui_manager/glob/share_3rdparty.py @@ -1,5 +1,6 @@ import mimetypes -import manager_core as core +from . import manager_core as core + import os from aiohttp import web import aiohttp @@ -53,7 +54,7 @@ def compute_sha256_checksum(filepath): return sha256.hexdigest() -@PromptServer.instance.routes.get("/manager/share_option") +@PromptServer.instance.routes.get("/v2/manager/share_option") async def share_option(request): if "value" in request.rel_url.query: core.get_config()['share_option'] = request.rel_url.query['value'] @@ -122,7 +123,7 @@ def set_youml_settings(settings): f.write(settings) -@PromptServer.instance.routes.get("/manager/get_openart_auth") +@PromptServer.instance.routes.get("/v2/manager/get_openart_auth") async def api_get_openart_auth(request): # print("Getting stored Matrix credentials...") openart_key = get_openart_auth() @@ -131,7 +132,7 @@ async def api_get_openart_auth(request): return web.json_response({"openart_key": openart_key}) -@PromptServer.instance.routes.post("/manager/set_openart_auth") +@PromptServer.instance.routes.post("/v2/manager/set_openart_auth") async def api_set_openart_auth(request): json_data = await request.json() openart_key = json_data['openart_key'] @@ -140,7 +141,7 @@ async def api_set_openart_auth(request): return web.Response(status=200) -@PromptServer.instance.routes.get("/manager/get_matrix_auth") +@PromptServer.instance.routes.get("/v2/manager/get_matrix_auth") async def api_get_matrix_auth(request): # print("Getting stored Matrix credentials...") matrix_auth = get_matrix_auth() @@ -149,7 +150,7 @@ async def api_get_matrix_auth(request): return web.json_response(matrix_auth) -@PromptServer.instance.routes.get("/manager/youml/settings") +@PromptServer.instance.routes.get("/v2/manager/youml/settings") async def api_get_youml_settings(request): youml_settings = get_youml_settings() if not youml_settings: @@ -157,14 +158,14 @@ async def api_get_youml_settings(request): return web.json_response(json.loads(youml_settings)) -@PromptServer.instance.routes.post("/manager/youml/settings") +@PromptServer.instance.routes.post("/v2/manager/youml/settings") async def api_set_youml_settings(request): json_data = await request.json() set_youml_settings(json.dumps(json_data)) return web.Response(status=200) -@PromptServer.instance.routes.get("/manager/get_comfyworkflows_auth") +@PromptServer.instance.routes.get("/v2/manager/get_comfyworkflows_auth") async def api_get_comfyworkflows_auth(request): # Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken' # in the same directory as the ComfyUI base folder @@ -175,7 +176,7 @@ async def api_get_comfyworkflows_auth(request): return web.json_response({"comfyworkflows_sharekey": comfyworkflows_auth}) -@PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images") +@PromptServer.instance.routes.post("/v2/manager/set_esheep_workflow_and_images") async def set_esheep_workflow_and_images(request): json_data = await request.json() with open(os.path.join(core.manager_files_path, "esheep_share_message.json"), "w", encoding='utf-8') as file: @@ -183,7 +184,7 @@ async def set_esheep_workflow_and_images(request): return web.Response(status=200) -@PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images") +@PromptServer.instance.routes.get("/v2/manager/get_esheep_workflow_and_images") async def get_esheep_workflow_and_images(request): with open(os.path.join(core.manager_files_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file: data = json.load(file) @@ -211,7 +212,7 @@ def has_provided_comfyworkflows_auth(comfyworkflows_sharekey): return comfyworkflows_sharekey.strip() -@PromptServer.instance.routes.post("/manager/share") +@PromptServer.instance.routes.post("/v2/manager/share") async def share_art(request): # get json data json_data = await request.json() diff --git a/js/cm-api.js b/comfyui_manager/js/cm-api.js similarity index 90% rename from js/cm-api.js rename to comfyui_manager/js/cm-api.js index dabc6f1dd..21e9f705e 100644 --- a/js/cm-api.js +++ b/comfyui_manager/js/cm-api.js @@ -25,7 +25,7 @@ async function tryInstallCustomNode(event) { const res = await customConfirm(msg); if(res) { if(event.detail.target.installed == 'Disabled') { - const response = await api.fetchApi(`/customnode/toggle_active`, { + const response = await api.fetchApi(`/v2/customnode/toggle_active`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event.detail.target) @@ -35,7 +35,7 @@ async function tryInstallCustomNode(event) { await sleep(300); app.ui.dialog.show(`Installing... '${event.detail.target.title}'`); - const response = await api.fetchApi(`/customnode/install`, { + const response = await api.fetchApi(`/v2/customnode/install`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event.detail.target) @@ -52,7 +52,7 @@ async function tryInstallCustomNode(event) { } } - let response = await api.fetchApi("/manager/reboot"); + let response = await api.fetchApi("/v2/manager/reboot"); if(response.status == 403) { show_message('This action is not allowed with this security level configuration.'); return false; diff --git a/js/comfyui-manager.js b/comfyui_manager/js/comfyui-manager.js similarity index 95% rename from js/comfyui-manager.js rename to comfyui_manager/js/comfyui-manager.js index 6fc504b1f..df7d19de1 100644 --- a/js/comfyui-manager.js +++ b/comfyui_manager/js/comfyui-manager.js @@ -189,8 +189,7 @@ docStyle.innerHTML = ` } `; -function is_legacy_front() { - let compareVersion = '1.2.49'; +function isBeforeFrontendVersion(compareVersion) { try { const frontendVersion = window['__COMFYUI_FRONTEND_VERSION__']; if (typeof frontendVersion !== 'string') { @@ -223,6 +222,9 @@ function is_legacy_front() { } } +const is_legacy_front = () => isBeforeFrontendVersion('1.2.49'); +const isNewManagerUI = () => isBeforeFrontendVersion('1.16.4'); + document.head.appendChild(docStyle); var update_comfyui_button = null; @@ -415,7 +417,7 @@ const style = ` `; async function init_share_option() { - api.fetchApi('/manager/share_option') + api.fetchApi('/v2/manager/share_option') .then(response => response.text()) .then(data => { share_option = data || 'all'; @@ -423,7 +425,7 @@ async function init_share_option() { } async function init_notice(notice) { - api.fetchApi('/manager/notice') + api.fetchApi('/v2/manager/notice') .then(response => response.text()) .then(data => { notice.innerHTML = data; @@ -476,12 +478,12 @@ async function updateComfyUI() { set_inprogress_mode(); - const response = await api.fetchApi('/manager/queue/update_comfyui'); + const response = await api.fetchApi('/v2/manager/queue/update_comfyui'); showTerminal(); is_updating = true; - await api.fetchApi('/manager/queue/start'); + await api.fetchApi('/v2/manager/queue/start'); } function showVersionSelectorDialog(versions, current, onSelect) { @@ -612,7 +614,7 @@ async function switchComfyUI() { switch_comfyui_button.disabled = true; switch_comfyui_button.style.backgroundColor = "gray"; - let res = await api.fetchApi(`/comfyui_manager/comfyui_versions`, { cache: "no-store" }); + let res = await api.fetchApi(`/v2/comfyui_manager/comfyui_versions`, { cache: "no-store" }); switch_comfyui_button.disabled = false; switch_comfyui_button.style.backgroundColor = ""; @@ -631,14 +633,14 @@ async function switchComfyUI() { showVersionSelectorDialog(versions, obj.current, async (selected_version) => { if(selected_version == 'nightly') { update_policy_combo.value = 'nightly-comfyui'; - api.fetchApi('/manager/policy/update?value=nightly-comfyui'); + api.fetchApi('/v2/manager/policy/update?value=nightly-comfyui'); } else { update_policy_combo.value = 'stable-comfyui'; - api.fetchApi('/manager/policy/update?value=stable-comfyui'); + api.fetchApi('/v2/manager/policy/update?value=stable-comfyui'); } - let response = await api.fetchApi(`/comfyui_manager/comfyui_switch_version?ver=${selected_version}`, { cache: "no-store" }); + let response = await api.fetchApi(`/v2/comfyui_manager/comfyui_switch_version?ver=${selected_version}`, { cache: "no-store" }); if (response.status == 200) { infoToast(`ComfyUI version is switched to ${selected_version}`); } @@ -775,17 +777,17 @@ async function updateAll(update_comfyui) { if(update_comfyui) { update_all_button.innerText = "Updating ComfyUI..."; - await api.fetchApi('/manager/queue/update_comfyui'); + await api.fetchApi('/v2/manager/queue/update_comfyui'); } - const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`); + const response = await api.fetchApi(`/v2/manager/queue/update_all?mode=${mode}`); if (response.status == 401) { customAlert('Another task is already in progress. Please stop the ongoing task first.'); } else if(response.status == 200) { is_updating = true; - await api.fetchApi('/manager/queue/start'); + await api.fetchApi('/v2/manager/queue/start'); } } @@ -814,7 +816,7 @@ function restartOrStop() { rebootAPI(); } else { - api.fetchApi('/manager/queue/reset'); + api.fetchApi('/v2/manager/queue/reset'); infoToast('Cancel', 'Remaining tasks will stop after completing the current task.'); } } @@ -962,12 +964,12 @@ class ManagerMenuDialog extends ComfyDialog { this.datasrc_combo.appendChild($el('option', { value: 'local', text: 'DB: Local' }, [])); this.datasrc_combo.appendChild($el('option', { value: 'remote', text: 'DB: Channel (remote)' }, [])); - api.fetchApi('/manager/db_mode') + api.fetchApi('/v2/manager/db_mode') .then(response => response.text()) .then(data => { this.datasrc_combo.value = data; }); this.datasrc_combo.addEventListener('change', function (event) { - api.fetchApi(`/manager/db_mode?value=${event.target.value}`); + api.fetchApi(`/v2/manager/db_mode?value=${event.target.value}`); }); // preview method @@ -979,19 +981,19 @@ class ManagerMenuDialog extends ComfyDialog { preview_combo.appendChild($el('option', { value: 'latent2rgb', text: 'Preview method: Latent2RGB (fast)' }, [])); preview_combo.appendChild($el('option', { value: 'none', text: 'Preview method: None (very fast)' }, [])); - api.fetchApi('/manager/preview_method') + api.fetchApi('/v2/manager/preview_method') .then(response => response.text()) .then(data => { preview_combo.value = data; }); preview_combo.addEventListener('change', function (event) { - api.fetchApi(`/manager/preview_method?value=${event.target.value}`); + api.fetchApi(`/v2/manager/preview_method?value=${event.target.value}`); }); // channel let channel_combo = document.createElement("select"); channel_combo.setAttribute("title", "Configure the channel for retrieving data from the Custom Node list (including missing nodes) or the Model list."); channel_combo.className = "cm-menu-combo"; - api.fetchApi('/manager/channel_url_list') + api.fetchApi('/v2/manager/channel_url_list') .then(response => response.json()) .then(async data => { try { @@ -1004,7 +1006,7 @@ class ManagerMenuDialog extends ComfyDialog { } channel_combo.addEventListener('change', function (event) { - api.fetchApi(`/manager/channel_url_list?value=${event.target.value}`); + api.fetchApi(`/v2/manager/channel_url_list?value=${event.target.value}`); }); channel_combo.value = data.selected; @@ -1032,7 +1034,7 @@ class ManagerMenuDialog extends ComfyDialog { share_combo.appendChild($el('option', { value: option[0], text: `Share: ${option[1]}` }, [])); } - api.fetchApi('/manager/share_option') + api.fetchApi('/v2/manager/share_option') .then(response => response.text()) .then(data => { share_combo.value = data || 'all'; @@ -1042,7 +1044,7 @@ class ManagerMenuDialog extends ComfyDialog { share_combo.addEventListener('change', function (event) { const value = event.target.value; share_option = value; - api.fetchApi(`/manager/share_option?value=${value}`); + api.fetchApi(`/v2/manager/share_option?value=${value}`); const shareButton = document.getElementById("shareButton"); if (value === 'none') { shareButton.style.display = "none"; @@ -1057,7 +1059,7 @@ class ManagerMenuDialog extends ComfyDialog { component_policy_combo.appendChild($el('option', { value: 'workflow', text: 'Component: Use workflow version' }, [])); component_policy_combo.appendChild($el('option', { value: 'higher', text: 'Component: Use higher version' }, [])); component_policy_combo.appendChild($el('option', { value: 'mine', text: 'Component: Use my version' }, [])); - api.fetchApi('/manager/policy/component') + api.fetchApi('/v2/manager/policy/component') .then(response => response.text()) .then(data => { component_policy_combo.value = data; @@ -1065,7 +1067,7 @@ class ManagerMenuDialog extends ComfyDialog { }); component_policy_combo.addEventListener('change', function (event) { - api.fetchApi(`/manager/policy/component?value=${event.target.value}`); + api.fetchApi(`/v2/manager/policy/component?value=${event.target.value}`); set_component_policy(event.target.value); }); @@ -1078,14 +1080,14 @@ class ManagerMenuDialog extends ComfyDialog { update_policy_combo.className = "cm-menu-combo"; update_policy_combo.appendChild($el('option', { value: 'stable-comfyui', text: 'Update: ComfyUI Stable Version' }, [])); update_policy_combo.appendChild($el('option', { value: 'nightly-comfyui', text: 'Update: ComfyUI Nightly Version' }, [])); - api.fetchApi('/manager/policy/update') + api.fetchApi('/v2/manager/policy/update') .then(response => response.text()) .then(data => { update_policy_combo.value = data; }); update_policy_combo.addEventListener('change', function (event) { - api.fetchApi(`/manager/policy/update?value=${event.target.value}`); + api.fetchApi(`/v2/manager/policy/update?value=${event.target.value}`); }); return [ @@ -1388,12 +1390,12 @@ class ManagerMenuDialog extends ComfyDialog { } async function getVersion() { - let version = await api.fetchApi(`/manager/version`); + let version = await api.fetchApi(`/v2/manager/version`); return await version.text(); } app.registerExtension({ - name: "Comfy.ManagerMenu", + name: "Comfy.Legacy.ManagerMenu", aboutPageBadges: [ { @@ -1525,7 +1527,10 @@ app.registerExtension({ }).element ); - app.menu?.settingsGroup.element.before(cmGroup.element); + const shouldShowLegacyMenuItems = !isNewManagerUI(); + if (shouldShowLegacyMenuItems) { + app.menu?.settingsGroup.element.before(cmGroup.element); + } } catch(exception) { console.log('ComfyUI is outdated. New style menu based features are disabled.'); diff --git a/js/comfyui-share-common.js b/comfyui_manager/js/comfyui-share-common.js similarity index 99% rename from js/comfyui-share-common.js rename to comfyui_manager/js/comfyui-share-common.js index e6f3e1039..9b570b8a0 100644 --- a/js/comfyui-share-common.js +++ b/comfyui_manager/js/comfyui-share-common.js @@ -172,7 +172,7 @@ export const shareToEsheep= () => { const nodes = app.graph._nodes const { potential_outputs, potential_output_nodes } = getPotentialOutputsAndOutputNodes(nodes); const workflow = prompt['workflow'] - api.fetchApi(`/manager/set_esheep_workflow_and_images`, { + api.fetchApi(`/v2/manager/set_esheep_workflow_and_images`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -812,7 +812,7 @@ export class ShareDialog extends ComfyDialog { // get the user's existing matrix auth and share key ShareDialog.matrix_auth = { homeserver: "matrix.org", username: "", password: "" }; try { - api.fetchApi(`/manager/get_matrix_auth`) + api.fetchApi(`/v2/manager/get_matrix_auth`) .then(response => response.json()) .then(data => { ShareDialog.matrix_auth = data; @@ -831,7 +831,7 @@ export class ShareDialog extends ComfyDialog { ShareDialog.cw_sharekey = ""; try { // console.log("Fetching comfyworkflows share key") - api.fetchApi(`/manager/get_comfyworkflows_auth`) + api.fetchApi(`/v2/manager/get_comfyworkflows_auth`) .then(response => response.json()) .then(data => { ShareDialog.cw_sharekey = data.comfyworkflows_sharekey; @@ -891,7 +891,7 @@ export class ShareDialog extends ComfyDialog { // Change the text of the share button to "Sharing..." to indicate that the share process has started this.share_button.textContent = "Sharing..."; - const response = await api.fetchApi(`/manager/share`, { + const response = await api.fetchApi(`/v2/manager/share`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/js/comfyui-share-copus.js b/comfyui_manager/js/comfyui-share-copus.js similarity index 100% rename from js/comfyui-share-copus.js rename to comfyui_manager/js/comfyui-share-copus.js diff --git a/js/comfyui-share-openart.js b/comfyui_manager/js/comfyui-share-openart.js similarity index 98% rename from js/comfyui-share-openart.js rename to comfyui_manager/js/comfyui-share-openart.js index 1c96a8c73..d867d4d79 100644 --- a/js/comfyui-share-openart.js +++ b/comfyui_manager/js/comfyui-share-openart.js @@ -67,7 +67,7 @@ export class OpenArtShareDialog extends ComfyDialog { async readKey() { let key = "" try { - key = await api.fetchApi(`/manager/get_openart_auth`) + key = await api.fetchApi(`/v2/manager/get_openart_auth`) .then(response => response.json()) .then(data => { return data.openart_key; @@ -82,7 +82,7 @@ export class OpenArtShareDialog extends ComfyDialog { } async saveKey(value) { - await api.fetchApi(`/manager/set_openart_auth`, { + await api.fetchApi(`/v2/manager/set_openart_auth`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ @@ -399,7 +399,7 @@ export class OpenArtShareDialog extends ComfyDialog { form.append("file", uploadFile); try { const res = await this.fetchApi( - `/workflows/upload_thumbnail`, + `/v2/workflows/upload_thumbnail`, { method: "POST", body: form, @@ -459,7 +459,7 @@ export class OpenArtShareDialog extends ComfyDialog { throw new Error("Title is required"); } - const current_snapshot = await api.fetchApi(`/snapshot/get_current`) + const current_snapshot = await api.fetchApi(`/v2/snapshot/get_current`) .then(response => response.json()) .catch(error => { // console.log(error); @@ -489,7 +489,7 @@ export class OpenArtShareDialog extends ComfyDialog { try { const response = await this.fetchApi( - "/workflows/publish", + "/v2/workflows/publish", { method: "POST", headers: {"Content-Type": "application/json"}, diff --git a/js/comfyui-share-youml.js b/comfyui_manager/js/comfyui-share-youml.js similarity index 98% rename from js/comfyui-share-youml.js rename to comfyui_manager/js/comfyui-share-youml.js index efd8916f6..20dc8a2e4 100644 --- a/js/comfyui-share-youml.js +++ b/comfyui_manager/js/comfyui-share-youml.js @@ -179,7 +179,7 @@ export class YouMLShareDialog extends ComfyDialog { async loadToken() { let key = "" try { - const response = await api.fetchApi(`/manager/youml/settings`) + const response = await api.fetchApi(`/v2/manager/youml/settings`) const settings = await response.json() return settings.token } catch (error) { @@ -188,7 +188,7 @@ export class YouMLShareDialog extends ComfyDialog { } async saveToken(value) { - await api.fetchApi(`/manager/youml/settings`, { + await api.fetchApi(`/v2/manager/youml/settings`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ @@ -380,7 +380,7 @@ export class YouMLShareDialog extends ComfyDialog { try { let snapshotData = null; try { - const snapshot = await api.fetchApi(`/snapshot/get_current`) + const snapshot = await api.fetchApi(`/v2/snapshot/get_current`) snapshotData = await snapshot.json() } catch (e) { console.error("Failed to get snapshot", e) diff --git a/js/common.js b/comfyui_manager/js/common.js similarity index 99% rename from js/common.js rename to comfyui_manager/js/common.js index 71cf58ea5..7617ab59a 100644 --- a/js/common.js +++ b/comfyui_manager/js/common.js @@ -172,7 +172,7 @@ export function rebootAPI() { customConfirm("Are you sure you'd like to reboot the server?").then((isConfirmed) => { if (isConfirmed) { try { - api.fetchApi("/manager/reboot"); + api.fetchApi("/v2/manager/reboot"); } catch(exception) {} } @@ -210,7 +210,7 @@ export async function install_pip(packages) { if(packages.includes('&')) app.ui.dialog.show(`Invalid PIP package enumeration: '${packages}'`); - const res = await api.fetchApi("/customnode/install/pip", { + const res = await api.fetchApi("/v2/customnode/install/pip", { method: "POST", body: packages, }); @@ -245,7 +245,7 @@ export async function install_via_git_url(url, manager_dialog) { show_message(`Wait...

Installing '${url}'`); - const res = await api.fetchApi("/customnode/install/git_url", { + const res = await api.fetchApi("/v2/customnode/install/git_url", { method: "POST", body: url, }); diff --git a/js/components-manager.js b/comfyui_manager/js/components-manager.js similarity index 98% rename from js/components-manager.js rename to comfyui_manager/js/components-manager.js index 9244d2a48..551c11f50 100644 --- a/js/components-manager.js +++ b/comfyui_manager/js/components-manager.js @@ -64,7 +64,7 @@ function storeGroupNode(name, data, register=true) { } export async function load_components() { - let data = await api.fetchApi('/manager/component/loads', {method: "POST"}); + let data = await api.fetchApi('/v2/manager/component/loads', {method: "POST"}); let components = await data.json(); let start_time = Date.now(); @@ -222,7 +222,7 @@ async function save_as_component(node, version, author, prefix, nodename, packna pack_map[packname] = component_name; rpack_map[component_name] = subgraph; - const res = await api.fetchApi('/manager/component/save', { + const res = await api.fetchApi('/v2/manager/component/save', { method: "POST", headers: { "Content-Type": "application/json", @@ -259,7 +259,7 @@ async function import_component(component_name, component, mode) { workflow: component }; - const res = await api.fetchApi('/manager/component/save', { + const res = await api.fetchApi('/v2/manager/component/save', { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(body) @@ -709,7 +709,7 @@ app.handleFile = handleFile; let current_component_policy = 'workflow'; try { - api.fetchApi('/manager/policy/component') + api.fetchApi('/v2/manager/policy/component') .then(response => response.text()) .then(data => { current_component_policy = data; }); } diff --git a/js/custom-nodes-manager.css b/comfyui_manager/js/custom-nodes-manager.css similarity index 100% rename from js/custom-nodes-manager.css rename to comfyui_manager/js/custom-nodes-manager.css diff --git a/js/custom-nodes-manager.js b/comfyui_manager/js/custom-nodes-manager.js similarity index 98% rename from js/custom-nodes-manager.js rename to comfyui_manager/js/custom-nodes-manager.js index a42e018e6..7c11aa91e 100644 --- a/js/custom-nodes-manager.js +++ b/comfyui_manager/js/custom-nodes-manager.js @@ -66,7 +66,7 @@ export class CustomNodesManager { this.id = "cn-manager"; app.registerExtension({ - name: "Comfy.CustomNodesManager", + name: "Comfy.Legacy.CustomNodesManager", afterConfigureGraph: (missingNodeTypes) => { const item = this.getFilterItem(ShowMode.MISSING); if (item) { @@ -459,7 +459,7 @@ export class CustomNodesManager { ".cn-manager-stop": { click: () => { - api.fetchApi('/manager/queue/reset'); + api.fetchApi('/v2/manager/queue/reset'); infoToast('Cancel', 'Remaining tasks will stop after completing the current task.'); } }, @@ -635,7 +635,7 @@ export class CustomNodesManager { }; } - const response = await api.fetchApi(`/customnode/import_fail_info`, { + const response = await api.fetchApi(`/v2/customnode/import_fail_info`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(info) @@ -1243,7 +1243,7 @@ export class CustomNodesManager { async loadNodes(node_packs) { const mode = manager_instance.datasrc_combo.value; this.showStatus(`Loading node mappings (${mode}) ...`); - const res = await fetchData(`/customnode/getmappings?mode=${mode}`); + const res = await fetchData(`/v2/customnode/getmappings?mode=${mode}`); if (res.error) { console.log(res.error); return; @@ -1395,10 +1395,10 @@ export class CustomNodesManager { this.showLoading(); let res; if(is_enable) { - res = await api.fetchApi(`/customnode/disabled_versions/${node_id}`, { cache: "no-store" }); + res = await api.fetchApi(`/v2/customnode/disabled_versions/${node_id}`, { cache: "no-store" }); } else { - res = await api.fetchApi(`/customnode/versions/${node_id}`, { cache: "no-store" }); + res = await api.fetchApi(`/v2/customnode/versions/${node_id}`, { cache: "no-store" }); } this.hideLoading(); @@ -1439,7 +1439,7 @@ export class CustomNodesManager { } async installNodes(list, btn, title, selected_version) { - let stats = await api.fetchApi('/manager/queue/status'); + let stats = await api.fetchApi('/v2/manager/queue/status'); stats = await stats.json(); if(stats.is_processing) { customAlert(`[ComfyUI-Manager] There are already tasks in progress. Please try again after it is completed. (${stats.done_count}/${stats.total_count})`); @@ -1472,7 +1472,7 @@ export class CustomNodesManager { let needRestart = false; let errorMsg = ""; - await api.fetchApi('/manager/queue/reset'); + await api.fetchApi('/v2/manager/queue/reset'); let target_items = []; @@ -1517,7 +1517,7 @@ export class CustomNodesManager { api_mode = 'reinstall'; } - const res = await api.fetchApi(`/manager/queue/${api_mode}`, { + const res = await api.fetchApi(`/v2/manager/queue/${api_mode}`, { method: 'POST', body: JSON.stringify(data) }); @@ -1550,7 +1550,7 @@ export class CustomNodesManager { } } else { - await api.fetchApi('/manager/queue/start'); + await api.fetchApi('/v2/manager/queue/start'); this.showStop(); showTerminal(); } @@ -1558,6 +1558,9 @@ export class CustomNodesManager { async onQueueStatus(event) { let self = CustomNodesManager.instance; + // If legacy manager front is not open, return early (using new manager front) + if (self.element?.style.display === 'none') return + if(event.detail.status == 'in_progress' && event.detail.ui_target == 'nodepack_manager') { const hash = event.detail.target; @@ -1744,7 +1747,7 @@ export class CustomNodesManager { async getMissingNodesLegacy(hashMap, missing_nodes) { const mode = manager_instance.datasrc_combo.value; this.showStatus(`Loading missing nodes (${mode}) ...`); - const res = await fetchData(`/customnode/getmappings?mode=${mode}`); + const res = await fetchData(`/v2/customnode/getmappings?mode=${mode}`); if (res.error) { this.showError(`Failed to get custom node mappings: ${res.error}`); return; @@ -1859,7 +1862,7 @@ export class CustomNodesManager { async getAlternatives() { const mode = manager_instance.datasrc_combo.value; this.showStatus(`Loading alternatives (${mode}) ...`); - const res = await fetchData(`/customnode/alternatives?mode=${mode}`); + const res = await fetchData(`/v2/customnode/alternatives?mode=${mode}`); if (res.error) { this.showError(`Failed to get alternatives: ${res.error}`); return []; @@ -1907,7 +1910,7 @@ export class CustomNodesManager { infoToast('Fetching updated information. This may take some time if many custom nodes are installed.'); } - const res = await fetchData(`/customnode/getlist?mode=${mode}${skip_update}`); + const res = await fetchData(`/v2/customnode/getlist?mode=${mode}${skip_update}`); if (res.error) { this.showError("Failed to get custom node list."); this.hideLoading(); diff --git a/js/model-manager.css b/comfyui_manager/js/model-manager.css similarity index 100% rename from js/model-manager.css rename to comfyui_manager/js/model-manager.css diff --git a/js/model-manager.js b/comfyui_manager/js/model-manager.js similarity index 98% rename from js/model-manager.js rename to comfyui_manager/js/model-manager.js index d744a34df..f7586f1e5 100644 --- a/js/model-manager.js +++ b/comfyui_manager/js/model-manager.js @@ -172,7 +172,7 @@ export class ModelManager { ".cmm-manager-stop": { click: () => { - api.fetchApi('/manager/queue/reset'); + api.fetchApi('/v2/manager/queue/reset'); infoToast('Cancel', 'Remaining tasks will stop after completing the current task.'); } }, @@ -413,7 +413,7 @@ export class ModelManager { } async installModels(list, btn) { - let stats = await api.fetchApi('/manager/queue/status'); + let stats = await api.fetchApi('/v2/manager/queue/status'); stats = await stats.json(); if(stats.is_processing) { @@ -427,7 +427,7 @@ export class ModelManager { let needRefresh = false; let errorMsg = ""; - await api.fetchApi('/manager/queue/reset'); + await api.fetchApi('/v2/manager/queue/reset'); let target_items = []; @@ -446,7 +446,7 @@ export class ModelManager { const data = item.originalData; data.ui_id = item.hash; - const res = await api.fetchApi(`/manager/queue/install_model`, { + const res = await api.fetchApi(`/v2/manager/queue/install_model`, { method: 'POST', body: JSON.stringify(data) }); @@ -477,7 +477,7 @@ export class ModelManager { } } else { - await api.fetchApi('/manager/queue/start'); + await api.fetchApi('/v2/manager/queue/start'); this.showStop(); showTerminal(); } @@ -623,7 +623,7 @@ export class ModelManager { const mode = manager_instance.datasrc_combo.value; - const res = await fetchData(`/externalmodel/getlist?mode=${mode}`); + const res = await fetchData(`/v2/externalmodel/getlist?mode=${mode}`); if (res.error) { this.showError("Failed to get external model list."); this.hideLoading(); diff --git a/js/node_fixer.js b/comfyui_manager/js/node_fixer.js similarity index 98% rename from js/node_fixer.js rename to comfyui_manager/js/node_fixer.js index feec1cad5..e7ae2e3d8 100644 --- a/js/node_fixer.js +++ b/comfyui_manager/js/node_fixer.js @@ -142,7 +142,7 @@ function node_info_copy(src, dest, connect_both, copy_shape) { } app.registerExtension({ - name: "Comfy.Manager.NodeFixer", + name: "Comfy.Legacy.Manager.NodeFixer", beforeRegisterNodeDef(nodeType, nodeData, app) { addMenuHandler(nodeType, function (_, options) { options.push({ diff --git a/js/popover-helper.js b/comfyui_manager/js/popover-helper.js similarity index 100% rename from js/popover-helper.js rename to comfyui_manager/js/popover-helper.js diff --git a/js/snapshot.js b/comfyui_manager/js/snapshot.js similarity index 95% rename from js/snapshot.js rename to comfyui_manager/js/snapshot.js index 520ca6150..9a5835f2d 100644 --- a/js/snapshot.js +++ b/comfyui_manager/js/snapshot.js @@ -7,7 +7,7 @@ import { manager_instance, rebootAPI, show_message } from "./common.js"; async function restore_snapshot(target) { if(SnapshotManager.instance) { try { - const response = await api.fetchApi(`/snapshot/restore?target=${target}`, { cache: "no-store" }); + const response = await api.fetchApi(`/v2/snapshot/restore?target=${target}`, { cache: "no-store" }); if(response.status == 403) { show_message('This action is not allowed with this security level configuration.'); @@ -35,7 +35,7 @@ async function restore_snapshot(target) { async function remove_snapshot(target) { if(SnapshotManager.instance) { try { - const response = await api.fetchApi(`/snapshot/remove?target=${target}`, { cache: "no-store" }); + const response = await api.fetchApi(`/v2/snapshot/remove?target=${target}`, { cache: "no-store" }); if(response.status == 403) { show_message('This action is not allowed with this security level configuration.'); @@ -61,7 +61,7 @@ async function remove_snapshot(target) { async function save_current_snapshot() { try { - const response = await api.fetchApi('/snapshot/save', { cache: "no-store" }); + const response = await api.fetchApi('/v2/snapshot/save', { cache: "no-store" }); app.ui.dialog.close(); return true; } @@ -76,7 +76,7 @@ async function save_current_snapshot() { } async function getSnapshotList() { - const response = await api.fetchApi(`/snapshot/getlist`); + const response = await api.fetchApi(`/v2/snapshot/getlist`); const data = await response.json(); return data; } diff --git a/js/turbogrid.esm.js b/comfyui_manager/js/turbogrid.esm.js similarity index 100% rename from js/turbogrid.esm.js rename to comfyui_manager/js/turbogrid.esm.js diff --git a/js/workflow-metadata.js b/comfyui_manager/js/workflow-metadata.js similarity index 97% rename from js/workflow-metadata.js rename to comfyui_manager/js/workflow-metadata.js index 9bbf690b6..0f650df72 100644 --- a/js/workflow-metadata.js +++ b/comfyui_manager/js/workflow-metadata.js @@ -38,7 +38,7 @@ class WorkflowMetadataExtension { * enabled is true if the node is enabled, false if it is disabled */ async getInstalledNodes() { - const res = await api.fetchApi("/customnode/installed"); + const res = await api.fetchApi("/v2/customnode/installed"); return await res.json(); } diff --git a/prestartup_script.py b/comfyui_manager/prestartup_script.py similarity index 97% rename from prestartup_script.py rename to comfyui_manager/prestartup_script.py index e90f5d9d1..2e29ed65e 100644 --- a/prestartup_script.py +++ b/comfyui_manager/prestartup_script.py @@ -12,13 +12,10 @@ import logging import traceback -glob_path = os.path.join(os.path.dirname(__file__), "glob") -sys.path.append(glob_path) - -import security_check -import manager_util -import cm_global -import manager_downloader +from .glob import security_check +from .glob import manager_util +from .glob import cm_global +from .glob import manager_downloader import folder_paths manager_util.add_python_path_to_env() @@ -68,15 +65,17 @@ def is_import_failed_extension(name): comfy_base_path = os.environ.get('COMFYUI_FOLDERS_BASE_PATH') if comfy_path is None: - # legacy env var - comfy_path = os.environ.get('COMFYUI_PATH') - -if comfy_path is None: - comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__)) + try: + comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__)) + os.environ['COMFYUI_PATH'] = comfy_path + except: + print("[ComfyUI-Manager] environment variable 'COMFYUI_PATH' is not specified.") + exit(-1) if comfy_base_path is None: comfy_base_path = comfy_path + sys.__comfyui_manager_register_message_collapse = register_message_collapse sys.__comfyui_manager_is_import_failed_extension = is_import_failed_extension cm_global.register_api('cm.register_message_collapse', register_message_collapse) @@ -121,12 +120,11 @@ def check_file_logging(): read_uv_mode() check_file_logging() -cm_global.pip_overrides = {'numpy': 'numpy<2', 'ultralytics': 'ultralytics==8.3.40'} +cm_global.pip_overrides = {'numpy': 'numpy<2'} if os.path.exists(manager_pip_overrides_path): with open(manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file: cm_global.pip_overrides = json.load(json_file) cm_global.pip_overrides['numpy'] = 'numpy<2' - cm_global.pip_overrides['ultralytics'] = 'ultralytics==8.3.40' # for security if os.path.exists(manager_pip_blacklist_path): @@ -393,7 +391,11 @@ class LoggingHandler(logging.Handler): def emit(self, record): global is_start_mode - message = record.getMessage() + try: + message = record.getMessage() + except Exception as e: + message = f"<>: {record} - {e}" + original_stderr.write(message) if is_start_mode: match = re.search(pat_import_fail, message) diff --git a/notebooks/comfyui_colab_with_manager.ipynb b/notebooks/comfyui_colab_with_manager.ipynb deleted file mode 100644 index 3cfa484b9..000000000 --- a/notebooks/comfyui_colab_with_manager.ipynb +++ /dev/null @@ -1,373 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "aaaaaaaaaa" - }, - "source": [ - "Git clone the repo and install the requirements. (ignore the pip errors about protobuf)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "bbbbbbbbbb" - }, - "outputs": [], - "source": [ - "# #@title Environment Setup\n", - "\n", - "from pathlib import Path\n", - "\n", - "OPTIONS = {}\n", - "\n", - "USE_GOOGLE_DRIVE = True #@param {type:\"boolean\"}\n", - "UPDATE_COMFY_UI = True #@param {type:\"boolean\"}\n", - "USE_COMFYUI_MANAGER = True #@param {type:\"boolean\"}\n", - "INSTALL_CUSTOM_NODES_DEPENDENCIES = True #@param {type:\"boolean\"}\n", - "OPTIONS['USE_GOOGLE_DRIVE'] = USE_GOOGLE_DRIVE\n", - "OPTIONS['UPDATE_COMFY_UI'] = UPDATE_COMFY_UI\n", - "OPTIONS['USE_COMFYUI_MANAGER'] = USE_COMFYUI_MANAGER\n", - "OPTIONS['INSTALL_CUSTOM_NODES_DEPENDENCIES'] = INSTALL_CUSTOM_NODES_DEPENDENCIES\n", - "\n", - "current_dir = !pwd\n", - "WORKSPACE = f\"{current_dir[0]}/ComfyUI\"\n", - "\n", - "if OPTIONS['USE_GOOGLE_DRIVE']:\n", - " !echo \"Mounting Google Drive...\"\n", - " %cd /\n", - "\n", - " from google.colab import drive\n", - " drive.mount('/content/drive')\n", - "\n", - " WORKSPACE = \"/content/drive/MyDrive/ComfyUI\"\n", - " %cd /content/drive/MyDrive\n", - "\n", - "![ ! -d $WORKSPACE ] && echo -= Initial setup ComfyUI =- && git clone https://github.com/comfyanonymous/ComfyUI\n", - "%cd $WORKSPACE\n", - "\n", - "if OPTIONS['UPDATE_COMFY_UI']:\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", - "\n", - "!echo -= Install dependencies =-\n", - "!pip3 install accelerate\n", - "!pip3 install einops transformers>=4.28.1 safetensors>=0.4.2 aiohttp pyyaml Pillow scipy tqdm psutil tokenizers>=0.13.3\n", - "!pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121\n", - "!pip3 install torchsde\n", - "!pip3 install kornia>=0.7.1 spandrel soundfile sentencepiece\n", - "\n", - "if OPTIONS['USE_COMFYUI_MANAGER']:\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/node_db/tutorial/scan.sh\" ] && chmod 755 ComfyUI-Manager/node_db/tutorial/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", - " %cd ComfyUI-Manager\n", - " !git pull\n", - "\n", - "%cd $WORKSPACE\n", - "\n", - "if OPTIONS['INSTALL_CUSTOM_NODES_DEPENDENCIES']:\n", - " !echo -= Install custom nodes dependencies =-\n", - " !pip install GitPython\n", - " !python custom_nodes/ComfyUI-Manager/cm-cli.py restore-dependencies\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "cccccccccc" - }, - "source": [ - "Download some models/checkpoints/vae or custom comfyui nodes (uncomment the commands for the ones you want)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "dddddddddd" - }, - "outputs": [], - "source": [ - "# Checkpoints\n", - "\n", - "### SDXL\n", - "### I recommend these workflow examples: https://comfyanonymous.github.io/ComfyUI_examples/sdxl/\n", - "\n", - "#!wget -c https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors -P ./models/checkpoints/\n", - "#!wget -c https://huggingface.co/stabilityai/stable-diffusion-xl-refiner-1.0/resolve/main/sd_xl_refiner_1.0.safetensors -P ./models/checkpoints/\n", - "\n", - "# SDXL ReVision\n", - "#!wget -c https://huggingface.co/comfyanonymous/clip_vision_g/resolve/main/clip_vision_g.safetensors -P ./models/clip_vision/\n", - "\n", - "# SD1.5\n", - "!wget -c https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.ckpt -P ./models/checkpoints/\n", - "\n", - "# SD2\n", - "#!wget -c https://huggingface.co/stabilityai/stable-diffusion-2-1-base/resolve/main/v2-1_512-ema-pruned.safetensors -P ./models/checkpoints/\n", - "#!wget -c https://huggingface.co/stabilityai/stable-diffusion-2-1/resolve/main/v2-1_768-ema-pruned.safetensors -P ./models/checkpoints/\n", - "\n", - "# Some SD1.5 anime style\n", - "#!wget -c https://huggingface.co/WarriorMama777/OrangeMixs/resolve/main/Models/AbyssOrangeMix2/AbyssOrangeMix2_hard.safetensors -P ./models/checkpoints/\n", - "#!wget -c https://huggingface.co/WarriorMama777/OrangeMixs/resolve/main/Models/AbyssOrangeMix3/AOM3A1_orangemixs.safetensors -P ./models/checkpoints/\n", - "#!wget -c https://huggingface.co/WarriorMama777/OrangeMixs/resolve/main/Models/AbyssOrangeMix3/AOM3A3_orangemixs.safetensors -P ./models/checkpoints/\n", - "#!wget -c https://huggingface.co/Linaqruf/anything-v3.0/resolve/main/anything-v3-fp16-pruned.safetensors -P ./models/checkpoints/\n", - "\n", - "# Waifu Diffusion 1.5 (anime style SD2.x 768-v)\n", - "#!wget -c https://huggingface.co/waifu-diffusion/wd-1-5-beta3/resolve/main/wd-illusion-fp16.safetensors -P ./models/checkpoints/\n", - "\n", - "\n", - "# unCLIP models\n", - "#!wget -c https://huggingface.co/comfyanonymous/illuminatiDiffusionV1_v11_unCLIP/resolve/main/illuminatiDiffusionV1_v11-unclip-h-fp16.safetensors -P ./models/checkpoints/\n", - "#!wget -c https://huggingface.co/comfyanonymous/wd-1.5-beta2_unCLIP/resolve/main/wd-1-5-beta2-aesthetic-unclip-h-fp16.safetensors -P ./models/checkpoints/\n", - "\n", - "\n", - "# VAE\n", - "!wget -c https://huggingface.co/stabilityai/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.safetensors -P ./models/vae/\n", - "#!wget -c https://huggingface.co/WarriorMama777/OrangeMixs/resolve/main/VAEs/orangemix.vae.pt -P ./models/vae/\n", - "#!wget -c https://huggingface.co/hakurei/waifu-diffusion-v1-4/resolve/main/vae/kl-f8-anime2.ckpt -P ./models/vae/\n", - "\n", - "\n", - "# Loras\n", - "#!wget -c https://civitai.com/api/download/models/10350 -O ./models/loras/theovercomer8sContrastFix_sd21768.safetensors #theovercomer8sContrastFix SD2.x 768-v\n", - "#!wget -c https://civitai.com/api/download/models/10638 -O ./models/loras/theovercomer8sContrastFix_sd15.safetensors #theovercomer8sContrastFix SD1.x\n", - "#!wget -c https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_offset_example-lora_1.0.safetensors -P ./models/loras/ #SDXL offset noise lora\n", - "\n", - "\n", - "# T2I-Adapter\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_depth_sd14v1.pth -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_seg_sd14v1.pth -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_sketch_sd14v1.pth -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_keypose_sd14v1.pth -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_openpose_sd14v1.pth -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_color_sd14v1.pth -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_canny_sd14v1.pth -P ./models/controlnet/\n", - "\n", - "# T2I Styles Model\n", - "#!wget -c https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_style_sd14v1.pth -P ./models/style_models/\n", - "\n", - "# CLIPVision model (needed for styles model)\n", - "#!wget -c https://huggingface.co/openai/clip-vit-large-patch14/resolve/main/pytorch_model.bin -O ./models/clip_vision/clip_vit14.bin\n", - "\n", - "\n", - "# ControlNet\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11e_sd15_ip2p_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11e_sd15_shuffle_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_canny_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11f1p_sd15_depth_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_inpaint_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_lineart_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_mlsd_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_normalbae_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_openpose_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_scribble_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_seg_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_softedge_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15s2_lineart_anime_fp16.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11u_sd15_tile_fp16.safetensors -P ./models/controlnet/\n", - "\n", - "# ControlNet SDXL\n", - "#!wget -c https://huggingface.co/stabilityai/control-lora/resolve/main/control-LoRAs-rank256/control-lora-canny-rank256.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/stabilityai/control-lora/resolve/main/control-LoRAs-rank256/control-lora-depth-rank256.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/stabilityai/control-lora/resolve/main/control-LoRAs-rank256/control-lora-recolor-rank256.safetensors -P ./models/controlnet/\n", - "#!wget -c https://huggingface.co/stabilityai/control-lora/resolve/main/control-LoRAs-rank256/control-lora-sketch-rank256.safetensors -P ./models/controlnet/\n", - "\n", - "# Controlnet Preprocessor nodes by Fannovel16\n", - "#!cd custom_nodes && git clone https://github.com/Fannovel16/comfy_controlnet_preprocessors; cd comfy_controlnet_preprocessors && python install.py\n", - "\n", - "\n", - "# GLIGEN\n", - "#!wget -c https://huggingface.co/comfyanonymous/GLIGEN_pruned_safetensors/resolve/main/gligen_sd14_textbox_pruned_fp16.safetensors -P ./models/gligen/\n", - "\n", - "\n", - "# ESRGAN upscale model\n", - "#!wget -c https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P ./models/upscale_models/\n", - "#!wget -c https://huggingface.co/sberbank-ai/Real-ESRGAN/resolve/main/RealESRGAN_x2.pth -P ./models/upscale_models/\n", - "#!wget -c https://huggingface.co/sberbank-ai/Real-ESRGAN/resolve/main/RealESRGAN_x4.pth -P ./models/upscale_models/\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "kkkkkkkkkkkkkkk" - }, - "source": [ - "### Run ComfyUI with cloudflared (Recommended Way)\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "jjjjjjjjjjjjjj" - }, - "outputs": [], - "source": [ - "!wget -P ~ https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb\n", - "!dpkg -i ~/cloudflared-linux-amd64.deb\n", - "\n", - "import subprocess\n", - "import threading\n", - "import time\n", - "import socket\n", - "import urllib.request\n", - "\n", - "def iframe_thread(port):\n", - " while True:\n", - " time.sleep(0.5)\n", - " sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n", - " result = sock.connect_ex(('127.0.0.1', port))\n", - " if result == 0:\n", - " break\n", - " sock.close()\n", - " print(\"\\nComfyUI finished loading, trying to launch cloudflared (if it gets stuck here cloudflared is having issues)\\n\")\n", - "\n", - " p = subprocess.Popen([\"cloudflared\", \"tunnel\", \"--url\", \"http://127.0.0.1:{}\".format(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n", - " for line in p.stderr:\n", - " l = line.decode()\n", - " if \"trycloudflare.com \" in l:\n", - " print(\"This is the URL to access ComfyUI:\", l[l.find(\"http\"):], end='')\n", - " #print(l, end='')\n", - "\n", - "\n", - "threading.Thread(target=iframe_thread, daemon=True, args=(8188,)).start()\n", - "\n", - "!python main.py --dont-print-server" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "kkkkkkkkkkkkkk" - }, - "source": [ - "### Run ComfyUI with localtunnel\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "jjjjjjjjjjjjj" - }, - "outputs": [], - "source": [ - "!npm install -g localtunnel\n", - "\n", - "import subprocess\n", - "import threading\n", - "import time\n", - "import socket\n", - "import urllib.request\n", - "\n", - "def iframe_thread(port):\n", - " while True:\n", - " time.sleep(0.5)\n", - " sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n", - " result = sock.connect_ex(('127.0.0.1', port))\n", - " if result == 0:\n", - " break\n", - " sock.close()\n", - " print(\"\\nComfyUI finished loading, trying to launch localtunnel (if it gets stuck here localtunnel is having issues)\\n\")\n", - "\n", - " print(\"The password/enpoint ip for localtunnel is:\", urllib.request.urlopen('https://ipv4.icanhazip.com').read().decode('utf8').strip(\"\\n\"))\n", - " p = subprocess.Popen([\"lt\", \"--port\", \"{}\".format(port)], stdout=subprocess.PIPE)\n", - " for line in p.stdout:\n", - " print(line.decode(), end='')\n", - "\n", - "\n", - "threading.Thread(target=iframe_thread, daemon=True, args=(8188,)).start()\n", - "\n", - "!python main.py --dont-print-server" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "gggggggggg" - }, - "source": [ - "### Run ComfyUI with colab iframe (use only in case the previous way with localtunnel doesn't work)\n", - "\n", - "You should see the ui appear in an iframe. If you get a 403 error, it's your firefox settings or an extension that's messing things up.\n", - "\n", - "If you want to open it in another window use the link.\n", - "\n", - "Note that some UI features like live image previews won't work because the colab iframe blocks websockets." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "hhhhhhhhhh" - }, - "outputs": [], - "source": [ - "import threading\n", - "import time\n", - "import socket\n", - "def iframe_thread(port):\n", - " while True:\n", - " time.sleep(0.5)\n", - " sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n", - " result = sock.connect_ex(('127.0.0.1', port))\n", - " if result == 0:\n", - " break\n", - " sock.close()\n", - " from google.colab import output\n", - " output.serve_kernel_port_as_iframe(port, height=1024)\n", - " print(\"to open it in a window you can open this link here:\")\n", - " output.serve_kernel_port_as_window(port)\n", - "\n", - "threading.Thread(target=iframe_thread, daemon=True, args=(8188,)).start()\n", - "\n", - "!python main.py --dont-print-server" - ] - } - ], - "metadata": { - "accelerator": "GPU", - "colab": { - "provenance": [] - }, - "gpuClass": "standard", - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "name": "python" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/pyproject.toml b/pyproject.toml index 96948d17f..f970c4d93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,62 @@ +[build-system] +requires = ["setuptools >= 61.0"] +build-backend = "setuptools.build_meta" + [project] name = "comfyui-manager" +license = { text = "GPL-3.0-only" } +version = "4.0" +requires-python = ">= 3.9" description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI." -version = "3.31.9" -license = { file = "LICENSE.txt" } -dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"] +readme = "README.md" +keywords = ["comfyui", "comfyui-manager"] + +maintainers = [ + { name = "Dr.Lt.Data", email = "dr.lt.data@gmail.com" }, + { name = "Yoland Yan", email = "yoland@drip.art" }, + { name = "James Kwon", email = "hongilkwon316@gmail.com" }, + { name = "Robin Huang", email = "robin@drip.art" }, +] + +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", +] + +dependencies = [ + "GitPython", + "PyGithub", + "matrix-client==0.4.0", + "transformers", + "huggingface-hub>0.20", + "typer", + "rich", + "typing-extensions", + "toml", + "uv", + "chardet" +] + +[project.optional-dependencies] +dev = ["pre-commit", "pytest", "ruff", "pytest-cov"] [project.urls] Repository = "https://github.com/ltdrdata/ComfyUI-Manager" -# Used by Comfy Registry https://comfyregistry.org -[tool.comfy] -PublisherId = "drltdata" -DisplayName = "ComfyUI-Manager" -Icon = "" +[tool.setuptools.packages.find] +where = ["."] +include = ["comfyui_manager*"] + +[tool.ruff] +line-length = 120 +target-version = "py39" + +[tool.ruff.lint] +select = [ + "E4", # default + "E7", # default + "E9", # default + "F", # default + "I", # isort-like behavior (import statement sorting) +] diff --git a/scripts/colab-dependencies.py b/scripts/colab-dependencies.py deleted file mode 100644 index d5a70ed6d..000000000 --- a/scripts/colab-dependencies.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import subprocess - - -def get_enabled_subdirectories_with_files(base_directory): - subdirs_with_files = [] - for subdir in os.listdir(base_directory): - try: - full_path = os.path.join(base_directory, subdir) - if os.path.isdir(full_path) and not subdir.endswith(".disabled") and not subdir.startswith('.') and subdir != '__pycache__': - print(f"## Install dependencies for '{subdir}'") - requirements_file = os.path.join(full_path, "requirements.txt") - install_script = os.path.join(full_path, "install.py") - - if os.path.exists(requirements_file) or os.path.exists(install_script): - subdirs_with_files.append((full_path, requirements_file, install_script)) - except Exception as e: - print(f"EXCEPTION During Dependencies INSTALL on '{subdir}':\n{e}") - - return subdirs_with_files - - -def install_requirements(requirements_file_path): - if os.path.exists(requirements_file_path): - subprocess.run(["pip", "install", "-r", requirements_file_path]) - - -def run_install_script(install_script_path): - if os.path.exists(install_script_path): - subprocess.run(["python", install_script_path]) - - -custom_nodes_directory = "custom_nodes" -subdirs_with_files = get_enabled_subdirectories_with_files(custom_nodes_directory) - - -for subdir, requirements_file, install_script in subdirs_with_files: - install_requirements(requirements_file) - run_install_script(install_script) diff --git a/scripts/install-comfyui-venv-linux.sh b/scripts/install-comfyui-venv-linux.sh deleted file mode 100755 index 5a736ef1b..000000000 --- a/scripts/install-comfyui-venv-linux.sh +++ /dev/null @@ -1,21 +0,0 @@ -git clone https://github.com/comfyanonymous/ComfyUI -cd ComfyUI/custom_nodes -git clone https://github.com/ltdrdata/ComfyUI-Manager comfyui-manager -cd .. -python -m venv venv -source venv/bin/activate -python -m pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu121 -python -m pip install -r requirements.txt -python -m pip install -r custom_nodes/comfyui-manager/requirements.txt -cd .. -echo "#!/bin/bash" > run_gpu.sh -echo "cd ComfyUI" >> run_gpu.sh -echo "source venv/bin/activate" >> run_gpu.sh -echo "python main.py --preview-method auto" >> run_gpu.sh -chmod +x run_gpu.sh - -echo "#!/bin/bash" > run_cpu.sh -echo "cd ComfyUI" >> run_cpu.sh -echo "source venv/bin/activate" >> run_cpu.sh -echo "python main.py --preview-method auto --cpu" >> run_cpu.sh -chmod +x run_cpu.sh diff --git a/scripts/install-comfyui-venv-win.bat b/scripts/install-comfyui-venv-win.bat deleted file mode 100755 index 47470098b..000000000 --- a/scripts/install-comfyui-venv-win.bat +++ /dev/null @@ -1,17 +0,0 @@ -git clone https://github.com/comfyanonymous/ComfyUI -cd ComfyUI/custom_nodes -git clone https://github.com/ltdrdata/ComfyUI-Manager comfyui-manager -cd .. -python -m venv venv -call venv/Scripts/activate -python -m pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu121 -python -m pip install -r requirements.txt -python -m pip install -r custom_nodes/comfyui-manager/requirements.txt -cd .. -echo "cd ComfyUI" >> run_gpu.bat -echo "call venv/Scripts/activate" >> run_gpu.bat -echo "python main.py" >> run_gpu.bat - -echo "cd ComfyUI" >> run_cpu.bat -echo "call venv/Scripts/activate" >> run_cpu.bat -echo "python main.py --cpu" >> run_cpu.bat diff --git a/scripts/install-manager-for-portable-version.bat b/scripts/install-manager-for-portable-version.bat deleted file mode 100644 index 6eb58b741..000000000 --- a/scripts/install-manager-for-portable-version.bat +++ /dev/null @@ -1,3 +0,0 @@ -.\python_embeded\python.exe -s -m pip install gitpython -.\python_embeded\python.exe -c "import git; git.Repo.clone_from('https://github.com/ltdrdata/ComfyUI-Manager', './ComfyUI/custom_nodes/comfyui-manager')" -.\python_embeded\python.exe -m pip install -r ./ComfyUI/custom_nodes/comfyui-manager/requirements.txt diff --git a/snapshots/the_snapshot_files_are_located_here b/snapshots/the_snapshot_files_are_located_here deleted file mode 100644 index e69de29bb..000000000