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.
"""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.'''
This is intended to only be referenced within execution.py, as it has to handle all V3 APIs going forward."""
...

View File

@ -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")
@ -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 = []