Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4227b17e5 | ||
|
|
7538169251 | ||
|
|
31e300e4e8 | ||
|
|
599bf78f20 | ||
|
|
f53fdb8d7a | ||
|
|
3b4bfeab22 | ||
|
|
8c1f828c1f | ||
|
|
f896755a31 | ||
|
|
e406f8be81 | ||
|
|
84107d2b65 | ||
|
|
d890984c70 | ||
|
|
72e4c84f8a | ||
|
|
acd41d985c | ||
|
|
1312657aca | ||
|
|
a502bb9529 | ||
|
|
5947dee9f9 | ||
|
|
e68d59098f | ||
|
|
61efd60681 | ||
|
|
d3654b2ee4 | ||
|
|
ef943a588d | ||
|
|
8c6ebc665d | ||
|
|
2d2df3fc2c | ||
|
|
958ddcb49c | ||
|
|
5e9e988a96 | ||
|
|
34f3409f9b | ||
|
|
49c548494e | ||
|
|
7ba41fbb7d | ||
|
|
d95b974941 | ||
|
|
74bf39ab27 | ||
|
|
8897b9e0f7 | ||
|
|
d6de8644c0 | ||
|
|
190f3b1684 | ||
|
|
ae5961daf4 | ||
|
|
68b51b387a | ||
|
|
9097319c4b | ||
|
|
49a7db074d | ||
|
|
7f7ed04a80 | ||
|
|
ab5f42cc65 | ||
|
|
b1fd8fd51b | ||
|
|
16b98576c7 | ||
|
|
78f5d86f89 | ||
|
|
beec803eff | ||
|
|
3e0b55e8dc | ||
|
|
70db90f25b | ||
|
|
d84b79bee9 | ||
|
|
b491f51a04 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -12,4 +12,6 @@ matrix_auth
|
||||
channels.list
|
||||
comfyworkflows_sharekey
|
||||
github-stats-cache.json
|
||||
pip_overrides.json
|
||||
pip_overrides.json
|
||||
*.json
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ cli_mode_flag = os.path.join(os.path.dirname(__file__), '.enable-cli-only-mode')
|
||||
|
||||
if not os.path.exists(cli_mode_flag):
|
||||
from .glob import manager_server
|
||||
from .glob import share_3rdparty
|
||||
WEB_DIRECTORY = "js"
|
||||
else:
|
||||
print(f"\n[ComfyUI-Manager] !! cli-only-mode is enabled !!\n")
|
||||
|
||||
@@ -35,6 +35,7 @@ restore_snapshot_path = os.path.join(startup_script_path, "restore-snapshot.json
|
||||
pip_overrides_path = os.path.join(comfyui_manager_path, "pip_overrides.json")
|
||||
git_script_path = os.path.join(comfyui_manager_path, "git_helper.py")
|
||||
|
||||
cm_global.pip_blacklist = ['torch', 'torchsde', 'torchvision']
|
||||
cm_global.pip_downgrade_blacklist = ['torch', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia']
|
||||
cm_global.pip_overrides = {}
|
||||
if os.path.exists(pip_overrides_path):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4081
github-stats.json
4081
github-stats.json
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ sys.path.append(glob_path)
|
||||
import cm_global
|
||||
from manager_util import *
|
||||
|
||||
version = [2, 48, 6]
|
||||
version = [2, 50, 1]
|
||||
version_str = f"V{version[0]}.{version[1]}" + (f'.{version[2]}' if len(version) > 2 else '')
|
||||
|
||||
|
||||
@@ -103,6 +103,9 @@ def is_blacklisted(name):
|
||||
if match:
|
||||
name = match.group(1)
|
||||
|
||||
if name in cm_global.pip_blacklist:
|
||||
return True
|
||||
|
||||
if name in cm_global.pip_downgrade_blacklist:
|
||||
pips = get_installed_packages()
|
||||
|
||||
@@ -123,12 +126,15 @@ def is_installed(name):
|
||||
if name.startswith('#'):
|
||||
return True
|
||||
|
||||
pattern = r'([^<>!=]+)([<>!=]=?)([^ ]*)'
|
||||
pattern = r'([^<>!=]+)([<>!=]=?)([0-9.a-zA-Z]*)'
|
||||
match = re.search(pattern, name)
|
||||
|
||||
if match:
|
||||
name = match.group(1)
|
||||
|
||||
if name in cm_global.pip_blacklist:
|
||||
return True
|
||||
|
||||
if name in cm_global.pip_downgrade_blacklist:
|
||||
pips = get_installed_packages()
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import mimetypes
|
||||
import traceback
|
||||
|
||||
import folder_paths
|
||||
@@ -6,7 +5,6 @@ import locale
|
||||
import subprocess # don't remove this
|
||||
import concurrent
|
||||
import nodes
|
||||
import hashlib
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
@@ -22,6 +20,9 @@ print(f"### Loading: ComfyUI-Manager ({core.version_str})")
|
||||
|
||||
comfy_ui_hash = "-"
|
||||
|
||||
SECURITY_MESSAGE_MIDDLE_OR_BELOW = f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
|
||||
SECURITY_MESSAGE_NORMAL_MINUS = f"ERROR: To use this feature, you must either set '--listen' to a local IP and set the security level to 'normal-' or lower, or set the security level to 'middle' or 'weak'. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
|
||||
SECURITY_MESSAGE_GENERAL = f"ERROR: This installation is not allowed in this security_level. Please contact the administrator.\nReference: https://github.com/ltdrdata/ComfyUI-Manager#security-policy"
|
||||
|
||||
def handle_stream(stream, prefix):
|
||||
stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')
|
||||
@@ -249,8 +250,12 @@ def get_model_dir(data):
|
||||
model_type = data['type']
|
||||
if model_type == "checkpoints":
|
||||
base_model = folder_paths.folder_names_and_paths["checkpoints"][0][0]
|
||||
elif model_type == "checkpoint":
|
||||
base_model = folder_paths.folder_names_and_paths["checkpoints"][0][0]
|
||||
elif model_type == "unclip":
|
||||
base_model = folder_paths.folder_names_and_paths["checkpoints"][0][0]
|
||||
elif model_type == "clip":
|
||||
base_model = folder_paths.folder_names_and_paths["clip"][0][0]
|
||||
elif model_type == "VAE":
|
||||
base_model = folder_paths.folder_names_and_paths["vae"][0][0]
|
||||
elif model_type == "lora":
|
||||
@@ -388,7 +393,7 @@ async def fetch_updates(request):
|
||||
@PromptServer.instance.routes.get("/customnode/update_all")
|
||||
async def update_all(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
try:
|
||||
@@ -590,7 +595,7 @@ async def get_snapshot_list(request):
|
||||
@PromptServer.instance.routes.get("/snapshot/remove")
|
||||
async def remove_snapshot(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
try:
|
||||
@@ -608,7 +613,7 @@ async def remove_snapshot(request):
|
||||
@PromptServer.instance.routes.get("/snapshot/restore")
|
||||
async def remove_snapshot(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
try:
|
||||
@@ -777,14 +782,14 @@ def copy_set_active(files, is_disable, js_path_name='.'):
|
||||
@PromptServer.instance.routes.post("/customnode/install")
|
||||
async def install_custom_node(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
json_data = await request.json()
|
||||
|
||||
risky_level = await get_risky_level(json_data['files'])
|
||||
if not is_allowed_security_level(risky_level):
|
||||
print(f"ERROR: This installation is not allowed in this security_level. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_GENERAL)
|
||||
return web.Response(status=404)
|
||||
|
||||
install_type = json_data['install_type']
|
||||
@@ -824,7 +829,7 @@ async def install_custom_node(request):
|
||||
@PromptServer.instance.routes.post("/customnode/fix")
|
||||
async def fix_custom_node(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
json_data = await request.json()
|
||||
@@ -848,6 +853,10 @@ async def fix_custom_node(request):
|
||||
install_cmd = [sys.executable, "-m", "pip", "install", '-U', pname]
|
||||
core.try_install_script(json_data['files'][0], ".", install_cmd)
|
||||
|
||||
# HOTFIX: force downgrade to numpy<2
|
||||
install_cmd = [sys.executable, "-m", "pip", "install", "numpy<2"]
|
||||
core.try_install_script(json_data['files'][0], ".", install_cmd)
|
||||
|
||||
if res:
|
||||
print(f"After restarting ComfyUI, please refresh the browser.")
|
||||
return web.json_response({}, content_type='application/json')
|
||||
@@ -858,7 +867,7 @@ async def fix_custom_node(request):
|
||||
@PromptServer.instance.routes.post("/customnode/install/git_url")
|
||||
async def install_custom_node_git_url(request):
|
||||
if not is_allowed_security_level('high'):
|
||||
print(f"ERROR: To use this feature, you must either set '--listen' to a local IP and set the security level to 'normal-' or lower, or set the security level to 'middle' or 'weak'. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||
return web.Response(status=403)
|
||||
|
||||
url = await request.text()
|
||||
@@ -874,7 +883,7 @@ async def install_custom_node_git_url(request):
|
||||
@PromptServer.instance.routes.post("/customnode/install/pip")
|
||||
async def install_custom_node_git_url(request):
|
||||
if not is_allowed_security_level('high'):
|
||||
print(f"ERROR: To use this feature, you must either set '--listen' to a local IP and set the security level to 'normal-' or lower, or set the security level to 'middle' or 'weak'. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||
return web.Response(status=403)
|
||||
|
||||
packages = await request.text()
|
||||
@@ -886,7 +895,7 @@ async def install_custom_node_git_url(request):
|
||||
@PromptServer.instance.routes.post("/customnode/uninstall")
|
||||
async def uninstall_custom_node(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
json_data = await request.json()
|
||||
@@ -914,7 +923,7 @@ async def uninstall_custom_node(request):
|
||||
@PromptServer.instance.routes.post("/customnode/update")
|
||||
async def update_custom_node(request):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
json_data = await request.json()
|
||||
@@ -986,7 +995,7 @@ async def install_model(request):
|
||||
model_path = get_model_path(json_data)
|
||||
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
if not json_data['filename'].endswith('.safetensors') and not is_allowed_security_level('high'):
|
||||
@@ -999,7 +1008,7 @@ async def install_model(request):
|
||||
break
|
||||
|
||||
if not is_belongs_to_whitelist:
|
||||
print(f"ERROR: To use this feature, you must either set '--listen' to a local IP and set the security level to 'normal-' or lower, or set the security level to 'middle' or 'weak'. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||
return web.Response(status=403)
|
||||
|
||||
res = False
|
||||
@@ -1049,7 +1058,7 @@ manager_terminal_hook = ManagerTerminalHook()
|
||||
@PromptServer.instance.routes.get("/manager/terminal")
|
||||
async def terminal_mode(request):
|
||||
if not is_allowed_security_level('high'):
|
||||
print(f"ERROR: To use this feature, you must either set '--listen' to a local IP and set the security level to 'normal-' or lower, or set the security level to 'middle' or 'weak'. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_NORMAL_MINUS)
|
||||
return web.Response(status=403)
|
||||
|
||||
if "mode" in request.rel_url.query:
|
||||
@@ -1191,7 +1200,7 @@ async def get_notice(request):
|
||||
@PromptServer.instance.routes.get("/manager/reboot")
|
||||
def restart(self):
|
||||
if not is_allowed_security_level('middle'):
|
||||
print(f"ERROR: To use this action, a security_level of `middle or below` is required. Please contact the administrator.")
|
||||
print(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
|
||||
return web.Response(status=403)
|
||||
|
||||
try:
|
||||
@@ -1271,128 +1280,6 @@ async def load_components(request):
|
||||
return web.Response(status=400)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/share_option")
|
||||
async def share_option(request):
|
||||
if "value" in request.rel_url.query:
|
||||
core.get_config()['share_option'] = request.rel_url.query['value']
|
||||
core.write_config()
|
||||
else:
|
||||
return web.Response(text=core.get_config()['share_option'], status=200)
|
||||
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
def get_openart_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".openart_key")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "r") as f:
|
||||
openart_key = f.read().strip()
|
||||
return openart_key if openart_key else None
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def get_matrix_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, "matrix_auth")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "r") as f:
|
||||
matrix_auth = f.read()
|
||||
homeserver, username, password = matrix_auth.strip().split("\n")
|
||||
if not homeserver or not username or not password:
|
||||
return None
|
||||
return {
|
||||
"homeserver": homeserver,
|
||||
"username": username,
|
||||
"password": password,
|
||||
}
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def get_comfyworkflows_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "r") as f:
|
||||
share_key = f.read()
|
||||
if not share_key.strip():
|
||||
return None
|
||||
return share_key
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def get_youml_settings():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".youml")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, ".youml"), "r") as f:
|
||||
youml_settings = f.read().strip()
|
||||
return youml_settings if youml_settings else None
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def set_youml_settings(settings):
|
||||
with open(os.path.join(core.comfyui_manager_path, ".youml"), "w") as f:
|
||||
f.write(settings)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_openart_auth")
|
||||
async def api_get_openart_auth(request):
|
||||
# print("Getting stored Matrix credentials...")
|
||||
openart_key = get_openart_auth()
|
||||
if not openart_key:
|
||||
return web.Response(status=404)
|
||||
return web.json_response({"openart_key": openart_key})
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/set_openart_auth")
|
||||
async def api_set_openart_auth(request):
|
||||
json_data = await request.json()
|
||||
openart_key = json_data['openart_key']
|
||||
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "w") as f:
|
||||
f.write(openart_key)
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_matrix_auth")
|
||||
async def api_get_matrix_auth(request):
|
||||
# print("Getting stored Matrix credentials...")
|
||||
matrix_auth = get_matrix_auth()
|
||||
if not matrix_auth:
|
||||
return web.Response(status=404)
|
||||
return web.json_response(matrix_auth)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/youml/settings")
|
||||
async def api_get_youml_settings(request):
|
||||
youml_settings = get_youml_settings()
|
||||
if not youml_settings:
|
||||
return web.Response(status=404)
|
||||
return web.json_response(json.loads(youml_settings))
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/youml/settings")
|
||||
async def api_set_youml_settings(request):
|
||||
json_data = await request.json()
|
||||
set_youml_settings(json.dumps(json_data))
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_comfyworkflows_auth")
|
||||
async def api_get_comfyworkflows_auth(request):
|
||||
# Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken'
|
||||
# in the same directory as the ComfyUI base folder
|
||||
# print("Getting stored Comfyworkflows.com auth...")
|
||||
comfyworkflows_auth = get_comfyworkflows_auth()
|
||||
if not comfyworkflows_auth:
|
||||
return web.Response(status=404)
|
||||
return web.json_response({"comfyworkflows_sharekey": comfyworkflows_auth})
|
||||
|
||||
|
||||
args.enable_cors_header = "*"
|
||||
if hasattr(PromptServer.instance, "app"):
|
||||
app = PromptServer.instance.app
|
||||
@@ -1400,260 +1287,6 @@ if hasattr(PromptServer.instance, "app"):
|
||||
app.middlewares.append(cors_middleware)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images")
|
||||
async def set_esheep_workflow_and_images(request):
|
||||
json_data = await request.json()
|
||||
current_workflow = json_data['workflow']
|
||||
images = json_data['images']
|
||||
with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
||||
json.dump(json_data, file, indent=4)
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images")
|
||||
async def get_esheep_workflow_and_images(request):
|
||||
with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
||||
data = json.load(file)
|
||||
return web.Response(status=200, text=json.dumps(data))
|
||||
|
||||
|
||||
def set_matrix_auth(json_data):
|
||||
homeserver = json_data['homeserver']
|
||||
username = json_data['username']
|
||||
password = json_data['password']
|
||||
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "w") as f:
|
||||
f.write("\n".join([homeserver, username, password]))
|
||||
|
||||
|
||||
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "w") as f:
|
||||
f.write(comfyworkflows_sharekey)
|
||||
|
||||
|
||||
def has_provided_matrix_auth(matrix_auth):
|
||||
return matrix_auth['homeserver'].strip() and matrix_auth['username'].strip() and matrix_auth['password'].strip()
|
||||
|
||||
|
||||
def has_provided_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||
return comfyworkflows_sharekey.strip()
|
||||
|
||||
|
||||
def extract_model_file_names(json_data):
|
||||
"""Extract unique file names from the input JSON data."""
|
||||
file_names = set()
|
||||
model_filename_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'}
|
||||
|
||||
# Recursively search for file names in the JSON data
|
||||
def recursive_search(data):
|
||||
if isinstance(data, dict):
|
||||
for value in data.values():
|
||||
recursive_search(value)
|
||||
elif isinstance(data, list):
|
||||
for item in data:
|
||||
recursive_search(item)
|
||||
elif isinstance(data, str) and '.' in data:
|
||||
file_names.add(os.path.basename(data)) # file_names.add(data)
|
||||
|
||||
recursive_search(json_data)
|
||||
return [f for f in list(file_names) if os.path.splitext(f)[1] in model_filename_extensions]
|
||||
|
||||
|
||||
def find_file_paths(base_dir, file_names):
|
||||
"""Find the paths of the files in the base directory."""
|
||||
file_paths = {}
|
||||
|
||||
for root, dirs, files in os.walk(base_dir):
|
||||
# Exclude certain directories
|
||||
dirs[:] = [d for d in dirs if d not in ['.git']]
|
||||
|
||||
for file in files:
|
||||
if file in file_names:
|
||||
file_paths[file] = os.path.join(root, file)
|
||||
return file_paths
|
||||
|
||||
|
||||
def compute_sha256_checksum(filepath):
|
||||
"""Compute the SHA256 checksum of a file, in chunks"""
|
||||
sha256 = hashlib.sha256()
|
||||
with open(filepath, 'rb') as f:
|
||||
for chunk in iter(lambda: f.read(4096), b''):
|
||||
sha256.update(chunk)
|
||||
return sha256.hexdigest()
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/share")
|
||||
async def share_art(request):
|
||||
# get json data
|
||||
json_data = await request.json()
|
||||
|
||||
matrix_auth = json_data['matrix_auth']
|
||||
comfyworkflows_sharekey = json_data['cw_auth']['cw_sharekey']
|
||||
|
||||
set_matrix_auth(matrix_auth)
|
||||
set_comfyworkflows_auth(comfyworkflows_sharekey)
|
||||
|
||||
share_destinations = json_data['share_destinations']
|
||||
credits = json_data['credits']
|
||||
title = json_data['title']
|
||||
description = json_data['description']
|
||||
is_nsfw = json_data['is_nsfw']
|
||||
prompt = json_data['prompt']
|
||||
potential_outputs = json_data['potential_outputs']
|
||||
selected_output_index = json_data['selected_output_index']
|
||||
|
||||
try:
|
||||
output_to_share = potential_outputs[int(selected_output_index)]
|
||||
except:
|
||||
# for now, pick the first output
|
||||
output_to_share = potential_outputs[0]
|
||||
|
||||
assert output_to_share['type'] in ('image', 'output')
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
|
||||
if output_to_share['type'] == 'image':
|
||||
asset_filename = output_to_share['image']['filename']
|
||||
asset_subfolder = output_to_share['image']['subfolder']
|
||||
|
||||
if output_to_share['image']['type'] == 'temp':
|
||||
output_dir = folder_paths.get_temp_directory()
|
||||
else:
|
||||
asset_filename = output_to_share['output']['filename']
|
||||
asset_subfolder = output_to_share['output']['subfolder']
|
||||
|
||||
if asset_subfolder:
|
||||
asset_filepath = os.path.join(output_dir, asset_subfolder, asset_filename)
|
||||
else:
|
||||
asset_filepath = os.path.join(output_dir, asset_filename)
|
||||
|
||||
# get the mime type of the asset
|
||||
assetFileType = mimetypes.guess_type(asset_filepath)[0]
|
||||
|
||||
share_website_host = "UNKNOWN"
|
||||
if "comfyworkflows" in share_destinations:
|
||||
share_website_host = "https://comfyworkflows.com"
|
||||
share_endpoint = f"{share_website_host}/api"
|
||||
|
||||
# get presigned urls
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
async with session.post(
|
||||
f"{share_endpoint}/get_presigned_urls",
|
||||
json={
|
||||
"assetFileName": asset_filename,
|
||||
"assetFileType": assetFileType,
|
||||
"workflowJsonFileName": 'workflow.json',
|
||||
"workflowJsonFileType": 'application/json',
|
||||
},
|
||||
) as resp:
|
||||
assert resp.status == 200
|
||||
presigned_urls_json = await resp.json()
|
||||
assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"]
|
||||
assetFileKey = presigned_urls_json["assetFileKey"]
|
||||
workflowJsonFilePresignedUrl = presigned_urls_json["workflowJsonFilePresignedUrl"]
|
||||
workflowJsonFileKey = presigned_urls_json["workflowJsonFileKey"]
|
||||
|
||||
# upload asset
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
async with session.put(assetFilePresignedUrl, data=open(asset_filepath, "rb")) as resp:
|
||||
assert resp.status == 200
|
||||
|
||||
# upload workflow json
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
async with session.put(workflowJsonFilePresignedUrl, data=json.dumps(prompt['workflow']).encode('utf-8')) as resp:
|
||||
assert resp.status == 200
|
||||
|
||||
model_filenames = extract_model_file_names(prompt['workflow'])
|
||||
model_file_paths = find_file_paths(folder_paths.base_path, model_filenames)
|
||||
|
||||
models_info = {}
|
||||
for filename, filepath in model_file_paths.items():
|
||||
models_info[filename] = {
|
||||
"filename": filename,
|
||||
"sha256_checksum": compute_sha256_checksum(filepath),
|
||||
"relative_path": os.path.relpath(filepath, folder_paths.base_path),
|
||||
}
|
||||
|
||||
# make a POST request to /api/upload_workflow with form data key values
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
form = aiohttp.FormData()
|
||||
if comfyworkflows_sharekey:
|
||||
form.add_field("shareKey", comfyworkflows_sharekey)
|
||||
form.add_field("source", "comfyui_manager")
|
||||
form.add_field("assetFileKey", assetFileKey)
|
||||
form.add_field("assetFileType", assetFileType)
|
||||
form.add_field("workflowJsonFileKey", workflowJsonFileKey)
|
||||
form.add_field("sharedWorkflowWorkflowJsonString", json.dumps(prompt['workflow']))
|
||||
form.add_field("sharedWorkflowPromptJsonString", json.dumps(prompt['output']))
|
||||
form.add_field("shareWorkflowCredits", credits)
|
||||
form.add_field("shareWorkflowTitle", title)
|
||||
form.add_field("shareWorkflowDescription", description)
|
||||
form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower())
|
||||
form.add_field("currentSnapshot", json.dumps(core.get_current_snapshot()))
|
||||
form.add_field("modelsInfo", json.dumps(models_info))
|
||||
|
||||
async with session.post(
|
||||
f"{share_endpoint}/upload_workflow",
|
||||
data=form,
|
||||
) as resp:
|
||||
assert resp.status == 200
|
||||
upload_workflow_json = await resp.json()
|
||||
workflowId = upload_workflow_json["workflowId"]
|
||||
|
||||
# check if the user has provided Matrix credentials
|
||||
if "matrix" in share_destinations:
|
||||
comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org'
|
||||
filename = os.path.basename(asset_filepath)
|
||||
content_type = assetFileType
|
||||
|
||||
try:
|
||||
from matrix_client.api import MatrixHttpApi
|
||||
from matrix_client.client import MatrixClient
|
||||
|
||||
homeserver = 'matrix.org'
|
||||
if matrix_auth:
|
||||
homeserver = matrix_auth.get('homeserver', 'matrix.org')
|
||||
homeserver = homeserver.replace("http://", "https://")
|
||||
if not homeserver.startswith("https://"):
|
||||
homeserver = "https://" + homeserver
|
||||
|
||||
client = MatrixClient(homeserver)
|
||||
try:
|
||||
token = client.login(username=matrix_auth['username'], password=matrix_auth['password'])
|
||||
if not token:
|
||||
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
|
||||
except:
|
||||
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
|
||||
|
||||
matrix = MatrixHttpApi(homeserver, token=token)
|
||||
with open(asset_filepath, 'rb') as f:
|
||||
mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri']
|
||||
|
||||
workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri']
|
||||
|
||||
text_content = ""
|
||||
if title:
|
||||
text_content += f"{title}\n"
|
||||
if description:
|
||||
text_content += f"{description}\n"
|
||||
if credits:
|
||||
text_content += f"\ncredits: {credits}\n"
|
||||
response = matrix.send_message(comfyui_share_room_id, text_content)
|
||||
response = matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image')
|
||||
response = matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file')
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500)
|
||||
|
||||
return web.json_response({
|
||||
"comfyworkflows": {
|
||||
"url": None if "comfyworkflows" not in share_destinations else f"{share_website_host}/workflows/{workflowId}",
|
||||
},
|
||||
"matrix": {
|
||||
"success": None if "matrix" not in share_destinations else True
|
||||
}
|
||||
}, content_type='application/json', status=200)
|
||||
|
||||
|
||||
def sanitize(data):
|
||||
return data.replace("<", "<").replace(">", ">")
|
||||
|
||||
|
||||
@@ -1,63 +1,64 @@
|
||||
try:
|
||||
from distutils.version import StrictVersion
|
||||
except:
|
||||
print(f"[ComfyUI-Manager] 'distutils' package not found. Activating fallback mode for compatibility.")
|
||||
class StrictVersion:
|
||||
def __init__(self, version_string):
|
||||
self.version_string = version_string
|
||||
self.major = 0
|
||||
self.minor = 0
|
||||
self.patch = 0
|
||||
self.pre_release = None
|
||||
self.parse_version_string()
|
||||
# DON'T USE StrictVersion - cannot handle pre_release version
|
||||
# try:
|
||||
# from distutils.version import StrictVersion
|
||||
# except:
|
||||
# print(f"[ComfyUI-Manager] 'distutils' package not found. Activating fallback mode for compatibility.")
|
||||
class StrictVersion:
|
||||
def __init__(self, version_string):
|
||||
self.version_string = version_string
|
||||
self.major = 0
|
||||
self.minor = 0
|
||||
self.patch = 0
|
||||
self.pre_release = None
|
||||
self.parse_version_string()
|
||||
|
||||
def parse_version_string(self):
|
||||
parts = self.version_string.split('.')
|
||||
if not parts:
|
||||
raise ValueError("Version string must not be empty")
|
||||
def parse_version_string(self):
|
||||
parts = self.version_string.split('.')
|
||||
if not parts:
|
||||
raise ValueError("Version string must not be empty")
|
||||
|
||||
self.major = int(parts[0])
|
||||
self.minor = int(parts[1]) if len(parts) > 1 else 0
|
||||
self.patch = int(parts[2]) if len(parts) > 2 else 0
|
||||
self.major = int(parts[0])
|
||||
self.minor = int(parts[1]) if len(parts) > 1 else 0
|
||||
self.patch = int(parts[2]) if len(parts) > 2 else 0
|
||||
|
||||
# Handling pre-release versions if present
|
||||
if len(parts) > 3:
|
||||
self.pre_release = parts[3]
|
||||
# Handling pre-release versions if present
|
||||
if len(parts) > 3:
|
||||
self.pre_release = parts[3]
|
||||
|
||||
def __str__(self):
|
||||
version = f"{self.major}.{self.minor}.{self.patch}"
|
||||
if self.pre_release:
|
||||
version += f"-{self.pre_release}"
|
||||
return version
|
||||
def __str__(self):
|
||||
version = f"{self.major}.{self.minor}.{self.patch}"
|
||||
if self.pre_release:
|
||||
version += f"-{self.pre_release}"
|
||||
return version
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.major, self.minor, self.patch, self.pre_release) == \
|
||||
(other.major, other.minor, other.patch, other.pre_release)
|
||||
def __eq__(self, other):
|
||||
return (self.major, self.minor, self.patch, self.pre_release) == \
|
||||
(other.major, other.minor, other.patch, other.pre_release)
|
||||
|
||||
def __lt__(self, other):
|
||||
if (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch):
|
||||
return self.pre_release_compare(self.pre_release, other.pre_release) < 0
|
||||
return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)
|
||||
def __lt__(self, other):
|
||||
if (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch):
|
||||
return self.pre_release_compare(self.pre_release, other.pre_release) < 0
|
||||
return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)
|
||||
|
||||
@staticmethod
|
||||
def pre_release_compare(pre1, pre2):
|
||||
if pre1 == pre2:
|
||||
return 0
|
||||
if pre1 is None:
|
||||
return 1
|
||||
if pre2 is None:
|
||||
return -1
|
||||
return -1 if pre1 < pre2 else 1
|
||||
@staticmethod
|
||||
def pre_release_compare(pre1, pre2):
|
||||
if pre1 == pre2:
|
||||
return 0
|
||||
if pre1 is None:
|
||||
return 1
|
||||
if pre2 is None:
|
||||
return -1
|
||||
return -1 if pre1 < pre2 else 1
|
||||
|
||||
def __le__(self, other):
|
||||
return self == other or self < other
|
||||
def __le__(self, other):
|
||||
return self == other or self < other
|
||||
|
||||
def __gt__(self, other):
|
||||
return not self <= other
|
||||
def __gt__(self, other):
|
||||
return not self <= other
|
||||
|
||||
def __ge__(self, other):
|
||||
return not self < other
|
||||
def __ge__(self, other):
|
||||
return not self < other
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
|
||||
386
glob/share_3rdparty.py
Normal file
386
glob/share_3rdparty.py
Normal file
@@ -0,0 +1,386 @@
|
||||
import mimetypes
|
||||
import manager_core as core
|
||||
import os
|
||||
from aiohttp import web
|
||||
import aiohttp
|
||||
import json
|
||||
import hashlib
|
||||
|
||||
import folder_paths
|
||||
from server import PromptServer
|
||||
|
||||
|
||||
def extract_model_file_names(json_data):
|
||||
"""Extract unique file names from the input JSON data."""
|
||||
file_names = set()
|
||||
model_filename_extensions = {'.safetensors', '.ckpt', '.pt', '.pth', '.bin'}
|
||||
|
||||
# Recursively search for file names in the JSON data
|
||||
def recursive_search(data):
|
||||
if isinstance(data, dict):
|
||||
for value in data.values():
|
||||
recursive_search(value)
|
||||
elif isinstance(data, list):
|
||||
for item in data:
|
||||
recursive_search(item)
|
||||
elif isinstance(data, str) and '.' in data:
|
||||
file_names.add(os.path.basename(data)) # file_names.add(data)
|
||||
|
||||
recursive_search(json_data)
|
||||
return [f for f in list(file_names) if os.path.splitext(f)[1] in model_filename_extensions]
|
||||
|
||||
|
||||
def find_file_paths(base_dir, file_names):
|
||||
"""Find the paths of the files in the base directory."""
|
||||
file_paths = {}
|
||||
|
||||
for root, dirs, files in os.walk(base_dir):
|
||||
# Exclude certain directories
|
||||
dirs[:] = [d for d in dirs if d not in ['.git']]
|
||||
|
||||
for file in files:
|
||||
if file in file_names:
|
||||
file_paths[file] = os.path.join(root, file)
|
||||
return file_paths
|
||||
|
||||
|
||||
def compute_sha256_checksum(filepath):
|
||||
"""Compute the SHA256 checksum of a file, in chunks"""
|
||||
sha256 = hashlib.sha256()
|
||||
with open(filepath, 'rb') as f:
|
||||
for chunk in iter(lambda: f.read(4096), b''):
|
||||
sha256.update(chunk)
|
||||
return sha256.hexdigest()
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/share_option")
|
||||
async def share_option(request):
|
||||
if "value" in request.rel_url.query:
|
||||
core.get_config()['share_option'] = request.rel_url.query['value']
|
||||
core.write_config()
|
||||
else:
|
||||
return web.Response(text=core.get_config()['share_option'], status=200)
|
||||
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
def get_openart_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".openart_key")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "r") as f:
|
||||
openart_key = f.read().strip()
|
||||
return openart_key if openart_key else None
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def get_matrix_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, "matrix_auth")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "r") as f:
|
||||
matrix_auth = f.read()
|
||||
homeserver, username, password = matrix_auth.strip().split("\n")
|
||||
if not homeserver or not username or not password:
|
||||
return None
|
||||
return {
|
||||
"homeserver": homeserver,
|
||||
"username": username,
|
||||
"password": password,
|
||||
}
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def get_comfyworkflows_auth():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "r") as f:
|
||||
share_key = f.read()
|
||||
if not share_key.strip():
|
||||
return None
|
||||
return share_key
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def get_youml_settings():
|
||||
if not os.path.exists(os.path.join(core.comfyui_manager_path, ".youml")):
|
||||
return None
|
||||
try:
|
||||
with open(os.path.join(core.comfyui_manager_path, ".youml"), "r") as f:
|
||||
youml_settings = f.read().strip()
|
||||
return youml_settings if youml_settings else None
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def set_youml_settings(settings):
|
||||
with open(os.path.join(core.comfyui_manager_path, ".youml"), "w") as f:
|
||||
f.write(settings)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_openart_auth")
|
||||
async def api_get_openart_auth(request):
|
||||
# print("Getting stored Matrix credentials...")
|
||||
openart_key = get_openart_auth()
|
||||
if not openart_key:
|
||||
return web.Response(status=404)
|
||||
return web.json_response({"openart_key": openart_key})
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/set_openart_auth")
|
||||
async def api_set_openart_auth(request):
|
||||
json_data = await request.json()
|
||||
openart_key = json_data['openart_key']
|
||||
with open(os.path.join(core.comfyui_manager_path, ".openart_key"), "w") as f:
|
||||
f.write(openart_key)
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_matrix_auth")
|
||||
async def api_get_matrix_auth(request):
|
||||
# print("Getting stored Matrix credentials...")
|
||||
matrix_auth = get_matrix_auth()
|
||||
if not matrix_auth:
|
||||
return web.Response(status=404)
|
||||
return web.json_response(matrix_auth)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/youml/settings")
|
||||
async def api_get_youml_settings(request):
|
||||
youml_settings = get_youml_settings()
|
||||
if not youml_settings:
|
||||
return web.Response(status=404)
|
||||
return web.json_response(json.loads(youml_settings))
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/youml/settings")
|
||||
async def api_set_youml_settings(request):
|
||||
json_data = await request.json()
|
||||
set_youml_settings(json.dumps(json_data))
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_comfyworkflows_auth")
|
||||
async def api_get_comfyworkflows_auth(request):
|
||||
# Check if the user has provided Matrix credentials in a file called 'matrix_accesstoken'
|
||||
# in the same directory as the ComfyUI base folder
|
||||
# print("Getting stored Comfyworkflows.com auth...")
|
||||
comfyworkflows_auth = get_comfyworkflows_auth()
|
||||
if not comfyworkflows_auth:
|
||||
return web.Response(status=404)
|
||||
return web.json_response({"comfyworkflows_sharekey": comfyworkflows_auth})
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/set_esheep_workflow_and_images")
|
||||
async def set_esheep_workflow_and_images(request):
|
||||
json_data = await request.json()
|
||||
current_workflow = json_data['workflow']
|
||||
images = json_data['images']
|
||||
with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), "w", encoding='utf-8') as file:
|
||||
json.dump(json_data, file, indent=4)
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/manager/get_esheep_workflow_and_images")
|
||||
async def get_esheep_workflow_and_images(request):
|
||||
with open(os.path.join(core.comfyui_manager_path, "esheep_share_message.json"), 'r', encoding='utf-8') as file:
|
||||
data = json.load(file)
|
||||
return web.Response(status=200, text=json.dumps(data))
|
||||
|
||||
|
||||
def set_matrix_auth(json_data):
|
||||
homeserver = json_data['homeserver']
|
||||
username = json_data['username']
|
||||
password = json_data['password']
|
||||
with open(os.path.join(core.comfyui_manager_path, "matrix_auth"), "w") as f:
|
||||
f.write("\n".join([homeserver, username, password]))
|
||||
|
||||
|
||||
def set_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||
with open(os.path.join(core.comfyui_manager_path, "comfyworkflows_sharekey"), "w") as f:
|
||||
f.write(comfyworkflows_sharekey)
|
||||
|
||||
|
||||
def has_provided_matrix_auth(matrix_auth):
|
||||
return matrix_auth['homeserver'].strip() and matrix_auth['username'].strip() and matrix_auth['password'].strip()
|
||||
|
||||
|
||||
def has_provided_comfyworkflows_auth(comfyworkflows_sharekey):
|
||||
return comfyworkflows_sharekey.strip()
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/manager/share")
|
||||
async def share_art(request):
|
||||
# get json data
|
||||
json_data = await request.json()
|
||||
|
||||
matrix_auth = json_data['matrix_auth']
|
||||
comfyworkflows_sharekey = json_data['cw_auth']['cw_sharekey']
|
||||
|
||||
set_matrix_auth(matrix_auth)
|
||||
set_comfyworkflows_auth(comfyworkflows_sharekey)
|
||||
|
||||
share_destinations = json_data['share_destinations']
|
||||
credits = json_data['credits']
|
||||
title = json_data['title']
|
||||
description = json_data['description']
|
||||
is_nsfw = json_data['is_nsfw']
|
||||
prompt = json_data['prompt']
|
||||
potential_outputs = json_data['potential_outputs']
|
||||
selected_output_index = json_data['selected_output_index']
|
||||
|
||||
try:
|
||||
output_to_share = potential_outputs[int(selected_output_index)]
|
||||
except:
|
||||
# for now, pick the first output
|
||||
output_to_share = potential_outputs[0]
|
||||
|
||||
assert output_to_share['type'] in ('image', 'output')
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
|
||||
if output_to_share['type'] == 'image':
|
||||
asset_filename = output_to_share['image']['filename']
|
||||
asset_subfolder = output_to_share['image']['subfolder']
|
||||
|
||||
if output_to_share['image']['type'] == 'temp':
|
||||
output_dir = folder_paths.get_temp_directory()
|
||||
else:
|
||||
asset_filename = output_to_share['output']['filename']
|
||||
asset_subfolder = output_to_share['output']['subfolder']
|
||||
|
||||
if asset_subfolder:
|
||||
asset_filepath = os.path.join(output_dir, asset_subfolder, asset_filename)
|
||||
else:
|
||||
asset_filepath = os.path.join(output_dir, asset_filename)
|
||||
|
||||
# get the mime type of the asset
|
||||
assetFileType = mimetypes.guess_type(asset_filepath)[0]
|
||||
|
||||
share_website_host = "UNKNOWN"
|
||||
if "comfyworkflows" in share_destinations:
|
||||
share_website_host = "https://comfyworkflows.com"
|
||||
share_endpoint = f"{share_website_host}/api"
|
||||
|
||||
# get presigned urls
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
async with session.post(
|
||||
f"{share_endpoint}/get_presigned_urls",
|
||||
json={
|
||||
"assetFileName": asset_filename,
|
||||
"assetFileType": assetFileType,
|
||||
"workflowJsonFileName": 'workflow.json',
|
||||
"workflowJsonFileType": 'application/json',
|
||||
},
|
||||
) as resp:
|
||||
assert resp.status == 200
|
||||
presigned_urls_json = await resp.json()
|
||||
assetFilePresignedUrl = presigned_urls_json["assetFilePresignedUrl"]
|
||||
assetFileKey = presigned_urls_json["assetFileKey"]
|
||||
workflowJsonFilePresignedUrl = presigned_urls_json["workflowJsonFilePresignedUrl"]
|
||||
workflowJsonFileKey = presigned_urls_json["workflowJsonFileKey"]
|
||||
|
||||
# upload asset
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
async with session.put(assetFilePresignedUrl, data=open(asset_filepath, "rb")) as resp:
|
||||
assert resp.status == 200
|
||||
|
||||
# upload workflow json
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
async with session.put(workflowJsonFilePresignedUrl, data=json.dumps(prompt['workflow']).encode('utf-8')) as resp:
|
||||
assert resp.status == 200
|
||||
|
||||
model_filenames = extract_model_file_names(prompt['workflow'])
|
||||
model_file_paths = find_file_paths(folder_paths.base_path, model_filenames)
|
||||
|
||||
models_info = {}
|
||||
for filename, filepath in model_file_paths.items():
|
||||
models_info[filename] = {
|
||||
"filename": filename,
|
||||
"sha256_checksum": compute_sha256_checksum(filepath),
|
||||
"relative_path": os.path.relpath(filepath, folder_paths.base_path),
|
||||
}
|
||||
|
||||
# make a POST request to /api/upload_workflow with form data key values
|
||||
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
||||
form = aiohttp.FormData()
|
||||
if comfyworkflows_sharekey:
|
||||
form.add_field("shareKey", comfyworkflows_sharekey)
|
||||
form.add_field("source", "comfyui_manager")
|
||||
form.add_field("assetFileKey", assetFileKey)
|
||||
form.add_field("assetFileType", assetFileType)
|
||||
form.add_field("workflowJsonFileKey", workflowJsonFileKey)
|
||||
form.add_field("sharedWorkflowWorkflowJsonString", json.dumps(prompt['workflow']))
|
||||
form.add_field("sharedWorkflowPromptJsonString", json.dumps(prompt['output']))
|
||||
form.add_field("shareWorkflowCredits", credits)
|
||||
form.add_field("shareWorkflowTitle", title)
|
||||
form.add_field("shareWorkflowDescription", description)
|
||||
form.add_field("shareWorkflowIsNSFW", str(is_nsfw).lower())
|
||||
form.add_field("currentSnapshot", json.dumps(core.get_current_snapshot()))
|
||||
form.add_field("modelsInfo", json.dumps(models_info))
|
||||
|
||||
async with session.post(
|
||||
f"{share_endpoint}/upload_workflow",
|
||||
data=form,
|
||||
) as resp:
|
||||
assert resp.status == 200
|
||||
upload_workflow_json = await resp.json()
|
||||
workflowId = upload_workflow_json["workflowId"]
|
||||
|
||||
# check if the user has provided Matrix credentials
|
||||
if "matrix" in share_destinations:
|
||||
comfyui_share_room_id = '!LGYSoacpJPhIfBqVfb:matrix.org'
|
||||
filename = os.path.basename(asset_filepath)
|
||||
content_type = assetFileType
|
||||
|
||||
try:
|
||||
from matrix_client.api import MatrixHttpApi
|
||||
from matrix_client.client import MatrixClient
|
||||
|
||||
homeserver = 'matrix.org'
|
||||
if matrix_auth:
|
||||
homeserver = matrix_auth.get('homeserver', 'matrix.org')
|
||||
homeserver = homeserver.replace("http://", "https://")
|
||||
if not homeserver.startswith("https://"):
|
||||
homeserver = "https://" + homeserver
|
||||
|
||||
client = MatrixClient(homeserver)
|
||||
try:
|
||||
token = client.login(username=matrix_auth['username'], password=matrix_auth['password'])
|
||||
if not token:
|
||||
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
|
||||
except:
|
||||
return web.json_response({"error": "Invalid Matrix credentials."}, content_type='application/json', status=400)
|
||||
|
||||
matrix = MatrixHttpApi(homeserver, token=token)
|
||||
with open(asset_filepath, 'rb') as f:
|
||||
mxc_url = matrix.media_upload(f.read(), content_type, filename=filename)['content_uri']
|
||||
|
||||
workflow_json_mxc_url = matrix.media_upload(prompt['workflow'], 'application/json', filename='workflow.json')['content_uri']
|
||||
|
||||
text_content = ""
|
||||
if title:
|
||||
text_content += f"{title}\n"
|
||||
if description:
|
||||
text_content += f"{description}\n"
|
||||
if credits:
|
||||
text_content += f"\ncredits: {credits}\n"
|
||||
response = matrix.send_message(comfyui_share_room_id, text_content)
|
||||
response = matrix.send_content(comfyui_share_room_id, mxc_url, filename, 'm.image')
|
||||
response = matrix.send_content(comfyui_share_room_id, workflow_json_mxc_url, 'workflow.json', 'm.file')
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return web.json_response({"error": "An error occurred when sharing your art to Matrix."}, content_type='application/json', status=500)
|
||||
|
||||
return web.json_response({
|
||||
"comfyworkflows": {
|
||||
"url": None if "comfyworkflows" not in share_destinations else f"{share_website_host}/workflows/{workflowId}",
|
||||
},
|
||||
"matrix": {
|
||||
"success": None if "matrix" not in share_destinations else True
|
||||
}
|
||||
}, content_type='application/json', status=200)
|
||||
@@ -1,9 +1,31 @@
|
||||
{
|
||||
"models": [
|
||||
{
|
||||
"name": "TAEF1 Decoder",
|
||||
"type": "TAESD",
|
||||
"base": "FLUX.1",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(FLUX.1 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
"filename": "taef1_decoder.pth",
|
||||
"url": "https://github.com/madebyollin/taesd/raw/main/taef1_decoder.pth",
|
||||
"size": "4.71MB"
|
||||
},
|
||||
{
|
||||
"name": "TAEF1 Encoder",
|
||||
"type": "TAESD",
|
||||
"base": "FLUX.1",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(FLUX.1 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
"filename": "taef1_encoder.pth",
|
||||
"url": "https://github.com/madebyollin/taesd/raw/main/taef1_encoder.pth",
|
||||
"size": "4.71MB"
|
||||
},
|
||||
{
|
||||
"name": "TAESD3 Decoder",
|
||||
"type": "TAESD",
|
||||
"base": "SDXL",
|
||||
"base": "SD3",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(SD3 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
@@ -14,7 +36,7 @@
|
||||
{
|
||||
"name": "TAESD3 Encoder",
|
||||
"type": "TAESD",
|
||||
"base": "SDXL",
|
||||
"base": "SD3",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(SD3 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
|
||||
@@ -11,7 +11,127 @@
|
||||
|
||||
|
||||
|
||||
|
||||
{
|
||||
"author": "sebord",
|
||||
"title": "ComfyUI-LMCQ [WIP]",
|
||||
"reference": "https://github.com/sebord/ComfyUI-LMCQ",
|
||||
"files": [
|
||||
"https://github.com/sebord/ComfyUI-LMCQ"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "ComfyUI small node toolkit, this toolkit is mainly to update some practical small nodes, to make a contribution to the comfyui ecosystem, PS: 'LMCQ' is the abbreviation of the team name"
|
||||
},
|
||||
{
|
||||
"author": "logtd",
|
||||
"title": "ComfyUI-Fluxtapoz [WIP]",
|
||||
"reference": "https://github.com/logtd/ComfyUI-Fluxtapoz",
|
||||
"files": [
|
||||
"https://github.com/logtd/ComfyUI-Fluxtapoz"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A set of nodes for editing images using Flux in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "ChrisColeTech",
|
||||
"title": "ComfyUI-Get-Random-File [UNSAFE]",
|
||||
"reference": "https://github.com/ChrisColeTech/ComfyUI-Get-Random-File",
|
||||
"files": [
|
||||
"https://github.com/ChrisColeTech/ComfyUI-Get-Random-File"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Gets a random file from a directory. Returns the filpath as a STRING. [w/This node allows access to arbitrary files through the workflow, which could pose a security threat.]"
|
||||
},
|
||||
{
|
||||
"author": "logtd",
|
||||
"title": "ComfyUI-Fluxtapoz [WIP]",
|
||||
"reference": "https://github.com/logtd/ComfyUI-Fluxtapoz",
|
||||
"files": [
|
||||
"https://github.com/logtd/ComfyUI-Fluxtapoz"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A set of nodes for editing images using Flux in ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "neeltheninja",
|
||||
"title": "ComfyUI-ControlNeXt [WIP]",
|
||||
"reference": "https://github.com/neverbiasu/ComfyUI-ControlNeXt",
|
||||
"files": [
|
||||
"https://github.com/neverbiasu/ComfyUI-ControlNeXt"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "In progress🚧"
|
||||
},
|
||||
{
|
||||
"author": "neeltheninja",
|
||||
"title": "ComfyUI-TextOverlay",
|
||||
"reference": "https://github.com/neeltheninja/ComfyUI-TextOverlay",
|
||||
"files": [
|
||||
"https://github.com/neeltheninja/ComfyUI-TextOverlay"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A custom node for ComfyUI that adds text overlay to images, with options for text and background color, opacity, vertical positioning, and custom font selection. [w/Name conflict with munkyfoot/ComfyUI-TextOverlay. Cannot install simulatenously.]"
|
||||
},
|
||||
{
|
||||
"author": "comfyanonymous",
|
||||
"title": "ComfyUI_bitsandbytes_NF4 [EXPERIMENTAL]",
|
||||
"reference": "https://github.com/comfyanonymous/ComfyUI_bitsandbytes_NF4",
|
||||
"files": [
|
||||
"https://github.com/comfyanonymous/ComfyUI_bitsandbytes_NF4"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A quickly written custom node that uses code from Forge to support the nf4 flux dev checkpoint and nf4 flux schnell checkpoint.\nRequires installing bitsandbytes.\nMake sure your ComfyUI is updated.\nThe node is: CheckpointLoaderNF4, just plug it in your flux workflow instead of the regular one.[w/NF4 checckpoint doesn't support LoRA.]"
|
||||
},
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "ComfyUI-EasyAnimateWrapper [WIP]",
|
||||
"reference": "https://github.com/kijai/ComfyUI-EasyAnimateWrapper",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-EasyAnimateWrapper"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "EasyAnimateWrapper for ComfyUI"
|
||||
},
|
||||
{
|
||||
"author": "logtd",
|
||||
"title": "ComfyUI-Veevee [WIP]",
|
||||
"reference": "https://github.com/logtd/ComfyUI-Veevee",
|
||||
"files": [
|
||||
"https://github.com/logtd/ComfyUI-Veevee"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "A Video2Video framework for text2image models in ComfyUI. Supports SD1.5 and SDXL."
|
||||
},
|
||||
{
|
||||
"author": "kijai",
|
||||
"title": "ComfyUI-LLaVA-OneVision [WIP]",
|
||||
"reference": "https://github.com/kijai/ComfyUI-LLaVA-OneVision",
|
||||
"files": [
|
||||
"https://github.com/kijai/ComfyUI-LLaVA-OneVision"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Original repo: [a/https://github.com/LLaVA-VL/LLaVA-NeXT](https://github.com/LLaVA-VL/LLaVA-NeXT)\nUnsure of the dependencies, the original was a huge list, but I didn't install single new one to my environment and it worked."
|
||||
},
|
||||
{
|
||||
"author": "TTPlanetPig",
|
||||
"title": "for comfyui image proprocessor",
|
||||
"reference": "https://github.com/TTPlanetPig/Comfyui_TTP_CN_Preprocessor",
|
||||
"files": [
|
||||
"https://github.com/TTPlanetPig/Comfyui_TTP_CN_Preprocessor"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Adapt for Hunyuan now"
|
||||
},
|
||||
{
|
||||
"author": "IuvenisSapiens",
|
||||
"title": "ComfyUI_MiniCPM-V-2_6-int4",
|
||||
"id": "minicpm-v-2_6-int4",
|
||||
"reference": "https://github.com/IuvenisSapiens/ComfyUI_MiniCPM-V-2_6-int4",
|
||||
"files": [
|
||||
"https://github.com/IuvenisSapiens/ComfyUI_MiniCPM-V-2_6-int4"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This is an implementation of [a/MiniCPM-V-2_6-int4](https://github.com/OpenBMB/MiniCPM-V) by [a/ComfyUI](https://github.com/comfyanonymous/ComfyUI), including support for text-based queries, video queries, single-image queries, and multi-image queries to generate captions or responses."
|
||||
},
|
||||
{
|
||||
"author": "chrisdreid",
|
||||
"title": "ComfyUI_EnvAutopsyAPI [UNSAFE]",
|
||||
@@ -288,16 +408,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "If you wish to incorporate these changes into your repo, feel free to open an issue and ask. The commits should be pretty clear, and I also label almost all changes with #HACK so a full text search will work too.\nPlease let me know if you decide to incorporate any of these changes into your LivePortrait implementation so I can direct people to you repository. I do not intend to maintain this repo.\nSome operations are simply not supported on MPS and I didn't rewrite them. Most of my changes are just to .cuda calls and that sort of thing. Many operations are still done on CPU, so don't expect awesome performance."
|
||||
},
|
||||
{
|
||||
"author": "justUmen",
|
||||
"title": "Bjornulf_custom_nodes [WIP]",
|
||||
"reference": "https://github.com/justUmen/Bjornulf_custom_nodes",
|
||||
"files": [
|
||||
"https://github.com/justUmen/Bjornulf_custom_nodes"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes: ollamaLoader, ShowText, ShowInt, LoopTexts, LoopFloat, LoopInteger, ..."
|
||||
},
|
||||
{
|
||||
"author": "thderoo",
|
||||
"title": "_topfun_s_nodes",
|
||||
@@ -1651,16 +1761,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "This answers the itch for being able to easily paste [a/CivitAI.com](https://civitai.com/) generated data (or other simple metadata) into Comfy in a way that makes it easy to test with multiple checkpoints."
|
||||
},
|
||||
{
|
||||
"author": "ZHO-ZHO-ZHO",
|
||||
"title": "ComfyUI-AnyText [WIP]",
|
||||
"reference": "https://github.com/ZHO-ZHO-ZHO/ComfyUI-AnyText",
|
||||
"files": [
|
||||
"https://github.com/ZHO-ZHO-ZHO/ComfyUI-AnyText"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Unofficial implementation of [a/AnyText](https://github.com/tyxsspa/AnyText/tree/825bcc54687206b15bd7e28ba1a8b095989d58e3) for ComfyUI(EXP)"
|
||||
},
|
||||
{
|
||||
"author": "nidefawl",
|
||||
"title": "ComfyUI-nidefawl [UNSAFE]",
|
||||
@@ -1811,16 +1911,6 @@
|
||||
"install_type": "git-clone",
|
||||
"description": "Nodes: CheckpointVAELoaderSimpleText, CheckpointVAESelectorText, LoRA_Tag_To_Stack"
|
||||
},
|
||||
{
|
||||
"author": "dnl13",
|
||||
"title": "ComfyUI-dnl13-seg",
|
||||
"reference": "https://github.com/dnl13/ComfyUI-dnl13-seg",
|
||||
"files": [
|
||||
"https://github.com/dnl13/ComfyUI-dnl13-seg"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "After discovering @storyicon implementation here of Segment Anything, I realized its potential as a powerful tool for ComfyUI if implemented correctly. I delved into the SAM and Dino models. The following is my own adaptation of sam_hq for ComfyUI."
|
||||
},
|
||||
{
|
||||
"author": "Brandelan",
|
||||
"title": "ComfyUI_bd_customNodes",
|
||||
|
||||
@@ -351,6 +351,18 @@
|
||||
"title_aux": "ComfyUI_bd_customNodes"
|
||||
}
|
||||
],
|
||||
"https://github.com/ChrisColeTech/ComfyUI-Get-Random-File": [
|
||||
[
|
||||
"GetImageFileByIndexNode",
|
||||
"GetVideoFileByIndexNode",
|
||||
"RandomFilePathNode",
|
||||
"RandomImagePathNode",
|
||||
"RandomVideoPathNode"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-Get-Random-File [UNSAFE]"
|
||||
}
|
||||
],
|
||||
"https://github.com/DeTK/ComfyUI-Switch": [
|
||||
[
|
||||
"NodeSwitch"
|
||||
@@ -478,6 +490,19 @@
|
||||
"title_aux": "Isi-dev/ComfyUI-UniAnimate"
|
||||
}
|
||||
],
|
||||
"https://github.com/IuvenisSapiens/ComfyUI_MiniCPM-V-2_6-int4": [
|
||||
[
|
||||
"DisplayText",
|
||||
"LoadVideo",
|
||||
"MiniCPM_VQA",
|
||||
"MiniCPM_VQA_Polished",
|
||||
"MultipleImagesInput",
|
||||
"PreViewVideo"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_MiniCPM-V-2_6-int4"
|
||||
}
|
||||
],
|
||||
"https://github.com/IvanZhd/comfyui-codeformer": [
|
||||
[
|
||||
"RedBeanie_CustomImageInverter"
|
||||
@@ -498,9 +523,12 @@
|
||||
[
|
||||
"AppendNode",
|
||||
"ApplyVoiceConversion",
|
||||
"ImAppendQuickbackNode",
|
||||
"ImAppendQuickbackVideoNode",
|
||||
"ImAppendVideoNode",
|
||||
"ImApplyWav2lip",
|
||||
"ImDumpEntity",
|
||||
"ImDumpNode",
|
||||
"ImNodeTitleOverride",
|
||||
"LoadPackage",
|
||||
"MergeNode",
|
||||
@@ -806,6 +834,17 @@
|
||||
"title_aux": "ComfyUI-TSFNodes"
|
||||
}
|
||||
],
|
||||
"https://github.com/TTPlanetPig/Comfyui_TTP_CN_Preprocessor": [
|
||||
[
|
||||
"TTPlanet_Tile_Preprocessor_GF",
|
||||
"TTPlanet_Tile_Preprocessor_Simple",
|
||||
"TTPlanet_Tile_Preprocessor_cufoff",
|
||||
"TTPlanet_inpainting_Preprecessor"
|
||||
],
|
||||
{
|
||||
"title_aux": "for comfyui image proprocessor"
|
||||
}
|
||||
],
|
||||
"https://github.com/Video3DGenResearch/comfyui-batch-input-node": [
|
||||
[
|
||||
"BatchImageAndPrompt",
|
||||
@@ -850,14 +889,6 @@
|
||||
"title_aux": "visuallabs_comfyui_nodes"
|
||||
}
|
||||
],
|
||||
"https://github.com/ZHO-ZHO-ZHO/ComfyUI-AnyText": [
|
||||
[
|
||||
"AnyTextNode_Zho"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-AnyText [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/ZHO-ZHO-ZHO/ComfyUI-AuraSR-ZHO": [
|
||||
[
|
||||
"AuraSR_Lterative_Zho",
|
||||
@@ -1259,8 +1290,42 @@
|
||||
"StableCascade_SuperResolutionControlnet",
|
||||
"StableZero123_Conditioning",
|
||||
"StableZero123_Conditioning_Batched",
|
||||
"StubFloat",
|
||||
"StubImage",
|
||||
"StubInt",
|
||||
"StubMask",
|
||||
"StyleModelApply",
|
||||
"StyleModelLoader",
|
||||
"TestAccumulateNode",
|
||||
"TestAccumulationGetItemNode",
|
||||
"TestAccumulationGetLengthNode",
|
||||
"TestAccumulationHeadNode",
|
||||
"TestAccumulationSetItemNode",
|
||||
"TestAccumulationTailNode",
|
||||
"TestAccumulationToListNode",
|
||||
"TestBoolOperationNode",
|
||||
"TestCustomIsChanged",
|
||||
"TestCustomValidation1",
|
||||
"TestCustomValidation2",
|
||||
"TestCustomValidation3",
|
||||
"TestCustomValidation4",
|
||||
"TestCustomValidation5",
|
||||
"TestDynamicDependencyCycle",
|
||||
"TestExecutionBlocker",
|
||||
"TestFloatConditions",
|
||||
"TestForLoopClose",
|
||||
"TestForLoopOpen",
|
||||
"TestIntConditions",
|
||||
"TestIntMathOperation",
|
||||
"TestLazyMixImages",
|
||||
"TestListToAccumulationNode",
|
||||
"TestMakeListNode",
|
||||
"TestMixedExpansionReturns",
|
||||
"TestStringConditions",
|
||||
"TestToBoolNode",
|
||||
"TestVariadicAverage",
|
||||
"TestWhileLoopClose",
|
||||
"TestWhileLoopOpen",
|
||||
"ThresholdMask",
|
||||
"TomePatchModel",
|
||||
"TripleCLIPLoader",
|
||||
@@ -1289,6 +1354,14 @@
|
||||
"title_aux": "ComfyUI"
|
||||
}
|
||||
],
|
||||
"https://github.com/comfyanonymous/ComfyUI_bitsandbytes_NF4": [
|
||||
[
|
||||
"CheckpointLoaderNF4"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI_bitsandbytes_NF4 [EXPERIMENTAL]"
|
||||
}
|
||||
],
|
||||
"https://github.com/comfypod/ComfyUI-Comflow": [
|
||||
[
|
||||
"ComflowInputBoolean",
|
||||
@@ -1352,20 +1425,6 @@
|
||||
"title_aux": "comfyui-stylegan"
|
||||
}
|
||||
],
|
||||
"https://github.com/dnl13/ComfyUI-dnl13-seg": [
|
||||
[
|
||||
"Automatic Segmentation (dnl13)",
|
||||
"BatchSelector (dnl13)",
|
||||
"Combine Images By Mask (dnl13)",
|
||||
"Dinov1 Model Loader (dnl13)",
|
||||
"Mask with prompt (dnl13)",
|
||||
"RGB (dnl13)",
|
||||
"SAM Model Loader (dnl13)"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-dnl13-seg"
|
||||
}
|
||||
],
|
||||
"https://github.com/doucx/ComfyUI_WcpD_Utility_Kit": [
|
||||
[
|
||||
"BlackImage",
|
||||
@@ -1673,7 +1732,12 @@
|
||||
"https://github.com/jh-leon-kim/ComfyUI-JHK-utils": [
|
||||
[
|
||||
"JHK_Utils_ImageRemoveBackground",
|
||||
"JHK_Utils_LargestImageSelector",
|
||||
"JHK_Utils_LoadEmbed",
|
||||
"JHK_Utils_LoadImageFromPath",
|
||||
"JHK_Utils_RandomImageSelector",
|
||||
"JHK_Utils_SelectSingleImageFromPath",
|
||||
"JHK_Utils_string_filter",
|
||||
"JHK_Utils_string_merge"
|
||||
],
|
||||
{
|
||||
@@ -1795,47 +1859,6 @@
|
||||
"title_aux": "ComfyUI-Unique3D [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/justUmen/Bjornulf_custom_nodes": [
|
||||
[
|
||||
"Bjornulf_CheckBlackImage",
|
||||
"Bjornulf_ClearVRAM",
|
||||
"Bjornulf_CombineBackgroundOverlay",
|
||||
"Bjornulf_CombineTexts",
|
||||
"Bjornulf_CustomStringType",
|
||||
"Bjornulf_GrayscaleTransform",
|
||||
"Bjornulf_LoopBasicBatch",
|
||||
"Bjornulf_LoopCombosSamplersSchedulers",
|
||||
"Bjornulf_LoopFloat",
|
||||
"Bjornulf_LoopInteger",
|
||||
"Bjornulf_LoopSamplers",
|
||||
"Bjornulf_LoopSchedulers",
|
||||
"Bjornulf_LoopTexts",
|
||||
"Bjornulf_RandomModelClipVae",
|
||||
"Bjornulf_RandomTexts",
|
||||
"Bjornulf_RemoveTransparency",
|
||||
"Bjornulf_ResizeImage",
|
||||
"Bjornulf_SaveApiImage",
|
||||
"Bjornulf_SaveBjornulfLobeChat",
|
||||
"Bjornulf_SaveImagePath",
|
||||
"Bjornulf_SaveImageToFolder",
|
||||
"Bjornulf_SaveText",
|
||||
"Bjornulf_SaveTmpImage",
|
||||
"Bjornulf_ShowFloat",
|
||||
"Bjornulf_ShowInt",
|
||||
"Bjornulf_ShowText",
|
||||
"Bjornulf_VideoPingPong",
|
||||
"Bjornulf_WriteImageAllInOne",
|
||||
"Bjornulf_WriteImageCharacter",
|
||||
"Bjornulf_WriteImageCharacters",
|
||||
"Bjornulf_WriteImageEnvironment",
|
||||
"Bjornulf_WriteText",
|
||||
"Bjornulf_imagesToVideo",
|
||||
"Bjornulf_ollamaLoader"
|
||||
],
|
||||
{
|
||||
"title_aux": "Bjornulf_custom_nodes [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/kadirnar/ComfyUI-Adapter": [
|
||||
[
|
||||
"GarmentSegLoader"
|
||||
@@ -1932,6 +1955,19 @@
|
||||
"title_aux": "ComfyUI-DiffusersSD3Wrapper"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-EasyAnimateWrapper": [
|
||||
[
|
||||
"DownloadAndLoadEasyAnimateModel",
|
||||
"EasyAnimateDecode",
|
||||
"EasyAnimateImageEncoder",
|
||||
"EasyAnimateResize",
|
||||
"EasyAnimateSampler",
|
||||
"EasyAnimateTextEncode"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-EasyAnimateWrapper [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-FollowYourEmojiWrapper": [
|
||||
[
|
||||
"DownloadAndLoadFYEModel",
|
||||
@@ -1947,6 +1983,15 @@
|
||||
"title_aux": "ComfyUI-FollowYourEmojiWrapper [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/kijai/ComfyUI-LLaVA-OneVision": [
|
||||
[
|
||||
"DownloadAndLoadLLaVAOneVisionModel",
|
||||
"LLaVA_OneVision_Run"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-LLaVA-OneVision [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/komojini/ComfyUI_Prompt_Template_CustomNodes/raw/main/prompt_with_template.py": [
|
||||
[
|
||||
"ObjectPromptWithTemplate",
|
||||
@@ -2013,6 +2058,18 @@
|
||||
"title_aux": "ComfyUI Build and Train Your Network [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/logtd/ComfyUI-Fluxtapoz": [
|
||||
[
|
||||
"FluxDeGuidance",
|
||||
"FluxInverseSampler",
|
||||
"InFluxFlipSigmas",
|
||||
"InFluxModelSamplingPred",
|
||||
"OutFluxModelSamplingPred"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-Fluxtapoz [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/logtd/ComfyUI-MotionThiefExperiment": [
|
||||
[
|
||||
"ApplyRefMotionNode",
|
||||
@@ -2023,6 +2080,24 @@
|
||||
"title_aux": "ComfyUI-MotionThiefExperiment"
|
||||
}
|
||||
],
|
||||
"https://github.com/logtd/ComfyUI-Veevee": [
|
||||
[
|
||||
"ApplyVVModel",
|
||||
"FlowConfig",
|
||||
"FlowGetFlow",
|
||||
"GetRaftFlow",
|
||||
"InjectionConfig",
|
||||
"PivotConfig",
|
||||
"RaveConfig",
|
||||
"SCAConfig",
|
||||
"TemporalConfig",
|
||||
"VVSamplerSampler",
|
||||
"VVUnsamplerSampler"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-Veevee [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/longgui0318/comfyui-one-more-step": [
|
||||
[
|
||||
"Calculate More Step Latent",
|
||||
@@ -2147,6 +2222,14 @@
|
||||
"title_aux": "ComfyUI GLIGEN GUI Node"
|
||||
}
|
||||
],
|
||||
"https://github.com/neeltheninja/ComfyUI-TextOverlay": [
|
||||
[
|
||||
"TextOverlay"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-TextOverlay"
|
||||
}
|
||||
],
|
||||
"https://github.com/neuratech-ai/ComfyUI-MultiGPU": [
|
||||
[
|
||||
"CLIPLoaderMultiGPU",
|
||||
@@ -2160,6 +2243,15 @@
|
||||
"title_aux": "ComfyUI-MultiGPU"
|
||||
}
|
||||
],
|
||||
"https://github.com/neverbiasu/ComfyUI-ControlNeXt": [
|
||||
[
|
||||
"ControlNextPipelineConfig",
|
||||
"ControlNextSDXL"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-ControlNeXt [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/nidefawl/ComfyUI-nidefawl": [
|
||||
[
|
||||
"BlendImagesWithBoundedMasks",
|
||||
@@ -2303,6 +2395,17 @@
|
||||
"title_aux": "SDFXBridgeForComfyUI - ComfyUI Custom Node for SDFX Integration"
|
||||
}
|
||||
],
|
||||
"https://github.com/sebord/ComfyUI-LMCQ": [
|
||||
[
|
||||
"LmcqImageSaver",
|
||||
"LmcqImageSaverTransit",
|
||||
"LmcqImageSaverWeb",
|
||||
"LmcqLoadFluxNF4Checkpoint"
|
||||
],
|
||||
{
|
||||
"title_aux": "ComfyUI-LMCQ [WIP]"
|
||||
}
|
||||
],
|
||||
"https://github.com/shadowcz007/ComfyUI-PuLID-Test": [
|
||||
[
|
||||
"ApplyPulid",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,48 @@
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
"author": "ZHO-ZHO-ZHO",
|
||||
"title": "ComfyUI-AnyText [NOT MAINTAINED]",
|
||||
"reference": "https://github.com/ZHO-ZHO-ZHO/ComfyUI-AnyText",
|
||||
"files": [
|
||||
"https://github.com/ZHO-ZHO-ZHO/ComfyUI-AnyText"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "Unofficial implementation of [a/AnyText](https://github.com/tyxsspa/AnyText/tree/825bcc54687206b15bd7e28ba1a8b095989d58e3) for ComfyUI(EXP)"
|
||||
},
|
||||
{
|
||||
"author": "shinich39",
|
||||
"title": "comfyui-pkg39 [DEPRECATED]",
|
||||
"reference": "https://github.com/shinich39/comfyui-pkg39",
|
||||
"files": [
|
||||
"https://github.com/shinich39/comfyui-pkg39"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "This package has created for generate image from generated image and embedded workflow."
|
||||
},
|
||||
{
|
||||
"author": "dnl13",
|
||||
"title": "ComfyUI-dnl13-seg [DEPRECATED]",
|
||||
"reference": "https://github.com/dnl13/ComfyUI-dnl13-seg",
|
||||
"files": [
|
||||
"https://github.com/dnl13/ComfyUI-dnl13-seg"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "After discovering @storyicon implementation here of Segment Anything, I realized its potential as a powerful tool for ComfyUI if implemented correctly. I delved into the SAM and Dino models. The following is my own adaptation of sam_hq for ComfyUI."
|
||||
},
|
||||
{
|
||||
"author": "1038lab",
|
||||
"title": "ComfyUI-latentSizeSelector [REMOVED]",
|
||||
"id": "ComfyUI-latentSizeSelector",
|
||||
"reference": "https://github.com/1038lab/ComfyUI_LatentSizeSelector",
|
||||
"files": [
|
||||
"https://github.com/1038lab/ComfyUI_LatentSizeSelector"
|
||||
],
|
||||
"install_type": "git-clone",
|
||||
"description": "You'll get a new node Latent Size Selector, you can pick the x and y sizes from a list."
|
||||
},
|
||||
{
|
||||
"author": "hy134300",
|
||||
"title": "ComfyUI-PhotoMaker-V2 [REMOVED]",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,28 @@
|
||||
{
|
||||
"models": [
|
||||
{
|
||||
"name": "TAEF1 Decoder",
|
||||
"type": "TAESD",
|
||||
"base": "FLUX.1",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(FLUX.1 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
"filename": "taef1_decoder.pth",
|
||||
"url": "https://github.com/madebyollin/taesd/raw/main/taef1_decoder.pth",
|
||||
"size": "4.71MB"
|
||||
},
|
||||
{
|
||||
"name": "TAEF1 Encoder",
|
||||
"type": "TAESD",
|
||||
"base": "FLUX.1",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(FLUX.1 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
"filename": "taef1_encoder.pth",
|
||||
"url": "https://github.com/madebyollin/taesd/raw/main/taef1_encoder.pth",
|
||||
"size": "4.71MB"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "comfyanonymous/clip_l",
|
||||
"type": "clip",
|
||||
@@ -257,7 +280,7 @@
|
||||
{
|
||||
"name": "TAESD3 Decoder",
|
||||
"type": "TAESD",
|
||||
"base": "SDXL",
|
||||
"base": "SD3",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(SD3 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
@@ -268,7 +291,7 @@
|
||||
{
|
||||
"name": "TAESD3 Encoder",
|
||||
"type": "TAESD",
|
||||
"base": "SDXL",
|
||||
"base": "SD3",
|
||||
"save_path": "vae_approx",
|
||||
"description": "(SD3 Verison) To view the preview in high quality while running samples in ComfyUI, you will need this model.",
|
||||
"reference": "https://github.com/madebyollin/taesd",
|
||||
@@ -670,52 +693,6 @@
|
||||
"filename": "model.safetensors",
|
||||
"url": "https://huggingface.co/spaces/ID-Animator/ID-Animator/resolve/main/image_encoder/model.safetensors",
|
||||
"size": "2.53GB"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "IC-Light/fc",
|
||||
"type": "IC-Light",
|
||||
"base": "SD1.5",
|
||||
"save_path": "unet/IC-Light",
|
||||
"description": "The default relighting model, conditioned on text and foreground",
|
||||
"reference": "https://huggingface.co/lllyasviel/ic-light",
|
||||
"filename": "iclight_sd15_fc.safetensors",
|
||||
"url": "https://huggingface.co/lllyasviel/ic-light/resolve/main/iclight_sd15_fc.safetensors",
|
||||
"size": "1.72GB"
|
||||
},
|
||||
{
|
||||
"name": "IC-Light/fbc",
|
||||
"type": "IC-Light",
|
||||
"base": "SD1.5",
|
||||
"save_path": "unet/IC-Light",
|
||||
"description": "Relighting model conditioned with text, foreground, and background",
|
||||
"reference": "https://huggingface.co/lllyasviel/ic-light",
|
||||
"filename": "iclight_sd15_fbc.safetensors",
|
||||
"url": "https://huggingface.co/lllyasviel/ic-light/resolve/main/iclight_sd15_fbc.safetensors",
|
||||
"size": "1.72GB"
|
||||
},
|
||||
{
|
||||
"name": "IC-Light/fcon",
|
||||
"type": "IC-Light",
|
||||
"base": "SD1.5",
|
||||
"save_path": "unet/IC-Light",
|
||||
"description": "Same as iclight_sd15_fc.safetensors, but trained with offset noise",
|
||||
"reference": "https://huggingface.co/lllyasviel/ic-light",
|
||||
"filename": "iclight_sd15_fcon.safetensors",
|
||||
"url": "https://huggingface.co/lllyasviel/ic-light/resolve/main/iclight_sd15_fcon.safetensors",
|
||||
"size": "1.72GB"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "MonsterMMORPG/insightface (for InstantID)",
|
||||
"type": "insightface",
|
||||
"base": "SDXL",
|
||||
"save_path": "insightface/models",
|
||||
"description": "MonsterMMORPG insightface model for cubiq/InstantID",
|
||||
"reference": "https://huggingface.co/MonsterMMORPG/tools/tree/main",
|
||||
"filename": "antelopev2.zip",
|
||||
"url": "https://huggingface.co/MonsterMMORPG/tools/resolve/main/antelopev2.zip",
|
||||
"size": "360.7MB"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -228,8 +228,8 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb\n",
|
||||
"!dpkg -i cloudflared-linux-amd64.deb\n",
|
||||
"!wget -P ~ https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb\n",
|
||||
"!dpkg -i ~/cloudflared-linux-amd64.deb\n",
|
||||
"\n",
|
||||
"import subprocess\n",
|
||||
"import threading\n",
|
||||
@@ -369,4 +369,4 @@
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import cm_global
|
||||
|
||||
security_check.security_check()
|
||||
|
||||
cm_global.pip_blacklist = ['torch', 'torchsde', 'torchvision']
|
||||
cm_global.pip_downgrade_blacklist = ['torch', 'torchsde', 'torchvision', 'transformers', 'safetensors', 'kornia']
|
||||
|
||||
|
||||
@@ -448,12 +449,15 @@ def is_installed(name):
|
||||
if name.startswith('#'):
|
||||
return True
|
||||
|
||||
pattern = r'([^<>!=]+)([<>!=]=?)([^ ]*)'
|
||||
pattern = r'([^<>!=]+)([<>!=]=?)([0-9.a-zA-Z]*)'
|
||||
match = re.search(pattern, name)
|
||||
|
||||
if match:
|
||||
name = match.group(1)
|
||||
|
||||
if name in cm_global.pip_blacklist:
|
||||
return True
|
||||
|
||||
if name in cm_global.pip_downgrade_blacklist:
|
||||
pips = get_installed_packages()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
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."
|
||||
version = "2.48.6"
|
||||
version = "2.50.1"
|
||||
license = { file = "LICENSE.txt" }
|
||||
dependencies = ["GitPython", "PyGithub", "matrix-client==0.4.0", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user