Merge pull request #8929 from bigcat88/v3/nodes/preview-any

[V3] rename DEFINE_SCHEMA, PreviewAny & AudioAce nodes
This commit is contained in:
Jedrzej Kosinski 2025-07-16 11:37:30 -05:00 committed by GitHub
commit 205611cc22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 168 additions and 76 deletions

View File

@ -1,6 +1,6 @@
class ComfyNodeInternal:
'''Class that all V3-based APIs inhertif from for ComfyNode.
This is intended to only be referenced within execution.py, as it has to handle all V3 APIs going forward.'''
"""Class that all V3-based APIs inherit from for ComfyNode.
This is intended to only be referenced within execution.py, as it has to handle all V3 APIs going forward."""
...

View File

@ -230,7 +230,7 @@ class OutputV3(IO_V3):
self.display_name = display_name
self.tooltip = tooltip
self.is_output_list = is_output_list
def as_dict_V3(self):
return prune_dict({
"display_name": self.display_name,
@ -390,19 +390,19 @@ class String(ComfyTypeIO):
class Input(WidgetInputV3):
'''String input.'''
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
multiline=False, placeholder: str=None, default: str=None, dynamicPrompts: bool=None,
multiline=False, placeholder: str=None, default: str=None, dynamic_prompts: bool=None,
socketless: bool=None, force_input: bool=None):
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input)
self.multiline = multiline
self.placeholder = placeholder
self.dynamicPrompts = dynamicPrompts
self.dynamic_prompts = dynamic_prompts
self.default: str
def as_dict_V1(self):
return super().as_dict_V1() | prune_dict({
"multiline": self.multiline,
"placeholder": self.placeholder,
"dynamicPrompts": self.dynamicPrompts,
"dynamicPrompts": self.dynamic_prompts,
})
@comfytype(io_type="COMBO")
@ -893,16 +893,16 @@ class MatchType(ComfyTypeIO):
return super().as_dict_V1() | prune_dict({
"template": self.template.as_dict(),
})
class Output(DynamicOutput):
def __init__(self, id: str, template: MatchType.Template, display_name: str=None, tooltip: str=None,
is_output_list=False):
super().__init__(id, display_name, tooltip, is_output_list)
self.template = template
def get_dynamic(self) -> list[OutputV3]:
return [self]
def as_dict_V3(self):
return super().as_dict_V3() | prune_dict({
"template": self.template.as_dict(),
@ -1155,7 +1155,7 @@ class ComfyNodeV3(ComfyNodeInternal):
@classmethod
@abstractmethod
def DEFINE_SCHEMA(cls) -> SchemaV3:
def define_schema(cls) -> SchemaV3:
"""Override this function with one that returns a SchemaV3 instance."""
raise NotImplementedError
@ -1207,8 +1207,8 @@ class ComfyNodeV3(ComfyNodeInternal):
@classmethod
def VALIDATE_CLASS(cls):
if not callable(cls.DEFINE_SCHEMA):
raise Exception(f"No DEFINE_SCHEMA function was defined for node class {cls.__name__}.")
if not callable(cls.define_schema):
raise Exception(f"No define_schema function was defined for node class {cls.__name__}.")
if not callable(cls.execute):
raise Exception(f"No execute function was defined for node class {cls.__name__}.")
@ -1350,8 +1350,8 @@ class ComfyNodeV3(ComfyNodeInternal):
@classmethod
def FINALIZE_SCHEMA(cls):
"""Call DEFINE_SCHEMA and finalize it."""
schema = cls.DEFINE_SCHEMA()
"""Call define_schema and finalize it."""
schema = cls.define_schema()
schema.finalize()
return schema
@ -1482,7 +1482,7 @@ class _UIOutput(ABC):
class TestNode(ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return SchemaV3(
node_id="TestNode_v3",
display_name="Test Node (V3)",

View File

@ -27,7 +27,7 @@ class V3TestNode(io.ComfyNodeV3):
self.hahajkunless = ";)"
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="V3_01_TestNode1",
display_name="V3 Test Node",
@ -113,7 +113,7 @@ class V3TestNode(io.ComfyNodeV3):
class V3LoraLoader(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="V3_LoraLoader",
display_name="V3 LoRA Loader",
@ -163,7 +163,7 @@ class V3LoraLoader(io.ComfyNodeV3):
class NInputsTest(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="V3_NInputsTest",
display_name="V3 N Inputs Test",

View File

@ -0,0 +1,57 @@
from __future__ import annotations
import torch
import comfy.model_management
import node_helpers
from comfy_api.v3 import io
class TextEncodeAceStepAudio(io.ComfyNodeV3):
@classmethod
def define_schema(cls):
return io.SchemaV3(
node_id="TextEncodeAceStepAudio_V3",
category="conditioning",
inputs=[
io.Clip.Input("clip"),
io.String.Input("tags", multiline=True, dynamic_prompts=True),
io.String.Input("lyrics", multiline=True, dynamic_prompts=True),
io.Float.Input("lyrics_strength", default=1.0, min=0.0, max=10.0, step=0.01),
],
outputs=[io.Conditioning.Output()],
)
@classmethod
def execute(cls, clip, tags, lyrics, lyrics_strength) -> io.NodeOutput:
conditioning = clip.encode_from_tokens_scheduled(clip.tokenize(tags, lyrics=lyrics))
conditioning = node_helpers.conditioning_set_values(conditioning, {"lyrics_strength": lyrics_strength})
return io.NodeOutput(conditioning)
class EmptyAceStepLatentAudio(io.ComfyNodeV3):
@classmethod
def define_schema(cls):
return io.SchemaV3(
node_id="EmptyAceStepLatentAudio_V3",
category="latent/audio",
inputs=[
io.Float.Input("seconds", default=120.0, min=1.0, max=1000.0, step=0.1),
io.Int.Input(
"batch_size", default=1, min=1, max=4096, tooltip="The number of latent images in the batch."
),
],
outputs=[io.Latent.Output()],
)
@classmethod
def execute(cls, seconds, batch_size) -> io.NodeOutput:
length = int(seconds * 44100 / 512 / 8)
latent = torch.zeros([batch_size, 8, 16, length], device=comfy.model_management.intermediate_device())
return io.NodeOutput({"samples": latent, "type": "audio"})
NODES_LIST: list[type[io.ComfyNodeV3]] = [
TextEncodeAceStepAudio,
EmptyAceStepLatentAudio,
]

View File

@ -18,7 +18,7 @@ from comfy_api.v3 import io, ui
class ConditioningStableAudio_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ConditioningStableAudio_V3",
category="conditioning",
@ -48,7 +48,7 @@ class ConditioningStableAudio_V3(io.ComfyNodeV3):
class EmptyLatentAudio_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="EmptyLatentAudio_V3",
category="latent/audio",
@ -70,7 +70,7 @@ class EmptyLatentAudio_V3(io.ComfyNodeV3):
class LoadAudio_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="LoadAudio_V3", # frontend expects "LoadAudio" to work
display_name="Load Audio _V3", # frontend ignores "display_name" for this node
@ -108,7 +108,7 @@ class LoadAudio_V3(io.ComfyNodeV3):
class PreviewAudio_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="PreviewAudio_V3", # frontend expects "PreviewAudio" to work
display_name="Preview Audio _V3", # frontend ignores "display_name" for this node
@ -127,7 +127,7 @@ class PreviewAudio_V3(io.ComfyNodeV3):
class SaveAudioMP3_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="SaveAudioMP3_V3", # frontend expects "SaveAudioMP3" to work
display_name="Save Audio(MP3) _V3", # frontend ignores "display_name" for this node
@ -148,7 +148,7 @@ class SaveAudioMP3_V3(io.ComfyNodeV3):
class SaveAudioOpus_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="SaveAudioOpus_V3", # frontend expects "SaveAudioOpus" to work
display_name="Save Audio(Opus) _V3", # frontend ignores "display_name" for this node
@ -169,7 +169,7 @@ class SaveAudioOpus_V3(io.ComfyNodeV3):
class SaveAudio_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="SaveAudio_V3", # frontend expects "SaveAudio" to work
display_name="Save Audio _V3", # frontend ignores "display_name" for this node
@ -189,7 +189,7 @@ class SaveAudio_V3(io.ComfyNodeV3):
class VAEDecodeAudio_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="VAEDecodeAudio_V3",
category="latent/audio",
@ -211,7 +211,7 @@ class VAEDecodeAudio_V3(io.ComfyNodeV3):
class VAEEncodeAudio_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="VAEEncodeAudio_V3",
category="latent/audio",

View File

@ -5,7 +5,7 @@ from comfy_api.v3 import io
class ControlNetApplyAdvanced_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ControlNetApplyAdvanced_V3",
display_name="Apply ControlNet _V3",
@ -62,7 +62,7 @@ class ControlNetApplyAdvanced_V3(io.ComfyNodeV3):
class SetUnionControlNetType_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="SetUnionControlNetType_V3",
category="conditioning/controlnet",
@ -89,7 +89,7 @@ class SetUnionControlNetType_V3(io.ComfyNodeV3):
class ControlNetInpaintingAliMamaApply_V3(ControlNetApplyAdvanced_V3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ControlNetInpaintingAliMamaApply_V3",
category="conditioning/controlnet",

View File

@ -18,7 +18,7 @@ from server import PromptServer
class GetImageSize(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="GetImageSize_V3",
display_name="Get Image Size _V3",
@ -51,7 +51,7 @@ class GetImageSize(io.ComfyNodeV3):
class ImageAddNoise(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ImageAddNoise_V3",
display_name="Image Add Noise _V3",
@ -84,7 +84,7 @@ class ImageAddNoise(io.ComfyNodeV3):
class ImageCrop(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ImageCrop_V3",
display_name="Image Crop _V3",
@ -110,7 +110,7 @@ class ImageCrop(io.ComfyNodeV3):
class ImageFlip(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ImageFlip_V3",
display_name="Image Flip _V3",
@ -134,7 +134,7 @@ class ImageFlip(io.ComfyNodeV3):
class ImageFromBatch(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ImageFromBatch_V3",
display_name="Image From Batch _V3",
@ -158,7 +158,7 @@ class ImageFromBatch(io.ComfyNodeV3):
class ImageRotate(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ImageRotate_V3",
display_name="Image Rotate _V3",
@ -187,7 +187,7 @@ class ImageStitch(io.ComfyNodeV3):
"""Upstreamed from https://github.com/kijai/ComfyUI-KJNodes"""
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ImageStitch_V3",
display_name="Image Stitch _V3",
@ -355,7 +355,7 @@ class ImageStitch(io.ComfyNodeV3):
class LoadImage(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="LoadImage_V3",
display_name="Load Image _V3",
@ -443,7 +443,7 @@ class LoadImage(io.ComfyNodeV3):
class LoadImageOutput(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="LoadImageOutput_V3",
display_name="Load Image (from Outputs) _V3",
@ -532,7 +532,7 @@ class LoadImageOutput(io.ComfyNodeV3):
class PreviewImage(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="PreviewImage_V3",
display_name="Preview Image _V3",
@ -552,7 +552,7 @@ class PreviewImage(io.ComfyNodeV3):
class RepeatImageBatch(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="RepeatImageBatch_V3",
display_name="Repeat Image Batch _V3",
@ -571,7 +571,7 @@ class RepeatImageBatch(io.ComfyNodeV3):
class ResizeAndPadImage(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="ResizeAndPadImage_V3",
display_name="Resize and Pad Image _V3",
@ -616,7 +616,7 @@ class ResizeAndPadImage(io.ComfyNodeV3):
class SaveAnimatedPNG(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="SaveAnimatedPNG_V3",
display_name="Save Animated PNG _V3",
@ -681,7 +681,7 @@ class SaveAnimatedWEBP(io.ComfyNodeV3):
COMPRESS_METHODS = {"default": 4, "fastest": 0, "slowest": 6}
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="SaveAnimatedWEBP_V3",
display_name="Save Animated WEBP _V3",
@ -744,7 +744,7 @@ class SaveAnimatedWEBP(io.ComfyNodeV3):
class SaveImage(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="SaveImage_V3",
display_name="Save Image _V3",

View File

@ -9,7 +9,7 @@ class MaskPreview_V3(io.ComfyNodeV3):
"""
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="MaskPreview_V3",
display_name="Preview Mask _V3",

View File

@ -0,0 +1,47 @@
from __future__ import annotations
import json
from comfy_api.v3 import io, ui
class PreviewAny(io.ComfyNodeV3):
"""Originally implement from https://github.com/rgthree/rgthree-comfy/blob/main/py/display_any.py
upstream requested in https://github.com/Kosinkadink/rfcs/blob/main/rfcs/0000-corenodes.md#preview-nodes"""
@classmethod
def define_schema(cls):
return io.SchemaV3(
node_id="PreviewAny_V3", # frontend expects "PreviewAny" to work
display_name="Preview Any _V3", # frontend ignores "display_name" for this node
description="Preview any type of data by converting it to a readable text format.",
category="utils",
inputs=[
io.AnyType.Input("source"), # TODO: does not work currently, as `io.AnyType` does not define __ne__
],
is_output_node=True,
)
@classmethod
def execute(cls, source=None) -> io.NodeOutput:
value = "None"
if isinstance(source, str):
value = source
elif isinstance(source, (int, float, bool)):
value = str(source)
elif source is not None:
try:
value = json.dumps(source)
except Exception:
try:
value = str(source)
except Exception:
value = "source exists, but could not be serialized."
return io.NodeOutput(ui=ui.PreviewText(value))
NODES_LIST: list[type[io.ComfyNodeV3]] = [
PreviewAny,
]

View File

@ -7,7 +7,7 @@ from comfy_api.v3 import io
class String_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="PrimitiveString_V3",
display_name="String _V3",
@ -25,7 +25,7 @@ class String_V3(io.ComfyNodeV3):
class StringMultiline_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="PrimitiveStringMultiline_V3",
display_name="String (Multiline) _V3",
@ -43,7 +43,7 @@ class StringMultiline_V3(io.ComfyNodeV3):
class Int_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="PrimitiveInt_V3",
display_name="Int _V3",
@ -61,7 +61,7 @@ class Int_V3(io.ComfyNodeV3):
class Float_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="PrimitiveFloat_V3",
display_name="Float _V3",
@ -79,7 +79,7 @@ class Float_V3(io.ComfyNodeV3):
class Boolean_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="PrimitiveBoolean_V3",
display_name="Boolean _V3",

View File

@ -25,7 +25,7 @@ from comfy_api.v3 import io
class StableCascade_EmptyLatentImage_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="StableCascade_EmptyLatentImage_V3",
category="latent/stable_cascade",
@ -50,7 +50,7 @@ class StableCascade_EmptyLatentImage_V3(io.ComfyNodeV3):
class StableCascade_StageC_VAEEncode_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="StableCascade_StageC_VAEEncode_V3",
category="latent/stable_cascade",
@ -81,7 +81,7 @@ class StableCascade_StageC_VAEEncode_V3(io.ComfyNodeV3):
class StableCascade_StageB_Conditioning_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="StableCascade_StageB_Conditioning_V3",
category="conditioning/stable_cascade",
@ -107,7 +107,7 @@ class StableCascade_StageB_Conditioning_V3(io.ComfyNodeV3):
class StableCascade_SuperResolutionControlnet_V3(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="StableCascade_SuperResolutionControlnet_V3",
category="_for_testing/stable_cascade",

View File

@ -9,32 +9,18 @@ import node_helpers
import nodes
from comfy_api.v3 import io
MAX_RESOLUTION = nodes.MAX_RESOLUTION
class WebcamCapture_V3(io.ComfyNodeV3):
class WebcamCapture(io.ComfyNodeV3):
@classmethod
def DEFINE_SCHEMA(cls):
def define_schema(cls):
return io.SchemaV3(
node_id="WebcamCapture_V3",
display_name="Webcam Capture _V3",
category="image",
inputs=[
io.Webcam.Input("image"),
io.Int.Input(
"width",
default=0,
min=0,
max=MAX_RESOLUTION,
step=1,
),
io.Int.Input(
"height",
default=0,
min=0,
max=MAX_RESOLUTION,
step=1,
),
io.Int.Input("width", default=0, min=0, max=nodes.MAX_RESOLUTION, step=1),
io.Int.Input("height", default=0, min=0, max=nodes.MAX_RESOLUTION, step=1),
io.Boolean.Input("capture_on_queue", default=True),
],
outputs=[
@ -103,4 +89,4 @@ class WebcamCapture_V3(io.ComfyNodeV3):
return True
NODES_LIST: list[type[io.ComfyNodeV3]] = [WebcamCapture_V3]
NODES_LIST: list[type[io.ComfyNodeV3]] = [WebcamCapture]

View File

@ -2299,13 +2299,15 @@ def init_builtin_extra_nodes():
"nodes_tcfg.py",
"nodes_v3_test.py",
"nodes_v1_test.py",
"v3/nodes_ace.py",
"v3/nodes_audio.py",
"v3/nodes_controlnet.py",
"v3/nodes_images.py",
"v3/nodes_mask.py",
"v3/nodes_preview_any.py",
"v3/nodes_primitive.py",
"v3/nodes_webcam.py",
"v3/nodes_stable_cascade.py",
"v3/nodes_webcam.py",
]
import_failed = []