Compare commits
32 Commits
api/openap
...
draft-v4-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78269f6467 | ||
|
|
a9fedc0487 | ||
|
|
abfd85602e | ||
|
|
1816bb748e | ||
|
|
05ceab68f8 | ||
|
|
46a37907e6 | ||
|
|
7fc8ba587e | ||
|
|
7a35bd9d9a | ||
|
|
a76ef49d2d | ||
|
|
bb0fcf6ea6 | ||
|
|
539e0a1534 | ||
|
|
aaae6ce304 | ||
|
|
3c413840d7 | ||
|
|
29ca93fcb4 | ||
|
|
9dc8e630a0 | ||
|
|
10105ad737 | ||
|
|
5738ea861a | ||
|
|
dbd25b0f0a | ||
|
|
0de9d36c28 | ||
|
|
05f1a8ab0d | ||
|
|
5ce170b7ce | ||
|
|
2b47aad076 | ||
|
|
b4dc59331d | ||
|
|
81e84fad78 | ||
|
|
42e8a959dd | ||
|
|
208ca31836 | ||
|
|
a128baf894 | ||
|
|
57b847eebf | ||
|
|
149257e4f1 | ||
|
|
212b8e7ed2 | ||
|
|
01ac9c895a | ||
|
|
ebcb14e6aa |
1
.env.example
Normal file
1
.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
PYPI_TOKEN=your-pypi-token
|
||||||
58
.github/workflows/publish-to-pypi.yml
vendored
Normal file
58
.github/workflows/publish-to-pypi.yml
vendored
Normal file
@@ -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
|
||||||
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
publish-node:
|
publish-node:
|
||||||
name: Publish Custom Node to registry
|
name: Publish Custom Node to registry
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ github.repository_owner == 'ltdrdata' }}
|
if: ${{ github.repository_owner == 'ltdrdata' || github.repository_owner == 'Comfy-Org' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -17,4 +17,7 @@ github-stats-cache.json
|
|||||||
pip_overrides.json
|
pip_overrides.json
|
||||||
*.json
|
*.json
|
||||||
check2.sh
|
check2.sh
|
||||||
/venv/
|
/venv/
|
||||||
|
build
|
||||||
|
*.egg-info
|
||||||
|
.env
|
||||||
47
CONTRIBUTING.md
Normal file
47
CONTRIBUTING.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
## Testing Changes
|
||||||
|
|
||||||
|
1. Activate the ComfyUI environment.
|
||||||
|
|
||||||
|
2. Build package locally after making changes.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# from inside the ComfyUI-Manager directory, with the ComfyUI environment activated
|
||||||
|
python -m build
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install the package locally in the ComfyUI environment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Uninstall existing package
|
||||||
|
pip uninstall comfyui-manager
|
||||||
|
|
||||||
|
# Install the locale package
|
||||||
|
pip install dist/comfyui-manager-*.whl
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Start ComfyUI.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# after navigating to the ComfyUI directory
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manually Publish Test Version to PyPi
|
||||||
|
|
||||||
|
1. Set the `PYPI_TOKEN` environment variable in env file.
|
||||||
|
|
||||||
|
2. If manually publishing, you likely want to use a release candidate version, so set the version in [pyproject.toml](pyproject.toml) to something like `0.0.1rc1`.
|
||||||
|
|
||||||
|
3. Build the package.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m build
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Upload the package to PyPi.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m twine upload dist/* --username __token__ --password $PYPI_TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
|
5. View at https://pypi.org/project/comfyui-manager/
|
||||||
13
MANIFEST.in
Normal file
13
MANIFEST.in
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
include comfyui_manager/js/*
|
||||||
|
include comfyui_manager/*.json
|
||||||
|
include comfyui_manager/glob/*
|
||||||
|
include LICENSE.txt
|
||||||
|
include README.md
|
||||||
|
include requirements.txt
|
||||||
|
include pyproject.toml
|
||||||
|
include custom-node-list.json
|
||||||
|
include extension-node-list.json
|
||||||
|
include extras.json
|
||||||
|
include github-stats.json
|
||||||
|
include model-list.json
|
||||||
|
include alter-list.json
|
||||||
81
README.md
81
README.md
@@ -5,6 +5,7 @@
|
|||||||

|

|
||||||
|
|
||||||
## NOTICE
|
## 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.16: Support for `uv` has been added. Set `use_uv` in `config.ini`.
|
||||||
* V3.10: `double-click feature` is removed
|
* V3.10: `double-click feature` is removed
|
||||||
* This feature has been moved to https://github.com/ltdrdata/comfyui-connection-helper
|
* This feature has been moved to https://github.com/ltdrdata/comfyui-connection-helper
|
||||||
@@ -13,78 +14,26 @@
|
|||||||
|
|
||||||
## Installation
|
## 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
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 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
|
* See also: https://github.com/Comfy-Org/comfy-cli
|
||||||
|
|
||||||
|
|
||||||
### Installation[method4] (Installation for linux+venv: ComfyUI + ComfyUI-Manager)
|
## Front-end
|
||||||
|
|
||||||
To install ComfyUI with ComfyUI-Manager on Linux using a venv environment, you can follow these steps:
|
* 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).
|
||||||
* **prerequisite: python-is-python3, python3-venv, git**
|
* To enable the legacy front-end, set the environment variable `ENABLE_LEGACY_COMFYUI_MANAGER_FRONT` to `true` before running.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
|
|
||||||
## How To Use
|
## How To Use
|
||||||
|
|||||||
21
__init__.py
21
__init__.py
@@ -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']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
python cm-cli.py $*
|
python ./comfyui_manager/cm-cli.py $*
|
||||||
|
|||||||
43
comfyui_manager/__init__.py
Normal file
43
comfyui_manager/__init__.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from comfy.cli_args import args
|
||||||
|
|
||||||
|
def prestartup():
|
||||||
|
from . import prestartup_script # noqa: F401
|
||||||
|
logging.info('[PRE] ComfyUI-Manager')
|
||||||
|
|
||||||
|
|
||||||
|
def start():
|
||||||
|
logging.info('[START] ComfyUI-Manager')
|
||||||
|
from .common import cm_global # noqa: F401
|
||||||
|
|
||||||
|
if not args.disable_manager:
|
||||||
|
if args.enable_manager_legacy_ui:
|
||||||
|
try:
|
||||||
|
from .legacy import manager_server # noqa: F401
|
||||||
|
from .legacy import share_3rdparty # noqa: F401
|
||||||
|
import nodes
|
||||||
|
|
||||||
|
logging.info("[ComfyUI-Manager] Legacy UI is enabled.")
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
from .glob import manager_server # noqa: F401
|
||||||
|
from .glob import share_3rdparty # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
|
def should_be_disabled(fullpath:str) -> bool:
|
||||||
|
"""
|
||||||
|
1. Disables the legacy ComfyUI-Manager.
|
||||||
|
2. The blocklist can be expanded later based on policies.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not args.disable_manager:
|
||||||
|
# In cases where installation is done via a zip archive, the directory name may not be comfyui-manager, and it may not contain a git repository.
|
||||||
|
# It is assumed that any installed legacy ComfyUI-Manager will have at least 'comfyui-manager' in its directory name.
|
||||||
|
dir_name = os.path.basename(fullpath).lower()
|
||||||
|
if 'comfyui-manager' in dir_name:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
@@ -15,31 +15,31 @@ import git
|
|||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
from .common import manager_util
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), "glob"))
|
|
||||||
|
|
||||||
import manager_util
|
|
||||||
|
|
||||||
# read env vars
|
# read env vars
|
||||||
# COMFYUI_FOLDERS_BASE_PATH is not required in cm-cli.py
|
# COMFYUI_FOLDERS_BASE_PATH is not required in cm-cli.py
|
||||||
# `comfy_path` should be resolved before importing manager_core
|
# `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, '..', '..'))
|
|
||||||
|
|
||||||
# This should be placed here
|
comfy_path = os.environ.get('COMFYUI_PATH')
|
||||||
|
|
||||||
|
if comfy_path is None:
|
||||||
|
print("[bold red]cm-cli: environment variable 'COMFYUI_PATH' is not specified.[/bold red]")
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
sys.path.append(comfy_path)
|
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 utils.extra_config
|
||||||
import cm_global
|
from .common import cm_global
|
||||||
import manager_core as core
|
from .glob import manager_core as core
|
||||||
from manager_core import unified_manager
|
from .common import context
|
||||||
import cnr_utils
|
from .glob.manager_core import unified_manager
|
||||||
|
from .common import cnr_utils
|
||||||
|
|
||||||
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
|
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ def read_downgrade_blacklist():
|
|||||||
try:
|
try:
|
||||||
import configparser
|
import configparser
|
||||||
config = configparser.ConfigParser(strict=False)
|
config = configparser.ConfigParser(strict=False)
|
||||||
config.read(core.manager_config.path)
|
config.read(context.manager_config_path)
|
||||||
default_conf = config['default']
|
default_conf = config['default']
|
||||||
|
|
||||||
if 'downgrade_blacklist' in default_conf:
|
if 'downgrade_blacklist' in default_conf:
|
||||||
@@ -142,15 +142,15 @@ class Ctx:
|
|||||||
if os.path.exists(extra_model_paths_yaml):
|
if os.path.exists(extra_model_paths_yaml):
|
||||||
utils.extra_config.load_extra_path_config(extra_model_paths_yaml)
|
utils.extra_config.load_extra_path_config(extra_model_paths_yaml)
|
||||||
|
|
||||||
core.update_user_directory(user_directory)
|
context.update_user_directory(user_directory)
|
||||||
|
|
||||||
if os.path.exists(core.manager_pip_overrides_path):
|
if os.path.exists(context.manager_pip_overrides_path):
|
||||||
with open(core.manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
with open(context.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 = json.load(json_file)
|
||||||
cm_global.pip_overrides = {'numpy': 'numpy<2'}
|
cm_global.pip_overrides = {'numpy': 'numpy<2'}
|
||||||
|
|
||||||
if os.path.exists(core.manager_pip_blacklist_path):
|
if os.path.exists(context.manager_pip_blacklist_path):
|
||||||
with open(core.manager_pip_blacklist_path, 'r', encoding="UTF-8", errors="ignore") as f:
|
with open(context.manager_pip_blacklist_path, 'r', encoding="UTF-8", errors="ignore") as f:
|
||||||
for x in f.readlines():
|
for x in f.readlines():
|
||||||
y = x.strip()
|
y = x.strip()
|
||||||
if y != '':
|
if y != '':
|
||||||
@@ -163,15 +163,15 @@ class Ctx:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_startup_scripts_path():
|
def get_startup_scripts_path():
|
||||||
return os.path.join(core.manager_startup_script_path, "install-scripts.txt")
|
return os.path.join(context.manager_startup_script_path, "install-scripts.txt")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_restore_snapshot_path():
|
def get_restore_snapshot_path():
|
||||||
return os.path.join(core.manager_startup_script_path, "restore-snapshot.json")
|
return os.path.join(context.manager_startup_script_path, "restore-snapshot.json")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_snapshot_path():
|
def get_snapshot_path():
|
||||||
return core.manager_snapshot_path
|
return context.manager_snapshot_path
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_custom_nodes_paths():
|
def get_custom_nodes_paths():
|
||||||
@@ -647,7 +647,7 @@ def install(
|
|||||||
cmd_ctx.set_channel_mode(channel, mode)
|
cmd_ctx.set_channel_mode(channel, mode)
|
||||||
cmd_ctx.set_no_deps(no_deps)
|
cmd_ctx.set_no_deps(no_deps)
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
for_each_nodes(nodes, act=install_node)
|
for_each_nodes(nodes, act=install_node)
|
||||||
pip_fixer.fix_broken()
|
pip_fixer.fix_broken()
|
||||||
|
|
||||||
@@ -685,7 +685,7 @@ def reinstall(
|
|||||||
cmd_ctx.set_channel_mode(channel, mode)
|
cmd_ctx.set_channel_mode(channel, mode)
|
||||||
cmd_ctx.set_no_deps(no_deps)
|
cmd_ctx.set_no_deps(no_deps)
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
for_each_nodes(nodes, act=reinstall_node)
|
for_each_nodes(nodes, act=reinstall_node)
|
||||||
pip_fixer.fix_broken()
|
pip_fixer.fix_broken()
|
||||||
|
|
||||||
@@ -739,7 +739,7 @@ def update(
|
|||||||
if 'all' in nodes:
|
if 'all' in nodes:
|
||||||
asyncio.run(auto_save_snapshot())
|
asyncio.run(auto_save_snapshot())
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
|
|
||||||
for x in nodes:
|
for x in nodes:
|
||||||
if x.lower() in ['comfyui', 'comfy', 'all']:
|
if x.lower() in ['comfyui', 'comfy', 'all']:
|
||||||
@@ -840,7 +840,7 @@ def fix(
|
|||||||
if 'all' in nodes:
|
if 'all' in nodes:
|
||||||
asyncio.run(auto_save_snapshot())
|
asyncio.run(auto_save_snapshot())
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
for_each_nodes(nodes, fix_node, allow_all=True)
|
for_each_nodes(nodes, fix_node, allow_all=True)
|
||||||
pip_fixer.fix_broken()
|
pip_fixer.fix_broken()
|
||||||
|
|
||||||
@@ -1117,7 +1117,7 @@ def restore_snapshot(
|
|||||||
print(f"[bold red]ERROR: `{snapshot_path}` is not exists.[/bold red]")
|
print(f"[bold red]ERROR: `{snapshot_path}` is not exists.[/bold red]")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
try:
|
try:
|
||||||
asyncio.run(core.restore_snapshot(snapshot_path, extras))
|
asyncio.run(core.restore_snapshot(snapshot_path, extras))
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -1149,7 +1149,7 @@ def restore_dependencies(
|
|||||||
total = len(node_paths)
|
total = len(node_paths)
|
||||||
i = 1
|
i = 1
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
for x in node_paths:
|
for x in node_paths:
|
||||||
print("----------------------------------------------------------------------------------------------------")
|
print("----------------------------------------------------------------------------------------------------")
|
||||||
print(f"Restoring [{i}/{total}]: {x}")
|
print(f"Restoring [{i}/{total}]: {x}")
|
||||||
@@ -1168,7 +1168,7 @@ def post_install(
|
|||||||
):
|
):
|
||||||
path = os.path.expanduser(path)
|
path = os.path.expanduser(path)
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
unified_manager.execute_install_script('', path, instant_execution=True)
|
unified_manager.execute_install_script('', path, instant_execution=True)
|
||||||
pip_fixer.fix_broken()
|
pip_fixer.fix_broken()
|
||||||
|
|
||||||
@@ -1212,7 +1212,7 @@ def install_deps(
|
|||||||
print(f"[bold red]Invalid json file: {deps}[/bold red]")
|
print(f"[bold red]Invalid json file: {deps}[/bold red]")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, core.manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, context.manager_files_path)
|
||||||
for k in json_obj['custom_nodes'].keys():
|
for k in json_obj['custom_nodes'].keys():
|
||||||
state = core.simple_check_custom_node(k)
|
state = core.simple_check_custom_node(k)
|
||||||
if state == 'installed':
|
if state == 'installed':
|
||||||
@@ -6,8 +6,9 @@ import time
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import manager_core
|
from . import context
|
||||||
import manager_util
|
from . import manager_util
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
@@ -47,9 +48,9 @@ async def _get_cnr_data(cache_mode=True, dont_wait=True):
|
|||||||
# Get ComfyUI version tag
|
# Get ComfyUI version tag
|
||||||
if is_desktop:
|
if is_desktop:
|
||||||
# extract version from pyproject.toml instead of git tag
|
# extract version from pyproject.toml instead of git tag
|
||||||
comfyui_ver = manager_core.get_current_comfyui_ver() or 'unknown'
|
comfyui_ver = context.get_current_comfyui_ver() or 'unknown'
|
||||||
else:
|
else:
|
||||||
comfyui_ver = manager_core.get_comfyui_tag() or 'unknown'
|
comfyui_ver = context.get_comfyui_tag() or 'unknown'
|
||||||
|
|
||||||
if is_desktop:
|
if is_desktop:
|
||||||
if is_windows:
|
if is_windows:
|
||||||
109
comfyui_manager/common/context.py
Normal file
109
comfyui_manager/common/context.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from . import manager_util
|
||||||
|
import toml
|
||||||
|
import git
|
||||||
|
|
||||||
|
|
||||||
|
# read env vars
|
||||||
|
comfy_path: str = os.environ.get('COMFYUI_PATH')
|
||||||
|
comfy_base_path = os.environ.get('COMFYUI_FOLDERS_BASE_PATH')
|
||||||
|
|
||||||
|
if comfy_path is None:
|
||||||
|
try:
|
||||||
|
comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__))
|
||||||
|
os.environ['COMFYUI_PATH'] = comfy_path
|
||||||
|
except:
|
||||||
|
logging.error("[ComfyUI-Manager] environment variable 'COMFYUI_PATH' is not specified.")
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
if comfy_base_path is None:
|
||||||
|
comfy_base_path = comfy_path
|
||||||
|
|
||||||
|
channel_list_template_path = os.path.join(manager_util.comfyui_manager_path, 'channels.list.template')
|
||||||
|
git_script_path = os.path.join(manager_util.comfyui_manager_path, "git_helper.py")
|
||||||
|
|
||||||
|
manager_files_path = None
|
||||||
|
manager_config_path = None
|
||||||
|
manager_channel_list_path = None
|
||||||
|
manager_startup_script_path:str = None
|
||||||
|
manager_snapshot_path = None
|
||||||
|
manager_pip_overrides_path = None
|
||||||
|
manager_pip_blacklist_path = None
|
||||||
|
manager_components_path = None
|
||||||
|
manager_batch_history_path = None
|
||||||
|
|
||||||
|
def update_user_directory(user_dir):
|
||||||
|
global manager_files_path
|
||||||
|
global manager_config_path
|
||||||
|
global manager_channel_list_path
|
||||||
|
global manager_startup_script_path
|
||||||
|
global manager_snapshot_path
|
||||||
|
global manager_pip_overrides_path
|
||||||
|
global manager_pip_blacklist_path
|
||||||
|
global manager_components_path
|
||||||
|
global manager_batch_history_path
|
||||||
|
|
||||||
|
manager_files_path = os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
|
||||||
|
if not os.path.exists(manager_files_path):
|
||||||
|
os.makedirs(manager_files_path)
|
||||||
|
|
||||||
|
manager_snapshot_path = os.path.join(manager_files_path, "snapshots")
|
||||||
|
if not os.path.exists(manager_snapshot_path):
|
||||||
|
os.makedirs(manager_snapshot_path)
|
||||||
|
|
||||||
|
manager_startup_script_path = os.path.join(manager_files_path, "startup-scripts")
|
||||||
|
if not os.path.exists(manager_startup_script_path):
|
||||||
|
os.makedirs(manager_startup_script_path)
|
||||||
|
|
||||||
|
manager_config_path = os.path.join(manager_files_path, 'config.ini')
|
||||||
|
manager_channel_list_path = os.path.join(manager_files_path, 'channels.list')
|
||||||
|
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
|
||||||
|
manager_pip_blacklist_path = os.path.join(manager_files_path, "pip_blacklist.list")
|
||||||
|
manager_components_path = os.path.join(manager_files_path, "components")
|
||||||
|
manager_util.cache_dir = os.path.join(manager_files_path, "cache")
|
||||||
|
manager_batch_history_path = os.path.join(manager_files_path, "batch_history")
|
||||||
|
|
||||||
|
if not os.path.exists(manager_util.cache_dir):
|
||||||
|
os.makedirs(manager_util.cache_dir)
|
||||||
|
|
||||||
|
if not os.path.exists(manager_batch_history_path):
|
||||||
|
os.makedirs(manager_batch_history_path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import folder_paths
|
||||||
|
update_user_directory(folder_paths.get_user_directory())
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
# fallback:
|
||||||
|
# This case is only possible when running with cm-cli, and in practice, this case is not actually used.
|
||||||
|
update_user_directory(os.path.abspath(manager_util.comfyui_manager_path))
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_comfyui_ver():
|
||||||
|
"""
|
||||||
|
Extract version from pyproject.toml
|
||||||
|
"""
|
||||||
|
toml_path = os.path.join(comfy_path, 'pyproject.toml')
|
||||||
|
if not os.path.exists(toml_path):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
with open(toml_path, "r", encoding="utf-8") as f:
|
||||||
|
data = toml.load(f)
|
||||||
|
|
||||||
|
project = data.get('project', {})
|
||||||
|
return project.get('version')
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_comfyui_tag():
|
||||||
|
try:
|
||||||
|
with git.Repo(comfy_path) as repo:
|
||||||
|
return repo.git.describe('--tags')
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
17
comfyui_manager/common/enums.py
Normal file
17
comfyui_manager/common/enums.py
Normal file
@@ -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"
|
||||||
@@ -15,9 +15,12 @@ comfy_path = os.environ.get('COMFYUI_PATH')
|
|||||||
git_exe_path = os.environ.get('GIT_EXE_PATH')
|
git_exe_path = os.environ.get('GIT_EXE_PATH')
|
||||||
|
|
||||||
if comfy_path is None:
|
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)
|
print("git_helper: environment variable 'COMFYUI_PATH' is not specified.")
|
||||||
comfy_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
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):
|
def download_url(url, dest_folder, filename=None):
|
||||||
# Ensure the destination folder exists
|
# Ensure the destination folder exists
|
||||||
@@ -18,12 +18,15 @@ import shlex
|
|||||||
|
|
||||||
|
|
||||||
cache_lock = threading.Lock()
|
cache_lock = threading.Lock()
|
||||||
|
session_lock = threading.Lock()
|
||||||
|
|
||||||
comfyui_manager_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
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**.
|
cache_dir = os.path.join(comfyui_manager_path, '.cache') # This path is also updated together in **manager_core.update_user_directory**.
|
||||||
|
|
||||||
use_uv = False
|
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():
|
def add_python_path_to_env():
|
||||||
if platform.system() != "Windows":
|
if platform.system() != "Windows":
|
||||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from git_utils import get_commit_hash
|
from .git_utils import get_commit_hash
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
0
comfyui_manager/glob/__init__.py
Normal file
0
comfyui_manager/glob/__init__.py
Normal file
@@ -23,7 +23,6 @@ import yaml
|
|||||||
import zipfile
|
import zipfile
|
||||||
import traceback
|
import traceback
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
import toml
|
|
||||||
|
|
||||||
orig_print = print
|
orig_print = print
|
||||||
|
|
||||||
@@ -32,18 +31,17 @@ from packaging import version
|
|||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
glob_path = os.path.join(os.path.dirname(__file__)) # ComfyUI-Manager/glob
|
from ..common import cm_global
|
||||||
sys.path.append(glob_path)
|
from ..common import cnr_utils
|
||||||
|
from ..common import manager_util
|
||||||
import cm_global
|
from ..common import git_utils
|
||||||
import cnr_utils
|
from ..common import manager_downloader
|
||||||
import manager_util
|
from ..common.node_package import InstalledNodePackage
|
||||||
import git_utils
|
from ..common.enums import NetworkMode, SecurityLevel, DBMode
|
||||||
import manager_downloader
|
from ..common import context
|
||||||
from node_package import InstalledNodePackage
|
|
||||||
|
|
||||||
|
|
||||||
version_code = [3, 31, 10]
|
version_code = [4, 0]
|
||||||
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||||
|
|
||||||
|
|
||||||
@@ -58,6 +56,7 @@ class InvalidChannel(Exception):
|
|||||||
self.channel = channel
|
self.channel = channel
|
||||||
super().__init__(channel)
|
super().__init__(channel)
|
||||||
|
|
||||||
|
|
||||||
def get_default_custom_nodes_path():
|
def get_default_custom_nodes_path():
|
||||||
global default_custom_nodes_path
|
global default_custom_nodes_path
|
||||||
if default_custom_nodes_path is None:
|
if default_custom_nodes_path is None:
|
||||||
@@ -79,32 +78,6 @@ def get_custom_nodes_paths():
|
|||||||
return [custom_nodes_path]
|
return [custom_nodes_path]
|
||||||
|
|
||||||
|
|
||||||
def get_comfyui_tag():
|
|
||||||
try:
|
|
||||||
repo = git.Repo(comfy_path)
|
|
||||||
return repo.git.describe('--tags')
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_current_comfyui_ver():
|
|
||||||
"""
|
|
||||||
Extract version from pyproject.toml
|
|
||||||
"""
|
|
||||||
toml_path = os.path.join(comfy_path, 'pyproject.toml')
|
|
||||||
if not os.path.exists(toml_path):
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
with open(toml_path, "r", encoding="utf-8") as f:
|
|
||||||
data = toml.load(f)
|
|
||||||
|
|
||||||
project = data.get('project', {})
|
|
||||||
return project.get('version')
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_script_env():
|
def get_script_env():
|
||||||
new_env = os.environ.copy()
|
new_env = os.environ.copy()
|
||||||
git_exe = get_config().get('git_exe')
|
git_exe = get_config().get('git_exe')
|
||||||
@@ -112,10 +85,10 @@ def get_script_env():
|
|||||||
new_env['GIT_EXE_PATH'] = git_exe
|
new_env['GIT_EXE_PATH'] = git_exe
|
||||||
|
|
||||||
if 'COMFYUI_PATH' not in new_env:
|
if 'COMFYUI_PATH' not in new_env:
|
||||||
new_env['COMFYUI_PATH'] = comfy_path
|
new_env['COMFYUI_PATH'] = context.comfy_path
|
||||||
|
|
||||||
if 'COMFYUI_FOLDERS_BASE_PATH' not in new_env:
|
if 'COMFYUI_FOLDERS_BASE_PATH' not in new_env:
|
||||||
new_env['COMFYUI_FOLDERS_BASE_PATH'] = comfy_path
|
new_env['COMFYUI_FOLDERS_BASE_PATH'] = context.comfy_path
|
||||||
|
|
||||||
return new_env
|
return new_env
|
||||||
|
|
||||||
@@ -139,10 +112,10 @@ def check_invalid_nodes():
|
|||||||
import folder_paths
|
import folder_paths
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
sys.path.append(comfy_path)
|
sys.path.append(context.comfy_path)
|
||||||
import folder_paths
|
import folder_paths
|
||||||
except:
|
except:
|
||||||
raise Exception(f"Invalid COMFYUI_FOLDERS_BASE_PATH: {comfy_path}")
|
raise Exception(f"Invalid COMFYUI_FOLDERS_BASE_PATH: {context.comfy_path}")
|
||||||
|
|
||||||
def check(root):
|
def check(root):
|
||||||
global invalid_nodes
|
global invalid_nodes
|
||||||
@@ -177,75 +150,6 @@ def check_invalid_nodes():
|
|||||||
print("\n---------------------------------------------------------------------------\n")
|
print("\n---------------------------------------------------------------------------\n")
|
||||||
|
|
||||||
|
|
||||||
# read env vars
|
|
||||||
comfy_path: str = os.environ.get('COMFYUI_PATH')
|
|
||||||
comfy_base_path = os.environ.get('COMFYUI_FOLDERS_BASE_PATH')
|
|
||||||
|
|
||||||
if comfy_path is None:
|
|
||||||
try:
|
|
||||||
import folder_paths
|
|
||||||
comfy_path = os.path.join(os.path.dirname(folder_paths.__file__))
|
|
||||||
except:
|
|
||||||
comfy_path = os.path.abspath(os.path.join(manager_util.comfyui_manager_path, '..', '..'))
|
|
||||||
|
|
||||||
if comfy_base_path is None:
|
|
||||||
comfy_base_path = comfy_path
|
|
||||||
|
|
||||||
|
|
||||||
channel_list_template_path = os.path.join(manager_util.comfyui_manager_path, 'channels.list.template')
|
|
||||||
git_script_path = os.path.join(manager_util.comfyui_manager_path, "git_helper.py")
|
|
||||||
|
|
||||||
manager_files_path = None
|
|
||||||
manager_config_path = None
|
|
||||||
manager_channel_list_path = None
|
|
||||||
manager_startup_script_path:str = None
|
|
||||||
manager_snapshot_path = None
|
|
||||||
manager_pip_overrides_path = None
|
|
||||||
manager_pip_blacklist_path = None
|
|
||||||
manager_components_path = None
|
|
||||||
|
|
||||||
def update_user_directory(user_dir):
|
|
||||||
global manager_files_path
|
|
||||||
global manager_config_path
|
|
||||||
global manager_channel_list_path
|
|
||||||
global manager_startup_script_path
|
|
||||||
global manager_snapshot_path
|
|
||||||
global manager_pip_overrides_path
|
|
||||||
global manager_pip_blacklist_path
|
|
||||||
global manager_components_path
|
|
||||||
|
|
||||||
manager_files_path = os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
|
|
||||||
if not os.path.exists(manager_files_path):
|
|
||||||
os.makedirs(manager_files_path)
|
|
||||||
|
|
||||||
manager_snapshot_path = os.path.join(manager_files_path, "snapshots")
|
|
||||||
if not os.path.exists(manager_snapshot_path):
|
|
||||||
os.makedirs(manager_snapshot_path)
|
|
||||||
|
|
||||||
manager_startup_script_path = os.path.join(manager_files_path, "startup-scripts")
|
|
||||||
if not os.path.exists(manager_startup_script_path):
|
|
||||||
os.makedirs(manager_startup_script_path)
|
|
||||||
|
|
||||||
manager_config_path = os.path.join(manager_files_path, 'config.ini')
|
|
||||||
manager_channel_list_path = os.path.join(manager_files_path, 'channels.list')
|
|
||||||
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
|
|
||||||
manager_pip_blacklist_path = os.path.join(manager_files_path, "pip_blacklist.list")
|
|
||||||
manager_components_path = os.path.join(manager_files_path, "components")
|
|
||||||
manager_util.cache_dir = os.path.join(manager_files_path, "cache")
|
|
||||||
|
|
||||||
if not os.path.exists(manager_util.cache_dir):
|
|
||||||
os.makedirs(manager_util.cache_dir)
|
|
||||||
|
|
||||||
try:
|
|
||||||
import folder_paths
|
|
||||||
update_user_directory(folder_paths.get_user_directory())
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
# fallback:
|
|
||||||
# This case is only possible when running with cm-cli, and in practice, this case is not actually used.
|
|
||||||
update_user_directory(os.path.abspath(manager_util.comfyui_manager_path))
|
|
||||||
|
|
||||||
|
|
||||||
cached_config = None
|
cached_config = None
|
||||||
js_path = None
|
js_path = None
|
||||||
|
|
||||||
@@ -553,7 +457,7 @@ class UnifiedManager:
|
|||||||
ver = str(manager_util.StrictVersion(info['version']))
|
ver = str(manager_util.StrictVersion(info['version']))
|
||||||
return {'id': cnr['id'], 'cnr': cnr, 'ver': ver}
|
return {'id': cnr['id'], 'cnr': cnr, 'ver': ver}
|
||||||
else:
|
else:
|
||||||
return None
|
return {'id': info['id'], 'ver': info['version']}
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -729,7 +633,9 @@ class UnifiedManager:
|
|||||||
|
|
||||||
return latest
|
return latest
|
||||||
|
|
||||||
async def reload(self, cache_mode, dont_wait=True):
|
async def reload(self, cache_mode, dont_wait=True, update_cnr_map=True):
|
||||||
|
import folder_paths
|
||||||
|
|
||||||
self.custom_node_map_cache = {}
|
self.custom_node_map_cache = {}
|
||||||
self.cnr_inactive_nodes = {} # node_id -> node_version -> fullpath
|
self.cnr_inactive_nodes = {} # node_id -> node_version -> fullpath
|
||||||
self.nightly_inactive_nodes = {} # node_id -> fullpath
|
self.nightly_inactive_nodes = {} # node_id -> fullpath
|
||||||
@@ -737,17 +643,18 @@ class UnifiedManager:
|
|||||||
self.unknown_active_nodes = {} # node_id -> repo url * fullpath
|
self.unknown_active_nodes = {} # node_id -> repo url * fullpath
|
||||||
self.active_nodes = {} # node_id -> node_version * 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
|
dont_wait = True
|
||||||
|
|
||||||
# reload 'cnr_map' and 'repo_cnr_map'
|
if update_cnr_map:
|
||||||
cnrs = await cnr_utils.get_cnr_data(cache_mode=cache_mode=='cache', dont_wait=dont_wait)
|
# 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:
|
for x in cnrs:
|
||||||
self.cnr_map[x['id']] = x
|
self.cnr_map[x['id']] = x
|
||||||
if 'repository' in x:
|
if 'repository' in x:
|
||||||
normalized_url = git_utils.normalize_url(x['repository'])
|
normalized_url = git_utils.normalize_url(x['repository'])
|
||||||
self.repo_cnr_map[normalized_url] = x
|
self.repo_cnr_map[normalized_url] = x
|
||||||
|
|
||||||
# reload node status info from custom_nodes/*
|
# reload node status info from custom_nodes/*
|
||||||
for custom_nodes_path in folder_paths.get_folder_paths('custom_nodes'):
|
for custom_nodes_path in folder_paths.get_folder_paths('custom_nodes'):
|
||||||
@@ -862,7 +769,7 @@ class UnifiedManager:
|
|||||||
else:
|
else:
|
||||||
if os.path.exists(requirements_path) and not no_deps:
|
if os.path.exists(requirements_path) and not no_deps:
|
||||||
print("Install: pip packages")
|
print("Install: pip packages")
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), context.comfy_path, context.manager_files_path)
|
||||||
lines = manager_util.robust_readlines(requirements_path)
|
lines = manager_util.robust_readlines(requirements_path)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
package_name = remap_pip_package(line.strip())
|
package_name = remap_pip_package(line.strip())
|
||||||
@@ -883,7 +790,7 @@ class UnifiedManager:
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def reserve_cnr_switch(self, target, zip_url, from_path, to_path, no_deps):
|
def reserve_cnr_switch(self, target, zip_url, from_path, to_path, no_deps):
|
||||||
script_path = os.path.join(manager_startup_script_path, "install-scripts.txt")
|
script_path = os.path.join(context.manager_startup_script_path, "install-scripts.txt")
|
||||||
with open(script_path, "a") as file:
|
with open(script_path, "a") as file:
|
||||||
obj = [target, "#LAZY-CNR-SWITCH-SCRIPT", zip_url, from_path, to_path, no_deps, get_default_custom_nodes_path(), sys.executable]
|
obj = [target, "#LAZY-CNR-SWITCH-SCRIPT", zip_url, from_path, to_path, no_deps, get_default_custom_nodes_path(), sys.executable]
|
||||||
file.write(f"{obj}\n")
|
file.write(f"{obj}\n")
|
||||||
@@ -1289,7 +1196,7 @@ class UnifiedManager:
|
|||||||
print(f"Download: git clone '{clone_url}'")
|
print(f"Download: git clone '{clone_url}'")
|
||||||
|
|
||||||
if not instant_execution and platform.system() == 'Windows':
|
if not instant_execution and platform.system() == 'Windows':
|
||||||
res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", get_default_custom_nodes_path(), clone_url, repo_path], cwd=get_default_custom_nodes_path())
|
res = manager_funcs.run_script([sys.executable, context.git_script_path, "--clone", get_default_custom_nodes_path(), clone_url, repo_path], cwd=get_default_custom_nodes_path())
|
||||||
if res != 0:
|
if res != 0:
|
||||||
return result.fail(f"Failed to clone repo: {clone_url}")
|
return result.fail(f"Failed to clone repo: {clone_url}")
|
||||||
else:
|
else:
|
||||||
@@ -1441,12 +1348,20 @@ class UnifiedManager:
|
|||||||
return self.unified_enable(node_id, version_spec)
|
return self.unified_enable(node_id, version_spec)
|
||||||
|
|
||||||
elif version_spec == 'unknown' or version_spec == 'nightly':
|
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':
|
if version_spec == 'nightly':
|
||||||
# disable cnr nodes
|
# disable cnr nodes
|
||||||
if self.is_enabled(node_id, 'cnr'):
|
if self.is_enabled(node_id, 'cnr'):
|
||||||
self.unified_disable(node_id, False)
|
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)
|
res = self.repo_install(repo_url, to_path, instant_execution=instant_execution, no_deps=no_deps, return_postinstall=return_postinstall)
|
||||||
if res.result:
|
if res.result:
|
||||||
if version_spec == 'unknown':
|
if version_spec == 'unknown':
|
||||||
@@ -1562,10 +1477,10 @@ def get_channel_dict():
|
|||||||
if channel_dict is None:
|
if channel_dict is None:
|
||||||
channel_dict = {}
|
channel_dict = {}
|
||||||
|
|
||||||
if not os.path.exists(manager_channel_list_path):
|
if not os.path.exists(context.manager_channel_list_path):
|
||||||
shutil.copy(channel_list_template_path, manager_channel_list_path)
|
shutil.copy(context.channel_list_template_path, context.manager_channel_list_path)
|
||||||
|
|
||||||
with open(manager_channel_list_path, 'r') as file:
|
with open(context.manager_channel_list_path, 'r') as file:
|
||||||
channels = file.read()
|
channels = file.read()
|
||||||
for x in channels.split('\n'):
|
for x in channels.split('\n'):
|
||||||
channel_info = x.split("::")
|
channel_info = x.split("::")
|
||||||
@@ -1629,18 +1544,18 @@ def write_config():
|
|||||||
'db_mode': get_config()['db_mode'],
|
'db_mode': get_config()['db_mode'],
|
||||||
}
|
}
|
||||||
|
|
||||||
directory = os.path.dirname(manager_config_path)
|
directory = os.path.dirname(context.manager_config_path)
|
||||||
if not os.path.exists(directory):
|
if not os.path.exists(directory):
|
||||||
os.makedirs(directory)
|
os.makedirs(directory)
|
||||||
|
|
||||||
with open(manager_config_path, 'w') as configfile:
|
with open(context.manager_config_path, 'w') as configfile:
|
||||||
config.write(configfile)
|
config.write(configfile)
|
||||||
|
|
||||||
|
|
||||||
def read_config():
|
def read_config():
|
||||||
try:
|
try:
|
||||||
config = configparser.ConfigParser(strict=False)
|
config = configparser.ConfigParser(strict=False)
|
||||||
config.read(manager_config_path)
|
config.read(context.manager_config_path)
|
||||||
default_conf = config['default']
|
default_conf = config['default']
|
||||||
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
|
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
|
||||||
|
|
||||||
@@ -1663,9 +1578,9 @@ def read_config():
|
|||||||
'model_download_by_agent': get_bool('model_download_by_agent', False),
|
'model_download_by_agent': get_bool('model_download_by_agent', False),
|
||||||
'downgrade_blacklist': default_conf.get('downgrade_blacklist', '').lower(),
|
'downgrade_blacklist': default_conf.get('downgrade_blacklist', '').lower(),
|
||||||
'always_lazy_install': get_bool('always_lazy_install', False),
|
'always_lazy_install': get_bool('always_lazy_install', False),
|
||||||
'network_mode': default_conf.get('network_mode', 'public').lower(),
|
'network_mode': default_conf.get('network_mode', NetworkMode.PUBLIC.value).lower(),
|
||||||
'security_level': default_conf.get('security_level', 'normal').lower(),
|
'security_level': default_conf.get('security_level', SecurityLevel.NORMAL.value).lower(),
|
||||||
'db_mode': default_conf.get('db_mode', 'cache').lower(),
|
'db_mode': default_conf.get('db_mode', DBMode.CACHE.value).lower(),
|
||||||
}
|
}
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -1686,9 +1601,9 @@ def read_config():
|
|||||||
'model_download_by_agent': False,
|
'model_download_by_agent': False,
|
||||||
'downgrade_blacklist': '',
|
'downgrade_blacklist': '',
|
||||||
'always_lazy_install': False,
|
'always_lazy_install': False,
|
||||||
'network_mode': 'public', # public | private | offline
|
'network_mode': NetworkMode.OFFLINE.value,
|
||||||
'security_level': 'normal', # strong | normal | normal- | weak
|
'security_level': SecurityLevel.NORMAL.value,
|
||||||
'db_mode': 'cache', # local | cache | remote
|
'db_mode': DBMode.CACHE.value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1760,10 +1675,10 @@ def switch_to_default_branch(repo):
|
|||||||
|
|
||||||
|
|
||||||
def reserve_script(repo_path, install_cmds):
|
def reserve_script(repo_path, install_cmds):
|
||||||
if not os.path.exists(manager_startup_script_path):
|
if not os.path.exists(context.manager_startup_script_path):
|
||||||
os.makedirs(manager_startup_script_path)
|
os.makedirs(context.manager_startup_script_path)
|
||||||
|
|
||||||
script_path = os.path.join(manager_startup_script_path, "install-scripts.txt")
|
script_path = os.path.join(context.manager_startup_script_path, "install-scripts.txt")
|
||||||
with open(script_path, "a") as file:
|
with open(script_path, "a") as file:
|
||||||
obj = [repo_path] + install_cmds
|
obj = [repo_path] + install_cmds
|
||||||
file.write(f"{obj}\n")
|
file.write(f"{obj}\n")
|
||||||
@@ -1818,11 +1733,11 @@ def try_install_script(url, repo_path, install_cmd, instant_execution=False):
|
|||||||
# use subprocess to avoid file system lock by git (Windows)
|
# use subprocess to avoid file system lock by git (Windows)
|
||||||
def __win_check_git_update(path, do_fetch=False, do_update=False):
|
def __win_check_git_update(path, do_fetch=False, do_update=False):
|
||||||
if do_fetch:
|
if do_fetch:
|
||||||
command = [sys.executable, git_script_path, "--fetch", path]
|
command = [sys.executable, context.git_script_path, "--fetch", path]
|
||||||
elif do_update:
|
elif do_update:
|
||||||
command = [sys.executable, git_script_path, "--pull", path]
|
command = [sys.executable, context.git_script_path, "--pull", path]
|
||||||
else:
|
else:
|
||||||
command = [sys.executable, git_script_path, "--check", path]
|
command = [sys.executable, context.git_script_path, "--check", path]
|
||||||
|
|
||||||
new_env = get_script_env()
|
new_env = get_script_env()
|
||||||
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=get_default_custom_nodes_path(), env=new_env)
|
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=get_default_custom_nodes_path(), env=new_env)
|
||||||
@@ -1876,7 +1791,7 @@ def __win_check_git_update(path, do_fetch=False, do_update=False):
|
|||||||
|
|
||||||
|
|
||||||
def __win_check_git_pull(path):
|
def __win_check_git_pull(path):
|
||||||
command = [sys.executable, git_script_path, "--pull", path]
|
command = [sys.executable, context.git_script_path, "--pull", path]
|
||||||
process = subprocess.Popen(command, env=get_script_env(), cwd=get_default_custom_nodes_path())
|
process = subprocess.Popen(command, env=get_script_env(), cwd=get_default_custom_nodes_path())
|
||||||
process.wait()
|
process.wait()
|
||||||
|
|
||||||
@@ -1892,7 +1807,7 @@ def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=Fa
|
|||||||
else:
|
else:
|
||||||
if os.path.exists(requirements_path) and not no_deps:
|
if os.path.exists(requirements_path) and not no_deps:
|
||||||
print("Install: pip packages")
|
print("Install: pip packages")
|
||||||
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)
|
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), context.comfy_path, context.manager_files_path)
|
||||||
with open(requirements_path, "r") as requirements_file:
|
with open(requirements_path, "r") as requirements_file:
|
||||||
for line in requirements_file:
|
for line in requirements_file:
|
||||||
#handle comments
|
#handle comments
|
||||||
@@ -2118,7 +2033,7 @@ async def gitclone_install(url, instant_execution=False, msg_prefix='', no_deps=
|
|||||||
clone_url = git_utils.get_url_for_clone(url)
|
clone_url = git_utils.get_url_for_clone(url)
|
||||||
|
|
||||||
if not instant_execution and platform.system() == 'Windows':
|
if not instant_execution and platform.system() == 'Windows':
|
||||||
res = manager_funcs.run_script([sys.executable, git_script_path, "--clone", get_default_custom_nodes_path(), clone_url, repo_path], cwd=get_default_custom_nodes_path())
|
res = manager_funcs.run_script([sys.executable, context.git_script_path, "--clone", get_default_custom_nodes_path(), clone_url, repo_path], cwd=get_default_custom_nodes_path())
|
||||||
if res != 0:
|
if res != 0:
|
||||||
return result.fail(f"Failed to clone '{clone_url}' into '{repo_path}'")
|
return result.fail(f"Failed to clone '{clone_url}' into '{repo_path}'")
|
||||||
else:
|
else:
|
||||||
@@ -2185,7 +2100,7 @@ async def get_data_by_mode(mode, filename, channel_url=None):
|
|||||||
cache_uri = str(manager_util.simple_hash(uri))+'_'+filename
|
cache_uri = str(manager_util.simple_hash(uri))+'_'+filename
|
||||||
cache_uri = os.path.join(manager_util.cache_dir, cache_uri)
|
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
|
# offline network mode
|
||||||
if os.path.exists(cache_uri):
|
if os.path.exists(cache_uri):
|
||||||
json_obj = await manager_util.get_data(cache_uri)
|
json_obj = await manager_util.get_data(cache_uri)
|
||||||
@@ -2205,7 +2120,7 @@ async def get_data_by_mode(mode, filename, channel_url=None):
|
|||||||
with open(cache_uri, "w", encoding='utf-8') as file:
|
with open(cache_uri, "w", encoding='utf-8') as file:
|
||||||
json.dump(json_obj, file, indent=4, sort_keys=True)
|
json.dump(json_obj, file, indent=4, sort_keys=True)
|
||||||
except Exception as e:
|
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)
|
uri = os.path.join(manager_util.comfyui_manager_path, filename)
|
||||||
json_obj = await manager_util.get_data(uri)
|
json_obj = await manager_util.get_data(uri)
|
||||||
|
|
||||||
@@ -2276,7 +2191,7 @@ def gitclone_uninstall(files):
|
|||||||
url = url[:-1]
|
url = url[:-1]
|
||||||
try:
|
try:
|
||||||
for custom_nodes_dir in get_custom_nodes_paths():
|
for custom_nodes_dir in get_custom_nodes_paths():
|
||||||
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
|
dir_name:str = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
|
||||||
dir_path = os.path.join(custom_nodes_dir, dir_name)
|
dir_path = os.path.join(custom_nodes_dir, dir_name)
|
||||||
|
|
||||||
# safety check
|
# safety check
|
||||||
@@ -2324,7 +2239,7 @@ def gitclone_set_active(files, is_disable):
|
|||||||
url = url[:-1]
|
url = url[:-1]
|
||||||
try:
|
try:
|
||||||
for custom_nodes_dir in get_custom_nodes_paths():
|
for custom_nodes_dir in get_custom_nodes_paths():
|
||||||
dir_name = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
|
dir_name:str = os.path.splitext(os.path.basename(url))[0].replace(".git", "")
|
||||||
dir_path = os.path.join(custom_nodes_dir, dir_name)
|
dir_path = os.path.join(custom_nodes_dir, dir_name)
|
||||||
|
|
||||||
# safety check
|
# safety check
|
||||||
@@ -2597,7 +2512,7 @@ async def get_current_snapshot(custom_nodes_only = False):
|
|||||||
await unified_manager.get_custom_nodes('default', 'cache')
|
await unified_manager.get_custom_nodes('default', 'cache')
|
||||||
|
|
||||||
# Get ComfyUI hash
|
# Get ComfyUI hash
|
||||||
repo_path = comfy_path
|
repo_path = context.comfy_path
|
||||||
|
|
||||||
comfyui_commit_hash = None
|
comfyui_commit_hash = None
|
||||||
if not custom_nodes_only:
|
if not custom_nodes_only:
|
||||||
@@ -2673,7 +2588,7 @@ async def save_snapshot_with_postfix(postfix, path=None, custom_nodes_only = Fal
|
|||||||
date_time_format = now.strftime("%Y-%m-%d_%H-%M-%S")
|
date_time_format = now.strftime("%Y-%m-%d_%H-%M-%S")
|
||||||
file_name = f"{date_time_format}_{postfix}"
|
file_name = f"{date_time_format}_{postfix}"
|
||||||
|
|
||||||
path = os.path.join(manager_snapshot_path, f"{file_name}.json")
|
path = os.path.join(context.manager_snapshot_path, f"{file_name}.json")
|
||||||
else:
|
else:
|
||||||
file_name = path.replace('\\', '/').split('/')[-1]
|
file_name = path.replace('\\', '/').split('/')[-1]
|
||||||
file_name = file_name.split('.')[-2]
|
file_name = file_name.split('.')[-2]
|
||||||
@@ -3255,7 +3170,7 @@ async def restore_snapshot(snapshot_path, git_helper_extras=None):
|
|||||||
|
|
||||||
def get_comfyui_versions(repo=None):
|
def get_comfyui_versions(repo=None):
|
||||||
if repo is None:
|
if repo is None:
|
||||||
repo = git.Repo(comfy_path)
|
repo = git.Repo(context.comfy_path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
remote = get_remote_name(repo)
|
remote = get_remote_name(repo)
|
||||||
@@ -3289,7 +3204,7 @@ def get_comfyui_versions(repo=None):
|
|||||||
|
|
||||||
|
|
||||||
def switch_comfyui(tag):
|
def switch_comfyui(tag):
|
||||||
repo = git.Repo(comfy_path)
|
repo = git.Repo(context.comfy_path)
|
||||||
|
|
||||||
if tag == 'nightly':
|
if tag == 'nightly':
|
||||||
repo.git.checkout('master')
|
repo.git.checkout('master')
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import manager_core as core
|
from ..common import context
|
||||||
|
from . import manager_core as core
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -53,7 +55,7 @@ def compute_sha256_checksum(filepath):
|
|||||||
return sha256.hexdigest()
|
return sha256.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
@PromptServer.instance.routes.get("/manager/share_option")
|
@PromptServer.instance.routes.get("/v2/manager/share_option")
|
||||||
async def share_option(request):
|
async def share_option(request):
|
||||||
if "value" in request.rel_url.query:
|
if "value" in request.rel_url.query:
|
||||||
core.get_config()['share_option'] = request.rel_url.query['value']
|
core.get_config()['share_option'] = request.rel_url.query['value']
|
||||||
@@ -65,10 +67,10 @@ async def share_option(request):
|
|||||||
|
|
||||||
|
|
||||||
def get_openart_auth():
|
def get_openart_auth():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, ".openart_key")):
|
if not os.path.exists(os.path.join(context.manager_files_path, ".openart_key")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, ".openart_key"), "r") as f:
|
with open(os.path.join(context.manager_files_path, ".openart_key"), "r") as f:
|
||||||
openart_key = f.read().strip()
|
openart_key = f.read().strip()
|
||||||
return openart_key if openart_key else None
|
return openart_key if openart_key else None
|
||||||
except:
|
except:
|
||||||
@@ -76,10 +78,10 @@ def get_openart_auth():
|
|||||||
|
|
||||||
|
|
||||||
def get_matrix_auth():
|
def get_matrix_auth():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, "matrix_auth")):
|
if not os.path.exists(os.path.join(context.manager_files_path, "matrix_auth")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, "matrix_auth"), "r") as f:
|
with open(os.path.join(context.manager_files_path, "matrix_auth"), "r") as f:
|
||||||
matrix_auth = f.read()
|
matrix_auth = f.read()
|
||||||
homeserver, username, password = matrix_auth.strip().split("\n")
|
homeserver, username, password = matrix_auth.strip().split("\n")
|
||||||
if not homeserver or not username or not password:
|
if not homeserver or not username or not password:
|
||||||
@@ -94,10 +96,10 @@ def get_matrix_auth():
|
|||||||
|
|
||||||
|
|
||||||
def get_comfyworkflows_auth():
|
def get_comfyworkflows_auth():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, "comfyworkflows_sharekey")):
|
if not os.path.exists(os.path.join(context.manager_files_path, "comfyworkflows_sharekey")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, "comfyworkflows_sharekey"), "r") as f:
|
with open(os.path.join(context.manager_files_path, "comfyworkflows_sharekey"), "r") as f:
|
||||||
share_key = f.read()
|
share_key = f.read()
|
||||||
if not share_key.strip():
|
if not share_key.strip():
|
||||||
return None
|
return None
|
||||||
@@ -107,10 +109,10 @@ def get_comfyworkflows_auth():
|
|||||||
|
|
||||||
|
|
||||||
def get_youml_settings():
|
def get_youml_settings():
|
||||||
if not os.path.exists(os.path.join(core.manager_files_path, ".youml")):
|
if not os.path.exists(os.path.join(context.manager_files_path, ".youml")):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(core.manager_files_path, ".youml"), "r") as f:
|
with open(os.path.join(context.manager_files_path, ".youml"), "r") as f:
|
||||||
youml_settings = f.read().strip()
|
youml_settings = f.read().strip()
|
||||||
return youml_settings if youml_settings else None
|
return youml_settings if youml_settings else None
|
||||||
except:
|
except:
|
||||||
@@ -118,11 +120,11 @@ def get_youml_settings():
|
|||||||
|
|
||||||
|
|
||||||
def set_youml_settings(settings):
|
def set_youml_settings(settings):
|
||||||
with open(os.path.join(core.manager_files_path, ".youml"), "w") as f:
|
with open(os.path.join(context.manager_files_path, ".youml"), "w") as f:
|
||||||
f.write(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):
|
async def api_get_openart_auth(request):
|
||||||
# print("Getting stored Matrix credentials...")
|
# print("Getting stored Matrix credentials...")
|
||||||
openart_key = get_openart_auth()
|
openart_key = get_openart_auth()
|
||||||
@@ -131,16 +133,16 @@ async def api_get_openart_auth(request):
|
|||||||
return web.json_response({"openart_key": openart_key})
|
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):
|
async def api_set_openart_auth(request):
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
openart_key = json_data['openart_key']
|
openart_key = json_data['openart_key']
|
||||||
with open(os.path.join(core.manager_files_path, ".openart_key"), "w") as f:
|
with open(os.path.join(context.manager_files_path, ".openart_key"), "w") as f:
|
||||||
f.write(openart_key)
|
f.write(openart_key)
|
||||||
return web.Response(status=200)
|
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):
|
async def api_get_matrix_auth(request):
|
||||||
# print("Getting stored Matrix credentials...")
|
# print("Getting stored Matrix credentials...")
|
||||||
matrix_auth = get_matrix_auth()
|
matrix_auth = get_matrix_auth()
|
||||||
@@ -149,7 +151,7 @@ async def api_get_matrix_auth(request):
|
|||||||
return web.json_response(matrix_auth)
|
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):
|
async def api_get_youml_settings(request):
|
||||||
youml_settings = get_youml_settings()
|
youml_settings = get_youml_settings()
|
||||||
if not youml_settings:
|
if not youml_settings:
|
||||||
@@ -157,14 +159,14 @@ async def api_get_youml_settings(request):
|
|||||||
return web.json_response(json.loads(youml_settings))
|
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):
|
async def api_set_youml_settings(request):
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
set_youml_settings(json.dumps(json_data))
|
set_youml_settings(json.dumps(json_data))
|
||||||
return web.Response(status=200)
|
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):
|
async def api_get_comfyworkflows_auth(request):
|
||||||
# Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken'
|
# Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken'
|
||||||
# in the same directory as the ComfyUI base folder
|
# in the same directory as the ComfyUI base folder
|
||||||
@@ -175,17 +177,17 @@ async def api_get_comfyworkflows_auth(request):
|
|||||||
return web.json_response({"comfyworkflows_sharekey": comfyworkflows_auth})
|
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):
|
async def set_esheep_workflow_and_images(request):
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
with open(os.path.join(core.manager_files_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
with open(os.path.join(context.manager_files_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
||||||
json.dump(json_data, file, indent=4)
|
json.dump(json_data, file, indent=4)
|
||||||
return web.Response(status=200)
|
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):
|
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:
|
with open(os.path.join(context.manager_files_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
return web.Response(status=200, text=json.dumps(data))
|
return web.Response(status=200, text=json.dumps(data))
|
||||||
|
|
||||||
@@ -194,12 +196,12 @@ def set_matrix_auth(json_data):
|
|||||||
homeserver = json_data['homeserver']
|
homeserver = json_data['homeserver']
|
||||||
username = json_data['username']
|
username = json_data['username']
|
||||||
password = json_data['password']
|
password = json_data['password']
|
||||||
with open(os.path.join(core.manager_files_path, "matrix_auth"), "w") as f:
|
with open(os.path.join(context.manager_files_path, "matrix_auth"), "w") as f:
|
||||||
f.write("\n".join([homeserver, username, password]))
|
f.write("\n".join([homeserver, username, password]))
|
||||||
|
|
||||||
|
|
||||||
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||||
with open(os.path.join(core.manager_files_path, "comfyworkflows_sharekey"), "w") as f:
|
with open(os.path.join(context.manager_files_path, "comfyworkflows_sharekey"), "w") as f:
|
||||||
f.write(comfyworkflows_sharekey)
|
f.write(comfyworkflows_sharekey)
|
||||||
|
|
||||||
|
|
||||||
@@ -211,7 +213,7 @@ def has_provided_comfyworkflows_auth(comfyworkflows_sharekey):
|
|||||||
return comfyworkflows_sharekey.strip()
|
return comfyworkflows_sharekey.strip()
|
||||||
|
|
||||||
|
|
||||||
@PromptServer.instance.routes.post("/manager/share")
|
@PromptServer.instance.routes.post("/v2/manager/share")
|
||||||
async def share_art(request):
|
async def share_art(request):
|
||||||
# get json data
|
# get json data
|
||||||
json_data = await request.json()
|
json_data = await request.json()
|
||||||
@@ -25,7 +25,7 @@ async function tryInstallCustomNode(event) {
|
|||||||
const res = await customConfirm(msg);
|
const res = await customConfirm(msg);
|
||||||
if(res) {
|
if(res) {
|
||||||
if(event.detail.target.installed == 'Disabled') {
|
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',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(event.detail.target)
|
body: JSON.stringify(event.detail.target)
|
||||||
@@ -35,7 +35,7 @@ async function tryInstallCustomNode(event) {
|
|||||||
await sleep(300);
|
await sleep(300);
|
||||||
app.ui.dialog.show(`Installing... '${event.detail.target.title}'`);
|
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',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(event.detail.target)
|
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) {
|
if(response.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
show_message('This action is not allowed with this security level configuration.');
|
||||||
return false;
|
return false;
|
||||||
@@ -14,9 +14,9 @@ import { OpenArtShareDialog } from "./comfyui-share-openart.js";
|
|||||||
import {
|
import {
|
||||||
free_models, install_pip, install_via_git_url, manager_instance,
|
free_models, install_pip, install_via_git_url, manager_instance,
|
||||||
rebootAPI, setManagerInstance, show_message, customAlert, customPrompt,
|
rebootAPI, setManagerInstance, show_message, customAlert, customPrompt,
|
||||||
infoToast, showTerminal, setNeedRestart
|
infoToast, showTerminal, setNeedRestart, generateUUID
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
|
import { ComponentBuilderDialog, load_components, set_component_policy } from "./components-manager.js";
|
||||||
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
import { CustomNodesManager } from "./custom-nodes-manager.js";
|
||||||
import { ModelManager } from "./model-manager.js";
|
import { ModelManager } from "./model-manager.js";
|
||||||
import { SnapshotManager } from "./snapshot.js";
|
import { SnapshotManager } from "./snapshot.js";
|
||||||
@@ -189,8 +189,7 @@ docStyle.innerHTML = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function is_legacy_front() {
|
function isBeforeFrontendVersion(compareVersion) {
|
||||||
let compareVersion = '1.2.49';
|
|
||||||
try {
|
try {
|
||||||
const frontendVersion = window['__COMFYUI_FRONTEND_VERSION__'];
|
const frontendVersion = window['__COMFYUI_FRONTEND_VERSION__'];
|
||||||
if (typeof frontendVersion !== 'string') {
|
if (typeof frontendVersion !== 'string') {
|
||||||
@@ -223,6 +222,9 @@ function is_legacy_front() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const is_legacy_front = () => isBeforeFrontendVersion('1.2.49');
|
||||||
|
const isNotNewManagerUI = () => isBeforeFrontendVersion('1.16.4');
|
||||||
|
|
||||||
document.head.appendChild(docStyle);
|
document.head.appendChild(docStyle);
|
||||||
|
|
||||||
var update_comfyui_button = null;
|
var update_comfyui_button = null;
|
||||||
@@ -232,7 +234,7 @@ var restart_stop_button = null;
|
|||||||
var update_policy_combo = null;
|
var update_policy_combo = null;
|
||||||
|
|
||||||
let share_option = 'all';
|
let share_option = 'all';
|
||||||
var is_updating = false;
|
var batch_id = null;
|
||||||
|
|
||||||
|
|
||||||
// copied style from https://github.com/pythongosssss/ComfyUI-Custom-Scripts
|
// copied style from https://github.com/pythongosssss/ComfyUI-Custom-Scripts
|
||||||
@@ -415,7 +417,7 @@ const style = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
async function init_share_option() {
|
async function init_share_option() {
|
||||||
api.fetchApi('/manager/share_option')
|
api.fetchApi('/v2/manager/share_option')
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
share_option = data || 'all';
|
share_option = data || 'all';
|
||||||
@@ -423,7 +425,7 @@ async function init_share_option() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function init_notice(notice) {
|
async function init_notice(notice) {
|
||||||
api.fetchApi('/manager/notice')
|
api.fetchApi('/v2/manager/notice')
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
notice.innerHTML = data;
|
notice.innerHTML = data;
|
||||||
@@ -474,14 +476,19 @@ async function updateComfyUI() {
|
|||||||
let prev_text = update_comfyui_button.innerText;
|
let prev_text = update_comfyui_button.innerText;
|
||||||
update_comfyui_button.innerText = "Updating ComfyUI...";
|
update_comfyui_button.innerText = "Updating ComfyUI...";
|
||||||
|
|
||||||
set_inprogress_mode();
|
// set_inprogress_mode();
|
||||||
|
|
||||||
const response = await api.fetchApi('/manager/queue/update_comfyui');
|
|
||||||
|
|
||||||
showTerminal();
|
showTerminal();
|
||||||
|
|
||||||
is_updating = true;
|
batch_id = generateUUID();
|
||||||
await api.fetchApi('/manager/queue/start');
|
|
||||||
|
let batch = {};
|
||||||
|
batch['batch_id'] = batch_id;
|
||||||
|
batch['update_comfyui'] = true;
|
||||||
|
|
||||||
|
const res = await api.fetchApi(`/v2/manager/queue/batch`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(batch)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showVersionSelectorDialog(versions, current, onSelect) {
|
function showVersionSelectorDialog(versions, current, onSelect) {
|
||||||
@@ -612,7 +619,7 @@ async function switchComfyUI() {
|
|||||||
switch_comfyui_button.disabled = true;
|
switch_comfyui_button.disabled = true;
|
||||||
switch_comfyui_button.style.backgroundColor = "gray";
|
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.disabled = false;
|
||||||
switch_comfyui_button.style.backgroundColor = "";
|
switch_comfyui_button.style.backgroundColor = "";
|
||||||
@@ -631,14 +638,14 @@ async function switchComfyUI() {
|
|||||||
showVersionSelectorDialog(versions, obj.current, async (selected_version) => {
|
showVersionSelectorDialog(versions, obj.current, async (selected_version) => {
|
||||||
if(selected_version == 'nightly') {
|
if(selected_version == 'nightly') {
|
||||||
update_policy_combo.value = 'nightly-comfyui';
|
update_policy_combo.value = 'nightly-comfyui';
|
||||||
api.fetchApi('/manager/policy/update?value=nightly-comfyui');
|
api.fetchApi('/v2/manager/policy/update?value=nightly-comfyui');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
update_policy_combo.value = 'stable-comfyui';
|
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) {
|
if (response.status == 200) {
|
||||||
infoToast(`ComfyUI version is switched to ${selected_version}`);
|
infoToast(`ComfyUI version is switched to ${selected_version}`);
|
||||||
}
|
}
|
||||||
@@ -656,18 +663,17 @@ async function onQueueStatus(event) {
|
|||||||
const isElectron = 'electronAPI' in window;
|
const isElectron = 'electronAPI' in window;
|
||||||
|
|
||||||
if(event.detail.status == 'in_progress') {
|
if(event.detail.status == 'in_progress') {
|
||||||
set_inprogress_mode();
|
// set_inprogress_mode();
|
||||||
update_all_button.innerText = `in progress.. (${event.detail.done_count}/${event.detail.total_count})`;
|
update_all_button.innerText = `in progress.. (${event.detail.done_count}/${event.detail.total_count})`;
|
||||||
}
|
}
|
||||||
else if(event.detail.status == 'done') {
|
else if(event.detail.status == 'all-done') {
|
||||||
reset_action_buttons();
|
reset_action_buttons();
|
||||||
|
}
|
||||||
if(!is_updating) {
|
else if(event.detail.status == 'batch-done') {
|
||||||
|
if(batch_id != event.detail.batch_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_updating = false;
|
|
||||||
|
|
||||||
let success_list = [];
|
let success_list = [];
|
||||||
let failed_list = [];
|
let failed_list = [];
|
||||||
let comfyui_state = null;
|
let comfyui_state = null;
|
||||||
@@ -767,41 +773,28 @@ api.addEventListener("cm-queue-status", onQueueStatus);
|
|||||||
async function updateAll(update_comfyui) {
|
async function updateAll(update_comfyui) {
|
||||||
update_all_button.innerText = "Updating...";
|
update_all_button.innerText = "Updating...";
|
||||||
|
|
||||||
set_inprogress_mode();
|
// set_inprogress_mode();
|
||||||
|
|
||||||
var mode = manager_instance.datasrc_combo.value;
|
var mode = manager_instance.datasrc_combo.value;
|
||||||
|
|
||||||
showTerminal();
|
showTerminal();
|
||||||
|
|
||||||
|
batch_id = generateUUID();
|
||||||
|
|
||||||
|
let batch = {};
|
||||||
if(update_comfyui) {
|
if(update_comfyui) {
|
||||||
update_all_button.innerText = "Updating ComfyUI...";
|
update_all_button.innerText = "Updating ComfyUI...";
|
||||||
await api.fetchApi('/manager/queue/update_comfyui');
|
batch['update_comfyui'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`);
|
batch['update_all'] = mode;
|
||||||
|
|
||||||
if (response.status == 401) {
|
const res = await api.fetchApi(`/v2/manager/queue/batch`, {
|
||||||
customAlert('Another task is already in progress. Please stop the ongoing task first.');
|
method: 'POST',
|
||||||
}
|
body: JSON.stringify(batch)
|
||||||
else if(response.status == 200) {
|
});
|
||||||
is_updating = true;
|
|
||||||
await api.fetchApi('/manager/queue/start');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function newDOMTokenList(initialTokens) {
|
|
||||||
const tmp = document.createElement(`div`);
|
|
||||||
|
|
||||||
const classList = tmp.classList;
|
|
||||||
if (initialTokens) {
|
|
||||||
initialTokens.forEach(token => {
|
|
||||||
classList.add(token);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return classList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the node is a potential output node (img, gif or video output)
|
* Check whether the node is a potential output node (img, gif or video output)
|
||||||
*/
|
*/
|
||||||
@@ -814,7 +807,7 @@ function restartOrStop() {
|
|||||||
rebootAPI();
|
rebootAPI();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
api.fetchApi('/manager/queue/reset');
|
api.fetchApi('/v2/manager/queue/reset');
|
||||||
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -962,12 +955,12 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
this.datasrc_combo.appendChild($el('option', { value: 'local', text: 'DB: Local' }, []));
|
this.datasrc_combo.appendChild($el('option', { value: 'local', text: 'DB: Local' }, []));
|
||||||
this.datasrc_combo.appendChild($el('option', { value: 'remote', text: 'DB: Channel (remote)' }, []));
|
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(response => response.text())
|
||||||
.then(data => { this.datasrc_combo.value = data; });
|
.then(data => { this.datasrc_combo.value = data; });
|
||||||
|
|
||||||
this.datasrc_combo.addEventListener('change', function (event) {
|
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
|
// preview method
|
||||||
@@ -979,19 +972,19 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
preview_combo.appendChild($el('option', { value: 'latent2rgb', text: 'Preview method: Latent2RGB (fast)' }, []));
|
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)' }, []));
|
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(response => response.text())
|
||||||
.then(data => { preview_combo.value = data; });
|
.then(data => { preview_combo.value = data; });
|
||||||
|
|
||||||
preview_combo.addEventListener('change', function (event) {
|
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
|
// channel
|
||||||
let channel_combo = document.createElement("select");
|
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.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";
|
channel_combo.className = "cm-menu-combo";
|
||||||
api.fetchApi('/manager/channel_url_list')
|
api.fetchApi('/v2/manager/channel_url_list')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(async data => {
|
.then(async data => {
|
||||||
try {
|
try {
|
||||||
@@ -1004,7 +997,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel_combo.addEventListener('change', function (event) {
|
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;
|
channel_combo.value = data.selected;
|
||||||
@@ -1032,7 +1025,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
share_combo.appendChild($el('option', { value: option[0], text: `Share: ${option[1]}` }, []));
|
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(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
share_combo.value = data || 'all';
|
share_combo.value = data || 'all';
|
||||||
@@ -1042,7 +1035,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
share_combo.addEventListener('change', function (event) {
|
share_combo.addEventListener('change', function (event) {
|
||||||
const value = event.target.value;
|
const value = event.target.value;
|
||||||
share_option = value;
|
share_option = value;
|
||||||
api.fetchApi(`/manager/share_option?value=${value}`);
|
api.fetchApi(`/v2/manager/share_option?value=${value}`);
|
||||||
const shareButton = document.getElementById("shareButton");
|
const shareButton = document.getElementById("shareButton");
|
||||||
if (value === 'none') {
|
if (value === 'none') {
|
||||||
shareButton.style.display = "none";
|
shareButton.style.display = "none";
|
||||||
@@ -1057,7 +1050,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: '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: 'higher', text: 'Component: Use higher version' }, []));
|
||||||
component_policy_combo.appendChild($el('option', { value: 'mine', text: 'Component: Use my 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(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
component_policy_combo.value = data;
|
component_policy_combo.value = data;
|
||||||
@@ -1065,7 +1058,7 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
});
|
});
|
||||||
|
|
||||||
component_policy_combo.addEventListener('change', function (event) {
|
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);
|
set_component_policy(event.target.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1078,14 +1071,14 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
update_policy_combo.className = "cm-menu-combo";
|
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: 'stable-comfyui', text: 'Update: ComfyUI Stable Version' }, []));
|
||||||
update_policy_combo.appendChild($el('option', { value: 'nightly-comfyui', text: 'Update: ComfyUI Nightly 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(response => response.text())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
update_policy_combo.value = data;
|
update_policy_combo.value = data;
|
||||||
});
|
});
|
||||||
|
|
||||||
update_policy_combo.addEventListener('change', function (event) {
|
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 [
|
return [
|
||||||
@@ -1388,12 +1381,12 @@ class ManagerMenuDialog extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getVersion() {
|
async function getVersion() {
|
||||||
let version = await api.fetchApi(`/manager/version`);
|
let version = await api.fetchApi(`/v2/manager/version`);
|
||||||
return await version.text();
|
return await version.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.registerExtension({
|
app.registerExtension({
|
||||||
name: "Comfy.ManagerMenu",
|
name: "Comfy.Legacy.ManagerMenu",
|
||||||
|
|
||||||
aboutPageBadges: [
|
aboutPageBadges: [
|
||||||
{
|
{
|
||||||
@@ -1525,7 +1518,10 @@ app.registerExtension({
|
|||||||
}).element
|
}).element
|
||||||
);
|
);
|
||||||
|
|
||||||
app.menu?.settingsGroup.element.before(cmGroup.element);
|
const shouldShowLegacyMenuItems = isNotNewManagerUI();
|
||||||
|
if (shouldShowLegacyMenuItems) {
|
||||||
|
app.menu?.settingsGroup.element.before(cmGroup.element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(exception) {
|
catch(exception) {
|
||||||
console.log('ComfyUI is outdated. New style menu based features are disabled.');
|
console.log('ComfyUI is outdated. New style menu based features are disabled.');
|
||||||
@@ -172,7 +172,7 @@ export const shareToEsheep= () => {
|
|||||||
const nodes = app.graph._nodes
|
const nodes = app.graph._nodes
|
||||||
const { potential_outputs, potential_output_nodes } = getPotentialOutputsAndOutputNodes(nodes);
|
const { potential_outputs, potential_output_nodes } = getPotentialOutputsAndOutputNodes(nodes);
|
||||||
const workflow = prompt['workflow']
|
const workflow = prompt['workflow']
|
||||||
api.fetchApi(`/manager/set_esheep_workflow_and_images`, {
|
api.fetchApi(`/v2/manager/set_esheep_workflow_and_images`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -812,7 +812,7 @@ export class ShareDialog extends ComfyDialog {
|
|||||||
// get the user's existing matrix auth and share key
|
// get the user's existing matrix auth and share key
|
||||||
ShareDialog.matrix_auth = { homeserver: "matrix.org", username: "", password: "" };
|
ShareDialog.matrix_auth = { homeserver: "matrix.org", username: "", password: "" };
|
||||||
try {
|
try {
|
||||||
api.fetchApi(`/manager/get_matrix_auth`)
|
api.fetchApi(`/v2/manager/get_matrix_auth`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
ShareDialog.matrix_auth = data;
|
ShareDialog.matrix_auth = data;
|
||||||
@@ -831,7 +831,7 @@ export class ShareDialog extends ComfyDialog {
|
|||||||
ShareDialog.cw_sharekey = "";
|
ShareDialog.cw_sharekey = "";
|
||||||
try {
|
try {
|
||||||
// console.log("Fetching comfyworkflows share key")
|
// console.log("Fetching comfyworkflows share key")
|
||||||
api.fetchApi(`/manager/get_comfyworkflows_auth`)
|
api.fetchApi(`/v2/manager/get_comfyworkflows_auth`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
ShareDialog.cw_sharekey = data.comfyworkflows_sharekey;
|
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
|
// Change the text of the share button to "Sharing..." to indicate that the share process has started
|
||||||
this.share_button.textContent = "Sharing...";
|
this.share_button.textContent = "Sharing...";
|
||||||
|
|
||||||
const response = await api.fetchApi(`/manager/share`, {
|
const response = await api.fetchApi(`/v2/manager/share`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -67,7 +67,7 @@ export class OpenArtShareDialog extends ComfyDialog {
|
|||||||
async readKey() {
|
async readKey() {
|
||||||
let key = ""
|
let key = ""
|
||||||
try {
|
try {
|
||||||
key = await api.fetchApi(`/manager/get_openart_auth`)
|
key = await api.fetchApi(`/v2/manager/get_openart_auth`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
return data.openart_key;
|
return data.openart_key;
|
||||||
@@ -82,7 +82,7 @@ export class OpenArtShareDialog extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async saveKey(value) {
|
async saveKey(value) {
|
||||||
await api.fetchApi(`/manager/set_openart_auth`, {
|
await api.fetchApi(`/v2/manager/set_openart_auth`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -399,7 +399,7 @@ export class OpenArtShareDialog extends ComfyDialog {
|
|||||||
form.append("file", uploadFile);
|
form.append("file", uploadFile);
|
||||||
try {
|
try {
|
||||||
const res = await this.fetchApi(
|
const res = await this.fetchApi(
|
||||||
`/workflows/upload_thumbnail`,
|
`/v2/workflows/upload_thumbnail`,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: form,
|
body: form,
|
||||||
@@ -459,7 +459,7 @@ export class OpenArtShareDialog extends ComfyDialog {
|
|||||||
throw new Error("Title is required");
|
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())
|
.then(response => response.json())
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// console.log(error);
|
// console.log(error);
|
||||||
@@ -489,7 +489,7 @@ export class OpenArtShareDialog extends ComfyDialog {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.fetchApi(
|
const response = await this.fetchApi(
|
||||||
"/workflows/publish",
|
"/v2/workflows/publish",
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: {"Content-Type": "application/json"},
|
||||||
@@ -179,7 +179,7 @@ export class YouMLShareDialog extends ComfyDialog {
|
|||||||
async loadToken() {
|
async loadToken() {
|
||||||
let key = ""
|
let key = ""
|
||||||
try {
|
try {
|
||||||
const response = await api.fetchApi(`/manager/youml/settings`)
|
const response = await api.fetchApi(`/v2/manager/youml/settings`)
|
||||||
const settings = await response.json()
|
const settings = await response.json()
|
||||||
return settings.token
|
return settings.token
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -188,7 +188,7 @@ export class YouMLShareDialog extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async saveToken(value) {
|
async saveToken(value) {
|
||||||
await api.fetchApi(`/manager/youml/settings`, {
|
await api.fetchApi(`/v2/manager/youml/settings`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -380,7 +380,7 @@ export class YouMLShareDialog extends ComfyDialog {
|
|||||||
try {
|
try {
|
||||||
let snapshotData = null;
|
let snapshotData = null;
|
||||||
try {
|
try {
|
||||||
const snapshot = await api.fetchApi(`/snapshot/get_current`)
|
const snapshot = await api.fetchApi(`/v2/snapshot/get_current`)
|
||||||
snapshotData = await snapshot.json()
|
snapshotData = await snapshot.json()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to get snapshot", e)
|
console.error("Failed to get snapshot", e)
|
||||||
@@ -172,7 +172,7 @@ export function rebootAPI() {
|
|||||||
customConfirm("Are you sure you'd like to reboot the server?").then((isConfirmed) => {
|
customConfirm("Are you sure you'd like to reboot the server?").then((isConfirmed) => {
|
||||||
if (isConfirmed) {
|
if (isConfirmed) {
|
||||||
try {
|
try {
|
||||||
api.fetchApi("/manager/reboot");
|
api.fetchApi("/v2/manager/reboot");
|
||||||
}
|
}
|
||||||
catch(exception) {}
|
catch(exception) {}
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ export async function install_pip(packages) {
|
|||||||
if(packages.includes('&'))
|
if(packages.includes('&'))
|
||||||
app.ui.dialog.show(`Invalid PIP package enumeration: '${packages}'`);
|
app.ui.dialog.show(`Invalid PIP package enumeration: '${packages}'`);
|
||||||
|
|
||||||
const res = await api.fetchApi("/customnode/install/pip", {
|
const res = await api.fetchApi("/v2/customnode/install/pip", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: packages,
|
body: packages,
|
||||||
});
|
});
|
||||||
@@ -245,7 +245,7 @@ export async function install_via_git_url(url, manager_dialog) {
|
|||||||
|
|
||||||
show_message(`Wait...<BR><BR>Installing '${url}'`);
|
show_message(`Wait...<BR><BR>Installing '${url}'`);
|
||||||
|
|
||||||
const res = await api.fetchApi("/customnode/install/git_url", {
|
const res = await api.fetchApi("/v2/customnode/install/git_url", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: url,
|
body: url,
|
||||||
});
|
});
|
||||||
@@ -630,6 +630,14 @@ export function showTooltip(target, text, className = 'cn-tooltip', styleMap = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateUUID() {
|
||||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||||
|
const r = Math.random() * 16 | 0;
|
||||||
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||||
|
return v.toString(16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function initTooltip () {
|
function initTooltip () {
|
||||||
const mouseenterHandler = (e) => {
|
const mouseenterHandler = (e) => {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
@@ -64,7 +64,7 @@ function storeGroupNode(name, data, register=true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function load_components() {
|
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 components = await data.json();
|
||||||
|
|
||||||
let start_time = Date.now();
|
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;
|
pack_map[packname] = component_name;
|
||||||
rpack_map[component_name] = subgraph;
|
rpack_map[component_name] = subgraph;
|
||||||
|
|
||||||
const res = await api.fetchApi('/manager/component/save', {
|
const res = await api.fetchApi('/v2/manager/component/save', {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -259,7 +259,7 @@ async function import_component(component_name, component, mode) {
|
|||||||
workflow: component
|
workflow: component
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await api.fetchApi('/manager/component/save', {
|
const res = await api.fetchApi('/v2/manager/component/save', {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json", },
|
headers: { "Content-Type": "application/json", },
|
||||||
body: JSON.stringify(body)
|
body: JSON.stringify(body)
|
||||||
@@ -709,7 +709,7 @@ app.handleFile = handleFile;
|
|||||||
|
|
||||||
let current_component_policy = 'workflow';
|
let current_component_policy = 'workflow';
|
||||||
try {
|
try {
|
||||||
api.fetchApi('/manager/policy/component')
|
api.fetchApi('/v2/manager/policy/component')
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(data => { current_component_policy = data; });
|
.then(data => { current_component_policy = data; });
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt,
|
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt,
|
||||||
sanitizeHTML, infoToast, showTerminal, setNeedRestart,
|
sanitizeHTML, infoToast, showTerminal, setNeedRestart,
|
||||||
storeColumnWidth, restoreColumnWidth, getTimeAgo, copyText, loadCss,
|
storeColumnWidth, restoreColumnWidth, getTimeAgo, copyText, loadCss,
|
||||||
showPopover, hidePopover
|
showPopover, hidePopover, generateUUID
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
|
|
||||||
// https://cenfun.github.io/turbogrid/api.html
|
// https://cenfun.github.io/turbogrid/api.html
|
||||||
@@ -66,7 +66,7 @@ export class CustomNodesManager {
|
|||||||
this.id = "cn-manager";
|
this.id = "cn-manager";
|
||||||
|
|
||||||
app.registerExtension({
|
app.registerExtension({
|
||||||
name: "Comfy.CustomNodesManager",
|
name: "Comfy.Legacy.CustomNodesManager",
|
||||||
afterConfigureGraph: (missingNodeTypes) => {
|
afterConfigureGraph: (missingNodeTypes) => {
|
||||||
const item = this.getFilterItem(ShowMode.MISSING);
|
const item = this.getFilterItem(ShowMode.MISSING);
|
||||||
if (item) {
|
if (item) {
|
||||||
@@ -459,7 +459,7 @@ export class CustomNodesManager {
|
|||||||
|
|
||||||
".cn-manager-stop": {
|
".cn-manager-stop": {
|
||||||
click: () => {
|
click: () => {
|
||||||
api.fetchApi('/manager/queue/reset');
|
api.fetchApi('/v2/manager/queue/reset');
|
||||||
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
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',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(info)
|
body: JSON.stringify(info)
|
||||||
@@ -1243,7 +1243,7 @@ export class CustomNodesManager {
|
|||||||
async loadNodes(node_packs) {
|
async loadNodes(node_packs) {
|
||||||
const mode = manager_instance.datasrc_combo.value;
|
const mode = manager_instance.datasrc_combo.value;
|
||||||
this.showStatus(`Loading node mappings (${mode}) ...`);
|
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) {
|
if (res.error) {
|
||||||
console.log(res.error);
|
console.log(res.error);
|
||||||
return;
|
return;
|
||||||
@@ -1395,10 +1395,10 @@ export class CustomNodesManager {
|
|||||||
this.showLoading();
|
this.showLoading();
|
||||||
let res;
|
let res;
|
||||||
if(is_enable) {
|
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 {
|
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();
|
this.hideLoading();
|
||||||
|
|
||||||
@@ -1439,13 +1439,6 @@ export class CustomNodesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async installNodes(list, btn, title, selected_version) {
|
async installNodes(list, btn, title, selected_version) {
|
||||||
let stats = await api.fetchApi('/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})`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { target, label, mode} = btn;
|
const { target, label, mode} = btn;
|
||||||
|
|
||||||
if(mode === "uninstall") {
|
if(mode === "uninstall") {
|
||||||
@@ -1472,10 +1465,10 @@ export class CustomNodesManager {
|
|||||||
let needRestart = false;
|
let needRestart = false;
|
||||||
let errorMsg = "";
|
let errorMsg = "";
|
||||||
|
|
||||||
await api.fetchApi('/manager/queue/reset');
|
|
||||||
|
|
||||||
let target_items = [];
|
let target_items = [];
|
||||||
|
|
||||||
|
let batch = {};
|
||||||
|
|
||||||
for (const hash of list) {
|
for (const hash of list) {
|
||||||
const item = this.grid.getRowItemBy("hash", hash);
|
const item = this.grid.getRowItemBy("hash", hash);
|
||||||
target_items.push(item);
|
target_items.push(item);
|
||||||
@@ -1517,23 +1510,11 @@ export class CustomNodesManager {
|
|||||||
api_mode = 'reinstall';
|
api_mode = 'reinstall';
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await api.fetchApi(`/manager/queue/${api_mode}`, {
|
if(batch[api_mode]) {
|
||||||
method: 'POST',
|
batch[api_mode].push(data);
|
||||||
body: JSON.stringify(data)
|
}
|
||||||
});
|
else {
|
||||||
|
batch[api_mode] = [data];
|
||||||
if (res.status != 200) {
|
|
||||||
errorMsg = `'${item.title}': `;
|
|
||||||
|
|
||||||
if(res.status == 403) {
|
|
||||||
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
|
||||||
} else if(res.status == 404) {
|
|
||||||
errorMsg += `With the current security level configuration, only custom nodes from the <B>"default channel"</B> can be installed.\n`;
|
|
||||||
} else {
|
|
||||||
errorMsg += await res.text() + '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1550,7 +1531,24 @@ export class CustomNodesManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await api.fetchApi('/manager/queue/start');
|
this.batch_id = generateUUID();
|
||||||
|
batch['batch_id'] = this.batch_id;
|
||||||
|
|
||||||
|
const res = await api.fetchApi(`/v2/manager/queue/batch`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(batch)
|
||||||
|
});
|
||||||
|
|
||||||
|
let failed = await res.json();
|
||||||
|
|
||||||
|
if(failed.length > 0) {
|
||||||
|
for(let k in failed) {
|
||||||
|
let hash = failed[k];
|
||||||
|
const item = this.grid.getRowItemBy("hash", hash);
|
||||||
|
errorMsg = `[FAIL] ${item.title}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.showStop();
|
this.showStop();
|
||||||
showTerminal();
|
showTerminal();
|
||||||
}
|
}
|
||||||
@@ -1558,6 +1556,9 @@ export class CustomNodesManager {
|
|||||||
|
|
||||||
async onQueueStatus(event) {
|
async onQueueStatus(event) {
|
||||||
let self = CustomNodesManager.instance;
|
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') {
|
if(event.detail.status == 'in_progress' && event.detail.ui_target == 'nodepack_manager') {
|
||||||
const hash = event.detail.target;
|
const hash = event.detail.target;
|
||||||
|
|
||||||
@@ -1568,7 +1569,7 @@ export class CustomNodesManager {
|
|||||||
self.grid.updateCell(item, "action");
|
self.grid.updateCell(item, "action");
|
||||||
self.grid.setRowSelected(item, false);
|
self.grid.setRowSelected(item, false);
|
||||||
}
|
}
|
||||||
else if(event.detail.status == 'done') {
|
else if(event.detail.status == 'batch-done' && event.detail.batch_id == self.batch_id) {
|
||||||
self.hideStop();
|
self.hideStop();
|
||||||
self.onQueueCompleted(event.detail);
|
self.onQueueCompleted(event.detail);
|
||||||
}
|
}
|
||||||
@@ -1744,7 +1745,7 @@ export class CustomNodesManager {
|
|||||||
async getMissingNodesLegacy(hashMap, missing_nodes) {
|
async getMissingNodesLegacy(hashMap, missing_nodes) {
|
||||||
const mode = manager_instance.datasrc_combo.value;
|
const mode = manager_instance.datasrc_combo.value;
|
||||||
this.showStatus(`Loading missing nodes (${mode}) ...`);
|
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) {
|
if (res.error) {
|
||||||
this.showError(`Failed to get custom node mappings: ${res.error}`);
|
this.showError(`Failed to get custom node mappings: ${res.error}`);
|
||||||
return;
|
return;
|
||||||
@@ -1859,7 +1860,7 @@ export class CustomNodesManager {
|
|||||||
async getAlternatives() {
|
async getAlternatives() {
|
||||||
const mode = manager_instance.datasrc_combo.value;
|
const mode = manager_instance.datasrc_combo.value;
|
||||||
this.showStatus(`Loading alternatives (${mode}) ...`);
|
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) {
|
if (res.error) {
|
||||||
this.showError(`Failed to get alternatives: ${res.error}`);
|
this.showError(`Failed to get alternatives: ${res.error}`);
|
||||||
return [];
|
return [];
|
||||||
@@ -1907,7 +1908,7 @@ export class CustomNodesManager {
|
|||||||
infoToast('Fetching updated information. This may take some time if many custom nodes are installed.');
|
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) {
|
if (res.error) {
|
||||||
this.showError("Failed to get custom node list.");
|
this.showError("Failed to get custom node list.");
|
||||||
this.hideLoading();
|
this.hideLoading();
|
||||||
@@ -3,7 +3,7 @@ import { $el } from "../../scripts/ui.js";
|
|||||||
import {
|
import {
|
||||||
manager_instance, rebootAPI,
|
manager_instance, rebootAPI,
|
||||||
fetchData, md5, icons, show_message, customAlert, infoToast, showTerminal,
|
fetchData, md5, icons, show_message, customAlert, infoToast, showTerminal,
|
||||||
storeColumnWidth, restoreColumnWidth, loadCss
|
storeColumnWidth, restoreColumnWidth, loadCss, generateUUID
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
import { api } from "../../scripts/api.js";
|
import { api } from "../../scripts/api.js";
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ export class ModelManager {
|
|||||||
|
|
||||||
".cmm-manager-stop": {
|
".cmm-manager-stop": {
|
||||||
click: () => {
|
click: () => {
|
||||||
api.fetchApi('/manager/queue/reset');
|
api.fetchApi('/v2/manager/queue/reset');
|
||||||
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -413,24 +413,16 @@ export class ModelManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async installModels(list, btn) {
|
async installModels(list, btn) {
|
||||||
let stats = await api.fetchApi('/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})`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
btn.classList.add("cmm-btn-loading");
|
btn.classList.add("cmm-btn-loading");
|
||||||
this.showError("");
|
this.showError("");
|
||||||
|
|
||||||
let needRefresh = false;
|
let needRefresh = false;
|
||||||
let errorMsg = "";
|
let errorMsg = "";
|
||||||
|
|
||||||
await api.fetchApi('/manager/queue/reset');
|
|
||||||
|
|
||||||
let target_items = [];
|
let target_items = [];
|
||||||
|
|
||||||
|
let batch = {};
|
||||||
|
|
||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
this.grid.scrollRowIntoView(item);
|
this.grid.scrollRowIntoView(item);
|
||||||
target_items.push(item);
|
target_items.push(item);
|
||||||
@@ -446,21 +438,12 @@ export class ModelManager {
|
|||||||
const data = item.originalData;
|
const data = item.originalData;
|
||||||
data.ui_id = item.hash;
|
data.ui_id = item.hash;
|
||||||
|
|
||||||
const res = await api.fetchApi(`/manager/queue/install_model`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status != 200) {
|
if(batch['install_model']) {
|
||||||
errorMsg = `'${item.name}': `;
|
batch['install_model'].push(data);
|
||||||
|
}
|
||||||
if(res.status == 403) {
|
else {
|
||||||
errorMsg += `This action is not allowed with this security level configuration.\n`;
|
batch['install_model'] = [data];
|
||||||
} else {
|
|
||||||
errorMsg += await res.text() + '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,7 +460,24 @@ export class ModelManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await api.fetchApi('/manager/queue/start');
|
this.batch_id = generateUUID();
|
||||||
|
batch['batch_id'] = this.batch_id;
|
||||||
|
|
||||||
|
const res = await api.fetchApi(`/v2/manager/queue/batch`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(batch)
|
||||||
|
});
|
||||||
|
|
||||||
|
let failed = await res.json();
|
||||||
|
|
||||||
|
if(failed.length > 0) {
|
||||||
|
for(let k in failed) {
|
||||||
|
let hash = failed[k];
|
||||||
|
const item = self.grid.getRowItemBy("hash", hash);
|
||||||
|
errorMsg = `[FAIL] ${item.title}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.showStop();
|
this.showStop();
|
||||||
showTerminal();
|
showTerminal();
|
||||||
}
|
}
|
||||||
@@ -497,7 +497,7 @@ export class ModelManager {
|
|||||||
// self.grid.updateCell(item, "tg-column-select");
|
// self.grid.updateCell(item, "tg-column-select");
|
||||||
self.grid.updateRow(item);
|
self.grid.updateRow(item);
|
||||||
}
|
}
|
||||||
else if(event.detail.status == 'done') {
|
else if(event.detail.status == 'batch-done') {
|
||||||
self.hideStop();
|
self.hideStop();
|
||||||
self.onQueueCompleted(event.detail);
|
self.onQueueCompleted(event.detail);
|
||||||
}
|
}
|
||||||
@@ -623,7 +623,7 @@ export class ModelManager {
|
|||||||
|
|
||||||
const mode = manager_instance.datasrc_combo.value;
|
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) {
|
if (res.error) {
|
||||||
this.showError("Failed to get external model list.");
|
this.showError("Failed to get external model list.");
|
||||||
this.hideLoading();
|
this.hideLoading();
|
||||||
@@ -142,7 +142,7 @@ function node_info_copy(src, dest, connect_both, copy_shape) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.registerExtension({
|
app.registerExtension({
|
||||||
name: "Comfy.Manager.NodeFixer",
|
name: "Comfy.Legacy.Manager.NodeFixer",
|
||||||
beforeRegisterNodeDef(nodeType, nodeData, app) {
|
beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||||
addMenuHandler(nodeType, function (_, options) {
|
addMenuHandler(nodeType, function (_, options) {
|
||||||
options.push({
|
options.push({
|
||||||
@@ -7,7 +7,7 @@ import { manager_instance, rebootAPI, show_message } from "./common.js";
|
|||||||
async function restore_snapshot(target) {
|
async function restore_snapshot(target) {
|
||||||
if(SnapshotManager.instance) {
|
if(SnapshotManager.instance) {
|
||||||
try {
|
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) {
|
if(response.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
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) {
|
async function remove_snapshot(target) {
|
||||||
if(SnapshotManager.instance) {
|
if(SnapshotManager.instance) {
|
||||||
try {
|
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) {
|
if(response.status == 403) {
|
||||||
show_message('This action is not allowed with this security level configuration.');
|
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() {
|
async function save_current_snapshot() {
|
||||||
try {
|
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();
|
app.ui.dialog.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ async function save_current_snapshot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getSnapshotList() {
|
async function getSnapshotList() {
|
||||||
const response = await api.fetchApi(`/snapshot/getlist`);
|
const response = await api.fetchApi(`/v2/snapshot/getlist`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ class WorkflowMetadataExtension {
|
|||||||
* enabled is true if the node is enabled, false if it is disabled
|
* enabled is true if the node is enabled, false if it is disabled
|
||||||
*/
|
*/
|
||||||
async getInstalledNodes() {
|
async getInstalledNodes() {
|
||||||
const res = await api.fetchApi("/customnode/installed");
|
const res = await api.fetchApi("/v2/customnode/installed");
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
0
comfyui_manager/legacy/__init__.py
Normal file
0
comfyui_manager/legacy/__init__.py
Normal file
3248
comfyui_manager/legacy/manager_core.py
Normal file
3248
comfyui_manager/legacy/manager_core.py
Normal file
File diff suppressed because it is too large
Load Diff
1946
comfyui_manager/legacy/manager_server.py
Normal file
1946
comfyui_manager/legacy/manager_server.py
Normal file
File diff suppressed because it is too large
Load Diff
386
comfyui_manager/legacy/share_3rdparty.py
Normal file
386
comfyui_manager/legacy/share_3rdparty.py
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
import mimetypes
|
||||||
|
from ..common import context
|
||||||
|
from . import manager_core as core
|
||||||
|
|
||||||
|
import os
|
||||||
|
from aiohttp import web
|
||||||
|
import aiohttp
|
||||||
|
import json
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
import folder_paths
|
||||||
|
from server import PromptServer
|
||||||
|
|
||||||
|
|
||||||
|
def extract_model_file_names(json_data):
|
||||||
|
"""Extract unique file names from the input JSON data."""
|
||||||
|
file_names = set()
|
||||||
|
model_filename_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'}
|
||||||
|
|
||||||
|
# Recursively search for file names in the JSON data
|
||||||
|
def recursive_search(data):
|
||||||
|
if isinstance(data, dict):
|
||||||
|
for value in data.values():
|
||||||
|
recursive_search(value)
|
||||||
|
elif isinstance(data, list):
|
||||||
|
for item in data:
|
||||||
|
recursive_search(item)
|
||||||
|
elif isinstance(data, str) and '.' in data:
|
||||||
|
file_names.add(os.path.basename(data)) # file_names.add(data)
|
||||||
|
|
||||||
|
recursive_search(json_data)
|
||||||
|
return [f for f in list(file_names) if os.path.splitext(f)[1] in model_filename_extensions]
|
||||||
|
|
||||||
|
|
||||||
|
def find_file_paths(base_dir, file_names):
|
||||||
|
"""Find the paths of the files in the base directory."""
|
||||||
|
file_paths = {}
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(base_dir):
|
||||||
|
# Exclude certain directories
|
||||||
|
dirs[:] = [d for d in dirs if d not in ['.git']]
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
if file in file_names:
|
||||||
|
file_paths[file] = os.path.join(root, file)
|
||||||
|
return file_paths
|
||||||
|
|
||||||
|
|
||||||
|
def compute_sha256_checksum(filepath):
|
||||||
|
"""Compute the SHA256 checksum of a file, in chunks"""
|
||||||
|
sha256 = hashlib.sha256()
|
||||||
|
with open(filepath, 'rb') as f:
|
||||||
|
for chunk in iter(lambda: f.read(4096), b''):
|
||||||
|
sha256.update(chunk)
|
||||||
|
return sha256.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
@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']
|
||||||
|
core.write_config()
|
||||||
|
else:
|
||||||
|
return web.Response(text=core.get_config()['share_option'], status=200)
|
||||||
|
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
|
def get_openart_auth():
|
||||||
|
if not os.path.exists(os.path.join(context.manager_files_path, ".openart_key")):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
with open(os.path.join(context.manager_files_path, ".openart_key"), "r") as f:
|
||||||
|
openart_key = f.read().strip()
|
||||||
|
return openart_key if openart_key else None
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_matrix_auth():
|
||||||
|
if not os.path.exists(os.path.join(context.manager_files_path, "matrix_auth")):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
with open(os.path.join(context.manager_files_path, "matrix_auth"), "r") as f:
|
||||||
|
matrix_auth = f.read()
|
||||||
|
homeserver, username, password = matrix_auth.strip().split("\n")
|
||||||
|
if not homeserver or not username or not password:
|
||||||
|
return None
|
||||||
|
return {
|
||||||
|
"homeserver": homeserver,
|
||||||
|
"username": username,
|
||||||
|
"password": password,
|
||||||
|
}
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_comfyworkflows_auth():
|
||||||
|
if not os.path.exists(os.path.join(context.manager_files_path, "comfyworkflows_sharekey")):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
with open(os.path.join(context.manager_files_path, "comfyworkflows_sharekey"), "r") as f:
|
||||||
|
share_key = f.read()
|
||||||
|
if not share_key.strip():
|
||||||
|
return None
|
||||||
|
return share_key
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_youml_settings():
|
||||||
|
if not os.path.exists(os.path.join(context.manager_files_path, ".youml")):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
with open(os.path.join(context.manager_files_path, ".youml"), "r") as f:
|
||||||
|
youml_settings = f.read().strip()
|
||||||
|
return youml_settings if youml_settings else None
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def set_youml_settings(settings):
|
||||||
|
with open(os.path.join(context.manager_files_path, ".youml"), "w") as f:
|
||||||
|
f.write(settings)
|
||||||
|
|
||||||
|
|
||||||
|
@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()
|
||||||
|
if not openart_key:
|
||||||
|
return web.Response(status=404)
|
||||||
|
return web.json_response({"openart_key": openart_key})
|
||||||
|
|
||||||
|
|
||||||
|
@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']
|
||||||
|
with open(os.path.join(context.manager_files_path, ".openart_key"), "w") as f:
|
||||||
|
f.write(openart_key)
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
|
@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()
|
||||||
|
if not matrix_auth:
|
||||||
|
return web.Response(status=404)
|
||||||
|
return web.json_response(matrix_auth)
|
||||||
|
|
||||||
|
|
||||||
|
@PromptServer.instance.routes.get("/v2/manager/youml/settings")
|
||||||
|
async def api_get_youml_settings(request):
|
||||||
|
youml_settings = get_youml_settings()
|
||||||
|
if not youml_settings:
|
||||||
|
return web.Response(status=404)
|
||||||
|
return web.json_response(json.loads(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("/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
|
||||||
|
# print("Getting stored Comfyworkflows.com auth...")
|
||||||
|
comfyworkflows_auth = get_comfyworkflows_auth()
|
||||||
|
if not comfyworkflows_auth:
|
||||||
|
return web.Response(status=404)
|
||||||
|
return web.json_response({"comfyworkflows_sharekey": comfyworkflows_auth})
|
||||||
|
|
||||||
|
|
||||||
|
@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(context.manager_files_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
||||||
|
json.dump(json_data, file, indent=4)
|
||||||
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
|
||||||
|
@PromptServer.instance.routes.get("/v2/manager/get_esheep_workflow_and_images")
|
||||||
|
async def get_esheep_workflow_and_images(request):
|
||||||
|
with open(os.path.join(context.manager_files_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
||||||
|
data = json.load(file)
|
||||||
|
return web.Response(status=200, text=json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
|
def set_matrix_auth(json_data):
|
||||||
|
homeserver = json_data['homeserver']
|
||||||
|
username = json_data['username']
|
||||||
|
password = json_data['password']
|
||||||
|
with open(os.path.join(context.manager_files_path, "matrix_auth"), "w") as f:
|
||||||
|
f.write("\n".join([homeserver, username, password]))
|
||||||
|
|
||||||
|
|
||||||
|
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||||
|
with open(os.path.join(context.manager_files_path, "comfyworkflows_sharekey"), "w") as f:
|
||||||
|
f.write(comfyworkflows_sharekey)
|
||||||
|
|
||||||
|
|
||||||
|
def has_provided_matrix_auth(matrix_auth):
|
||||||
|
return matrix_auth['homeserver'].strip() and matrix_auth['username'].strip() and matrix_auth['password'].strip()
|
||||||
|
|
||||||
|
|
||||||
|
def has_provided_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||||
|
return comfyworkflows_sharekey.strip()
|
||||||
|
|
||||||
|
|
||||||
|
@PromptServer.instance.routes.post("/v2/manager/share")
|
||||||
|
async def share_art(request):
|
||||||
|
# get json data
|
||||||
|
json_data = await request.json()
|
||||||
|
|
||||||
|
matrix_auth = json_data['matrix_auth']
|
||||||
|
comfyworkflows_sharekey = json_data['cw_auth']['cw_sharekey']
|
||||||
|
|
||||||
|
set_matrix_auth(matrix_auth)
|
||||||
|
set_comfyworkflows_auth(comfyworkflows_sharekey)
|
||||||
|
|
||||||
|
share_destinations = json_data['share_destinations']
|
||||||
|
credits = json_data['credits']
|
||||||
|
title = json_data['title']
|
||||||
|
description = json_data['description']
|
||||||
|
is_nsfw = json_data['is_nsfw']
|
||||||
|
prompt = json_data['prompt']
|
||||||
|
potential_outputs = json_data['potential_outputs']
|
||||||
|
selected_output_index = json_data['selected_output_index']
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_to_share = potential_outputs[int(selected_output_index)]
|
||||||
|
except:
|
||||||
|
# for now, pick the first output
|
||||||
|
output_to_share = potential_outputs[0]
|
||||||
|
|
||||||
|
assert output_to_share['type'] in ('image', 'output')
|
||||||
|
output_dir = folder_paths.get_output_directory()
|
||||||
|
|
||||||
|
if output_to_share['type'] == 'image':
|
||||||
|
asset_filename = output_to_share['image']['filename']
|
||||||
|
asset_subfolder = output_to_share['image']['subfolder']
|
||||||
|
|
||||||
|
if output_to_share['image']['type'] == 'temp':
|
||||||
|
output_dir = folder_paths.get_temp_directory()
|
||||||
|
else:
|
||||||
|
asset_filename = output_to_share['output']['filename']
|
||||||
|
asset_subfolder = output_to_share['output']['subfolder']
|
||||||
|
|
||||||
|
if asset_subfolder:
|
||||||
|
asset_filepath = os.path.join(output_dir, asset_subfolder, asset_filename)
|
||||||
|
else:
|
||||||
|
asset_filepath = os.path.join(output_dir, asset_filename)
|
||||||
|
|
||||||
|
# get the mime type of the asset
|
||||||
|
assetFileType = mimetypes.guess_type(asset_filepath)[0]
|
||||||
|
|
||||||
|
share_website_host = "UNKNOWN"
|
||||||
|
if "comfyworkflows" in share_destinations:
|
||||||
|
share_website_host = "https://comfyworkflows.com"
|
||||||
|
share_endpoint = f"{share_website_host}/api"
|
||||||
|
|
||||||
|
# get presigned urls
|
||||||
|
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||||
|
async with session.post(
|
||||||
|
f"{share_endpoint}/get_presigned_urls",
|
||||||
|
json={
|
||||||
|
"assetFileName": asset_filename,
|
||||||
|
"assetFileType": assetFileType,
|
||||||
|
"workflowJsonFileName": 'workflow.json',
|
||||||
|
"workflowJsonFileType": 'application/json',
|
||||||
|
},
|
||||||
|
) as resp:
|
||||||
|
assert resp.status == 200
|
||||||
|
presigned_urls_json = await resp.json()
|
||||||
|
assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"]
|
||||||
|
assetFileKey = presigned_urls_json["assetFileKey"]
|
||||||
|
workflowJsonFilePresignedUrl = presigned_urls_json["workflowJsonFilePresignedUrl"]
|
||||||
|
workflowJsonFileKey = presigned_urls_json["workflowJsonFileKey"]
|
||||||
|
|
||||||
|
# upload asset
|
||||||
|
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||||
|
async with session.put(assetFilePresignedUrl, data=open(asset_filepath, "rb")) as resp:
|
||||||
|
assert resp.status == 200
|
||||||
|
|
||||||
|
# upload workflow json
|
||||||
|
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||||
|
async with session.put(workflowJsonFilePresignedUrl, data=json.dumps(prompt['workflow']).encode('utf-8')) as resp:
|
||||||
|
assert resp.status == 200
|
||||||
|
|
||||||
|
model_filenames = extract_model_file_names(prompt['workflow'])
|
||||||
|
model_file_paths = find_file_paths(folder_paths.base_path, model_filenames)
|
||||||
|
|
||||||
|
models_info = {}
|
||||||
|
for filename, filepath in model_file_paths.items():
|
||||||
|
models_info[filename] = {
|
||||||
|
"filename": filename,
|
||||||
|
"sha256_checksum": compute_sha256_checksum(filepath),
|
||||||
|
"relative_path": os.path.relpath(filepath, folder_paths.base_path),
|
||||||
|
}
|
||||||
|
|
||||||
|
# make a POST request to /api/upload_workflow with form data key values
|
||||||
|
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||||
|
form = aiohttp.FormData()
|
||||||
|
if comfyworkflows_sharekey:
|
||||||
|
form.add_field("shareKey", comfyworkflows_sharekey)
|
||||||
|
form.add_field("source", "comfyui_manager")
|
||||||
|
form.add_field("assetFileKey", assetFileKey)
|
||||||
|
form.add_field("assetFileType", assetFileType)
|
||||||
|
form.add_field("workflowJsonFileKey", workflowJsonFileKey)
|
||||||
|
form.add_field("sharedWorkflowWorkflowJsonString", json.dumps(prompt['workflow']))
|
||||||
|
form.add_field("sharedWorkflowPromptJsonString", json.dumps(prompt['output']))
|
||||||
|
form.add_field("shareWorkflowCredits", credits)
|
||||||
|
form.add_field("shareWorkflowTitle", title)
|
||||||
|
form.add_field("shareWorkflowDescription", description)
|
||||||
|
form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower())
|
||||||
|
form.add_field("currentSnapshot", json.dumps(await core.get_current_snapshot()))
|
||||||
|
form.add_field("modelsInfo", json.dumps(models_info))
|
||||||
|
|
||||||
|
async with session.post(
|
||||||
|
f"{share_endpoint}/upload_workflow",
|
||||||
|
data=form,
|
||||||
|
) as resp:
|
||||||
|
assert resp.status == 200
|
||||||
|
upload_workflow_json = await resp.json()
|
||||||
|
workflowId = upload_workflow_json["workflowId"]
|
||||||
|
|
||||||
|
# check if the user has provided Matrix credentials
|
||||||
|
if "matrix" in share_destinations:
|
||||||
|
comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org'
|
||||||
|
filename = os.path.basename(asset_filepath)
|
||||||
|
content_type = assetFileType
|
||||||
|
|
||||||
|
try:
|
||||||
|
from matrix_client.api import MatrixHttpApi
|
||||||
|
from matrix_client.client import MatrixClient
|
||||||
|
|
||||||
|
homeserver = 'matrix.org'
|
||||||
|
if matrix_auth:
|
||||||
|
homeserver = matrix_auth.get('homeserver', 'matrix.org')
|
||||||
|
homeserver = homeserver.replace("http://", "https://")
|
||||||
|
if not homeserver.startswith("https://"):
|
||||||
|
homeserver = "https://" + homeserver
|
||||||
|
|
||||||
|
client = MatrixClient(homeserver)
|
||||||
|
try:
|
||||||
|
token = client.login(username=matrix_auth['username'], password=matrix_auth['password'])
|
||||||
|
if not token:
|
||||||
|
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
|
||||||
|
except:
|
||||||
|
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
|
||||||
|
|
||||||
|
matrix = MatrixHttpApi(homeserver, token=token)
|
||||||
|
with open(asset_filepath, 'rb') as f:
|
||||||
|
mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri']
|
||||||
|
|
||||||
|
workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri']
|
||||||
|
|
||||||
|
text_content = ""
|
||||||
|
if title:
|
||||||
|
text_content += f"{title}\n"
|
||||||
|
if description:
|
||||||
|
text_content += f"{description}\n"
|
||||||
|
if credits:
|
||||||
|
text_content += f"\ncredits: {credits}\n"
|
||||||
|
matrix.send_message(comfyui_share_room_id, text_content)
|
||||||
|
matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image')
|
||||||
|
matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file')
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500)
|
||||||
|
|
||||||
|
return web.json_response({
|
||||||
|
"comfyworkflows": {
|
||||||
|
"url": None if "comfyworkflows" not in share_destinations else f"{share_website_host}/workflows/{workflowId}",
|
||||||
|
},
|
||||||
|
"matrix": {
|
||||||
|
"success": None if "matrix" not in share_destinations else True
|
||||||
|
}
|
||||||
|
}, content_type='application/json', status=200)
|
||||||
@@ -12,13 +12,10 @@ import ast
|
|||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
glob_path = os.path.join(os.path.dirname(__file__), "glob")
|
from .common import security_check
|
||||||
sys.path.append(glob_path)
|
from .common import manager_util
|
||||||
|
from .common import cm_global
|
||||||
import security_check
|
from .common import manager_downloader
|
||||||
import manager_util
|
|
||||||
import cm_global
|
|
||||||
import manager_downloader
|
|
||||||
import folder_paths
|
import folder_paths
|
||||||
|
|
||||||
manager_util.add_python_path_to_env()
|
manager_util.add_python_path_to_env()
|
||||||
@@ -68,15 +65,17 @@ comfy_path = os.environ.get('COMFYUI_PATH')
|
|||||||
comfy_base_path = os.environ.get('COMFYUI_FOLDERS_BASE_PATH')
|
comfy_base_path = os.environ.get('COMFYUI_FOLDERS_BASE_PATH')
|
||||||
|
|
||||||
if comfy_path is None:
|
if comfy_path is None:
|
||||||
# legacy env var
|
try:
|
||||||
comfy_path = os.environ.get('COMFYUI_PATH')
|
comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__))
|
||||||
|
os.environ['COMFYUI_PATH'] = comfy_path
|
||||||
if comfy_path is None:
|
except:
|
||||||
comfy_path = os.path.abspath(os.path.dirname(sys.modules['__main__'].__file__))
|
print("[ComfyUI-Manager] environment variable 'COMFYUI_PATH' is not specified.")
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
if comfy_base_path is None:
|
if comfy_base_path is None:
|
||||||
comfy_base_path = comfy_path
|
comfy_base_path = comfy_path
|
||||||
|
|
||||||
|
|
||||||
sys.__comfyui_manager_register_message_collapse = register_message_collapse
|
sys.__comfyui_manager_register_message_collapse = register_message_collapse
|
||||||
sys.__comfyui_manager_is_import_failed_extension = is_import_failed_extension
|
sys.__comfyui_manager_is_import_failed_extension = is_import_failed_extension
|
||||||
cm_global.register_api('cm.register_message_collapse', register_message_collapse)
|
cm_global.register_api('cm.register_message_collapse', register_message_collapse)
|
||||||
@@ -121,12 +120,11 @@ read_config()
|
|||||||
read_uv_mode()
|
read_uv_mode()
|
||||||
check_file_logging()
|
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):
|
if os.path.exists(manager_pip_overrides_path):
|
||||||
with open(manager_pip_overrides_path, 'r', encoding="UTF-8", errors="ignore") as json_file:
|
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 = json.load(json_file)
|
||||||
cm_global.pip_overrides['numpy'] = 'numpy<2'
|
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):
|
if os.path.exists(manager_pip_blacklist_path):
|
||||||
@@ -393,7 +391,11 @@ try:
|
|||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
global is_start_mode
|
global is_start_mode
|
||||||
|
|
||||||
message = record.getMessage()
|
try:
|
||||||
|
message = record.getMessage()
|
||||||
|
except Exception as e:
|
||||||
|
message = f"<<logging error>>: {record} - {e}"
|
||||||
|
original_stderr.write(message)
|
||||||
|
|
||||||
if is_start_mode:
|
if is_start_mode:
|
||||||
match = re.search(pat_import_fail, message)
|
match = re.search(pat_import_fail, message)
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,62 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools >= 61.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "comfyui-manager"
|
name = "comfyui-manager"
|
||||||
|
license = { text = "GPL-3.0-only" }
|
||||||
|
version = "4.0.0-beta.1"
|
||||||
|
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."
|
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.10"
|
readme = "README.md"
|
||||||
license = { file = "LICENSE.txt" }
|
keywords = ["comfyui", "comfyui-manager"]
|
||||||
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]
|
|
||||||
|
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]
|
[project.urls]
|
||||||
Repository = "https://github.com/ltdrdata/ComfyUI-Manager"
|
Repository = "https://github.com/ltdrdata/ComfyUI-Manager"
|
||||||
# Used by Comfy Registry https://comfyregistry.org
|
|
||||||
|
|
||||||
[tool.comfy]
|
[tool.setuptools.packages.find]
|
||||||
PublisherId = "drltdata"
|
where = ["."]
|
||||||
DisplayName = "ComfyUI-Manager"
|
include = ["comfyui_manager*"]
|
||||||
Icon = ""
|
|
||||||
|
[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)
|
||||||
|
]
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user