mirror of
https://git.datalinker.icu/comfyanonymous/ComfyUI
synced 2026-09-02 07:07:03 +08:00
add http routes for custom nodes
This commit is contained in:
parent
5b12b55e32
commit
8b1226dac2
44
nodes.py
44
nodes.py
@ -2078,6 +2078,7 @@ EXTENSION_WEB_DIRS = {}
|
|||||||
# Dictionary of successfully loaded module names and associated directories.
|
# Dictionary of successfully loaded module names and associated directories.
|
||||||
LOADED_MODULE_DIRS = {}
|
LOADED_MODULE_DIRS = {}
|
||||||
|
|
||||||
|
LOADED_CUSTOM_NODES = {}
|
||||||
|
|
||||||
def get_module_name(module_path: str) -> str:
|
def get_module_name(module_path: str) -> str:
|
||||||
"""
|
"""
|
||||||
@ -2103,6 +2104,8 @@ def get_module_name(module_path: str) -> str:
|
|||||||
|
|
||||||
def load_custom_node(module_path: str, ignore=set(), module_parent="custom_nodes") -> bool:
|
def load_custom_node(module_path: str, ignore=set(), module_parent="custom_nodes") -> bool:
|
||||||
module_name = get_module_name(module_path)
|
module_name = get_module_name(module_path)
|
||||||
|
project_name = module_name
|
||||||
|
|
||||||
if os.path.isfile(module_path):
|
if os.path.isfile(module_path):
|
||||||
sp = os.path.splitext(module_path)
|
sp = os.path.splitext(module_path)
|
||||||
module_name = sp[0]
|
module_name = sp[0]
|
||||||
@ -2110,6 +2113,15 @@ def load_custom_node(module_path: str, ignore=set(), module_parent="custom_nodes
|
|||||||
elif os.path.isdir(module_path):
|
elif os.path.isdir(module_path):
|
||||||
sys_module_name = module_path.replace(".", "_x_")
|
sys_module_name = module_path.replace(".", "_x_")
|
||||||
|
|
||||||
|
is_custom_node = module_parent == "custom_nodes"
|
||||||
|
|
||||||
|
if is_custom_node:
|
||||||
|
LOADED_CUSTOM_NODES[project_name] = {
|
||||||
|
"project_name": project_name,
|
||||||
|
"status": "loading",
|
||||||
|
"error": None
|
||||||
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logging.debug("Trying to load custom node {}".format(module_path))
|
logging.debug("Trying to load custom node {}".format(module_path))
|
||||||
if os.path.isfile(module_path):
|
if os.path.isfile(module_path):
|
||||||
@ -2130,14 +2142,20 @@ def load_custom_node(module_path: str, ignore=set(), module_parent="custom_nodes
|
|||||||
|
|
||||||
project_config = config_parser.extract_node_configuration(module_path)
|
project_config = config_parser.extract_node_configuration(module_path)
|
||||||
|
|
||||||
|
project_name_from_config = project_config.project.name
|
||||||
|
|
||||||
|
if is_custom_node and project_name_from_config != project_name:
|
||||||
|
LOADED_CUSTOM_NODES[project_name_from_config] = LOADED_CUSTOM_NODES.pop(project_name)
|
||||||
|
LOADED_CUSTOM_NODES[project_name_from_config]["project_name"] = project_name_from_config
|
||||||
|
|
||||||
|
project_name = project_name_from_config
|
||||||
|
|
||||||
web_dir_name = project_config.tool_comfy.web
|
web_dir_name = project_config.tool_comfy.web
|
||||||
|
|
||||||
if web_dir_name:
|
if web_dir_name:
|
||||||
web_dir_path = os.path.join(module_path, web_dir_name)
|
web_dir_path = os.path.join(module_path, web_dir_name)
|
||||||
|
|
||||||
if os.path.isdir(web_dir_path):
|
if os.path.isdir(web_dir_path):
|
||||||
project_name = project_config.project.name
|
|
||||||
|
|
||||||
EXTENSION_WEB_DIRS[project_name] = web_dir_path
|
EXTENSION_WEB_DIRS[project_name] = web_dir_path
|
||||||
|
|
||||||
logging.info("Automatically register web folder {} for {}".format(web_dir_name, project_name))
|
logging.info("Automatically register web folder {} for {}".format(web_dir_name, project_name))
|
||||||
@ -2150,17 +2168,39 @@ def load_custom_node(module_path: str, ignore=set(), module_parent="custom_nodes
|
|||||||
EXTENSION_WEB_DIRS[module_name] = web_dir
|
EXTENSION_WEB_DIRS[module_name] = web_dir
|
||||||
|
|
||||||
if hasattr(module, "NODE_CLASS_MAPPINGS") and getattr(module, "NODE_CLASS_MAPPINGS") is not None:
|
if hasattr(module, "NODE_CLASS_MAPPINGS") and getattr(module, "NODE_CLASS_MAPPINGS") is not None:
|
||||||
|
node_count = 0
|
||||||
for name, node_cls in module.NODE_CLASS_MAPPINGS.items():
|
for name, node_cls in module.NODE_CLASS_MAPPINGS.items():
|
||||||
if name not in ignore:
|
if name not in ignore:
|
||||||
NODE_CLASS_MAPPINGS[name] = node_cls
|
NODE_CLASS_MAPPINGS[name] = node_cls
|
||||||
node_cls.RELATIVE_PYTHON_MODULE = "{}.{}".format(module_parent, get_module_name(module_path))
|
node_cls.RELATIVE_PYTHON_MODULE = "{}.{}".format(module_parent, get_module_name(module_path))
|
||||||
|
node_count += 1
|
||||||
|
|
||||||
if hasattr(module, "NODE_DISPLAY_NAME_MAPPINGS") and getattr(module, "NODE_DISPLAY_NAME_MAPPINGS") is not None:
|
if hasattr(module, "NODE_DISPLAY_NAME_MAPPINGS") and getattr(module, "NODE_DISPLAY_NAME_MAPPINGS") is not None:
|
||||||
NODE_DISPLAY_NAME_MAPPINGS.update(module.NODE_DISPLAY_NAME_MAPPINGS)
|
NODE_DISPLAY_NAME_MAPPINGS.update(module.NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
|
|
||||||
|
if is_custom_node:
|
||||||
|
LOADED_CUSTOM_NODES[project_name].update({
|
||||||
|
"status": "loaded",
|
||||||
|
"node_count": node_count,
|
||||||
|
"nodes": list(module.NODE_CLASS_MAPPINGS.keys())
|
||||||
|
})
|
||||||
|
logging.info(f"Successfully loaded custom node: {project_name} with {node_count} nodes")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
if is_custom_node:
|
||||||
|
LOADED_CUSTOM_NODES[project_name].update({
|
||||||
|
"status": "skipped",
|
||||||
|
"error": "No NODE_CLASS_MAPPINGS found"
|
||||||
|
})
|
||||||
logging.warning(f"Skip {module_path} module for custom nodes due to the lack of NODE_CLASS_MAPPINGS.")
|
logging.warning(f"Skip {module_path} module for custom nodes due to the lack of NODE_CLASS_MAPPINGS.")
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
if is_custom_node:
|
||||||
|
LOADED_CUSTOM_NODES[project_name].update({
|
||||||
|
"status": "failed",
|
||||||
|
"error": str(e)
|
||||||
|
})
|
||||||
logging.warning(traceback.format_exc())
|
logging.warning(traceback.format_exc())
|
||||||
logging.warning(f"Cannot import {module_path} module for custom nodes: {e}")
|
logging.warning(f"Cannot import {module_path} module for custom nodes: {e}")
|
||||||
return False
|
return False
|
||||||
|
|||||||
121
server.py
121
server.py
@ -711,6 +711,127 @@ class PromptServer():
|
|||||||
|
|
||||||
return web.Response(status=200)
|
return web.Response(status=200)
|
||||||
|
|
||||||
|
@routes.get("/custom_nodes")
|
||||||
|
async def get_custom_nodes(request):
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"custom_nodes": [
|
||||||
|
{
|
||||||
|
"project_name": "node_1",
|
||||||
|
"status": "loaded|failed|skipped|loading",
|
||||||
|
"node_count": 5,
|
||||||
|
"nodes": ["NodeClass1", "NodeClass2"],
|
||||||
|
"error": "error message if failed"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_count": 10,
|
||||||
|
"loaded_count": 8,
|
||||||
|
"failed_count": 1,
|
||||||
|
"skipped_count": 1
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
custom_nodes_list = []
|
||||||
|
loaded_count = 0
|
||||||
|
failed_count = 0
|
||||||
|
skipped_count = 0
|
||||||
|
|
||||||
|
for project_name, node_info in nodes.LOADED_CUSTOM_NODES.items():
|
||||||
|
node_data = {
|
||||||
|
"project_name": node_info.get("project_name", project_name),
|
||||||
|
"status": node_info.get("status", "unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
if node_info.get("status") == "loaded":
|
||||||
|
node_data.update({
|
||||||
|
"node_count": node_info.get("node_count", 0),
|
||||||
|
"nodes": node_info.get("nodes", [])
|
||||||
|
})
|
||||||
|
loaded_count += 1
|
||||||
|
elif node_info.get("status") == "failed":
|
||||||
|
node_data["error"] = node_info.get("error", "Unknown error")
|
||||||
|
failed_count += 1
|
||||||
|
elif node_info.get("status") == "skipped":
|
||||||
|
node_data["error"] = node_info.get("error", "No NODE_CLASS_MAPPINGS found")
|
||||||
|
skipped_count += 1
|
||||||
|
|
||||||
|
custom_nodes_list.append(node_data)
|
||||||
|
|
||||||
|
response_data = {
|
||||||
|
"custom_nodes": custom_nodes_list,
|
||||||
|
"total_count": len(custom_nodes_list),
|
||||||
|
"loaded_count": loaded_count,
|
||||||
|
"failed_count": failed_count,
|
||||||
|
"skipped_count": skipped_count
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.json_response(response_data)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error in get_custom_nodes: {e}")
|
||||||
|
logging.error(traceback.format_exc())
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"Failed to get custom nodes: {str(e)}",
|
||||||
|
"custom_nodes": [],
|
||||||
|
"total_count": 0,
|
||||||
|
"loaded_count": 0,
|
||||||
|
"failed_count": 0,
|
||||||
|
"skipped_count": 0
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
@routes.get("/custom_node/{project_name}")
|
||||||
|
async def get_custom_node_by_name(request):
|
||||||
|
try:
|
||||||
|
project_name = request.match_info["project_name"]
|
||||||
|
|
||||||
|
if not project_name:
|
||||||
|
return web.json_response({
|
||||||
|
"error": "Project name is required",
|
||||||
|
"message": "Please provide a valid project name in the URL path"
|
||||||
|
}, status=400)
|
||||||
|
|
||||||
|
import urllib.parse
|
||||||
|
project_name = urllib.parse.unquote(project_name)
|
||||||
|
|
||||||
|
if project_name not in nodes.LOADED_CUSTOM_NODES:
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"Custom node '{project_name}' not found",
|
||||||
|
"message": f"The custom node '{project_name}' is not loaded or does not exist"
|
||||||
|
}, status=404)
|
||||||
|
|
||||||
|
node_info = nodes.LOADED_CUSTOM_NODES[project_name]
|
||||||
|
|
||||||
|
response_data = {
|
||||||
|
"project_name": node_info.get("project_name", project_name),
|
||||||
|
"status": node_info.get("status", "unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
if node_info.get("status") == "loaded":
|
||||||
|
response_data.update({
|
||||||
|
"node_count": node_info.get("node_count", 0),
|
||||||
|
"nodes": node_info.get("nodes", [])
|
||||||
|
})
|
||||||
|
elif node_info.get("status") in ["failed", "skipped"]:
|
||||||
|
response_data["error"] = node_info.get("error", "Unknown error")
|
||||||
|
|
||||||
|
return web.json_response(response_data)
|
||||||
|
|
||||||
|
except KeyError as e:
|
||||||
|
logging.error(f"Missing parameter in get_custom_node_by_name: {e}")
|
||||||
|
return web.json_response({
|
||||||
|
"error": "Invalid request",
|
||||||
|
"message": "Required parameter is missing from the request"
|
||||||
|
}, status=400)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error in get_custom_node_by_name: {e}")
|
||||||
|
logging.error(traceback.format_exc())
|
||||||
|
return web.json_response({
|
||||||
|
"error": f"Failed to get custom node information: {str(e)}",
|
||||||
|
"message": "An internal error occurred while retrieving the custom node information"
|
||||||
|
}, status=500)
|
||||||
|
|
||||||
|
|
||||||
async def setup(self):
|
async def setup(self):
|
||||||
timeout = aiohttp.ClientTimeout(total=None) # no timeout
|
timeout = aiohttp.ClientTimeout(total=None) # no timeout
|
||||||
self.client_session = aiohttp.ClientSession(timeout=timeout)
|
self.client_session = aiohttp.ClientSession(timeout=timeout)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user