Files
MajoorWaldi-ComfyUI-Majoor-…/__init__.py
T

223 lines
7.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
ComfyUI-Majoor-AssetsManager
Advanced asset browser for ComfyUI with ratings, tags, and metadata management.
"""
from __future__ import annotations
import importlib
import logging
import os
import re
import sys
from pathlib import Path
from typing import Any
# ComfyUI extension metadata – populated from nodes.py below.
NODE_CLASS_MAPPINGS: dict[str, Any] = {}
NODE_DISPLAY_NAME_MAPPINGS: dict[str, str] = {}
try:
from .nodes import (
NODE_CLASS_MAPPINGS as _ncm,
)
from .nodes import (
NODE_DISPLAY_NAME_MAPPINGS as _ndnm,
)
NODE_CLASS_MAPPINGS.update(_ncm)
NODE_DISPLAY_NAME_MAPPINGS.update(_ndnm)
except Exception:
logging.getLogger("majoor_assets_manager").debug(
"failed to import custom nodes", exc_info=True,
)
# Resolved below after `root` is known; keep None as sentinel so imports
# executed before root assignment don't accidentally use a relative path.
WEB_DIRECTORY = None
_logger = logging.getLogger("majoor_assets_manager")
_REGISTRY_HOOKS_DONE = False
_REGISTERED_APPS: set[int] = set()
def _read_version_from_pyproject() -> str:
try:
root = Path(__file__).resolve().parent
pyproject_path = root / "pyproject.toml"
if not pyproject_path.exists():
return "0.0.0"
raw = pyproject_path.read_text(encoding="utf-8")
match = re.search(r'^version\s*=\s*"(.*?)"', raw, flags=re.MULTILINE)
if match:
return match.group(1).strip()
except Exception:
pass
return "0.0.0"
def _detect_branch_from_env() -> str:
candidates = (
"MAJOR_ASSETS_MANAGER_BRANCH",
"MAJOOR_ASSETS_MANAGER_BRANCH",
)
for key in candidates:
value = os.environ.get(key)
if value:
return value.strip()
return "main"
__version__ = _read_version_from_pyproject()
__branch__ = _detect_branch_from_env()
root = Path(__file__).resolve().parent
if WEB_DIRECTORY is None:
# ComfyUI only auto-loads browser-ready .js files from WEB_DIRECTORY.
# The TypeScript/Vue source under ui/ must be bundled first with `npm run build`.
_dist = root / "dist"
WEB_DIRECTORY = str(_dist)
if not (_dist / "entry.js").is_file():
_logger.warning(
"Majoor Assets Manager frontend bundle is missing at %s. "
"Run `npm run build` before loading the custom node.",
_dist / "entry.js",
)
# Ensure extension-local packages (e.g. `mjr_am_backend`) are importable even when
# ComfyUI loads this module by file path without adding custom node root to sys.path.
try:
root_str = str(root)
if root_str not in sys.path:
sys.path.append(root_str)
except Exception:
_logger.debug("failed to ensure extension root on sys.path", exc_info=True)
def init_prompt_server() -> None:
"""
Initialize routes against ComfyUI PromptServer.
This is kept as a convenience wrapper for ComfyUI runtime.
Bootstrap stages are recorded in ``mjr_am_backend.bootstrap_report``
so their status is visible via ``/mjr/am/health``.
"""
global _REGISTRY_HOOKS_DONE
try:
from mjr_am_backend.bootstrap_report import (
record_stage,
)
except Exception:
record_stage = None # type: ignore[assignment]
def _record(name: str, status: str, severity: str = "none", detail: str | None = None) -> None:
if callable(record_stage):
try:
record_stage(name, status, severity, detail)
except Exception:
pass
try:
try:
from mjr_am_backend.runtime_activity import ensure_prompt_lifecycle_provider_registered
ensure_prompt_lifecycle_provider_registered()
_record("prompt_lifecycle", "ok")
except Exception as exc:
_logger.debug("failed to register prompt lifecycle provider", exc_info=True)
_record("prompt_lifecycle", "degraded", "internal", str(exc)[:120])
_registry = importlib.import_module("mjr_am_backend.routes.registry")
register_all_routes = getattr(_registry, "register_all_routes", None)
register_routes = getattr(_registry, "register_routes", None)
install_observability = getattr(_registry, "_install_observability_on_prompt_server", None)
# Always register decorator-backed routes first; this does not require app.
if not _REGISTRY_HOOKS_DONE and callable(register_all_routes):
register_all_routes()
_record("route_table", "ok")
from server import PromptServer # type: ignore
prompt_server = getattr(PromptServer, "instance", None)
app = getattr(prompt_server, "app", None)
user_manager = getattr(prompt_server, "user_manager", None)
if app is None:
_logger.debug("PromptServer app is not available yet; route table registered only")
_record("app_mount", "degraded", "internal", "PromptServer app not yet available")
return
if not _REGISTRY_HOOKS_DONE and callable(install_observability):
try:
install_observability()
_record("observability", "ok")
except Exception as exc:
_record("observability", "degraded", "internal", str(exc)[:120])
_REGISTRY_HOOKS_DONE = True
if callable(register_routes):
app_id = id(app)
if app_id not in _REGISTERED_APPS:
register_routes(app, user_manager=user_manager)
_REGISTERED_APPS.add(app_id)
_record("routes", "ok")
except Exception as exc:
_logger.exception("failed to initialize prompt server routes")
_record("init", "fatal", "fatal", str(exc)[:120])
def init(app) -> None:
"""Public explicit initializer for host integrations and tests."""
if app is None:
raise ValueError("init(app) requires a valid aiohttp app instance")
try:
from mjr_am_backend.routes.registry import register_routes
user_manager = None
try:
from server import PromptServer # type: ignore
user_manager = getattr(getattr(PromptServer, "instance", None), "user_manager", None)
except Exception:
user_manager = None
app_id = id(app)
if app_id not in _REGISTERED_APPS:
register_routes(app, user_manager=user_manager)
_REGISTERED_APPS.add(app_id)
except Exception:
_logger.exception("failed to initialize routes on provided app")
def register(app, user_manager=None) -> None:
"""
Explicit host integration entrypoint.
Args:
app: aiohttp application instance
user_manager: optional ComfyUI user manager for auth-aware route policies
"""
if app is None:
raise ValueError("register(app, user_manager=None) requires a valid aiohttp app instance")
try:
from mjr_am_backend.routes.registry import register_routes
app_id = id(app)
if app_id not in _REGISTERED_APPS:
register_routes(app, user_manager=user_manager)
_REGISTERED_APPS.add(app_id)
except Exception:
_logger.exception("failed to register routes on provided app")
try:
# Minimal ComfyUI custom_nodes import-time behavior:
# register routes/UI via explicit init path, no sys.modules mutation.
init_prompt_server()
except Exception:
_logger.exception("failed to initialize at import time")
__all__ = [
"NODE_CLASS_MAPPINGS",
"NODE_DISPLAY_NAME_MAPPINGS",
"WEB_DIRECTORY",
"__version__",
"__branch__",
"init",
"register",
"init_prompt_server",
]