Auto-generated nodes for the entire live fal catalog (1,391 models → 1,482 total nodes) built at startup from a committed registry, plus a full rewrite of the core layer. All 87 v1 node keys, inputs and outputs are preserved — existing workflows load and run unchanged. New: - data/fal_registry.json + scripts/build_registry.py: distills fal's catalog and per-endpoint OpenAPI schemas into a deterministic registry - nodes/dynamic/: schema→node factory (typed widgets, tooltips, pricing in node help, IMAGE/VIDEO/AUDIO auto-upload, native VIDEO/AUDIO outputs, seed -1=random, force_rerun), plus a generic Fal Any Endpoint node for arbitrary endpoints - nodes/utils/: rewritten core — FalApiError surfacing fal's real error payloads, queue progress logs, ComfyUI cancel support, retries and timeouts everywhere, parallel uploads/downloads, structured logging - tests/ (45 tests incl. a legacy-key snapshot lock), CI lint+test workflow, weekly registry-refresh workflow that opens a PR on changes - README regenerated from the registry (scripts/build_readme.py) Fixed: - GPTImage2 / GPTImage2Edit were defined but never registered - Topaz video upscale sent a nonexistent API field (desired_increase) - SeedVR video upscaler had its error handling commented out + wrong model label; ProRes enum value mismatch translated at argument level - 10x `is ""` comparisons, bare excepts, missing HTTP timeouts, temp-file leaks, fps=0 crash in LoadVideoURL, duplicate enum entry - opencv-python & friends missing from pyproject (Registry installs) - API failures now raise visible errors instead of silently returning blank images or "Error:" strings that downstream nodes tried to load BREAKING (behavioral only): failed API calls raise instead of returning blank/black images or error strings. Node signatures are unchanged.
43 lines
1.1 KiB
Python
43 lines
1.1 KiB
Python
import importlib
|
|
import importlib.util
|
|
|
|
node_list = [
|
|
"image_node",
|
|
"video_node",
|
|
"llm_node",
|
|
"vlm_node",
|
|
"trainer_node",
|
|
"upscaler_node",
|
|
]
|
|
|
|
NODE_CLASS_MAPPINGS = {}
|
|
NODE_DISPLAY_NAME_MAPPINGS = {}
|
|
|
|
for module_name in node_list:
|
|
imported_module = importlib.import_module(f".nodes.{module_name}", __name__)
|
|
|
|
NODE_CLASS_MAPPINGS = {**NODE_CLASS_MAPPINGS, **imported_module.NODE_CLASS_MAPPINGS}
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
**NODE_DISPLAY_NAME_MAPPINGS,
|
|
**imported_module.NODE_DISPLAY_NAME_MAPPINGS,
|
|
}
|
|
|
|
try:
|
|
from .nodes.dynamic import get_dynamic_mappings
|
|
|
|
dyn_classes, dyn_display = get_dynamic_mappings()
|
|
# static nodes win on any key collision
|
|
for k, v in dyn_classes.items():
|
|
NODE_CLASS_MAPPINGS.setdefault(k, v)
|
|
for k, v in dyn_display.items():
|
|
NODE_DISPLAY_NAME_MAPPINGS.setdefault(k, v)
|
|
except Exception as _dynamic_error: # never break static nodes
|
|
import logging
|
|
|
|
logging.getLogger(__name__).error(
|
|
"Failed to load dynamic fal nodes: %s", _dynamic_error
|
|
)
|
|
|
|
|
|
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
|