Compare commits

...

15 Commits
3.13 ... 3.16

Author SHA1 Message Date
Dr.Lt.Data
bd9aae40b8 update DB 2025-02-02 17:40:07 +09:00
Dr.Lt.Data
33f931c0a4 feat: Support for uv has been added.
Set `use_uv` in `config.ini`.
2025-02-02 17:26:29 +09:00
Dr.Lt.Data
ede8279c17 remove legacy ui components
- default_ui
- a1111
2025-02-02 15:27:29 +09:00
Dr.Lt.Data
268b84a2b6 fixed: broken db item
fixed: robust getlist

https://github.com/ltdrdata/ComfyUI-Manager/issues/1508
2025-02-02 14:52:46 +09:00
Dr.Lt.Data
0a67145d80 code formatting 2025-02-02 14:40:11 +09:00
bymyself
2e55bc470c Add commands to toggle visibility of manager and custom nodes manager menus (#1505)
* Add commands for manager keybindings

* use more consistent isVisible condition check

* remove hide method in favor of super class's close method

* fix formatting

* fix tabs formatting
2025-02-02 14:37:04 +09:00
Dr.Lt.Data
cf0d038978 update DB 2025-02-02 14:33:35 +09:00
Dr.Lt.Data
92e7db1082 update DB 2025-02-02 14:30:30 +09:00
aiartvn
c45c47f935 Add A2V Multi Image Composite node (#1507)
* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

* Update custom-node-list.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-02-02 14:29:27 +09:00
Dr.Lt.Data
341e27f9a3 update DB 2025-02-02 11:07:09 +09:00
ProGamerGov
ab167175c9 Add Preview 360 Panorma custom node (#1506)
* Update custom-node-list.json

* Update extension-node-map.json

* Update custom-node-list.json

* Update custom-node-list.json

* Update extension-node-map.json

---------

Co-authored-by: Dr.Lt.Data <128333288+ltdrdata@users.noreply.github.com>
2025-02-02 10:46:17 +09:00
Dr.Lt.Data
3c2933338f fixed: /manager/queue/status - race condition issue 2025-02-02 10:38:05 +09:00
Robin Huang
829784fa50 Fix conditional for switch ComfyUI. 2025-02-01 16:16:37 -08:00
Robin Huang
3c45f8dc91 Hide update comfyui buttons in electron. 2025-02-01 16:15:27 -08:00
Dr.Lt.Data
f8ebf7c6ad update DB 2025-02-01 16:45:24 +09:00
19 changed files with 3034 additions and 2629 deletions

View File

@@ -5,6 +5,7 @@
![menu](https://raw.githubusercontent.com/ltdrdata/ComfyUI-extension-tutorials/refs/heads/Main/ComfyUI-Manager/images/dialog.jpg) ![menu](https://raw.githubusercontent.com/ltdrdata/ComfyUI-extension-tutorials/refs/heads/Main/ComfyUI-Manager/images/dialog.jpg)
## NOTICE ## NOTICE
* 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
* V3.3.2: Overhauled. Officially supports [https://comfyregistry.org/](https://comfyregistry.org/). * V3.3.2: Overhauled. Officially supports [https://comfyregistry.org/](https://comfyregistry.org/).
@@ -246,6 +247,24 @@ The following settings are applied based on the section marked as `is_default`.
![missing-list](https://raw.githubusercontent.com/ltdrdata/ComfyUI-extension-tutorials/Main/ComfyUI-Manager/images/missing-list.jpg) ![missing-list](https://raw.githubusercontent.com/ltdrdata/ComfyUI-extension-tutorials/Main/ComfyUI-Manager/images/missing-list.jpg)
# Config
* You can modify the `config.ini` file to apply the settings for ComfyUI-Manager.
* The path to the `config.ini` used by ComfyUI-Manager is displayed in the startup log messages.
* See also: [https://github.com/ltdrdata/ComfyUI-Manager#paths]
* Configuration options:
```
[default]
git_exe = <Manually specify the path to the git executable. If left empty, the default git executable path will be used.>
use_uv = <Use uv instead of pip for dependency installation.>
channel_url = https://raw.githubusercontent.com/ltdrdata/ComfyUI-Manager/main
bypass_ssl = <Set to True if SSL errors occur to disable SSL.>
file_logging = <Configure whether to create a log file used by ComfyUI-Manager.>
windows_selector_event_loop_policy = <If an event loop error occurs on Windows, set this to True.>
model_download_by_agent = <When downloading models, use an agent instead of torchvision_download_url.>
downgrade_blacklist = <Set a list of packages to prevent downgrades. List them separated by commas.>
security_level = <Set the security level.>
```
## Additional Feature ## Additional Feature
* Logging to file feature * Logging to file feature
* This feature is enabled by default and can be disabled by setting `file_logging = False` in the `config.ini`. * This feature is enabled by default and can be disabled by setting `file_logging = False` in the `config.ini`.

View File

@@ -4067,6 +4067,17 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Image metrics nodes for ComfyUI" "description": "Image metrics nodes for ComfyUI"
}, },
{
"author": "amorano",
"title": "Jovi_MIDI",
"id": "jovi_midi",
"reference": "https://github.com/Amorano/Jovi_MIDI",
"files": [
"https://github.com/Amorano/Jovi_MIDI"
],
"install_type": "git-clone",
"description": "Read and Process data from MIDI devices inside of ComfyUI."
},
{ {
"author": "Umikaze-job", "author": "Umikaze-job",
"title": "select_folder_path_easy", "title": "select_folder_path_easy",
@@ -6496,6 +6507,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Add nodes that generates danbooru tags by [a/Dart(Danbooru Tags Transformer)](https://huggingface.co/p1atdev/dart-v1-sft)." "description": "Add nodes that generates danbooru tags by [a/Dart(Danbooru Tags Transformer)](https://huggingface.co/p1atdev/dart-v1-sft)."
}, },
{
"author": "nkchocoai",
"title": "ComfyUI-DanbooruPromptQuiz",
"reference": "https://github.com/nkchocoai/ComfyUI-DanbooruPromptQuiz",
"files": [
"https://github.com/nkchocoai/ComfyUI-DanbooruPromptQuiz"
],
"install_type": "git-clone",
"description": "This node is for playing the game of guessing prompts by looking at images generated from prompts output by TIPO, Tagger, etc.."
},
{ {
"author": "JaredTherriault", "author": "JaredTherriault",
"title": "ComfyUI-JNodes", "title": "ComfyUI-JNodes",
@@ -11042,6 +11063,16 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "Custom node for using Prompt S/R in XY Plot\nAlso includes nodes for listing generic parameters like seed and cfg\nEasy to manipulate as elements are separated by line breaks\nDesigned for use with the XY Plot custom node qq-nodes-comfyui, but may work with other custom nodes as well" "description": "Custom node for using Prompt S/R in XY Plot\nAlso includes nodes for listing generic parameters like seed and cfg\nEasy to manipulate as elements are separated by line breaks\nDesigned for use with the XY Plot custom node qq-nodes-comfyui, but may work with other custom nodes as well"
}, },
{
"author": "da2el-ai",
"title": "D2-PromptSelector-comfyUI",
"reference": "https://github.com/da2el-ai/D2-PromptSelector-comfyUI",
"files": [
"https://github.com/da2el-ai/D2-PromptSelector-comfyUI"
],
"install_type": "git-clone",
"description": "This is a version of [a/sd-d2-prompt-selector](https://github.com/da2el-ai/sd-d2-prompt-selector) reworked for ComfyUI. It's just a prototype that I've put together for now. The random syntax of sd-d2-prompt-selector cannot be used; instead, the DynamicPrompt syntax is used"
},
{ {
"author": "nat-chan", "author": "nat-chan",
"title": "ComfyUI-Transceiver📡", "title": "ComfyUI-Transceiver📡",
@@ -19966,7 +19997,7 @@
"https://github.com/DJ-Tribefull/Comfyui_FOCUS_nodes" "https://github.com/DJ-Tribefull/Comfyui_FOCUS_nodes"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "This is a small collection of nodes designed for efficiency and the reduction of screen clutter. I work primarily with a two-stage SDXL workflow, so some of the nodes are tailored to that, but many of the most useful nodes can be used in any context." "description": "A collection of nodes designed for efficiency and the reduction of screen-clutter. Includes a Global Seed controller with boolean toggles, SDXL All-in-One conditioner, a custom SDXL control module, Wildcard processor, Style Injector, and more. [w/WARNING: Updating this node-pack wil overwrite any changes you've made to the included wildcards and styles. Please backup your folders before updating.]"
}, },
{ {
"author": "KLL535", "author": "KLL535",
@@ -20190,7 +20221,18 @@
"https://github.com/ProGamerGov/ComfyUI_pytorch360convert" "https://github.com/ProGamerGov/ComfyUI_pytorch360convert"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "A collection of custom nodes for working with and converting between 360 degree equirectangular images, cubemap, and perspective images. Panoramic 360 images are also sometimes known as VR photography (virtual reality), HDRI environments (ex: skyboxes), image spheres, spherical images, 360 pano." "description": "A collection of custom nodes for working with and converting between 360 degree equirectangular images, cubemap, and perspective images. Panoramic 360 images are also sometimes known as VR photography (virtual reality), HDRI environments (ex: skyboxes), image spheres, spherical images, 360 pano, and 360 degree photos."
},
{
"author": "ProGamerGov",
"title": "Preview 360 Panorama for ComfyUI",
"id": "comfyui-preview360panorama",
"reference": "https://github.com/ProGamerGov/ComfyUI_preview360panorama",
"files": [
"https://github.com/ProGamerGov/ComfyUI_preview360panorama"
],
"install_type": "git-clone",
"description": "A custom ComfyUI node for interactive 360° panorama image previews. Panoramic 360 images are also sometimes known as VR photography (virtual reality), HDRI environments (ex: skyboxes), image spheres, spherical images, 360 pano, and 360 degree photos."
}, },
{ {
"author": "burnsbert", "author": "burnsbert",
@@ -20251,7 +20293,7 @@
"https://github.com/willmiao/ComfyUI-Lora-Manager" "https://github.com/willmiao/ComfyUI-Lora-Manager"
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "LoRA Manager for ComfyUI - An extension for managing LoRA models with previews and metadata integration." "description": "LoRA Manager for ComfyUI - Access it at http://localhost:8188/loras for managing LoRA models with previews and metadata integration."
}, },
{ {
"author": "tigeryy2", "author": "tigeryy2",
@@ -20364,6 +20406,28 @@
"install_type": "git-clone", "install_type": "git-clone",
"description": "This node group contains a series of ComfyUI nodes with built-in counters and specific output results based on the counter's output, aimed at implementing folder traversal functionality in the ComfyUI frontend. For specific examples, please refer to the sample workflow. Of course, you can also use your imagination to create other interesting things." "description": "This node group contains a series of ComfyUI nodes with built-in counters and specific output results based on the counter's output, aimed at implementing folder traversal functionality in the ComfyUI frontend. For specific examples, please refer to the sample workflow. Of course, you can also use your imagination to create other interesting things."
}, },
{
"author": "agilly1989",
"title": "ComfyUI_agilly1989_motorway",
"reference": "https://github.com/agilly1989/ComfyUI_agilly1989_motorway",
"files": [
"https://github.com/agilly1989/ComfyUI_agilly1989_motorway"
],
"install_type": "git-clone",
"description": "This my implemenation of a `pipe` in ComfyUI. Is it better or worse than others? No idea."
},
{
"author": "AiartvnTeam",
"title": "A2V Multi Image Composite",
"id": "Aiartvn",
"reference": "https://github.com/aiartvn/A2V_Multi_Image_Composite",
"files": [
"https://github.com/aiartvn/A2V_Multi_Image_Composite"
],
"description": "Node for compositing multiple images with interactive preview and layer management",
"install_type": "git-clone",
"tags": ["image", "composite", "layer", "blend", "transform"]
},

View File

@@ -493,6 +493,7 @@
"https://github.com/852wa/ComfyUI-ColorshiftColor": [ "https://github.com/852wa/ComfyUI-ColorshiftColor": [
[ [
"ColorshiftColor", "ColorshiftColor",
"CsCFill",
"CsCPaletteEditor" "CsCPaletteEditor"
], ],
{ {
@@ -1427,6 +1428,18 @@
"title_aux": "Jovi_GLSL" "title_aux": "Jovi_GLSL"
} }
], ],
"https://github.com/Amorano/Jovi_MIDI": [
[
"MIDI FILTER (JOV_MIDI)",
"MIDI FILTER EZ (JOV_MIDI)",
"MIDI LOADER (JOV_MIDI)",
"MIDI MESSAGE (JOV_MIDI)",
"MIDI READER (JOV_MIDI)"
],
{
"title_aux": "Jovi_MIDI"
}
],
"https://github.com/Amorano/Jovi_Measure": [ "https://github.com/Amorano/Jovi_Measure": [
[ [
"BLUR EFFECT (JOV_MEASURE)", "BLUR EFFECT (JOV_MEASURE)",
@@ -5017,6 +5030,7 @@
[ [
"Simple Extract Lora From Text", "Simple Extract Lora From Text",
"Simple Image Saver (as Forge)", "Simple Image Saver (as Forge)",
"Simple Load Image With Metadata",
"Simple Load Line From Text File", "Simple Load Line From Text File",
"Simple Lora Loader" "Simple Lora Loader"
], ],
@@ -6433,10 +6447,13 @@
], ],
"https://github.com/MzMaXaM/ComfyUi-MzMaXaM": [ "https://github.com/MzMaXaM/ComfyUi-MzMaXaM": [
[ [
"ImageToText",
"KSamplerWithVAE", "KSamplerWithVAE",
"SelectLatentSize1MP", "SelectLatentSize1MP",
"SelectLatentSize2MP", "SelectLatentSize2MP",
"TextEncode3in1", "TextEncode3in1",
"TextToText",
"UpscaleImageBy1_5x",
"UpscaleLatentBy1_5x" "UpscaleLatentBy1_5x"
], ],
{ {
@@ -7060,6 +7077,14 @@
"title_aux": "ComfyUI-StringsAndThings" "title_aux": "ComfyUI-StringsAndThings"
} }
], ],
"https://github.com/ProGamerGov/ComfyUI_preview360panorama": [
[
"PanoramaViewerNode"
],
{
"title_aux": "Preview 360 Panorama for ComfyUI"
}
],
"https://github.com/ProGamerGov/ComfyUI_pytorch360convert": [ "https://github.com/ProGamerGov/ComfyUI_pytorch360convert": [
[ [
"Crop Image with Coords", "Crop Image with Coords",
@@ -8453,6 +8478,7 @@
"Star Face Loader", "Star Face Loader",
"StarFiveWildcards", "StarFiveWildcards",
"StarImageSwitch", "StarImageSwitch",
"StarLatentSwitch",
"StarTextFilter", "StarTextFilter",
"StarTextInput", "StarTextInput",
"Starupscale" "Starupscale"
@@ -10647,6 +10673,18 @@
"title_aux": "ComfyUI-styles-all" "title_aux": "ComfyUI-styles-all"
} }
], ],
"https://github.com/agilly1989/ComfyUI_agilly1989_motorway": [
[
"MotorwayFloat",
"MotorwayInt",
"MotorwaySeed",
"MotorwayStr",
"MotorwayStrMulti"
],
{
"title_aux": "ComfyUI_agilly1989_motorway"
}
],
"https://github.com/ahernandezmiro/ComfyUI-GCP_Storage_tools": [ "https://github.com/ahernandezmiro/ComfyUI-GCP_Storage_tools": [
[ [
"GCPReadImageNode", "GCPReadImageNode",
@@ -10722,6 +10760,14 @@
"title_aux": "Comfy UI FatLabels" "title_aux": "Comfy UI FatLabels"
} }
], ],
"https://github.com/aiartvn/A2V_Multi_Image_Composite": [
[
"A2V_Multi_Image_Composite"
],
{
"title_aux": "A2V Multi Image Composite"
}
],
"https://github.com/aidec/Comfyui_TextBatch_aidec": [ "https://github.com/aidec/Comfyui_TextBatch_aidec": [
[ [
"ImageQueueProcessor", "ImageQueueProcessor",
@@ -15458,7 +15504,8 @@
"SelOutModel", "SelOutModel",
"SelOutPolar", "SelOutPolar",
"Selector", "Selector",
"Selector Advanced" "Selector Advanced",
"Selector Hub"
], ],
{ {
"author": "\"\u02f6\ud835\udfa2\u292c\u2ad2\u2d56s\u143c\u02f6\"", "author": "\"\u02f6\ud835\udfa2\u292c\u2ad2\u2d56s\u143c\u02f6\"",
@@ -19314,6 +19361,7 @@
"GetImageRangeFromBatch", "GetImageRangeFromBatch",
"GetImageSizeAndCount", "GetImageSizeAndCount",
"GetImagesFromBatchIndexed", "GetImagesFromBatchIndexed",
"GetLatentRangeFromBatch",
"GetLatentsFromBatchIndexed", "GetLatentsFromBatchIndexed",
"GetMaskSizeAndCount", "GetMaskSizeAndCount",
"GradientToFloat", "GradientToFloat",
@@ -19332,6 +19380,7 @@
"ImageGridComposite2x2", "ImageGridComposite2x2",
"ImageGridComposite3x3", "ImageGridComposite3x3",
"ImageGridtoBatch", "ImageGridtoBatch",
"ImageNoiseAugmentation",
"ImageNormalize_Neg1_To_1", "ImageNormalize_Neg1_To_1",
"ImagePadForOutpaintMasked", "ImagePadForOutpaintMasked",
"ImagePadForOutpaintTargetSize", "ImagePadForOutpaintTargetSize",
@@ -19347,6 +19396,7 @@
"Intrinsic_lora_sampling", "Intrinsic_lora_sampling",
"JoinStringMulti", "JoinStringMulti",
"JoinStrings", "JoinStrings",
"LeapfusionHunyuanI2VPatcher",
"LoadAndResizeImage", "LoadAndResizeImage",
"LoadImagesFromFolderKJ", "LoadImagesFromFolderKJ",
"LoadResAdapterNormalization", "LoadResAdapterNormalization",
@@ -20741,6 +20791,7 @@
"Enhanced Random Light Source", "Enhanced Random Light Source",
"Float Relay", "Float Relay",
"HLFrequencyDetailRestore", "HLFrequencyDetailRestore",
"Hex to Color",
"Image Add Alpha", "Image Add Alpha",
"Image Frequency Analyzer", "Image Frequency Analyzer",
"Image Relay", "Image Relay",
@@ -22582,6 +22633,15 @@
"title_aux": "ComfyUI OpenAI Prompter" "title_aux": "ComfyUI OpenAI Prompter"
} }
], ],
"https://github.com/nkchocoai/ComfyUI-DanbooruPromptQuiz": [
[
"DanbooruPromptComparison",
"DanbooruPromptQuiz"
],
{
"title_aux": "ComfyUI-DanbooruPromptQuiz"
}
],
"https://github.com/nkchocoai/ComfyUI-Dart": [ "https://github.com/nkchocoai/ComfyUI-Dart": [
[ [
"DanbooruTagsTransformerBanTagsFromRegex", "DanbooruTagsTransformerBanTagsFromRegex",
@@ -22687,6 +22747,7 @@
], ],
"https://github.com/nofunstudio/Node_Fun_ComfyUI": [ "https://github.com/nofunstudio/Node_Fun_ComfyUI": [
[ [
"IframeView",
"LayeredInfiniteZoom", "LayeredInfiniteZoom",
"Replicate flux 1.1 pro ultra", "Replicate flux 1.1 pro ultra",
"ReplicateAPI_flux_1_1_pro_ultra", "ReplicateAPI_flux_1_1_pro_ultra",
@@ -26170,6 +26231,7 @@
"quadmoonChangeBackground", "quadmoonChangeBackground",
"quadmoonConvertBoolToString", "quadmoonConvertBoolToString",
"quadmoonConvertFloatToString", "quadmoonConvertFloatToString",
"quadmoonConvertImageToPrompt",
"quadmoonConvertIntToString", "quadmoonConvertIntToString",
"quadmoonConvertNormalizeHW", "quadmoonConvertNormalizeHW",
"quadmoonConvertNumberToString", "quadmoonConvertNumberToString",
@@ -27146,6 +27208,7 @@
], ],
"https://github.com/xlinx/ComfyUI-decadetw-auto-prompt-llm": [ "https://github.com/xlinx/ComfyUI-decadetw-auto-prompt-llm": [
[ [
"Auto-LLM-Chat",
"Auto-LLM-Text", "Auto-LLM-Text",
"Auto-LLM-Text-Vision", "Auto-LLM-Text-Vision",
"Auto-LLM-Vision" "Auto-LLM-Vision"

View File

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ description:
""" """
import json import json
import logging
import os import os
import sys import sys
import subprocess import subprocess
@@ -41,7 +42,7 @@ import manager_downloader
from node_package import InstalledNodePackage from node_package import InstalledNodePackage
version_code = [3, 13] version_code = [3, 16]
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 '')
@@ -808,7 +809,7 @@ class UnifiedManager:
package_name = remap_pip_package(line.strip()) package_name = remap_pip_package(line.strip())
if package_name and not package_name.startswith('#') and package_name not in self.processed_install: if package_name and not package_name.startswith('#') and package_name not in self.processed_install:
self.processed_install.add(package_name) self.processed_install.add(package_name)
install_cmd = [sys.executable, "-m", "pip", "install", package_name] install_cmd = manager_util.make_pip_cmd(["install", package_name])
if package_name.strip() != "" and not package_name.startswith('#'): if package_name.strip() != "" and not package_name.startswith('#'):
res = res and try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution) res = res and try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution)
@@ -818,7 +819,7 @@ class UnifiedManager:
if os.path.exists(install_script_path) and install_script_path not in self.processed_install: if os.path.exists(install_script_path) and install_script_path not in self.processed_install:
self.processed_install.add(install_script_path) self.processed_install.add(install_script_path)
print("Install: install script") print("Install: install script")
install_cmd = [sys.executable, "install.py"] install_cmd = manager_util.make_pip_cmd(["install.py"])
return try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution) return try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution)
return True return True
@@ -1544,12 +1545,12 @@ def write_config():
config = configparser.ConfigParser() config = configparser.ConfigParser()
config['default'] = { config['default'] = {
'preview_method': manager_funcs.get_current_preview_method(), 'preview_method': manager_funcs.get_current_preview_method(),
'git_exe': get_config()['git_exe'], 'git_exe': get_config()['git_exe'],
'use_uv': get_config()['use_uv'],
'channel_url': get_config()['channel_url'], 'channel_url': get_config()['channel_url'],
'share_option': get_config()['share_option'], 'share_option': get_config()['share_option'],
'bypass_ssl': get_config()['bypass_ssl'], 'bypass_ssl': get_config()['bypass_ssl'],
"file_logging": get_config()['file_logging'], "file_logging": get_config()['file_logging'],
'default_ui': get_config()['default_ui'],
'component_policy': get_config()['component_policy'], 'component_policy': get_config()['component_policy'],
'windows_selector_event_loop_policy': get_config()['windows_selector_event_loop_policy'], 'windows_selector_event_loop_policy': get_config()['windows_selector_event_loop_policy'],
'model_download_by_agent': get_config()['model_download_by_agent'], 'model_download_by_agent': get_config()['model_download_by_agent'],
@@ -1581,31 +1582,34 @@ def read_config():
else: else:
security_level = default_conf['security_level'] if 'security_level' in default_conf else 'normal' security_level = default_conf['security_level'] if 'security_level' in default_conf else 'normal'
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
return { return {
'preview_method': default_conf['preview_method'] if 'preview_method' in default_conf else manager_funcs.get_current_preview_method(), 'preview_method': default_conf['preview_method'] if 'preview_method' in default_conf else manager_funcs.get_current_preview_method(),
'git_exe': default_conf['git_exe'] if 'git_exe' in default_conf else '', 'git_exe': default_conf['git_exe'] if 'git_exe' in default_conf else '',
'use_uv': default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False,
'channel_url': default_conf['channel_url'] if 'channel_url' in default_conf else DEFAULT_CHANNEL, 'channel_url': default_conf['channel_url'] if 'channel_url' in default_conf else DEFAULT_CHANNEL,
'share_option': default_conf['share_option'] if 'share_option' in default_conf else 'all', 'share_option': default_conf['share_option'] if 'share_option' in default_conf else 'all',
'bypass_ssl': default_conf['bypass_ssl'].lower() == 'true' if 'bypass_ssl' in default_conf else False, 'bypass_ssl': default_conf['bypass_ssl'].lower() == 'true' if 'bypass_ssl' in default_conf else False,
'file_logging': default_conf['file_logging'].lower() == 'true' if 'file_logging' in default_conf else True, 'file_logging': default_conf['file_logging'].lower() == 'true' if 'file_logging' in default_conf else True,
'default_ui': default_conf['default_ui'] if 'default_ui' in default_conf else 'none',
'component_policy': default_conf['component_policy'] if 'component_policy' in default_conf else 'workflow', 'component_policy': default_conf['component_policy'] if 'component_policy' in default_conf else 'workflow',
'windows_selector_event_loop_policy': default_conf['windows_selector_event_loop_policy'].lower() == 'true' if 'windows_selector_event_loop_policy' in default_conf else False, 'windows_selector_event_loop_policy': default_conf['windows_selector_event_loop_policy'].lower() == 'true' if 'windows_selector_event_loop_policy' in default_conf else False,
'model_download_by_agent': default_conf['model_download_by_agent'].lower() == 'true' if 'model_download_by_agent' in default_conf else False, 'model_download_by_agent': default_conf['model_download_by_agent'].lower() == 'true' if 'model_download_by_agent' in default_conf else False,
'downgrade_blacklist': default_conf['downgrade_blacklist'] if 'downgrade_blacklist' in default_conf else '', 'downgrade_blacklist': default_conf['downgrade_blacklist'] if 'downgrade_blacklist' in default_conf else '',
'skip_migration_check': default_conf['skip_migration_check'].lower() == 'true' if 'skip_migration_check' in default_conf else False, 'skip_migration_check': default_conf['skip_migration_check'].lower() == 'true' if 'skip_migration_check' in default_conf else False,
'security_level': security_level 'security_level': security_level,
} }
except Exception: except Exception:
manager_util.use_uv = False
return { return {
'preview_method': manager_funcs.get_current_preview_method(), 'preview_method': manager_funcs.get_current_preview_method(),
'git_exe': '', 'git_exe': '',
'use_uv': False,
'channel_url': DEFAULT_CHANNEL, 'channel_url': DEFAULT_CHANNEL,
'share_option': 'all', 'share_option': 'all',
'bypass_ssl': False, 'bypass_ssl': False,
'file_logging': True, 'file_logging': True,
'default_ui': 'none',
'component_policy': 'workflow', 'component_policy': 'workflow',
'windows_selector_event_loop_policy': False, 'windows_selector_event_loop_policy': False,
'model_download_by_agent': False, 'model_download_by_agent': False,
@@ -1683,6 +1687,10 @@ def try_install_script(url, repo_path, install_cmd, instant_execution=False):
if is_blacklisted(install_cmd[4]): if is_blacklisted(install_cmd[4]):
print(f"[ComfyUI-Manager] skip black listed pip installation: '{install_cmd[4]}'") print(f"[ComfyUI-Manager] skip black listed pip installation: '{install_cmd[4]}'")
return True return True
elif len(install_cmd) == 6 and install_cmd[3:5] == ['pip', 'install']: # uv mode
if is_blacklisted(install_cmd[5]):
print(f"[ComfyUI-Manager] skip black listed pip installation: '{install_cmd[5]}'")
return True
print(f"\n## ComfyUI-Manager: EXECUTE => {install_cmd}") print(f"\n## ComfyUI-Manager: EXECUTE => {install_cmd}")
code = manager_funcs.run_script(install_cmd, cwd=repo_path) code = manager_funcs.run_script(install_cmd, cwd=repo_path)
@@ -1799,9 +1807,9 @@ def execute_install_script(url, repo_path, lazy_mode=False, instant_execution=Fa
if package_name and not package_name.startswith('#'): if package_name and not package_name.startswith('#'):
if '--index-url' in package_name: if '--index-url' in package_name:
s = package_name.split('--index-url') s = package_name.split('--index-url')
install_cmd = [sys.executable, "-m", "pip", "install", s[0].strip(), '--index-url', s[1].strip()] install_cmd = manager_util.make_pip_cmd(["install", s[0].strip(), '--index-url', s[1].strip()])
else: else:
install_cmd = [sys.executable, "-m", "pip", "install", package_name] install_cmd = manager_util.make_pip_cmd(["install", package_name])
if package_name.strip() != "" and not package_name.startswith('#'): if package_name.strip() != "" and not package_name.startswith('#'):
try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution) try_install_script(url, repo_path, install_cmd, instant_execution=instant_execution)
@@ -2122,7 +2130,7 @@ def gitclone_fix(files, instant_execution=False, no_deps=False):
def pip_install(packages): def pip_install(packages):
install_cmd = ['#FORCE', sys.executable, "-m", "pip", "install", '-U'] + packages install_cmd = ['#FORCE'] + manager_util.make_pip_cmd(["install", '-U']) + packages
try_install_script('pip install via manager', '..', install_cmd) try_install_script('pip install via manager', '..', install_cmd)
@@ -2419,7 +2427,8 @@ def check_state_of_git_node_pack_single(item, do_fetch=False, do_update_check=Tr
def get_installed_pip_packages(): def get_installed_pip_packages():
# extract pip package infos # extract pip package infos
pips = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'], text=True).split('\n') cmd = manager_util.make_pip_cmd(['pip', 'freeze'])
pips = subprocess.check_output(cmd, text=True).split('\n')
res = {} res = {}
for x in pips: for x in pips:
@@ -2835,15 +2844,18 @@ async def get_unified_total_nodes(channel, mode, regsitry_cache_mode='cache'):
def populate_github_stats(node_packs, json_obj_github): def populate_github_stats(node_packs, json_obj_github):
for k, v in node_packs.items(): for k, v in node_packs.items():
url = v['reference'] try:
if url in json_obj_github: url = v['reference']
v['stars'] = json_obj_github[url]['stars'] if url in json_obj_github:
v['last_update'] = json_obj_github[url]['last_update'] v['stars'] = json_obj_github[url]['stars']
v['trust'] = json_obj_github[url]['author_account_age_days'] > 600 v['last_update'] = json_obj_github[url]['last_update']
else: v['trust'] = json_obj_github[url]['author_account_age_days'] > 600
v['stars'] = -1 else:
v['last_update'] = -1 v['stars'] = -1
v['trust'] = False v['last_update'] = -1
v['trust'] = False
except:
logging.error(f"[ComfyUI-Manager] DB item is broken:\n{v}")
def populate_favorites(node_packs, json_obj_extras): def populate_favorites(node_packs, json_obj_extras):

View File

@@ -175,10 +175,6 @@ def set_preview_method(method):
set_preview_method(core.get_config()['preview_method']) set_preview_method(core.get_config()['preview_method'])
def set_default_ui_mode(mode):
core.get_config()['default_ui'] = mode
def set_component_policy(mode): def set_component_policy(mode):
core.get_config()['component_policy'] = mode core.get_config()['component_policy'] = mode
@@ -372,13 +368,16 @@ def nickname_filter(json_obj):
task_queue = queue.Queue() task_queue = queue.Queue()
nodepack_result = {} nodepack_result = {}
model_result = {} model_result = {}
tasks_in_progress = set()
task_worker_lock = threading.Lock()
async def task_worker(): async def task_worker():
global task_queue global task_queue
global nodepack_result global nodepack_result
global model_result global model_result
global tasks_in_progress
async def do_install(item): async def do_install(item) -> str:
ui_id, node_spec_str, channel, mode, skip_post_install = item ui_id, node_spec_str, channel, mode, skip_post_install = item
try: try:
@@ -386,8 +385,7 @@ async def task_worker():
if node_spec is None: if node_spec is None:
logging.error(f"Cannot resolve install target: '{node_spec_str}'") logging.error(f"Cannot resolve install target: '{node_spec_str}'")
nodepack_result[ui_id] = f"Cannot resolve install target: '{node_spec_str}'" return f"Cannot resolve install target: '{node_spec_str}'"
return
node_name, version_spec, is_specified = node_spec node_name, version_spec, is_specified = node_spec
res = await core.unified_manager.install_by_id(node_name, version_spec, channel, mode, return_postinstall=skip_post_install) res = await core.unified_manager.install_by_id(node_name, version_spec, channel, mode, return_postinstall=skip_post_install)
@@ -395,20 +393,18 @@ async def task_worker():
if res.action not in ['skip', 'enable', 'install-git', 'install-cnr', 'switch-cnr']: if res.action not in ['skip', 'enable', 'install-git', 'install-cnr', 'switch-cnr']:
logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}") logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}")
nodepack_result[ui_id] = res.msg return res.msg
return
elif not res.result: elif not res.result:
logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}") logging.error(f"[ComfyUI-Manager] Installation failed:\n{res.msg}")
nodepack_result[ui_id] = res.msg return res.msg
return
nodepack_result[ui_id] = 'success' return 'success'
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
nodepack_result[ui_id] = f"Installation failed:\n{node_spec_str}" return f"Installation failed:\n{node_spec_str}"
async def do_update(item): async def do_update(item) -> str:
ui_id, node_name, node_ver = item ui_id, node_name, node_ver = item
try: try:
@@ -417,70 +413,68 @@ async def task_worker():
manager_util.clear_pip_cache() manager_util.clear_pip_cache()
if res.result: if res.result:
nodepack_result[ui_id] = 'success' return 'success'
return
logging.error(f"\nERROR: An error occurred while updating '{node_name}'.") logging.error(f"\nERROR: An error occurred while updating '{node_name}'.")
nodepack_result[ui_id] = f"An error occurred while updating '{node_name}'."
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
nodepack_result[ui_id] = f"An error occurred while updating '{node_name}'."
async def do_fix(item): return f"An error occurred while updating '{node_name}'."
async def do_fix(item) -> str:
ui_id, node_name, node_ver = item ui_id, node_name, node_ver = item
try: try:
res = core.unified_manager.unified_fix(node_name, node_ver) res = core.unified_manager.unified_fix(node_name, node_ver)
if res.result: if res.result:
nodepack_result[ui_id] = 'success' return 'success'
return
else: else:
logging.error(res.msg) logging.error(res.msg)
logging.error(f"\nERROR: An error occurred while fixing '{node_name}@{node_ver}'.") logging.error(f"\nERROR: An error occurred while fixing '{node_name}@{node_ver}'.")
nodepack_result[ui_id] = f"An error occurred while fixing '{node_name}@{node_ver}'."
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
nodepack_result[ui_id] = f"An error occurred while fixing '{node_name}@{node_ver}'."
async def do_uninstall(item): return f"An error occurred while fixing '{node_name}@{node_ver}'."
async def do_uninstall(item) -> str:
ui_id, node_name, is_unknown = item ui_id, node_name, is_unknown = item
try: try:
res = core.unified_manager.unified_uninstall(node_name, is_unknown) res = core.unified_manager.unified_uninstall(node_name, is_unknown)
if res.result: if res.result:
nodepack_result[ui_id] = 'success' return 'success'
return
logging.error(f"\nERROR: An error occurred while uninstalling '{node_name}'.") logging.error(f"\nERROR: An error occurred while uninstalling '{node_name}'.")
nodepack_result[ui_id] = f"An error occurred while uninstalling '{node_name}'."
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
nodepack_result[ui_id] = f"An error occurred while uninstalling '{node_name}'."
async def do_disable(item): return f"An error occurred while uninstalling '{node_name}'."
async def do_disable(item) -> str:
ui_id, node_name, is_unknown = item ui_id, node_name, is_unknown = item
try: try:
res = core.unified_manager.unified_disable(node_name, is_unknown) res = core.unified_manager.unified_disable(node_name, is_unknown)
if res: if res:
nodepack_result[ui_id] = 'success' return 'success'
return
nodepack_result[ui_id] = f"Failed to disable: '{node_name}'"
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
nodepack_result[ui_id] = f"Failed to disable: '{node_name}'"
async def do_install_model(item): return f"Failed to disable: '{node_name}'"
async def do_install_model(item) -> str:
ui_id, json_data = item ui_id, json_data = item
model_path = get_model_path(json_data) model_path = get_model_path(json_data)
model_url = json_data['url'] model_url = json_data['url']
res = False
try: try:
if model_path is not None: if model_path is not None:
logging.info(f"Install model '{json_data['name']}' from '{model_url}' into '{model_path}'") logging.info(f"Install model '{json_data['name']}' from '{model_url}' into '{model_path}'")
@@ -494,24 +488,21 @@ async def task_worker():
res = True res = True
if res: if res:
model_result[ui_id] = 'success' return 'success'
return
else: else:
res = download_url_with_agent(model_url, model_path) res = download_url_with_agent(model_url, model_path)
if res and model_path.endswith('.zip'): if res and model_path.endswith('.zip'):
res = core.unzip(model_path) res = core.unzip(model_path)
else: else:
logging.error(f"Model installation error: invalid model type - {json_data['type']}") logging.error(f"Model installation error: invalid model type - {json_data['type']}")
return
if res: if res:
model_result[ui_id] = 'success' return 'success'
return
except Exception as e: except Exception as e:
logging.error(f"[ERROR] {e}", file=sys.stderr) logging.error(f"[ERROR] {e}", file=sys.stderr)
model_result[ui_id] = f"Model installation error: {model_url}" return f"Model installation error: {model_url}"
stats = {} stats = {}
@@ -529,32 +520,44 @@ async def task_worker():
'total_count': total_count, 'done_count': done_count}) 'total_count': total_count, 'done_count': done_count})
nodepack_result = {} nodepack_result = {}
task_queue = queue.Queue() task_queue = queue.Queue()
return return # terminate worker thread
kind, item = task_queue.get() with task_worker_lock:
kind, item = task_queue.get()
tasks_in_progress.add((kind, item[0]))
try: try:
if kind == 'install': if kind == 'install':
await do_install(item) msg = await do_install(item)
if kind == 'install-model': elif kind == 'install-model':
await do_install_model(item) msg = await do_install_model(item)
elif kind == 'update': elif kind == 'update':
await do_update(item) msg = await do_update(item)
elif kind == 'fix': elif kind == 'fix':
await do_fix(item) msg = await do_fix(item)
elif kind == 'uninstall': elif kind == 'uninstall':
await do_uninstall(item) msg = await do_uninstall(item)
elif kind == 'disable': elif kind == 'disable':
await do_disable(item) msg = await do_disable(item)
else:
msg = "Unexpected kind: " + kind
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
msg = f"Exception: {(kind, item)}"
with task_worker_lock:
tasks_in_progress.remove((kind, item[0]))
ui_id = item[0]
if kind == 'install-model':
model_result[ui_id] = msg
ui_target = "model_manager"
else:
nodepack_result[ui_id] = msg
ui_target = "nodepack_manager"
stats[kind] = stats.get(kind, 0) + 1 stats[kind] = stats.get(kind, 0) + 1
ui_target = "model_manager" if kind == 'install-model' else 'nodepack_manager'
print(f"kind: {kind} / ui_target: {ui_target}")
PromptServer.instance.send_sync("cm-queue-status", PromptServer.instance.send_sync("cm-queue-status",
{'status': 'in_progress', 'target': item[0], 'ui_target': ui_target, {'status': 'in_progress', 'target': item[0], 'ui_target': ui_target,
'total_count': total_count, 'done_count': done_count}) 'total_count': total_count, 'done_count': done_count})
@@ -1073,11 +1076,15 @@ async def reset_queue(request):
async def queue_count(request): async def queue_count(request):
global task_queue global task_queue
done_count = len(nodepack_result) + len(model_result) with task_worker_lock:
total_count = done_count + task_queue.qsize() done_count = len(nodepack_result) + len(model_result)
in_progress = task_worker_thread is not None and task_worker_thread.is_alive() in_progress_count = len(tasks_in_progress)
total_count = done_count + in_progress_count + task_queue.qsize()
is_processing = task_worker_thread is not None and task_worker_thread.is_alive()
return web.json_response({'total_count': total_count, 'done_count': done_count, 'in_progress': in_progress}) return web.json_response({
'total_count': total_count, 'done_count': done_count, 'in_progress_count': in_progress_count,
'is_processing': is_processing})
@routes.post("/manager/queue/install") @routes.post("/manager/queue/install")
@@ -1129,7 +1136,7 @@ async def install_custom_node(request):
return web.Response(status=200) return web.Response(status=200)
task_worker_thread = None task_worker_thread:threading.Thread = None
@routes.get("/manager/queue/start") @routes.get("/manager/queue/start")
async def queue_start(request): async def queue_start(request):
@@ -1363,17 +1370,6 @@ async def preview_method(request):
return web.Response(status=200) return web.Response(status=200)
@routes.get("/manager/default_ui")
async def default_ui_mode(request):
if "value" in request.rel_url.query:
set_default_ui_mode(request.rel_url.query['value'])
core.write_config()
else:
return web.Response(text=core.get_config()['default_ui'], status=200)
return web.Response(status=200)
@routes.get("/manager/component/policy") @routes.get("/manager/component/policy")
async def component_policy(request): async def component_policy(request):
if "value" in request.rel_url.query: if "value" in request.rel_url.query:

View File

@@ -19,6 +19,14 @@ cache_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
def make_pip_cmd(cmd):
if use_uv:
return [sys.executable, '-m', 'uv', 'pip'] + cmd
else:
return [sys.executable, '-m', 'pip'] + cmd
# DON'T USE StrictVersion - cannot handle pre_release version # DON'T USE StrictVersion - cannot handle pre_release version
# try: # try:
@@ -209,7 +217,7 @@ def get_installed_packages(renew=False):
if renew or pip_map is None: if renew or pip_map is None:
try: try:
result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True) result = subprocess.check_output(make_pip_cmd(['list']), universal_newlines=True)
pip_map = {} pip_map = {}
for line in result.split('\n'): for line in result.split('\n'):
@@ -260,7 +268,7 @@ class PIPFixer:
if len(spec) > 0: if len(spec) > 0:
platform = spec[1] platform = spec[1]
else: else:
cmd = [sys.executable, '-m', 'pip', 'install', '--force', 'torch', 'torchvision', 'torchaudio'] cmd = make_pip_cmd(['install', '--force', 'torch', 'torchvision', 'torchaudio'])
subprocess.check_output(cmd, universal_newlines=True) subprocess.check_output(cmd, universal_newlines=True)
logging.error(cmd) logging.error(cmd)
return return
@@ -270,15 +278,13 @@ class PIPFixer:
torch_torchvision_torchaudio_ver = torch_torchvision_torchaudio_version_map.get(torch_ver) torch_torchvision_torchaudio_ver = torch_torchvision_torchaudio_version_map.get(torch_ver)
if torch_torchvision_torchaudio_ver is None: if torch_torchvision_torchaudio_ver is None:
cmd = [sys.executable, '-m', 'pip', 'install', '--pre', cmd = make_pip_cmd(['install', '--pre', 'torch', 'torchvision', 'torchaudio',
'torch', 'torchvision', 'torchaudio', '--index-url', f"https://download.pytorch.org/whl/nightly/{platform}"])
'--index-url', f"https://download.pytorch.org/whl/nightly/{platform}"]
logging.info("[ComfyUI-Manager] restore PyTorch to nightly version") logging.info("[ComfyUI-Manager] restore PyTorch to nightly version")
else: else:
torchvision_ver, torchaudio_ver = torch_torchvision_torchaudio_ver torchvision_ver, torchaudio_ver = torch_torchvision_torchaudio_ver
cmd = [sys.executable, '-m', 'pip', 'install', cmd = make_pip_cmd(['install', f'torch=={torch_ver}', f'torchvision=={torchvision_ver}', f"torchaudio=={torchaudio_ver}",
f'torch=={torch_ver}', f'torchvision=={torchvision_ver}', f"torchaudio=={torchaudio_ver}", '--index-url', f"https://download.pytorch.org/whl/{platform}"])
'--index-url', f"https://download.pytorch.org/whl/{platform}"]
logging.info(f"[ComfyUI-Manager] restore PyTorch to {torch_ver}+{platform}") logging.info(f"[ComfyUI-Manager] restore PyTorch to {torch_ver}+{platform}")
subprocess.check_output(cmd, universal_newlines=True) subprocess.check_output(cmd, universal_newlines=True)
@@ -289,7 +295,7 @@ class PIPFixer:
# remove `comfy` python package # remove `comfy` python package
try: try:
if 'comfy' in new_pip_versions: if 'comfy' in new_pip_versions:
cmd = [sys.executable, '-m', 'pip', 'uninstall', 'comfy'] cmd = make_pip_cmd(['uninstall', 'comfy'])
subprocess.check_output(cmd, universal_newlines=True) subprocess.check_output(cmd, universal_newlines=True)
logging.warning("[ComfyUI-Manager] 'comfy' python package is uninstalled.\nWARN: The 'comfy' package is completely unrelated to ComfyUI and should never be installed as it causes conflicts with ComfyUI.") logging.warning("[ComfyUI-Manager] 'comfy' python package is uninstalled.\nWARN: The 'comfy' package is completely unrelated to ComfyUI and should never be installed as it causes conflicts with ComfyUI.")
@@ -335,7 +341,7 @@ class PIPFixer:
if len(targets) > 0: if len(targets) > 0:
for x in targets: for x in targets:
cmd = [sys.executable, '-m', 'pip', 'install', f"{x}=={versions[0].version_string}"] cmd = make_pip_cmd(['install', f"{x}=={versions[0].version_string}"])
subprocess.check_output(cmd, universal_newlines=True) subprocess.check_output(cmd, universal_newlines=True)
logging.info(f"[ComfyUI-Manager] 'opencv' dependencies were fixed: {targets}") logging.info(f"[ComfyUI-Manager] 'opencv' dependencies were fixed: {targets}")
@@ -348,7 +354,8 @@ class PIPFixer:
np = new_pip_versions.get('numpy') np = new_pip_versions.get('numpy')
if np is not None: if np is not None:
if StrictVersion(np) >= StrictVersion('2'): if StrictVersion(np) >= StrictVersion('2'):
subprocess.check_output([sys.executable, '-m', 'pip', 'install', "numpy<2"], universal_newlines=True) cmd = make_pip_cmd(['install', "numpy<2"])
subprocess.check_output(cmd , universal_newlines=True)
except Exception as e: except Exception as e:
logging.error("[ComfyUI-Manager] Failed to restore numpy") logging.error("[ComfyUI-Manager] Failed to restore numpy")
logging.error(e) logging.error(e)

View File

@@ -40,7 +40,7 @@ docStyle.innerHTML = `
#cm-manager-dialog { #cm-manager-dialog {
width: 1000px; width: 1000px;
height: 520px; height: 450px;
box-sizing: content-box; box-sizing: content-box;
z-index: 1000; z-index: 1000;
overflow-y: auto; overflow-y: auto;
@@ -137,7 +137,7 @@ docStyle.innerHTML = `
.cm-notice-board { .cm-notice-board {
width: 290px; width: 290px;
height: 270px; height: 210px;
overflow: auto; overflow: auto;
color: var(--input-text); color: var(--input-text);
border: 1px solid var(--descrip-text); border: 1px solid var(--descrip-text);
@@ -811,11 +811,15 @@ const isOutputNode = (node) => {
class ManagerMenuDialog extends ComfyDialog { class ManagerMenuDialog extends ComfyDialog {
createControlsMid() { createControlsMid() {
let self = this; let self = this;
const isElectron = 'electronAPI' in window;
update_comfyui_button = update_comfyui_button =
$el("button.cm-button", { $el("button.cm-button", {
type: "button", type: "button",
textContent: "Update ComfyUI", textContent: "Update ComfyUI",
style: {
display: isElectron ? 'none' : 'block'
},
onclick: onclick:
() => updateComfyUI() () => updateComfyUI()
}); });
@@ -824,6 +828,9 @@ class ManagerMenuDialog extends ComfyDialog {
$el("button.cm-button", { $el("button.cm-button", {
type: "button", type: "button",
textContent: "Switch ComfyUI", textContent: "Switch ComfyUI",
style: {
display: isElectron ? 'none' : 'block'
},
onclick: onclick:
() => switchComfyUI() () => switchComfyUI()
}); });
@@ -901,19 +908,6 @@ class ManagerMenuDialog extends ComfyDialog {
switch_comfyui_button, switch_comfyui_button,
fetch_updates_button, fetch_updates_button,
$el("br", {}, []),
$el("button.cm-button", {
type: "button",
textContent: "Alternatives of A1111",
onclick:
() => {
if(!CustomNodesManager.instance) {
CustomNodesManager.instance = new CustomNodesManager(app, self);
}
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.ALTERNATIVES);
}
}),
$el("br", {}, []), $el("br", {}, []),
$el("button.cm-button-red", { $el("button.cm-button-red", {
type: "button", type: "button",
@@ -1008,21 +1002,6 @@ class ManagerMenuDialog extends ComfyDialog {
} }
}); });
// default ui state
let default_ui_combo = document.createElement("select");
default_ui_combo.setAttribute("title", "Set the default state to be displayed in the main menu when the browser starts.");
default_ui_combo.className = "cm-menu-combo";
default_ui_combo.appendChild($el('option', { value: 'none', text: 'Default UI: None' }, []));
default_ui_combo.appendChild($el('option', { value: 'history', text: 'Default UI: History' }, []));
default_ui_combo.appendChild($el('option', { value: 'queue', text: 'Default UI: Queue' }, []));
api.fetchApi('/manager/default_ui')
.then(response => response.text())
.then(data => { default_ui_combo.value = data; });
default_ui_combo.addEventListener('change', function (event) {
api.fetchApi(`/manager/default_ui?value=${event.target.value}`);
});
// share // share
let share_combo = document.createElement("select"); let share_combo = document.createElement("select");
@@ -1085,7 +1064,6 @@ class ManagerMenuDialog extends ComfyDialog {
this.datasrc_combo, this.datasrc_combo,
channel_combo, channel_combo,
preview_combo, preview_combo,
default_ui_combo,
share_combo, share_combo,
component_policy_combo, component_policy_combo,
$el("br", {}, []), $el("br", {}, []),
@@ -1268,10 +1246,22 @@ class ManagerMenuDialog extends ComfyDialog {
this.element = $el("div.comfy-modal", { id:'cm-manager-dialog', parent: document.body }, [ content ]); this.element = $el("div.comfy-modal", { id:'cm-manager-dialog', parent: document.body }, [ content ]);
} }
get isVisible() {
return this.element?.style?.display !== "none";
}
show() { show() {
this.element.style.display = "block"; this.element.style.display = "block";
} }
toggleVisibility() {
if (this.isVisible) {
this.close();
} else {
this.show();
}
}
handleWorkflowGalleryButtonClick(e) { handleWorkflowGalleryButtonClick(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@@ -1389,6 +1379,41 @@ app.registerExtension({
} }
], ],
commands: [
{
id: "Comfy.Manager.Menu.ToggleVisibility",
label: "Toggle Manager Menu Visibility",
icon: "mdi mdi-puzzle",
function: () => {
if (!manager_instance) {
setManagerInstance(new ManagerMenuDialog());
manager_instance.show();
} else {
manager_instance.toggleVisibility();
}
},
},
{
id: "Comfy.Manager.CustomNodesManager.ToggleVisibility",
label: "Toggle Custom Nodes Manager Visibility",
icon: "pi pi-server",
function: () => {
if (CustomNodesManager.instance?.isVisible) {
CustomNodesManager.instance.close();
return;
}
if (!manager_instance) {
setManagerInstance(new ManagerMenuDialog());
}
if (!CustomNodesManager.instance) {
CustomNodesManager.instance = new CustomNodesManager(app, self);
}
CustomNodesManager.instance.show(CustomNodesManager.ShowMode.NORMAL);
},
}
],
init() { init() {
$el("style", { $el("style", {
textContent: style, textContent: style,
@@ -1583,27 +1608,3 @@ app.registerExtension({
} }
}, },
}); });
async function set_default_ui()
{
let res = await api.fetchApi('/manager/default_ui');
if(res.status == 200) {
let mode = await res.text();
switch(mode) {
case 'history':
app.ui.queue.hide();
app.ui.history.show();
break;
case 'queue':
app.ui.queue.show();
app.ui.history.hide();
break;
default:
// do nothing
break;
}
}
}
set_default_ui();

View File

@@ -1287,7 +1287,7 @@ 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'); let stats = await api.fetchApi('/manager/queue/status');
stats = await stats.json(); stats = await stats.json();
if(stats.in_progress) { 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})`); customAlert(`[ComfyUI-Manager] There are already tasks in progress. Please try again after it is completed. (${stats.done_count}/${stats.total_count})`);
return; return;
} }
@@ -1446,7 +1446,7 @@ export class CustomNodesManager {
let v = result[hash]; let v = result[hash];
if(v != 'success') if(v != 'success')
errorMsg += v; errorMsg += v+'\n';
} }
for(let k in self.install_context.targets) { for(let k in self.install_context.targets) {
@@ -1916,4 +1916,8 @@ export class CustomNodesManager {
close() { close() {
this.element.style.display = "none"; this.element.style.display = "none";
} }
get isVisible() {
return this.element?.style?.display !== "none";
}
} }

View File

@@ -634,7 +634,7 @@ export class ModelManager {
let stats = await api.fetchApi('/manager/queue/status'); let stats = await api.fetchApi('/manager/queue/status');
stats = await stats.json(); stats = await stats.json();
if(stats.in_progress) { 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})`); customAlert(`[ComfyUI-Manager] There are already tasks in progress. Please try again after it is completed. (${stats.done_count}/${stats.total_count})`);
return; return;
} }
@@ -738,7 +738,7 @@ export class ModelManager {
let v = result[hash]; let v = result[hash];
if(v != 'success') if(v != 'success')
errorMsg += v; errorMsg += v + '\n';
} }
for(let k in self.install_context.targets) { for(let k in self.install_context.targets) {

View File

@@ -11,6 +11,36 @@
{
"author": "molbal",
"title": "comfy-url-fetcher [WIP]",
"reference": "https://github.com/molbal/comfy-url-fetcher",
"files": [
"https://github.com/molbal/comfy-url-fetcher"
],
"install_type": "git-clone",
"description": "Fetches URLs"
},
{
"author": "myAiLemon",
"title": "MagicAutomaticPicture [WIP]",
"reference": "https://github.com/myAiLemon/MagicAutomaticPicture",
"files": [
"https://github.com/myAiLemon/MagicAutomaticPicture"
],
"install_type": "git-clone",
"description": "A comfyui node package that can generate pictures and automatically save positive prompts and eliminate unwanted prompts"
},
{
"author": "neverbiasu",
"title": "ComfyUI_Output_as_Input",
"reference": "https://github.com/a-und-b/ComfyUI_Output_as_Input",
"files": [
"https://github.com/a-und-b/ComfyUI_Output_as_Input"
],
"install_type": "git-clone",
"description": "This is a simple custom ComfyUI node that allows you to easily use recent output images as input in your workflows. It does not allow image uploads on purpose and does not require any additional dependencies.\nNOTE: The files in the repo are not organized."
},
{ {
"author": "neverbiasu", "author": "neverbiasu",
"title": "ComfyUI-DeepSeek", "title": "ComfyUI-DeepSeek",

View File

@@ -1629,7 +1629,9 @@
"FrameBlend", "FrameBlend",
"ImageReferenceUpdate", "ImageReferenceUpdate",
"ImageSelector", "ImageSelector",
"KeypointsInput",
"KeypointsInputNode", "KeypointsInputNode",
"KeypointsToPose",
"KeypointsToPoseNode", "KeypointsToPoseNode",
"SimHashCompare", "SimHashCompare",
"TemporalConsistency" "TemporalConsistency"
@@ -1762,6 +1764,14 @@
"title_aux": "ComfyUI-Blenderesque-Nodes [WIP]" "title_aux": "ComfyUI-Blenderesque-Nodes [WIP]"
} }
], ],
"https://github.com/a-und-b/ComfyUI_Output_as_Input": [
[
"OutputAsInput"
],
{
"title_aux": "ComfyUI_Output_as_Input"
}
],
"https://github.com/aiden1020/ComfyUI_Artcoder": [ "https://github.com/aiden1020/ComfyUI_Artcoder": [
[ [
"ArtCoder" "ArtCoder"
@@ -3325,7 +3335,6 @@
"MangaPanelSegmentationNode", "MangaPanelSegmentationNode",
"Mask_Fill_Region", "Mask_Fill_Region",
"MatchImageCountToMaskCount", "MatchImageCountToMaskCount",
"ParallaxGPUTest",
"ParallaxTest", "ParallaxTest",
"RandomCharacterPrompts", "RandomCharacterPrompts",
"TargetLocationCrop", "TargetLocationCrop",
@@ -4082,6 +4091,14 @@
"title_aux": "ComfyUI-FramerComfy [WIP]" "title_aux": "ComfyUI-FramerComfy [WIP]"
} }
], ],
"https://github.com/molbal/comfy-url-fetcher": [
[
"URL Fetcher"
],
{
"title_aux": "comfy-url-fetcher [WIP]"
}
],
"https://github.com/monate0615/ComfyUI-Affine-Transform": [ "https://github.com/monate0615/ComfyUI-Affine-Transform": [
[ [
"AffineTransform" "AffineTransform"
@@ -4115,6 +4132,17 @@
"title_aux": "ComfyUI-Claude-I2T" "title_aux": "ComfyUI-Claude-I2T"
} }
], ],
"https://github.com/myAiLemon/MagicAutomaticPicture": [
[
"EditableStringNode",
"IntegratedCLIPTextEncodeWithExtract",
"ProcessAndSave",
"StringConcat"
],
{
"title_aux": "MagicAutomaticPicture [WIP]"
}
],
"https://github.com/naderzare/comfyui-inodes": [ "https://github.com/naderzare/comfyui-inodes": [
[ [
"IAzureAiApi", "IAzureAiApi",
@@ -4975,6 +5003,7 @@
"FixUTF8StringNode", "FixUTF8StringNode",
"ImageResizeNode", "ImageResizeNode",
"ImagesToVideoNode", "ImagesToVideoNode",
"LoadImageFormURLNode",
"LoadImageFromFolderNode", "LoadImageFromFolderNode",
"SaveImageToFolderNode", "SaveImageToFolderNode",
"SaveImagesToFolderNode", "SaveImagesToFolderNode",

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,15 @@
{ {
"custom_nodes": [ "custom_nodes": [
{
"author": "PramaLLC",
"title": "ComfyUI BEN - Background Erase Network",
"reference": "https://github.com/PramaLLC/BEN2_ComfyUI",
"files": [
"https://github.com/PramaLLC/BEN2_ComfyUI"
],
"install_type": "git-clone",
"description": "Remove backgrounds from images with [a/BEN2](https://huggingface.co/PramaLLC/BEN2) in ComfyUI\nOriginal repo: [a/https://github.com/DoctorDiffusion/ComfyUI-BEN](https://github.com/DoctorDiffusion/ComfyUI-BEN)"
},
{ {
"author": "BlenderNeko", "author": "BlenderNeko",
"title": "ltdrdata/ComfyUI_TiledKSampler", "title": "ltdrdata/ComfyUI_TiledKSampler",

View File

@@ -11,6 +11,16 @@
{
"author": "myAiLemon",
"title": "MagicGetPromptAutomatically",
"reference": "https://github.com/myAiLemon/MagicGetPromptAutomatically",
"files": [
"https://github.com/myAiLemon/MagicGetPromptAutomatically"
],
"install_type": "git-clone",
"description": "A plug-in that can automatically generate pictures and save txt files in comfyui"
},
{ {
"author": "ryanontheinside", "author": "ryanontheinside",
"title": "ComfyUI_ScavengerHunt [REMOVED]", "title": "ComfyUI_ScavengerHunt [REMOVED]",

View File

@@ -8,7 +8,72 @@
"description": "If you see this message, your ComfyUI-Manager is outdated.\nRecent channel provides only the list of the latest nodes. If you want to find the complete node list, please go to the Default channel.\nMaking LoRA has never been easier!" "description": "If you see this message, your ComfyUI-Manager is outdated.\nRecent channel provides only the list of the latest nodes. If you want to find the complete node list, please go to the Default channel.\nMaking LoRA has never been easier!"
}, },
{
"title": "A2V Multi Image Composite",
"author": "AiartvnTeam",
"id": "Aiartvn",
"description": "Node for compositing multiple images with interactive preview and layer management",
"repository": "https://github.com/aiartvn/A2V_Multi_Image_Composite",
"install_type": "git-clone",
"files": [
"https://github.com/aiartvn/A2V_Multi_Image_Composite"
],
"tags": ["image", "composite", "layer", "blend", "transform"]
},
{
"author": "ProGamerGov",
"title": "Preview 360 Panorama for ComfyUI",
"id": "comfyui-preview360panorama",
"reference": "https://github.com/ProGamerGov/ComfyUI_preview360panorama",
"files": [
"https://github.com/ProGamerGov/ComfyUI_preview360panorama"
],
"install_type": "git-clone",
"description": "A custom ComfyUI node for interactive 360° panorama image previews. Panoramic 360 images are also sometimes known as VR photography (virtual reality), HDRI environments (ex: skyboxes), image spheres, spherical images, 360 pano, and 360 degree photos."
},
{
"author": "amorano",
"title": "Jovi_MIDI",
"id": "jovi_midi",
"reference": "https://github.com/Amorano/Jovi_MIDI",
"files": [
"https://github.com/Amorano/Jovi_MIDI"
],
"install_type": "git-clone",
"description": "Read and Process data from MIDI devices inside of ComfyUI."
},
{
"author": "nkchocoai",
"title": "ComfyUI-DanbooruPromptQuiz",
"reference": "https://github.com/nkchocoai/ComfyUI-DanbooruPromptQuiz",
"files": [
"https://github.com/nkchocoai/ComfyUI-DanbooruPromptQuiz"
],
"install_type": "git-clone",
"description": "This node is for playing the game of guessing prompts by looking at images generated from prompts output by TIPO, Tagger, etc.."
},
{
"author": "agilly1989",
"title": "ComfyUI_agilly1989_motorway",
"reference": "https://github.com/agilly1989/ComfyUI_agilly1989_motorway",
"files": [
"https://github.com/agilly1989/ComfyUI_agilly1989_motorway"
],
"install_type": "git-clone",
"description": "This my implemenation of a `pipe` in ComfyUI. Is it better or worse than others? No idea."
},
{
"author": "da2el-ai",
"title": "D2-PromptSelector-comfyUI",
"reference": "https://github.com/da2el-ai/D2-PromptSelector-comfyUI",
"files": [
"https://github.com/da2el-ai/D2-PromptSelector-comfyUI"
],
"install_type": "git-clone",
"description": "This is a version of [a/sd-d2-prompt-selector](https://github.com/da2el-ai/sd-d2-prompt-selector) reworked for ComfyUI. It's just a prototype that I've put together for now. The random syntax of sd-d2-prompt-selector cannot be used; instead, the DynamicPrompt syntax is used"
},
{ {
"author": "kijai", "author": "kijai",
"title": "ComfyUI-StableXWrapper", "title": "ComfyUI-StableXWrapper",
@@ -667,26 +732,6 @@
], ],
"install_type": "git-clone", "install_type": "git-clone",
"description": "A Text To Speech node using Kokoro TTS in ComfyUI." "description": "A Text To Speech node using Kokoro TTS in ComfyUI."
},
{
"author": "WangPengxing",
"title": "ComfyUI WPX Nodes",
"reference": "https://github.com/WangPengxing/ComfyUI_WPX_Node",
"files": [
"https://github.com/WangPengxing/ComfyUI_WPX_Node"
],
"install_type": "git-clone",
"description": "A custom node collection for ComfyUI, offering enhanced image processing features."
},
{
"author": "PixelFunAI",
"title": "Hunyuan LoRA Loader Nodes",
"reference": "https://github.com/PixelFunAI/ComfyUI_PixelFun",
"files": [
"https://github.com/PixelFunAI/ComfyUI_PixelFun"
],
"install_type": "git-clone",
"description": "This collection provides four additional nodes for loading and managing Hunyuan Video LoRAs in ComfyUI"
} }
] ]
} }

View File

@@ -493,6 +493,7 @@
"https://github.com/852wa/ComfyUI-ColorshiftColor": [ "https://github.com/852wa/ComfyUI-ColorshiftColor": [
[ [
"ColorshiftColor", "ColorshiftColor",
"CsCFill",
"CsCPaletteEditor" "CsCPaletteEditor"
], ],
{ {
@@ -1427,6 +1428,18 @@
"title_aux": "Jovi_GLSL" "title_aux": "Jovi_GLSL"
} }
], ],
"https://github.com/Amorano/Jovi_MIDI": [
[
"MIDI FILTER (JOV_MIDI)",
"MIDI FILTER EZ (JOV_MIDI)",
"MIDI LOADER (JOV_MIDI)",
"MIDI MESSAGE (JOV_MIDI)",
"MIDI READER (JOV_MIDI)"
],
{
"title_aux": "Jovi_MIDI"
}
],
"https://github.com/Amorano/Jovi_Measure": [ "https://github.com/Amorano/Jovi_Measure": [
[ [
"BLUR EFFECT (JOV_MEASURE)", "BLUR EFFECT (JOV_MEASURE)",
@@ -5017,6 +5030,7 @@
[ [
"Simple Extract Lora From Text", "Simple Extract Lora From Text",
"Simple Image Saver (as Forge)", "Simple Image Saver (as Forge)",
"Simple Load Image With Metadata",
"Simple Load Line From Text File", "Simple Load Line From Text File",
"Simple Lora Loader" "Simple Lora Loader"
], ],
@@ -6433,10 +6447,13 @@
], ],
"https://github.com/MzMaXaM/ComfyUi-MzMaXaM": [ "https://github.com/MzMaXaM/ComfyUi-MzMaXaM": [
[ [
"ImageToText",
"KSamplerWithVAE", "KSamplerWithVAE",
"SelectLatentSize1MP", "SelectLatentSize1MP",
"SelectLatentSize2MP", "SelectLatentSize2MP",
"TextEncode3in1", "TextEncode3in1",
"TextToText",
"UpscaleImageBy1_5x",
"UpscaleLatentBy1_5x" "UpscaleLatentBy1_5x"
], ],
{ {
@@ -7060,6 +7077,14 @@
"title_aux": "ComfyUI-StringsAndThings" "title_aux": "ComfyUI-StringsAndThings"
} }
], ],
"https://github.com/ProGamerGov/ComfyUI_preview360panorama": [
[
"PanoramaViewerNode"
],
{
"title_aux": "Preview 360 Panorama for ComfyUI"
}
],
"https://github.com/ProGamerGov/ComfyUI_pytorch360convert": [ "https://github.com/ProGamerGov/ComfyUI_pytorch360convert": [
[ [
"Crop Image with Coords", "Crop Image with Coords",
@@ -8453,6 +8478,7 @@
"Star Face Loader", "Star Face Loader",
"StarFiveWildcards", "StarFiveWildcards",
"StarImageSwitch", "StarImageSwitch",
"StarLatentSwitch",
"StarTextFilter", "StarTextFilter",
"StarTextInput", "StarTextInput",
"Starupscale" "Starupscale"
@@ -10647,6 +10673,18 @@
"title_aux": "ComfyUI-styles-all" "title_aux": "ComfyUI-styles-all"
} }
], ],
"https://github.com/agilly1989/ComfyUI_agilly1989_motorway": [
[
"MotorwayFloat",
"MotorwayInt",
"MotorwaySeed",
"MotorwayStr",
"MotorwayStrMulti"
],
{
"title_aux": "ComfyUI_agilly1989_motorway"
}
],
"https://github.com/ahernandezmiro/ComfyUI-GCP_Storage_tools": [ "https://github.com/ahernandezmiro/ComfyUI-GCP_Storage_tools": [
[ [
"GCPReadImageNode", "GCPReadImageNode",
@@ -10722,6 +10760,14 @@
"title_aux": "Comfy UI FatLabels" "title_aux": "Comfy UI FatLabels"
} }
], ],
"https://github.com/aiartvn/A2V_Multi_Image_Composite": [
[
"A2V_Multi_Image_Composite"
],
{
"title_aux": "A2V Multi Image Composite"
}
],
"https://github.com/aidec/Comfyui_TextBatch_aidec": [ "https://github.com/aidec/Comfyui_TextBatch_aidec": [
[ [
"ImageQueueProcessor", "ImageQueueProcessor",
@@ -15458,7 +15504,8 @@
"SelOutModel", "SelOutModel",
"SelOutPolar", "SelOutPolar",
"Selector", "Selector",
"Selector Advanced" "Selector Advanced",
"Selector Hub"
], ],
{ {
"author": "\"\u02f6\ud835\udfa2\u292c\u2ad2\u2d56s\u143c\u02f6\"", "author": "\"\u02f6\ud835\udfa2\u292c\u2ad2\u2d56s\u143c\u02f6\"",
@@ -19314,6 +19361,7 @@
"GetImageRangeFromBatch", "GetImageRangeFromBatch",
"GetImageSizeAndCount", "GetImageSizeAndCount",
"GetImagesFromBatchIndexed", "GetImagesFromBatchIndexed",
"GetLatentRangeFromBatch",
"GetLatentsFromBatchIndexed", "GetLatentsFromBatchIndexed",
"GetMaskSizeAndCount", "GetMaskSizeAndCount",
"GradientToFloat", "GradientToFloat",
@@ -19332,6 +19380,7 @@
"ImageGridComposite2x2", "ImageGridComposite2x2",
"ImageGridComposite3x3", "ImageGridComposite3x3",
"ImageGridtoBatch", "ImageGridtoBatch",
"ImageNoiseAugmentation",
"ImageNormalize_Neg1_To_1", "ImageNormalize_Neg1_To_1",
"ImagePadForOutpaintMasked", "ImagePadForOutpaintMasked",
"ImagePadForOutpaintTargetSize", "ImagePadForOutpaintTargetSize",
@@ -19347,6 +19396,7 @@
"Intrinsic_lora_sampling", "Intrinsic_lora_sampling",
"JoinStringMulti", "JoinStringMulti",
"JoinStrings", "JoinStrings",
"LeapfusionHunyuanI2VPatcher",
"LoadAndResizeImage", "LoadAndResizeImage",
"LoadImagesFromFolderKJ", "LoadImagesFromFolderKJ",
"LoadResAdapterNormalization", "LoadResAdapterNormalization",
@@ -20741,6 +20791,7 @@
"Enhanced Random Light Source", "Enhanced Random Light Source",
"Float Relay", "Float Relay",
"HLFrequencyDetailRestore", "HLFrequencyDetailRestore",
"Hex to Color",
"Image Add Alpha", "Image Add Alpha",
"Image Frequency Analyzer", "Image Frequency Analyzer",
"Image Relay", "Image Relay",
@@ -22582,6 +22633,15 @@
"title_aux": "ComfyUI OpenAI Prompter" "title_aux": "ComfyUI OpenAI Prompter"
} }
], ],
"https://github.com/nkchocoai/ComfyUI-DanbooruPromptQuiz": [
[
"DanbooruPromptComparison",
"DanbooruPromptQuiz"
],
{
"title_aux": "ComfyUI-DanbooruPromptQuiz"
}
],
"https://github.com/nkchocoai/ComfyUI-Dart": [ "https://github.com/nkchocoai/ComfyUI-Dart": [
[ [
"DanbooruTagsTransformerBanTagsFromRegex", "DanbooruTagsTransformerBanTagsFromRegex",
@@ -22687,6 +22747,7 @@
], ],
"https://github.com/nofunstudio/Node_Fun_ComfyUI": [ "https://github.com/nofunstudio/Node_Fun_ComfyUI": [
[ [
"IframeView",
"LayeredInfiniteZoom", "LayeredInfiniteZoom",
"Replicate flux 1.1 pro ultra", "Replicate flux 1.1 pro ultra",
"ReplicateAPI_flux_1_1_pro_ultra", "ReplicateAPI_flux_1_1_pro_ultra",
@@ -26170,6 +26231,7 @@
"quadmoonChangeBackground", "quadmoonChangeBackground",
"quadmoonConvertBoolToString", "quadmoonConvertBoolToString",
"quadmoonConvertFloatToString", "quadmoonConvertFloatToString",
"quadmoonConvertImageToPrompt",
"quadmoonConvertIntToString", "quadmoonConvertIntToString",
"quadmoonConvertNormalizeHW", "quadmoonConvertNormalizeHW",
"quadmoonConvertNumberToString", "quadmoonConvertNumberToString",
@@ -27146,6 +27208,7 @@
], ],
"https://github.com/xlinx/ComfyUI-decadetw-auto-prompt-llm": [ "https://github.com/xlinx/ComfyUI-decadetw-auto-prompt-llm": [
[ [
"Auto-LLM-Chat",
"Auto-LLM-Text", "Auto-LLM-Text",
"Auto-LLM-Text-Vision", "Auto-LLM-Text-Vision",
"Auto-LLM-Vision" "Auto-LLM-Vision"

View File

@@ -103,6 +103,24 @@ manager_config_path = os.path.join(manager_files_path, 'config.ini')
cm_cli_path = os.path.join(comfyui_manager_path, "cm-cli.py") cm_cli_path = os.path.join(comfyui_manager_path, "cm-cli.py")
default_conf = {}
def read_config():
global default_conf
import configparser
config = configparser.ConfigParser()
config.read(manager_config_path)
default_conf = config['default']
def read_uv_mode():
if 'use_uv' in default_conf:
manager_util.use_uv = default_conf['use_uv']
read_config()
read_uv_mode()
cm_global.pip_overrides = {'numpy': 'numpy<2', 'ultralytics': 'ultralytics==8.3.40'} cm_global.pip_overrides = {'numpy': 'numpy<2', 'ultralytics': 'ultralytics==8.3.40'}
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:
@@ -419,11 +437,11 @@ except ModuleNotFoundError:
print("## ComfyUI-Manager: installing dependencies. (GitPython)") print("## ComfyUI-Manager: installing dependencies. (GitPython)")
try: try:
result = subprocess.check_output([sys.executable, '-s', '-m', 'pip', 'install', '-r', requirements_path]) result = subprocess.check_output(manager_util.make_pip_cmd(['install', '-r', requirements_path]))
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print("## [ERROR] ComfyUI-Manager: Attempting to reinstall dependencies using an alternative method.") print("## [ERROR] ComfyUI-Manager: Attempting to reinstall dependencies using an alternative method.")
try: try:
result = subprocess.check_output([sys.executable, '-s', '-m', 'pip', 'install', '--user', '-r', requirements_path]) result = subprocess.check_output(manager_util.make_pip_cmd(['install', '--user', '-r', requirements_path]))
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print("## [ERROR] ComfyUI-Manager: Failed to install the GitPython package in the correct Python environment. Please install it manually in the appropriate environment. (You can seek help at https://app.element.io/#/room/%23comfyui_space%3Amatrix.org)") print("## [ERROR] ComfyUI-Manager: Failed to install the GitPython package in the correct Python environment. Please install it manually in the appropriate environment. (You can seek help at https://app.element.io/#/room/%23comfyui_space%3Amatrix.org)")
@@ -452,11 +470,6 @@ else:
def read_downgrade_blacklist(): def read_downgrade_blacklist():
try: try:
import configparser
config = configparser.ConfigParser()
config.read(manager_config_path)
default_conf = config['default']
if 'downgrade_blacklist' in default_conf: if 'downgrade_blacklist' in default_conf:
items = default_conf['downgrade_blacklist'].split(',') items = default_conf['downgrade_blacklist'].split(',')
items = [x.strip() for x in items if x != ''] items = [x.strip() for x in items if x != '']
@@ -471,19 +484,13 @@ read_downgrade_blacklist()
def check_bypass_ssl(): def check_bypass_ssl():
try: try:
import configparser
import ssl import ssl
config = configparser.ConfigParser()
config.read(manager_config_path)
default_conf = config['default']
if 'bypass_ssl' in default_conf and default_conf['bypass_ssl'].lower() == 'true': if 'bypass_ssl' in default_conf and default_conf['bypass_ssl'].lower() == 'true':
print(f"[ComfyUI-Manager] WARN: Unsafe - SSL verification bypass option is Enabled. (see {manager_config_path})") print(f"[ComfyUI-Manager] WARN: Unsafe - SSL verification bypass option is Enabled. (see {manager_config_path})")
ssl._create_default_https_context = ssl._create_unverified_context # SSL certificate error fix. ssl._create_default_https_context = ssl._create_unverified_context # SSL certificate error fix.
except Exception: except Exception:
pass pass
check_bypass_ssl() check_bypass_ssl()
@@ -603,9 +610,9 @@ def execute_lazy_install_script(repo_path, executable):
if package_name and not is_installed(package_name): if package_name and not is_installed(package_name):
if '--index-url' in package_name: if '--index-url' in package_name:
s = package_name.split('--index-url') s = package_name.split('--index-url')
install_cmd = [sys.executable, "-m", "pip", "install", s[0].strip(), '--index-url', s[1].strip()] install_cmd = manager_util.make_pip_cmd(["install", s[0].strip(), '--index-url', s[1].strip()])
else: else:
install_cmd = [sys.executable, "-m", "pip", "install", package_name] install_cmd = manager_util.make_pip_cmd(["install", package_name])
process_wrap(install_cmd, repo_path) process_wrap(install_cmd, repo_path)

View File

@@ -1,7 +1,7 @@
[project] [project]
name = "comfyui-manager" name = "comfyui-manager"
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.13" version = "3.16"
license = { file = "LICENSE.txt" } license = { file = "LICENSE.txt" }
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"] dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]