Compare commits

...

2 Commits
3.12.2 ... 3.13

Author SHA1 Message Date
Dr.Lt.Data
510c364607 feat: stop feature
feat: model-manager - support background tasking
2025-02-01 16:35:56 +09:00
Dr.Lt.Data
a3d6fcccb7 update DB 2025-02-01 14:01:18 +09:00
10 changed files with 1897 additions and 1689 deletions

View File

@@ -2818,11 +2818,17 @@
], ],
"https://github.com/DesertPixelAi/ComfyUI-Desert-Pixel-Nodes": [ "https://github.com/DesertPixelAi/ComfyUI-Desert-Pixel-Nodes": [
[ [
"DP 10 String Switch", "DP 10 Images Switch Or Batch",
"DP 10 String Switch Or Connect",
"DP 2 String Switch", "DP 2 String Switch",
"DP 3 Images Switch Or Batch",
"DP 3 String Switch Or Connect",
"DP 5 Find And Replace", "DP 5 Find And Replace",
"DP 5 String Switch", "DP 5 Images Switch Or Batch",
"DP 5 String Switch Or Connect",
"DP Add Background To Png",
"DP Add Weight To String Sdxl", "DP Add Weight To String Sdxl",
"DP Advanced Sampler",
"DP Advanced Weight String Sdxl", "DP Advanced Weight String Sdxl",
"DP Animation Calculator 10 Inputs", "DP Animation Calculator 10 Inputs",
"DP Animation Calculator 5 Inputs", "DP Animation Calculator 5 Inputs",
@@ -2832,8 +2838,7 @@
"DP Broken Token", "DP Broken Token",
"DP Clean Prompt", "DP Clean Prompt",
"DP Clean Prompt Travel", "DP Clean Prompt Travel",
"DP Combo Controller", "DP Condition Switch",
"DP Condition Mixer",
"DP ControlNet Apply Advanced", "DP ControlNet Apply Advanced",
"DP Crazy Prompt Mixer", "DP Crazy Prompt Mixer",
"DP Create Json File", "DP Create Json File",
@@ -2845,6 +2850,7 @@
"DP Fast Slow Motion", "DP Fast Slow Motion",
"DP Five Lora", "DP Five Lora",
"DP Five Lora Random", "DP Five Lora Random",
"DP Float Stepper",
"DP Image And String Pairs Switch", "DP Image And String Pairs Switch",
"DP Image Color Analyzer", "DP Image Color Analyzer",
"DP Image Color Analyzer Small", "DP Image Color Analyzer Small",
@@ -2855,12 +2861,10 @@
"DP Image Empty Latent Switch SDXL", "DP Image Empty Latent Switch SDXL",
"DP Image Slide Show", "DP Image Slide Show",
"DP Image Strip", "DP Image Strip",
"DP Image Switch 10",
"DP Image Switch 3",
"DP Image Switch 5",
"DP Int 0-1000", "DP Int 0-1000",
"DP Int 0-1000 4 Step", "DP Int 0-1000 4 Step",
"DP Int 0-1000 8 Step", "DP Int 0-1000 8 Step",
"DP Latent Split",
"DP Line Cycler", "DP Line Cycler",
"DP Load Checkpoint With Info", "DP Load Checkpoint With Info",
"DP Load Controlnet Model With Name", "DP Load Controlnet Model With Name",
@@ -2870,13 +2874,10 @@
"DP Load Image Minimal", "DP Load Image Minimal",
"DP Load UNET With Info", "DP Load UNET With Info",
"DP Logo Animator", "DP Logo Animator",
"DP Logo Animator Advanced",
"DP Lora Random Strength Controller", "DP Lora Random Strength Controller",
"DP Lora Strength Controller", "DP Lora Strength Controller",
"DP Lora Strength Stepper",
"DP Mask Settings", "DP Mask Settings",
"DP Prompt Inverter", "DP Prompt Inverter",
"DP Prompt Manager",
"DP Prompt Manager Small", "DP Prompt Manager Small",
"DP Prompt Mode Controller", "DP Prompt Mode Controller",
"DP Prompt Styler", "DP Prompt Styler",
@@ -2894,9 +2895,7 @@
"DP Save Preview Image", "DP Save Preview Image",
"DP Set New Model Folder Link", "DP Set New Model Folder Link",
"DP String Text", "DP String Text",
"DP String Text With Weight", "DP String Text With Sdxl Weight",
"DP String With Switch",
"DP Strings Connector",
"DP Strip Edge Masks", "DP Strip Edge Masks",
"DP Switch Controller", "DP Switch Controller",
"DP Text Preview", "DP Text Preview",
@@ -2907,10 +2906,8 @@
"DP Video Looper", "DP Video Looper",
"DP Video Transition", "DP Video Transition",
"DP_Crazy_Prompt_Mixer", "DP_Crazy_Prompt_Mixer",
"DP_Logo_Animator_Advanced", "DP_Float_Stepper",
"DP_Lora_Strength_Stepper", "DP_Prompt_Inverter"
"DP_Prompt_Inverter",
"DP_Strings_Connector"
], ],
{ {
"title_aux": "ComfyUI-Desert-Pixel-Nodes" "title_aux": "ComfyUI-Desert-Pixel-Nodes"
@@ -4714,6 +4711,8 @@
], ],
"https://github.com/JTriggerFish/ComfyLatentTools": [ "https://github.com/JTriggerFish/ComfyLatentTools": [
[ [
"DownsampledAttentionGuidance",
"DownsampledLatentGuidance",
"LatentNormalizedLanczosResize", "LatentNormalizedLanczosResize",
"RescaledPAG", "RescaledPAG",
"RescaledSEG" "RescaledSEG"
@@ -7351,6 +7350,7 @@
"AspectRatioAdvanced", "AspectRatioAdvanced",
"DisplayEverything", "DisplayEverything",
"ImageComparer", "ImageComparer",
"LensFlare",
"MultiFloat", "MultiFloat",
"MultiTextNode", "MultiTextNode",
"SKB_AnySwitch", "SKB_AnySwitch",
@@ -8450,6 +8450,7 @@
"SD35StartSettings", "SD35StartSettings",
"SDXLStartSettings", "SDXLStartSettings",
"SDstarsampler", "SDstarsampler",
"Star Face Loader",
"StarFiveWildcards", "StarFiveWildcards",
"StarImageSwitch", "StarImageSwitch",
"StarTextFilter", "StarTextFilter",
@@ -11881,18 +11882,22 @@
"SamplerSonarEuler", "SamplerSonarEuler",
"SamplerSonarEulerA", "SamplerSonarEulerA",
"SonarAdvanced1fNoise", "SonarAdvanced1fNoise",
"SonarAdvancedDistroNoise",
"SonarAdvancedPowerLawNoise", "SonarAdvancedPowerLawNoise",
"SonarAdvancedPyramidNoise", "SonarAdvancedPyramidNoise",
"SonarBlendedNoise", "SonarBlendedNoise",
"SonarChannelNoise", "SonarChannelNoise",
"SonarCompositeNoise", "SonarCompositeNoise",
"SonarCustomNoise", "SonarCustomNoise",
"SonarCustomNoiseAdv",
"SonarGuidanceConfig", "SonarGuidanceConfig",
"SonarGuidedNoise", "SonarGuidedNoise",
"SonarModulatedNoise", "SonarModulatedNoise",
"SonarRandomNoise", "SonarRandomNoise",
"SonarRepeatedNoise", "SonarRepeatedNoise",
"SonarScheduledNoise" "SonarResizedNoise",
"SonarScheduledNoise",
"SonarWaveletFilteredNoise"
], ],
{ {
"title_aux": "ComfyUI-sonar" "title_aux": "ComfyUI-sonar"
@@ -13897,6 +13902,7 @@
"PolyexponentialScheduler", "PolyexponentialScheduler",
"PorterDuffImageComposite", "PorterDuffImageComposite",
"Preview3D", "Preview3D",
"Preview3DAnimation",
"PreviewAudio", "PreviewAudio",
"PreviewImage", "PreviewImage",
"RandomNoise", "RandomNoise",
@@ -16638,8 +16644,10 @@
"Griptape Replace: Rulesets on Agent", "Griptape Replace: Rulesets on Agent",
"Griptape Replace: Tools on Agent", "Griptape Replace: Tools on Agent",
"Griptape Rerank Driver: Cohere", "Griptape Rerank Driver: Cohere",
"Griptape Retrieve: Cloud Ruleset",
"Griptape Run: Agent", "Griptape Run: Agent",
"Griptape Run: Audio Transcription", "Griptape Run: Audio Transcription",
"Griptape Run: Cloud Assistant",
"Griptape Run: Image Description", "Griptape Run: Image Description",
"Griptape Run: Parallel Image Description", "Griptape Run: Parallel Image Description",
"Griptape Run: Prompt Task", "Griptape Run: Prompt Task",
@@ -22682,8 +22690,7 @@
"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",
"ReplicateAPI_flux_fill_pro", "ReplicateAPI_flux_fill_pro"
"WebViewer"
], ],
{ {
"title_aux": "Node_Fun_ComfyUI" "title_aux": "Node_Fun_ComfyUI"

View File

File diff suppressed because it is too large Load Diff

View File

@@ -41,7 +41,7 @@ import manager_downloader
from node_package import InstalledNodePackage from node_package import InstalledNodePackage
version_code = [3, 12, 2] version_code = [3, 13]
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 '')

View File

@@ -369,12 +369,14 @@ def nickname_filter(json_obj):
return json_obj return json_obj
install_queue = queue.Queue() task_queue = queue.Queue()
install_result = {} nodepack_result = {}
model_result = {}
async def install_worker(): async def task_worker():
global install_result global task_queue
global install_queue global nodepack_result
global model_result
async def do_install(item): async def do_install(item):
ui_id, node_spec_str, channel, mode, skip_post_install = item ui_id, node_spec_str, channel, mode, skip_post_install = item
@@ -384,7 +386,7 @@ async def install_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}'")
install_result[ui_id] = f"Cannot resolve install target: '{node_spec_str}'" nodepack_result[ui_id] = f"Cannot resolve install target: '{node_spec_str}'"
return return
node_name, version_spec, is_specified = node_spec node_name, version_spec, is_specified = node_spec
@@ -393,18 +395,18 @@ async def install_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}")
install_result[ui_id] = res.msg nodepack_result[ui_id] = res.msg
return 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}")
install_result[ui_id] = res.msg nodepack_result[ui_id] = res.msg
return return
install_result[ui_id] = 'success' nodepack_result[ui_id] = 'success'
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
install_result[ui_id] = f"Installation failed:\n{node_spec_str}" nodepack_result[ui_id] = f"Installation failed:\n{node_spec_str}"
async def do_update(item): async def do_update(item):
ui_id, node_name, node_ver = item ui_id, node_name, node_ver = item
@@ -415,14 +417,14 @@ async def install_worker():
manager_util.clear_pip_cache() manager_util.clear_pip_cache()
if res.result: if res.result:
install_result[ui_id] = 'success' nodepack_result[ui_id] = 'success'
return return
logging.error(f"\nERROR: An error occurred while updating '{node_name}'.") logging.error(f"\nERROR: An error occurred while updating '{node_name}'.")
install_result[ui_id] = f"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()
install_result[ui_id] = f"An error occurred while updating '{node_name}'." nodepack_result[ui_id] = f"An error occurred while updating '{node_name}'."
async def do_fix(item): async def do_fix(item):
ui_id, node_name, node_ver = item ui_id, node_name, node_ver = item
@@ -431,16 +433,16 @@ async def install_worker():
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:
install_result[ui_id] = 'success' nodepack_result[ui_id] = 'success'
return 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}'.")
install_result[ui_id] = f"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()
install_result[ui_id] = f"An error occurred while fixing '{node_name}@{node_ver}'." nodepack_result[ui_id] = f"An error occurred while fixing '{node_name}@{node_ver}'."
async def do_uninstall(item): async def do_uninstall(item):
ui_id, node_name, is_unknown = item ui_id, node_name, is_unknown = item
@@ -449,14 +451,14 @@ async def install_worker():
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:
install_result[ui_id] = 'success' nodepack_result[ui_id] = 'success'
return return
logging.error(f"\nERROR: An error occurred while uninstalling '{node_name}'.") logging.error(f"\nERROR: An error occurred while uninstalling '{node_name}'.")
install_result[ui_id] = f"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()
install_result[ui_id] = f"An error occurred while uninstalling '{node_name}'." nodepack_result[ui_id] = f"An error occurred while uninstalling '{node_name}'."
async def do_disable(item): async def do_disable(item):
ui_id, node_name, is_unknown = item ui_id, node_name, is_unknown = item
@@ -465,48 +467,96 @@ async def install_worker():
res = core.unified_manager.unified_disable(node_name, is_unknown) res = core.unified_manager.unified_disable(node_name, is_unknown)
if res: if res:
install_result[ui_id] = 'success' nodepack_result[ui_id] = 'success'
return return
install_result[ui_id] = f"Failed to disable: '{node_name}'" nodepack_result[ui_id] = f"Failed to disable: '{node_name}'"
except Exception: except Exception:
traceback.print_exc() traceback.print_exc()
install_result[ui_id] = f"Failed to disable: '{node_name}'" nodepack_result[ui_id] = f"Failed to disable: '{node_name}'"
async def do_install_model(item):
ui_id, json_data = item
model_path = get_model_path(json_data)
model_url = json_data['url']
try:
if model_path is not None:
logging.info(f"Install model '{json_data['name']}' from '{model_url}' into '{model_path}'")
if not core.get_config()['model_download_by_agent'] and (
model_url.startswith('https://github.com') or model_url.startswith('https://huggingface.co') or model_url.startswith('https://heibox.uni-heidelberg.de')):
model_dir = get_model_dir(json_data, True)
download_url(model_url, model_dir, filename=json_data['filename'])
if model_path.endswith('.zip'):
res = core.unzip(model_path)
else:
res = True
if res:
model_result[ui_id] = 'success'
return
else:
res = download_url_with_agent(model_url, model_path)
if res and model_path.endswith('.zip'):
res = core.unzip(model_path)
else:
logging.error(f"Model installation error: invalid model type - {json_data['type']}")
return
if res:
model_result[ui_id] = 'success'
return
except Exception as e:
logging.error(f"[ERROR] {e}", file=sys.stderr)
model_result[ui_id] = f"Model installation error: {model_url}"
stats = {} stats = {}
while True: while True:
done_count = len(install_result) done_count = len(nodepack_result) + len(model_result)
total_count = done_count + install_queue.qsize() total_count = done_count + task_queue.qsize()
if install_queue.empty(): if task_queue.empty():
logging.info(f"\n[ComfyUI-Manager] Queued works are completed.\n{stats}") logging.info(f"\n[ComfyUI-Manager] Queued works are completed.\n{stats}")
logging.info("\nAfter restarting ComfyUI, please refresh the browser.") logging.info("\nAfter restarting ComfyUI, please refresh the browser.")
PromptServer.instance.send_sync("cm-install-status", PromptServer.instance.send_sync("cm-queue-status",
{'status': 'done', 'result': install_result, {'status': 'done',
'nodepack_result': nodepack_result, 'model_result': model_result,
'total_count': total_count, 'done_count': done_count}) 'total_count': total_count, 'done_count': done_count})
install_result = {} nodepack_result = {}
install_queue = queue.Queue() task_queue = queue.Queue()
return return
kind, item = install_queue.get() kind, item = task_queue.get()
if kind == 'install': try:
await do_install(item) if kind == 'install':
elif kind == 'update': await do_install(item)
await do_update(item) if kind == 'install-model':
elif kind == 'fix': await do_install_model(item)
await do_fix(item) elif kind == 'update':
elif kind == 'uninstall': await do_update(item)
await do_uninstall(item) elif kind == 'fix':
elif kind == 'disable': await do_fix(item)
await do_disable(item) elif kind == 'uninstall':
await do_uninstall(item)
elif kind == 'disable':
await do_disable(item)
except Exception:
traceback.print_exc()
stats[kind] = stats.get(kind, 0) + 1 stats[kind] = stats.get(kind, 0) + 1
PromptServer.instance.send_sync("cm-install-status", ui_target = "model_manager" if kind == 'install-model' else 'nodepack_manager'
{'status': 'in_progress', 'target': item[0],
print(f"kind: {kind} / ui_target: {ui_target}")
PromptServer.instance.send_sync("cm-queue-status",
{'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})
@@ -1006,30 +1056,31 @@ async def import_fail_info(request):
return web.Response(status=400) return web.Response(status=400)
@routes.post("/customnode/reinstall") @routes.post("/manager/queue/reinstall")
async def reinstall_custom_node(request): async def reinstall_custom_node(request):
await uninstall_custom_node(request) await uninstall_custom_node(request)
await install_custom_node(request) await install_custom_node(request)
@routes.get("/customnode/queue/reset") @routes.get("/manager/queue/reset")
async def reset_queue(request): async def reset_queue(request):
global install_queue global task_queue
install_queue = queue.Queue() task_queue = queue.Queue()
return web.Response(status=200) return web.Response(status=200)
@routes.get("/customnode/queue/count") @routes.get("/manager/queue/status")
async def queue_count(request): async def queue_count(request):
global install_queue global task_queue
done_count = len(install_result) done_count = len(nodepack_result) + len(model_result)
total_count = done_count + install_queue.qsize() total_count = done_count + task_queue.qsize()
in_progress = task_worker_thread is not None and task_worker_thread.is_alive()
return web.json_response({'total_count': total_count, 'done_count': done_count}) return web.json_response({'total_count': total_count, 'done_count': done_count, 'in_progress': in_progress})
@routes.post("/customnode/queue/install") @routes.post("/manager/queue/install")
async def install_custom_node(request): async def install_custom_node(request):
if not is_allowed_security_level('middle'): if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
@@ -1073,22 +1124,32 @@ async def install_custom_node(request):
return web.Response(status=404, text="A security error has occurred. Please check the terminal logs") return web.Response(status=404, text="A security error has occurred. Please check the terminal logs")
install_item = json_data.get('ui_id'), node_spec_str, json_data['channel'], json_data['mode'], skip_post_install install_item = json_data.get('ui_id'), node_spec_str, json_data['channel'], json_data['mode'], skip_post_install
install_queue.put(("install", install_item)) task_queue.put(("install", install_item))
return web.Response(status=200) return web.Response(status=200)
@routes.get("/customnode/queue/start") task_worker_thread = None
@routes.get("/manager/queue/start")
async def queue_start(request): async def queue_start(request):
global install_result global nodepack_result
install_result = {} global model_result
global task_worker_thread
threading.Thread(target=lambda: asyncio.run(install_worker())).start() if task_worker_thread is not None and task_worker_thread.is_alive():
return web.Response(status=201) # already in-progress
nodepack_result = {}
model_result = {}
task_worker_thread = threading.Thread(target=lambda: asyncio.run(task_worker()))
task_worker_thread.start()
return web.Response(status=200) return web.Response(status=200)
@routes.post("/customnode/queue/fix") @routes.post("/manager/queue/fix")
async def fix_custom_node(request): async def fix_custom_node(request):
if not is_allowed_security_level('middle'): if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_GENERAL) logging.error(SECURITY_MESSAGE_GENERAL)
@@ -1105,7 +1166,7 @@ async def fix_custom_node(request):
node_name = os.path.basename(json_data['files'][0]) node_name = os.path.basename(json_data['files'][0])
update_item = json_data.get('ui_id'), node_name, json_data['version'] update_item = json_data.get('ui_id'), node_name, json_data['version']
install_queue.put(("fix", update_item)) task_queue.put(("fix", update_item))
return web.Response(status=200) return web.Response(status=200)
@@ -1142,7 +1203,7 @@ async def install_custom_node_pip(request):
return web.Response(status=200) return web.Response(status=200)
@routes.post("/customnode/queue/uninstall") @routes.post("/manager/queue/uninstall")
async def uninstall_custom_node(request): async def uninstall_custom_node(request):
if not is_allowed_security_level('middle'): if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
@@ -1160,12 +1221,12 @@ async def uninstall_custom_node(request):
node_name = os.path.basename(json_data['files'][0]) node_name = os.path.basename(json_data['files'][0])
uninstall_item = json_data.get('ui_id'), node_name, is_unknown uninstall_item = json_data.get('ui_id'), node_name, is_unknown
install_queue.put(("uninstall", uninstall_item)) task_queue.put(("uninstall", uninstall_item))
return web.Response(status=200) return web.Response(status=200)
@routes.post("/customnode/queue/update") @routes.post("/manager/queue/update")
async def update_custom_node(request): async def update_custom_node(request):
if not is_allowed_security_level('middle'): if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
@@ -1181,7 +1242,7 @@ async def update_custom_node(request):
node_name = os.path.basename(json_data['files'][0]) node_name = os.path.basename(json_data['files'][0])
update_item = json_data.get('ui_id'), node_name, json_data['version'] update_item = json_data.get('ui_id'), node_name, json_data['version']
install_queue.put(("update", update_item)) task_queue.put(("update", update_item))
return web.Response(status=200) return web.Response(status=200)
@@ -1232,7 +1293,7 @@ async def comfyui_switch_version(request):
return web.Response(status=400) return web.Response(status=400)
@routes.post("/customnode/queue/disable") @routes.post("/manager/queue/disable")
async def disable_node(request): async def disable_node(request):
json_data = await request.json() json_data = await request.json()
@@ -1246,7 +1307,7 @@ async def disable_node(request):
node_name = os.path.basename(json_data['files'][0]) node_name = os.path.basename(json_data['files'][0])
update_item = json_data.get('ui_id'), node_name, is_unknown update_item = json_data.get('ui_id'), node_name, is_unknown
install_queue.put(("disable", update_item)) task_queue.put(("disable", update_item))
return web.Response(status=200) return web.Response(status=200)
@@ -1264,12 +1325,10 @@ async def need_to_migrate(request):
return web.Response(text=str(core.need_to_migrate), status=200) return web.Response(text=str(core.need_to_migrate), status=200)
@routes.post("/model/install") @routes.post("/manager/queue/install_model")
async def install_model(request): async def install_model(request):
json_data = await request.json() json_data = await request.json()
model_path = get_model_path(json_data)
if not is_allowed_security_level('middle'): if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW) logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
return web.Response(status=403) return web.Response(status=403)
@@ -1287,42 +1346,8 @@ async def install_model(request):
logging.error(SECURITY_MESSAGE_NORMAL_MINUS) logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
return web.Response(status=403) return web.Response(status=403)
def do_install(): install_item = json_data.get('ui_id'), json_data
res = False task_queue.put(("install-model", install_item))
try:
if model_path is not None:
model_url = json_data['url']
logging.info(f"Install model '{json_data['name']}' from '{model_url}' into '{model_path}'")
if not core.get_config()['model_download_by_agent'] and (
model_url.startswith('https://github.com') or model_url.startswith('https://huggingface.co') or model_url.startswith('https://heibox.uni-heidelberg.de')):
model_dir = get_model_dir(json_data, True)
download_url(model_url, model_dir, filename=json_data['filename'])
if model_path.endswith('.zip'):
res = core.unzip(model_path)
else:
res = True
if res:
return web.json_response({}, content_type='application/json')
else:
res = download_url_with_agent(model_url, model_path)
if res and model_path.endswith('.zip'):
res = core.unzip(model_path)
else:
logging.error(f"Model installation error: invalid model type - {json_data['type']}")
if res:
return web.json_response({}, content_type='application/json')
except Exception as e:
logging.error(f"[ERROR] {e}", file=sys.stderr)
return web.Response(status=400)
# Run the installation in a thread pool
with concurrent.futures.ThreadPoolExecutor() as executor:
asyncio.get_event_loop().run_in_executor(executor, do_install)
return web.Response(status=200) return web.Response(status=200)

View File

@@ -55,6 +55,12 @@ const pageCss = `
color: white; color: white;
} }
.cn-manager .cn-manager-stop {
display: none;
background-color: #500000;
color: white;
}
.cn-manager .cn-manager-back { .cn-manager .cn-manager-back {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -344,13 +350,14 @@ const pageHtml = `
<div class="cn-manager-selection"></div> <div class="cn-manager-selection"></div>
<div class="cn-manager-message"></div> <div class="cn-manager-message"></div>
<div class="cn-manager-footer"> <div class="cn-manager-footer">
<button class="cn-manager-back"> <button class="cn-manager-back">
<svg class="arrow-icon" width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg class="arrow-icon" width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 8H18M2 8L8 2M2 8L8 14" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M2 8H18M2 8L8 2M2 8L8 14" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
Back Back
</button> </button>
<button class="cn-manager-restart">Restart</button> <button class="cn-manager-restart">Restart</button>
<button class="cn-manager-stop">Stop</button>
<div class="cn-flex-auto"></div> <div class="cn-flex-auto"></div>
<button class="cn-manager-check-update">Check Update</button> <button class="cn-manager-check-update">Check Update</button>
<button class="cn-manager-check-missing">Check Missing</button> <button class="cn-manager-check-missing">Check Missing</button>
@@ -392,7 +399,7 @@ export class CustomNodesManager {
this.init(); this.init();
api.addEventListener("cm-install-status", this.onInstallStatus); api.addEventListener("cm-queue-status", this.onQueueStatus);
} }
init() { init() {
@@ -762,6 +769,13 @@ export class CustomNodesManager {
} }
}, },
".cn-manager-stop": {
click: () => {
api.fetchApi('/manager/queue/reset');
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
}
},
".cn-manager-check-update": { ".cn-manager-check-update": {
click: (e) => { click: (e) => {
e.target.classList.add("cn-btn-loading"); e.target.classList.add("cn-btn-loading");
@@ -1271,9 +1285,9 @@ export class CustomNodesManager {
} }
async installNodes(list, btn, title, selected_version) { async installNodes(list, btn, title, selected_version) {
let stats = await api.fetchApi('/customnode/queue/count'); let stats = await api.fetchApi('/manager/queue/status');
stats = await stats.json(); stats = await stats.json();
if(stats.total_count > 0) { if(stats.in_progress) {
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;
} }
@@ -1304,11 +1318,13 @@ export class CustomNodesManager {
let needRestart = false; let needRestart = false;
let errorMsg = ""; let errorMsg = "";
await api.fetchApi('/customnode/queue/reset'); await api.fetchApi('/manager/queue/reset');
this.install_context = btn;
let target_items = [];
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);
if (!item) { if (!item) {
errorMsg = `Not found custom node: ${hash}`; errorMsg = `Not found custom node: ${hash}`;
@@ -1347,7 +1363,7 @@ export class CustomNodesManager {
api_mode = 'reinstall'; api_mode = 'reinstall';
} }
const res = await api.fetchApi(`/customnode/queue/${api_mode}`, { const res = await api.fetchApi(`/manager/queue/${api_mode}`, {
method: 'POST', method: 'POST',
body: JSON.stringify(data) body: JSON.stringify(data)
}); });
@@ -1367,18 +1383,32 @@ export class CustomNodesManager {
} }
} }
this.install_context = {btn: btn, targets: target_items};
for(let k in target_items) {
let item = this.install_context.targets[k];
this.grid.updateCell(item, "action");
}
if(errorMsg) { if(errorMsg) {
this.showError(errorMsg); this.showError(errorMsg);
show_message("Installation Error:\n"+errorMsg); show_message("Installation Error:\n"+errorMsg);
// reset
for (const hash of list) {
const item = this.grid.getRowItemBy("hash", hash);
self.grid.updateCell(item, "action");
}
} }
else { else {
await api.fetchApi('/customnode/queue/start'); await api.fetchApi('/manager/queue/start');
this.showStop();
} }
} }
async onInstallStatus(event) { async onQueueStatus(event) {
let self = CustomNodesManager.instance; let self = CustomNodesManager.instance;
if(event.detail.status == 'in_progress') { if(event.detail.status == 'in_progress' && event.detail.ui_target == 'nodepack_manager') {
const hash = event.detail.target; const hash = event.detail.target;
const item = self.grid.getRowItemBy("hash", hash); const item = self.grid.getRowItemBy("hash", hash);
@@ -1386,14 +1416,20 @@ export class CustomNodesManager {
item.restart = true; item.restart = true;
self.restartMap[item.hash] = true; self.restartMap[item.hash] = true;
self.grid.updateCell(item, "action"); self.grid.updateCell(item, "action");
self.grid.setRowSelected(item, false);
} }
else if(event.detail.status == 'done') { else if(event.detail.status == 'done') {
self.onInstallCompleted(event.detail); self.hideStop();
self.onQueueCompleted(event.detail);
} }
} }
async onInstallCompleted(info) { async onQueueCompleted(info) {
let result = info.result; let result = info.nodepack_result;
if(result.length == 0) {
return;
}
let self = CustomNodesManager.instance; let self = CustomNodesManager.instance;
@@ -1401,7 +1437,7 @@ export class CustomNodesManager {
return; return;
} }
const { target, label, mode } = self.install_context; const { target, label, mode } = self.install_context.btn;
target.classList.remove("cn-btn-loading"); target.classList.remove("cn-btn-loading");
let errorMsg = ""; let errorMsg = "";
@@ -1409,13 +1445,15 @@ export class CustomNodesManager {
for(let hash in result){ for(let hash in result){
let v = result[hash]; let v = result[hash];
const item = self.grid.getRowItemBy("hash", hash);
self.grid.setRowSelected(item, false);
if(v != 'success') if(v != 'success')
errorMsg += v; errorMsg += v;
} }
for(let k in self.install_context.targets) {
let item = self.install_context.targets[k];
self.grid.updateCell(item, "action");
}
if (errorMsg) { if (errorMsg) {
self.showError(errorMsg); self.showError(errorMsg);
show_message("Installation Error:\n"+errorMsg); show_message("Installation Error:\n"+errorMsg);
@@ -1426,7 +1464,7 @@ export class CustomNodesManager {
self.showRestart(); self.showRestart();
self.showMessage(`To apply the installed/updated/disabled/enabled custom node, please restart ComfyUI. And refresh browser.`, "red"); self.showMessage(`To apply the installed/updated/disabled/enabled custom node, please restart ComfyUI. And refresh browser.`, "red");
infoToast(`[ComfyUI-Manager] All tasks in the queue have been completed.\n${info.done_count}/${info.total_count}`); infoToast(`[ComfyUI-Manager] All node pack tasks in the queue have been completed.\n${info.done_count}/${info.total_count}`);
self.install_context = undefined; self.install_context = undefined;
} }
@@ -1808,9 +1846,9 @@ export class CustomNodesManager {
} }
setDisabled(disabled) { setDisabled(disabled) {
const $close = this.element.querySelector(".cn-manager-close"); const $close = this.element.querySelector(".cn-manager-close");
const $restart = this.element.querySelector(".cn-manager-restart"); const $restart = this.element.querySelector(".cn-manager-restart");
const $stop = this.element.querySelector(".cn-manager-stop");
const list = [ const list = [
".cn-manager-header input", ".cn-manager-header input",
@@ -1822,7 +1860,7 @@ export class CustomNodesManager {
}) })
.flat() .flat()
.filter(it => { .filter(it => {
return it !== $close && it !== $restart; return it !== $close && it !== $restart && it !== $stop;
}); });
list.forEach($elem => { list.forEach($elem => {
@@ -1843,6 +1881,14 @@ export class CustomNodesManager {
this.element.querySelector(".cn-manager-restart").style.display = "block"; this.element.querySelector(".cn-manager-restart").style.display = "block";
} }
showStop() {
this.element.querySelector(".cn-manager-stop").style.display = "block";
}
hideStop() {
this.element.querySelector(".cn-manager-stop").style.display = "none";
}
setFilter(filterValue) { setFilter(filterValue) {
let filter = ""; let filter = "";
const filterItem = this.getFilterItem(filterValue); const filterItem = this.getFilterItem(filterValue);

View File

@@ -1,8 +1,10 @@
import { app } from "../../scripts/app.js";
import { $el } from "../../scripts/ui.js"; import { $el } from "../../scripts/ui.js";
import { import {
manager_instance, rebootAPI, manager_instance, rebootAPI,
fetchData, md5, icons fetchData, md5, icons, show_message, customAlert, infoToast
} from "./common.js"; } from "./common.js";
import { api } from "../../scripts/api.js";
// https://cenfun.github.io/turbogrid/api.html // https://cenfun.github.io/turbogrid/api.html
import TG from "./turbogrid.esm.js"; import TG from "./turbogrid.esm.js";
@@ -46,6 +48,18 @@ const pageCss = `
background-color: var(--comfy-input-bg); background-color: var(--comfy-input-bg);
} }
.cmm-manager .cmm-manager-refresh {
display: none;
background-color: #000080;
color: white;
}
.cmm-manager .cmm-manager-stop {
display: none;
background-color: #500000;
color: white;
}
.cmm-manager-header { .cmm-manager-header {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@@ -235,7 +249,14 @@ const pageHtml = `
<div class="cmm-manager-selection"></div> <div class="cmm-manager-selection"></div>
<div class="cmm-manager-message"></div> <div class="cmm-manager-message"></div>
<div class="cmm-manager-footer"> <div class="cmm-manager-footer">
<button class="cmm-manager-back">Back</button> <button class="cmm-manager-back">
<svg class="arrow-icon" width="14" height="14" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 8H18M2 8L8 2M2 8L8 14" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Back
</button>
<button class="cmm-manager-refresh">Refresh</button>
<button class="cmm-manager-stop">Stop</button>
<div class="cmm-flex-auto"></div> <div class="cmm-flex-auto"></div>
</div> </div>
`; `;
@@ -254,6 +275,8 @@ export class ModelManager {
this.keywords = ''; this.keywords = '';
this.init(); this.init();
api.addEventListener("cm-queue-status", this.onQueueStatus);
} }
init() { init() {
@@ -365,12 +388,25 @@ export class ModelManager {
} }
}, },
".cmm-manager-refresh": {
click: () => {
app.refreshComboInNodes();
}
},
".cmm-manager-stop": {
click: () => {
api.fetchApi('/manager/queue/reset');
infoToast('Cancel', 'Remaining tasks will stop after completing the current task.');
}
},
".cmm-manager-back": { ".cmm-manager-back": {
click: (e) => { click: (e) => {
this.close() this.close()
manager_instance.show(); manager_instance.show();
} }
}, }
}; };
Object.keys(eventsMap).forEach(selector => { Object.keys(eventsMap).forEach(selector => {
const target = this.element.querySelector(selector); const target = this.element.querySelector(selector);
@@ -595,17 +631,28 @@ 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.in_progress) {
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.showLoading(); this.showLoading();
this.showError(""); this.showError("");
let needRestart = false; let needRefresh = false;
let errorMsg = ""; let errorMsg = "";
await api.fetchApi('/manager/queue/reset');
let target_items = [];
for (const item of list) { for (const item of list) {
this.grid.scrollRowIntoView(item); this.grid.scrollRowIntoView(item);
target_items.push(item);
if (!this.focusInstall(item)) { if (!this.focusInstall(item)) {
this.grid.onNextUpdated(() => { this.grid.onNextUpdated(() => {
@@ -616,48 +663,104 @@ export class ModelManager {
this.showStatus(`Install ${item.name} ...`); this.showStatus(`Install ${item.name} ...`);
const data = item.originalData; const data = item.originalData;
const res = await fetchData('/model/install', { data.ui_id = item.hash;
const res = await api.fetchApi(`/manager/queue/install_model`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data) body: JSON.stringify(data)
}); });
if (res.status != 200) {
if (res.error) {
errorMsg = `Install failed: ${item.name} ${res.error.message}`; errorMsg = `Install failed: ${item.name} ${res.error.message}`;
break;; break;
} }
}
needRestart = true; this.install_context = {btn: btn, targets: target_items};
this.grid.setRowSelected(item, false); if(errorMsg) {
this.showError(errorMsg);
show_message("Installation Error:\n"+errorMsg);
// reset
for (const hash of list) {
const item = this.grid.getRowItemBy("hash", hash);
this.grid.updateCell(item, "installed");
}
}
else {
await api.fetchApi('/manager/queue/start');
this.showStop();
}
}
async onQueueStatus(event) {
let self = ModelManager.instance;
if(event.detail.status == 'in_progress' && event.detail.ui_target == 'model_manager') {
const hash = event.detail.target;
const item = self.grid.getRowItemBy("hash", hash);
item.refresh = true; item.refresh = true;
self.grid.setRowSelected(item, false);
item.selectable = false; item.selectable = false;
this.grid.updateCell(item, "installed"); // self.grid.updateCell(item, "tg-column-select");
this.grid.updateCell(item, "tg-column-select"); self.grid.updateRow(item);
}
else if(event.detail.status == 'done') {
self.hideStop();
self.onQueueCompleted(event.detail);
}
}
this.showStatus(`Install ${item.name} successfully`); async onQueueCompleted(info) {
let result = info.model_result;
if(result.length == 0) {
return;
} }
this.hideLoading(); let self = ModelManager.instance;
if(!self.install_context) {
return;
}
let btn = self.install_context.btn;
self.hideLoading();
btn.classList.remove("cmm-btn-loading"); btn.classList.remove("cmm-btn-loading");
let errorMsg = "";
for(let hash in result){
let v = result[hash];
if(v != 'success')
errorMsg += v;
}
for(let k in self.install_context.targets) {
let item = self.install_context.targets[k];
self.grid.updateCell(item, "installed");
}
if (errorMsg) { if (errorMsg) {
this.showError(errorMsg); self.showError(errorMsg);
show_message("Installation Error:\n"+errorMsg);
} else { } else {
this.showStatus(`Install ${list.length} models successfully`); self.showStatus(`Install ${result.length} models successfully`);
} }
if (needRestart) { self.showRefresh();
this.showMessage(`To apply the installed model, please click the 'Refresh' button on the main menu.`, "red") self.showMessage(`To apply the installed model, please click the 'Refresh' button.`, "red")
}
infoToast('Tasks done', `[ComfyUI-Manager] All model downloading tasks in the queue have been completed.\n${info.done_count}/${info.total_count}`);
self.install_context = undefined;
} }
getModelList(models) { getModelList(models) {
const typeMap = new Map(); const typeMap = new Map();
const baseMap = new Map(); const baseMap = new Map();
@@ -826,7 +929,7 @@ export class ModelManager {
} }
showLoading() { showLoading() {
this.setDisabled(true); // this.setDisabled(true);
if (this.grid) { if (this.grid) {
this.grid.showLoading(); this.grid.showLoading();
this.grid.showMask({ this.grid.showMask({
@@ -836,7 +939,7 @@ export class ModelManager {
} }
hideLoading() { hideLoading() {
this.setDisabled(false); // this.setDisabled(false);
if (this.grid) { if (this.grid) {
this.grid.hideLoading(); this.grid.hideLoading();
this.grid.hideMask(); this.grid.hideMask();
@@ -844,8 +947,9 @@ export class ModelManager {
} }
setDisabled(disabled) { setDisabled(disabled) {
const $close = this.element.querySelector(".cmm-manager-close"); const $close = this.element.querySelector(".cmm-manager-close");
const $refresh = this.element.querySelector(".cmm-manager-refresh");
const $stop = this.element.querySelector(".cmm-manager-stop");
const list = [ const list = [
".cmm-manager-header input", ".cmm-manager-header input",
@@ -857,7 +961,7 @@ export class ModelManager {
}) })
.flat() .flat()
.filter(it => { .filter(it => {
return it !== $close; return it !== $close && it !== $refresh && it !== $stop;
}); });
list.forEach($elem => { list.forEach($elem => {
@@ -874,6 +978,18 @@ export class ModelManager {
} }
showRefresh() {
this.element.querySelector(".cmm-manager-refresh").style.display = "block";
}
showStop() {
this.element.querySelector(".cmm-manager-stop").style.display = "block";
}
hideStop() {
this.element.querySelector(".cmm-manager-stop").style.display = "none";
}
setKeywords(keywords = "") { setKeywords(keywords = "") {
this.keywords = keywords; this.keywords = keywords;
this.element.querySelector(".cmm-manager-keywords").value = keywords; this.element.querySelector(".cmm-manager-keywords").value = keywords;

View File

@@ -924,6 +924,7 @@
"DeepSeekImageGeneration", "DeepSeekImageGeneration",
"DeepSeekImageUnderstanding", "DeepSeekImageUnderstanding",
"DeepSeekModelLoader", "DeepSeekModelLoader",
"LLM_Loader",
"OpenAICompatibleLoader" "OpenAICompatibleLoader"
], ],
{ {
@@ -1628,6 +1629,8 @@
"FrameBlend", "FrameBlend",
"ImageReferenceUpdate", "ImageReferenceUpdate",
"ImageSelector", "ImageSelector",
"KeypointsInputNode",
"KeypointsToPoseNode",
"SimHashCompare", "SimHashCompare",
"TemporalConsistency" "TemporalConsistency"
], ],
@@ -2438,6 +2441,7 @@
"PolyexponentialScheduler", "PolyexponentialScheduler",
"PorterDuffImageComposite", "PorterDuffImageComposite",
"Preview3D", "Preview3D",
"Preview3DAnimation",
"PreviewAudio", "PreviewAudio",
"PreviewImage", "PreviewImage",
"RandomNoise", "RandomNoise",
@@ -3317,6 +3321,7 @@
[ [
"ForceMinimumBatchSize", "ForceMinimumBatchSize",
"ImageCompositeChained", "ImageCompositeChained",
"LineDetection",
"MangaPanelSegmentationNode", "MangaPanelSegmentationNode",
"Mask_Fill_Region", "Mask_Fill_Region",
"MatchImageCountToMaskCount", "MatchImageCountToMaskCount",
@@ -3325,6 +3330,7 @@
"RandomCharacterPrompts", "RandomCharacterPrompts",
"TargetLocationCrop", "TargetLocationCrop",
"TargetLocationPaste", "TargetLocationPaste",
"Yolov8Detection",
"easy_parallax", "easy_parallax",
"string_list_to_prompt_schedule" "string_list_to_prompt_schedule"
], ],
@@ -4247,7 +4253,8 @@
], ],
"https://github.com/nomcycle/ComfyUI_Cluster": [ "https://github.com/nomcycle/ComfyUI_Cluster": [
[ [
"FenceClusteredWorkflow" "ClusterFanInTensorsToBatch",
"ClusterInstanceIndex"
], ],
{ {
"title_aux": "ComfyUI_Cluster [WIP]" "title_aux": "ComfyUI_Cluster [WIP]"

View File

File diff suppressed because it is too large Load Diff

View File

@@ -2818,11 +2818,17 @@
], ],
"https://github.com/DesertPixelAi/ComfyUI-Desert-Pixel-Nodes": [ "https://github.com/DesertPixelAi/ComfyUI-Desert-Pixel-Nodes": [
[ [
"DP 10 String Switch", "DP 10 Images Switch Or Batch",
"DP 10 String Switch Or Connect",
"DP 2 String Switch", "DP 2 String Switch",
"DP 3 Images Switch Or Batch",
"DP 3 String Switch Or Connect",
"DP 5 Find And Replace", "DP 5 Find And Replace",
"DP 5 String Switch", "DP 5 Images Switch Or Batch",
"DP 5 String Switch Or Connect",
"DP Add Background To Png",
"DP Add Weight To String Sdxl", "DP Add Weight To String Sdxl",
"DP Advanced Sampler",
"DP Advanced Weight String Sdxl", "DP Advanced Weight String Sdxl",
"DP Animation Calculator 10 Inputs", "DP Animation Calculator 10 Inputs",
"DP Animation Calculator 5 Inputs", "DP Animation Calculator 5 Inputs",
@@ -2832,8 +2838,7 @@
"DP Broken Token", "DP Broken Token",
"DP Clean Prompt", "DP Clean Prompt",
"DP Clean Prompt Travel", "DP Clean Prompt Travel",
"DP Combo Controller", "DP Condition Switch",
"DP Condition Mixer",
"DP ControlNet Apply Advanced", "DP ControlNet Apply Advanced",
"DP Crazy Prompt Mixer", "DP Crazy Prompt Mixer",
"DP Create Json File", "DP Create Json File",
@@ -2845,6 +2850,7 @@
"DP Fast Slow Motion", "DP Fast Slow Motion",
"DP Five Lora", "DP Five Lora",
"DP Five Lora Random", "DP Five Lora Random",
"DP Float Stepper",
"DP Image And String Pairs Switch", "DP Image And String Pairs Switch",
"DP Image Color Analyzer", "DP Image Color Analyzer",
"DP Image Color Analyzer Small", "DP Image Color Analyzer Small",
@@ -2855,12 +2861,10 @@
"DP Image Empty Latent Switch SDXL", "DP Image Empty Latent Switch SDXL",
"DP Image Slide Show", "DP Image Slide Show",
"DP Image Strip", "DP Image Strip",
"DP Image Switch 10",
"DP Image Switch 3",
"DP Image Switch 5",
"DP Int 0-1000", "DP Int 0-1000",
"DP Int 0-1000 4 Step", "DP Int 0-1000 4 Step",
"DP Int 0-1000 8 Step", "DP Int 0-1000 8 Step",
"DP Latent Split",
"DP Line Cycler", "DP Line Cycler",
"DP Load Checkpoint With Info", "DP Load Checkpoint With Info",
"DP Load Controlnet Model With Name", "DP Load Controlnet Model With Name",
@@ -2870,13 +2874,10 @@
"DP Load Image Minimal", "DP Load Image Minimal",
"DP Load UNET With Info", "DP Load UNET With Info",
"DP Logo Animator", "DP Logo Animator",
"DP Logo Animator Advanced",
"DP Lora Random Strength Controller", "DP Lora Random Strength Controller",
"DP Lora Strength Controller", "DP Lora Strength Controller",
"DP Lora Strength Stepper",
"DP Mask Settings", "DP Mask Settings",
"DP Prompt Inverter", "DP Prompt Inverter",
"DP Prompt Manager",
"DP Prompt Manager Small", "DP Prompt Manager Small",
"DP Prompt Mode Controller", "DP Prompt Mode Controller",
"DP Prompt Styler", "DP Prompt Styler",
@@ -2894,9 +2895,7 @@
"DP Save Preview Image", "DP Save Preview Image",
"DP Set New Model Folder Link", "DP Set New Model Folder Link",
"DP String Text", "DP String Text",
"DP String Text With Weight", "DP String Text With Sdxl Weight",
"DP String With Switch",
"DP Strings Connector",
"DP Strip Edge Masks", "DP Strip Edge Masks",
"DP Switch Controller", "DP Switch Controller",
"DP Text Preview", "DP Text Preview",
@@ -2907,10 +2906,8 @@
"DP Video Looper", "DP Video Looper",
"DP Video Transition", "DP Video Transition",
"DP_Crazy_Prompt_Mixer", "DP_Crazy_Prompt_Mixer",
"DP_Logo_Animator_Advanced", "DP_Float_Stepper",
"DP_Lora_Strength_Stepper", "DP_Prompt_Inverter"
"DP_Prompt_Inverter",
"DP_Strings_Connector"
], ],
{ {
"title_aux": "ComfyUI-Desert-Pixel-Nodes" "title_aux": "ComfyUI-Desert-Pixel-Nodes"
@@ -4714,6 +4711,8 @@
], ],
"https://github.com/JTriggerFish/ComfyLatentTools": [ "https://github.com/JTriggerFish/ComfyLatentTools": [
[ [
"DownsampledAttentionGuidance",
"DownsampledLatentGuidance",
"LatentNormalizedLanczosResize", "LatentNormalizedLanczosResize",
"RescaledPAG", "RescaledPAG",
"RescaledSEG" "RescaledSEG"
@@ -7351,6 +7350,7 @@
"AspectRatioAdvanced", "AspectRatioAdvanced",
"DisplayEverything", "DisplayEverything",
"ImageComparer", "ImageComparer",
"LensFlare",
"MultiFloat", "MultiFloat",
"MultiTextNode", "MultiTextNode",
"SKB_AnySwitch", "SKB_AnySwitch",
@@ -8450,6 +8450,7 @@
"SD35StartSettings", "SD35StartSettings",
"SDXLStartSettings", "SDXLStartSettings",
"SDstarsampler", "SDstarsampler",
"Star Face Loader",
"StarFiveWildcards", "StarFiveWildcards",
"StarImageSwitch", "StarImageSwitch",
"StarTextFilter", "StarTextFilter",
@@ -11881,18 +11882,22 @@
"SamplerSonarEuler", "SamplerSonarEuler",
"SamplerSonarEulerA", "SamplerSonarEulerA",
"SonarAdvanced1fNoise", "SonarAdvanced1fNoise",
"SonarAdvancedDistroNoise",
"SonarAdvancedPowerLawNoise", "SonarAdvancedPowerLawNoise",
"SonarAdvancedPyramidNoise", "SonarAdvancedPyramidNoise",
"SonarBlendedNoise", "SonarBlendedNoise",
"SonarChannelNoise", "SonarChannelNoise",
"SonarCompositeNoise", "SonarCompositeNoise",
"SonarCustomNoise", "SonarCustomNoise",
"SonarCustomNoiseAdv",
"SonarGuidanceConfig", "SonarGuidanceConfig",
"SonarGuidedNoise", "SonarGuidedNoise",
"SonarModulatedNoise", "SonarModulatedNoise",
"SonarRandomNoise", "SonarRandomNoise",
"SonarRepeatedNoise", "SonarRepeatedNoise",
"SonarScheduledNoise" "SonarResizedNoise",
"SonarScheduledNoise",
"SonarWaveletFilteredNoise"
], ],
{ {
"title_aux": "ComfyUI-sonar" "title_aux": "ComfyUI-sonar"
@@ -13897,6 +13902,7 @@
"PolyexponentialScheduler", "PolyexponentialScheduler",
"PorterDuffImageComposite", "PorterDuffImageComposite",
"Preview3D", "Preview3D",
"Preview3DAnimation",
"PreviewAudio", "PreviewAudio",
"PreviewImage", "PreviewImage",
"RandomNoise", "RandomNoise",
@@ -16638,8 +16644,10 @@
"Griptape Replace: Rulesets on Agent", "Griptape Replace: Rulesets on Agent",
"Griptape Replace: Tools on Agent", "Griptape Replace: Tools on Agent",
"Griptape Rerank Driver: Cohere", "Griptape Rerank Driver: Cohere",
"Griptape Retrieve: Cloud Ruleset",
"Griptape Run: Agent", "Griptape Run: Agent",
"Griptape Run: Audio Transcription", "Griptape Run: Audio Transcription",
"Griptape Run: Cloud Assistant",
"Griptape Run: Image Description", "Griptape Run: Image Description",
"Griptape Run: Parallel Image Description", "Griptape Run: Parallel Image Description",
"Griptape Run: Prompt Task", "Griptape Run: Prompt Task",
@@ -22682,8 +22690,7 @@
"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",
"ReplicateAPI_flux_fill_pro", "ReplicateAPI_flux_fill_pro"
"WebViewer"
], ],
{ {
"title_aux": "Node_Fun_ComfyUI" "title_aux": "Node_Fun_ComfyUI"

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.12.2" version = "3.13"
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"]