Gives the monitor a clickable history of where a generation has been, at real decoded quality rather than the 1/8-scale latent previews live_preview streams. A node collecting image_1..image_N cannot do this. ComfyUI executes a node only once ALL its inputs resolve, so a hub node emits nothing until the final stage finishes - exactly when the information stops being useful. Same barrier documented in save_lineage.py, and the reason RMSaveLineage cannot serve this purpose either. So this patches the funnel instead: comfy.sd.VAE.decode and .decode_tiled. Every decoded image passes through one of the two, including images from custom nodes calling vae.decode directly, so existing workflows gain stage history with nothing wired. Accepted cost: it captures every decode, including ones inside detailers and upscalers, and stages cannot be hand-named. Unlike live previews this queues rather than single-slots - a preview frame is disposable because a newer one is moments away, but every stage is a distinct event and losing one leaves a hole in the history. Bounded at 12 pending, dropping oldest. Capture is guarded at the wrapper as well as inside _capture. A test that threw from _capture proved the safety property was only incidental: the wrapper had no guard of its own, so one future edit moving a line outside _capture would have broken every generation in every workflow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012uM7Ru1JYn48n6c5Rzwd99
119 lines
5.5 KiB
Python
119 lines
5.5 KiB
Python
"""
|
|
ComfyUI-RMAutomation
|
|
A collection of workflow automation nodes for ComfyUI.
|
|
"""
|
|
|
|
from .nodes.power_lora_loader import NODE_CLASS_MAPPINGS as POWER_LORA_MAPPINGS
|
|
from .nodes.power_lora_loader import NODE_DISPLAY_NAME_MAPPINGS as POWER_LORA_DISPLAY
|
|
from .nodes.styles_full import NODE_CLASS_MAPPINGS as STYLES_FULL_MAPPINGS
|
|
from .nodes.styles_full import NODE_DISPLAY_NAME_MAPPINGS as STYLES_FULL_DISPLAY
|
|
from .nodes.styles_pipe import NODE_CLASS_MAPPINGS as STYLES_PIPE_MAPPINGS
|
|
from .nodes.styles_pipe import NODE_DISPLAY_NAME_MAPPINGS as STYLES_PIPE_DISPLAY
|
|
from .nodes.video_combine import NODE_CLASS_MAPPINGS as VIDEO_MAPPINGS
|
|
from .nodes.video_combine import NODE_DISPLAY_NAME_MAPPINGS as VIDEO_DISPLAY
|
|
from .nodes.image_fallback import NODE_CLASS_MAPPINGS as IMAGE_FALLBACK_MAPPINGS
|
|
from .nodes.image_fallback import NODE_DISPLAY_NAME_MAPPINGS as IMAGE_FALLBACK_DISPLAY
|
|
from .nodes.mask_gate import NODE_CLASS_MAPPINGS as MASK_GATE_MAPPINGS
|
|
from .nodes.mask_gate import NODE_DISPLAY_NAME_MAPPINGS as MASK_GATE_DISPLAY
|
|
from .nodes.mask_combine import NODE_CLASS_MAPPINGS as MASK_COMBINE_MAPPINGS
|
|
from .nodes.mask_combine import NODE_DISPLAY_NAME_MAPPINGS as MASK_COMBINE_DISPLAY
|
|
from .nodes.latent_nodes import NODE_CLASS_MAPPINGS as LATENT_MAPPINGS
|
|
from .nodes.latent_nodes import NODE_DISPLAY_NAME_MAPPINGS as LATENT_DISPLAY
|
|
from .nodes.text_embed import NODE_CLASS_MAPPINGS as TEXT_EMBED_MAPPINGS
|
|
from .nodes.text_embed import NODE_DISPLAY_NAME_MAPPINGS as TEXT_EMBED_DISPLAY
|
|
from .nodes.save_image_with_metadata import NODE_CLASS_MAPPINGS as SAVE_IMAGE_MAPPINGS
|
|
from .nodes.save_image_with_metadata import NODE_DISPLAY_NAME_MAPPINGS as SAVE_IMAGE_DISPLAY
|
|
from .nodes.face_detailer import NODE_CLASS_MAPPINGS as FACE_DETAILER_MAPPINGS
|
|
from .nodes.face_detailer import NODE_DISPLAY_NAME_MAPPINGS as FACE_DETAILER_DISPLAY
|
|
from .nodes.multi_detect_crop import NODE_CLASS_MAPPINGS as MULTI_DETECT_MAPPINGS
|
|
from .nodes.multi_detect_crop import NODE_DISPLAY_NAME_MAPPINGS as MULTI_DETECT_DISPLAY
|
|
from .nodes.math_expression import NODE_CLASS_MAPPINGS as MATH_EXPR_MAPPINGS
|
|
from .nodes.math_expression import NODE_DISPLAY_NAME_MAPPINGS as MATH_EXPR_DISPLAY
|
|
from .nodes.make_image_batch import NODE_CLASS_MAPPINGS as IMAGE_BATCH_MAPPINGS
|
|
from .nodes.make_image_batch import NODE_DISPLAY_NAME_MAPPINGS as IMAGE_BATCH_DISPLAY
|
|
from .nodes.mask_denoise_remap import NODE_CLASS_MAPPINGS as MASK_DENOISE_REMAP_MAPPINGS
|
|
from .nodes.mask_denoise_remap import NODE_DISPLAY_NAME_MAPPINGS as MASK_DENOISE_REMAP_DISPLAY
|
|
from .nodes.save_lineage import NODE_CLASS_MAPPINGS as SAVE_LINEAGE_MAPPINGS
|
|
from .nodes.save_lineage import NODE_DISPLAY_NAME_MAPPINGS as SAVE_LINEAGE_DISPLAY
|
|
from .nodes.load_image_tracked import NODE_CLASS_MAPPINGS as LOAD_TRACKED_MAPPINGS
|
|
from .nodes.load_image_tracked import NODE_DISPLAY_NAME_MAPPINGS as LOAD_TRACKED_DISPLAY
|
|
from .nodes.add_label import NODE_CLASS_MAPPINGS as ADD_LABEL_MAPPINGS
|
|
from .nodes.add_label import NODE_DISPLAY_NAME_MAPPINGS as ADD_LABEL_DISPLAY
|
|
from .nodes.image_comparer import NODE_CLASS_MAPPINGS as IMAGE_COMPARER_MAPPINGS
|
|
from .nodes.image_comparer import NODE_DISPLAY_NAME_MAPPINGS as IMAGE_COMPARER_DISPLAY
|
|
|
|
# Content Policy editor routes. Registered at import so the modal has a backend as
|
|
# soon as ComfyUI is up; failure here must not take the whole pack down with it.
|
|
try:
|
|
from .nodes import policy_api
|
|
policy_api.register_routes()
|
|
except Exception as _err: # pragma: no cover
|
|
print("[RMAutomation] content policy routes unavailable: %s" % _err)
|
|
|
|
# Background extensions that register no nodes. Both talk to the Playground Viewer, and
|
|
# both install themselves on import, so each is isolated: a Viewer that isn't running, or
|
|
# a missing optional dependency, must not take the node pack down with it.
|
|
try:
|
|
from .nodes import live_preview # noqa: F401 (installs a sampler hook on import)
|
|
except Exception as _err: # pragma: no cover
|
|
print("[RMAutomation] live preview unavailable: %s" % _err)
|
|
|
|
try:
|
|
from .nodes import auto_retry # noqa: F401 (starts a websocket listener on import)
|
|
except Exception as _err: # pragma: no cover
|
|
print("[RMAutomation] auto retry unavailable: %s" % _err)
|
|
|
|
try:
|
|
from .nodes import stage_capture # noqa: F401 (wraps VAE decode on import)
|
|
except Exception as _err: # pragma: no cover
|
|
print("[RMAutomation] stage capture unavailable: %s" % _err)
|
|
|
|
# Combine all mappings
|
|
NODE_CLASS_MAPPINGS = {
|
|
**POWER_LORA_MAPPINGS,
|
|
**STYLES_FULL_MAPPINGS,
|
|
**STYLES_PIPE_MAPPINGS,
|
|
**VIDEO_MAPPINGS,
|
|
**IMAGE_FALLBACK_MAPPINGS,
|
|
**MASK_GATE_MAPPINGS,
|
|
**MASK_COMBINE_MAPPINGS,
|
|
**LATENT_MAPPINGS,
|
|
**TEXT_EMBED_MAPPINGS,
|
|
**SAVE_IMAGE_MAPPINGS,
|
|
**FACE_DETAILER_MAPPINGS,
|
|
**MULTI_DETECT_MAPPINGS,
|
|
**MATH_EXPR_MAPPINGS,
|
|
**IMAGE_BATCH_MAPPINGS,
|
|
**MASK_DENOISE_REMAP_MAPPINGS,
|
|
**SAVE_LINEAGE_MAPPINGS,
|
|
**LOAD_TRACKED_MAPPINGS,
|
|
**ADD_LABEL_MAPPINGS,
|
|
**IMAGE_COMPARER_MAPPINGS,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
**POWER_LORA_DISPLAY,
|
|
**STYLES_FULL_DISPLAY,
|
|
**STYLES_PIPE_DISPLAY,
|
|
**VIDEO_DISPLAY,
|
|
**IMAGE_FALLBACK_DISPLAY,
|
|
**MASK_GATE_DISPLAY,
|
|
**MASK_COMBINE_DISPLAY,
|
|
**LATENT_DISPLAY,
|
|
**TEXT_EMBED_DISPLAY,
|
|
**SAVE_IMAGE_DISPLAY,
|
|
**FACE_DETAILER_DISPLAY,
|
|
**MULTI_DETECT_DISPLAY,
|
|
**MATH_EXPR_DISPLAY,
|
|
**IMAGE_BATCH_DISPLAY,
|
|
**MASK_DENOISE_REMAP_DISPLAY,
|
|
**SAVE_LINEAGE_DISPLAY,
|
|
**LOAD_TRACKED_DISPLAY,
|
|
**ADD_LABEL_DISPLAY,
|
|
**IMAGE_COMPARER_DISPLAY,
|
|
}
|
|
|
|
WEB_DIRECTORY = "./js"
|
|
|
|
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|