Add REQUIRED_FRONTEND_VERSION prop on node def

This commit is contained in:
Chenlei Hu 2025-03-21 17:04:31 -04:00
parent e73c78e292
commit 92de68aabd
3 changed files with 69 additions and 21 deletions

View File

@ -31,12 +31,12 @@ def frontend_install_warning_message():
return f"Please install the updated requirements.txt file by running:\n{sys.executable} {extra}-m pip install -r {req_path}\n\nThis error is happening because the ComfyUI frontend is no longer shipped as part of the main repo but as a pip package instead.\n\nIf you are on the portable package you can run: update\\update_comfyui.bat to solve this problem"
def parse_version(version: str) -> tuple[int, int, int]:
return tuple(map(int, version.split(".")))
def check_frontend_version():
"""Check if the frontend version is up to date."""
def parse_version(version: str) -> tuple[int, int, int]:
return tuple(map(int, version.split(".")))
try:
frontend_version_str = version("comfyui-frontend-package")
frontend_version = parse_version(frontend_version_str)
@ -73,6 +73,11 @@ class FrontEndProvider:
owner: str
repo: str
@property
def is_official(self) -> bool:
"""Check if the provider is the default official one."""
return self.owner == "Comfy-Org" and self.repo == "ComfyUI_frontend"
@property
def folder_name(self) -> str:
return f"{self.owner}_{self.repo}"
@ -143,14 +148,24 @@ def download_release_asset_zip(release: Release, destination_path: str) -> None:
zip_ref.extractall(destination_path)
class FrontendInit(TypedDict):
web_root: str
""" The path to the initialized frontend. """
version: tuple[int, int, int] | None
""" The version of the initialized frontend. None for unrecognized version."""
class FrontendManager:
CUSTOM_FRONTENDS_ROOT = str(Path(__file__).parents[1] / "web_custom_versions")
@classmethod
def default_frontend_path(cls) -> str:
def init_default_frontend(cls) -> FrontendInit:
check_frontend_version()
try:
import comfyui_frontend_package
return str(importlib.resources.files(comfyui_frontend_package) / "static")
return FrontendInit(
web_root=str(importlib.resources.files(comfyui_frontend_package) / "static"),
version=parse_version(version("comfyui-frontend-package")),
)
except ImportError:
logging.error(f"\n\n********** ERROR ***********\n\ncomfyui-frontend-package is not installed. {frontend_install_warning_message()}\n********** ERROR **********\n")
sys.exit(-1)
@ -175,7 +190,7 @@ class FrontendManager:
return match_result.group(1), match_result.group(2), match_result.group(3)
@classmethod
def init_frontend_unsafe(cls, version_string: str, provider: Optional[FrontEndProvider] = None) -> str:
def init_frontend_unsafe(cls, version_string: str, provider: Optional[FrontEndProvider] = None) -> FrontendInit:
"""
Initializes the frontend for the specified version.
@ -191,8 +206,7 @@ class FrontendManager:
main error source might be request timeout or invalid URL.
"""
if version_string == DEFAULT_VERSION_STRING:
check_frontend_version()
return cls.default_frontend_path()
return cls.init_default_frontend()
repo_owner, repo_name, version = cls.parse_version_string(version_string)
@ -227,10 +241,13 @@ class FrontendManager:
if not os.listdir(web_root):
os.rmdir(web_root)
return web_root
return FrontendInit(
web_root=web_root,
version=parse_version(semantic_version) if provider.is_official else None,
)
@classmethod
def init_frontend(cls, version_string: str) -> str:
def init_frontend(cls, version_string: str) -> FrontendInit:
"""
Initializes the frontend with the specified version string.
@ -245,5 +262,4 @@ class FrontendManager:
except Exception as e:
logging.error("Failed to initialize frontend: %s", e)
logging.info("Falling back to the default frontend.")
check_frontend_version()
return cls.default_frontend_path()
return cls.init_default_frontend()

View File

@ -220,7 +220,7 @@ class ComfyNodeABC(ABC):
"""Flags a node as experimental, informing users that it may change or not work as expected."""
DEPRECATED: bool
"""Flags a node as deprecated, indicating to users that they should find alternatives to this node."""
REQUIRED_FRONTEND_VERSION: str
REQUIRED_FRONTEND_VERSION: str | None
"""The minimum version of the ComfyUI frontend required to load this node.
Usage::

View File

@ -24,11 +24,12 @@ import logging
import mimetypes
from comfy.cli_args import args
from comfy.comfy_types.node_typing import ComfyNodeABC
import comfy.utils
import comfy.model_management
import node_helpers
from comfyui_version import __version__
from app.frontend_management import FrontendManager
from app.frontend_management import FrontendInit, FrontendManager, parse_version
from app.user_manager import UserManager
from app.model_manager import ModelFileManager
from app.custom_node_manager import CustomNodeManager
@ -146,6 +147,11 @@ def create_origin_only_middleware():
return origin_only_middleware
class PromptServer():
web_root: str
"""The path to the initialized frontend assets."""
frontend_version: tuple[int, int, int] | None = None
"""The version of the initialized frontend. None for unrecognized version."""
def __init__(self, loop):
PromptServer.instance = self
@ -176,12 +182,19 @@ class PromptServer():
max_upload_size = round(args.max_upload_size * 1024 * 1024)
self.app = web.Application(client_max_size=max_upload_size, middlewares=middlewares)
self.sockets = dict()
self.web_root = (
FrontendManager.init_frontend(args.front_end_version)
if args.front_end_root is None
else args.front_end_root
)
if args.front_end_root:
frontend_init = FrontendInit(
web_root=args.front_end_root,
version=None,
)
else:
frontend_init = FrontendManager.init_frontend(args.front_end_version)
self.frontend_version = frontend_init["version"]
self.web_root = frontend_init["web_root"]
logging.info(f"[Prompt Server] web root: {self.web_root}")
routes = web.RouteTableDef()
self.routes = routes
self.last_node_id = None
@ -587,6 +600,9 @@ class PromptServer():
with folder_paths.cache_helper:
out = {}
for x in nodes.NODE_CLASS_MAPPINGS:
if not self.node_is_supported(x):
continue
try:
out[x] = node_info(x)
except Exception:
@ -598,7 +614,11 @@ class PromptServer():
async def get_object_info_node(request):
node_class = request.match_info.get("node_class", None)
out = {}
if (node_class is not None) and (node_class in nodes.NODE_CLASS_MAPPINGS):
if (
node_class is not None
and node_class in nodes.NODE_CLASS_MAPPINGS
and self.node_is_supported(node_class)
):
out[node_class] = node_info(node_class)
return web.json_response(out)
@ -863,3 +883,15 @@ class PromptServer():
logging.warning(traceback.format_exc())
return json_data
def node_is_supported(self, node_class: ComfyNodeABC) -> bool:
"""Check if the node is supported by the frontend."""
# For unrecognized frontend version, we assume the node is supported.
if self.frontend_version is None:
return True
# Check if the node is supported by the frontend.
if node_class.REQUIRED_FRONTEND_VERSION is None:
return True
return parse_version(node_class.REQUIRED_FRONTEND_VERSION) <= self.frontend_version