feat(search): draw real node box from disabled-pack source
Publish to Comfy registry / Publish Custom Node to registry (push) Has been cancelled
Publish to Comfy registry / Publish Custom Node to registry (push) Has been cancelled
Click a node name (or 'Draw this node') in the mirror-search palette to render an imitation ComfyUI node box with its real input sockets, widget defaults, and output sockets. Since disabled packs aren't loaded (no /object_info entry), a new read-only backend module (node_introspect.py) AST-parses the pack on disk — never importing or executing it — to recover INPUT_TYPES / RETURN_TYPES from a literal NODE_CLASS_MAPPINGS. New GET /nodes-stats/node-schema endpoint resolves the disabled pack dir (handling @version suffixes / case) and returns the schema off the event loop. Frontend lazily fetches + caches per node, renders sockets vs widgets with type-colored dots, and falls back to a placeholder for packs that build their node list dynamically. End-to-end against the live install: 67/68 disabled packs resolve on disk, ~92% of nodes render a real box, the rest fall back cleanly. Adds 7 parser unit tests (36 total green). Bump to 1.6.0.
This commit is contained in:
+29
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import threading
|
||||
|
||||
@@ -5,6 +6,7 @@ from aiohttp import web
|
||||
from server import PromptServer
|
||||
|
||||
from .mapper import NodePackageMapper, ModelMapper
|
||||
from .node_introspect import find_disabled_pack_path, get_node_schema
|
||||
from .tracker import UsageTracker
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -115,6 +117,33 @@ async def reset_stats(request):
|
||||
return web.json_response({"error": "internal error"}, status=500)
|
||||
|
||||
|
||||
@routes.get("/nodes-stats/node-schema")
|
||||
async def get_node_schema_route(request):
|
||||
"""Parse a disabled pack's source and return one node's input/output schema.
|
||||
|
||||
Read-only and never imports/executes the pack. Used by the mirror-search
|
||||
palette to draw a faithful node box for a node that isn't loaded.
|
||||
"""
|
||||
try:
|
||||
class_type = request.query.get("class_type")
|
||||
pack = request.query.get("pack")
|
||||
if not class_type or not pack:
|
||||
return web.json_response({"error": "class_type and pack required"}, status=400)
|
||||
|
||||
def _resolve():
|
||||
path = find_disabled_pack_path(pack)
|
||||
if not path:
|
||||
return {"parseable": False, "reason": "source_not_found"}
|
||||
return get_node_schema(class_type, path)
|
||||
|
||||
# AST-parsing a whole pack can take tens of ms; keep it off the event loop.
|
||||
schema = await asyncio.get_event_loop().run_in_executor(None, _resolve)
|
||||
return web.json_response(schema)
|
||||
except Exception:
|
||||
logger.error("nodes-stats: error parsing node schema", exc_info=True)
|
||||
return web.json_response({"error": "internal error"}, status=500)
|
||||
|
||||
|
||||
@routes.get("/nodes-stats/trials")
|
||||
async def get_trials(request):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user