mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-07-27 16:26:39 +00:00
Merge pull request #8879 from comfyanonymous/v3-definition-wip
V3 update - make id on Outputs optional, make widgetType only included with MultiType
This commit is contained in:
commit
926a2b1579
@ -202,6 +202,7 @@ class WidgetInputV3(InputV3):
|
||||
return super().as_dict_V1() | prune_dict({
|
||||
"default": self.default,
|
||||
"socketless": self.socketless,
|
||||
"widgetType": self.widgetType,
|
||||
"forceInput": self.force_input,
|
||||
})
|
||||
|
||||
@ -210,7 +211,7 @@ class WidgetInputV3(InputV3):
|
||||
|
||||
|
||||
class OutputV3(IO_V3):
|
||||
def __init__(self, id: str, display_name: str=None, tooltip: str=None,
|
||||
def __init__(self, id: str=None, display_name: str=None, tooltip: str=None,
|
||||
is_output_list=False):
|
||||
self.id = id
|
||||
self.display_name = display_name
|
||||
@ -296,7 +297,7 @@ class Boolean:
|
||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
||||
default: bool=None, label_on: str=None, label_off: str=None,
|
||||
socketless: bool=None, force_input: bool=None):
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, self.io_type, force_input)
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input)
|
||||
self.label_on = label_on
|
||||
self.label_off = label_off
|
||||
self.default: bool
|
||||
@ -319,7 +320,7 @@ class Int:
|
||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
||||
default: int=None, min: int=None, max: int=None, step: int=None, control_after_generate: bool=None,
|
||||
display_mode: NumberDisplay=None, socketless: bool=None, force_input: bool=None):
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, self.io_type, force_input)
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input)
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.step = step
|
||||
@ -348,7 +349,7 @@ class Float(ComfyTypeIO):
|
||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
||||
default: float=None, min: float=None, max: float=None, step: float=None, round: float=None,
|
||||
display_mode: NumberDisplay=None, socketless: bool=None, force_input: bool=None):
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, self.io_type, force_input)
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input)
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.step = step
|
||||
@ -374,7 +375,7 @@ class String(ComfyTypeIO):
|
||||
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,
|
||||
socketless: bool=None, force_input: bool=None):
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, self.io_type, force_input)
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, None, force_input)
|
||||
self.multiline = multiline
|
||||
self.placeholder = placeholder
|
||||
self.default: str
|
||||
@ -396,7 +397,7 @@ class Combo(ComfyType):
|
||||
image_upload: bool=None, image_folder: FolderType=None, content_types: list[Literal["image", "video", "audio", "model"]]=None,
|
||||
remote: RemoteOptions=None,
|
||||
socketless: bool=None):
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, self.io_type)
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless)
|
||||
self.multiselect = False
|
||||
self.options = options
|
||||
self.control_after_generate = control_after_generate
|
||||
@ -456,7 +457,7 @@ class Webcam(ComfyTypeIO):
|
||||
self, id: str, display_name: str=None, optional=False,
|
||||
tooltip: str=None, lazy: bool=None, default: str=None, socketless: bool=None
|
||||
):
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless, self.io_type)
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, default, socketless)
|
||||
|
||||
|
||||
@comfytype(io_type="MASK")
|
||||
@ -739,12 +740,15 @@ class MultiType:
|
||||
# if id is an Input, then use that Input with overridden values
|
||||
self.input_override = None
|
||||
if isinstance(id, InputV3):
|
||||
self.input_override = id
|
||||
self.input_override = copy.copy(id)
|
||||
optional = id.optional if id.optional is True else optional
|
||||
tooltip = id.tooltip if id.tooltip is not None else tooltip
|
||||
display_name = id.display_name if id.display_name is not None else display_name
|
||||
lazy = id.lazy if id.lazy is not None else lazy
|
||||
id = id.id
|
||||
# if is a widget input, make sure widgetType is set appropriately
|
||||
if isinstance(self.input_override, WidgetInputV3):
|
||||
self.input_override.widgetType = self.input_override.get_io_type_V1()
|
||||
super().__init__(id, display_name, optional, tooltip, lazy, extra_dict)
|
||||
self._io_types = types
|
||||
|
||||
@ -786,6 +790,10 @@ class DynamicOutput(OutputV3, ABC):
|
||||
'''
|
||||
Abstract class for dynamic output registration.
|
||||
'''
|
||||
def __init__(self, id: str, display_name: str=None, tooltip: str=None,
|
||||
is_output_list=False):
|
||||
super().__init__(id, display_name, tooltip, is_output_list)
|
||||
|
||||
@abstractmethod
|
||||
def get_dynamic(self) -> list[OutputV3]:
|
||||
...
|
||||
@ -987,7 +995,7 @@ class SchemaV3:
|
||||
raise ValueError("\n".join(issues))
|
||||
|
||||
def finalize(self):
|
||||
"""Add hidden based on selected schema options."""
|
||||
"""Add hidden based on selected schema options, and give outputs without ids default ids."""
|
||||
# if is an api_node, will need key-related hidden
|
||||
if self.is_api_node:
|
||||
if self.hidden is None:
|
||||
@ -1004,6 +1012,11 @@ class SchemaV3:
|
||||
self.hidden.append(Hidden.prompt)
|
||||
if Hidden.extra_pnginfo not in self.hidden:
|
||||
self.hidden.append(Hidden.extra_pnginfo)
|
||||
# give outputs without ids default ids
|
||||
if self.outputs is not None:
|
||||
for i, output in enumerate(self.outputs):
|
||||
if output.id is None:
|
||||
output.id = f"_{i}_{output.io_type}_"
|
||||
|
||||
|
||||
class Serializer:
|
||||
|
@ -27,7 +27,7 @@ class SavedResult:
|
||||
}
|
||||
|
||||
class PreviewImage(_UIOutput):
|
||||
def __init__(self, image: Image.Type, animated: bool=False, node: ComfyNodeV3=None, **kwargs):
|
||||
def __init__(self, image: Image.Type, animated: bool=False, cls: ComfyNodeV3=None, **kwargs):
|
||||
output_dir = folder_paths.get_temp_directory()
|
||||
type = "temp"
|
||||
prefix_append = "_temp_" + ''.join(random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5))
|
||||
@ -41,13 +41,13 @@ class PreviewImage(_UIOutput):
|
||||
i = 255. * image.cpu().numpy()
|
||||
img = PILImage.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
||||
metadata = None
|
||||
if not args.disable_metadata and node is not None:
|
||||
if not args.disable_metadata and cls is not None:
|
||||
metadata = PngInfo()
|
||||
if node.hidden.prompt is not None:
|
||||
metadata.add_text("prompt", json.dumps(node.hidden.prompt))
|
||||
if node.hidden.extra_pnginfo is not None:
|
||||
for x in node.hidden.extra_pnginfo:
|
||||
metadata.add_text(x, json.dumps(node.hidden.extra_pnginfo[x]))
|
||||
if cls.hidden.prompt is not None:
|
||||
metadata.add_text("prompt", json.dumps(cls.hidden.prompt))
|
||||
if cls.hidden.extra_pnginfo is not None:
|
||||
for x in cls.hidden.extra_pnginfo:
|
||||
metadata.add_text(x, json.dumps(cls.hidden.extra_pnginfo[x]))
|
||||
|
||||
filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
|
||||
file = f"{filename_with_batch_num}_{counter:05}_.png"
|
||||
@ -66,9 +66,9 @@ class PreviewImage(_UIOutput):
|
||||
}
|
||||
|
||||
class PreviewMask(PreviewImage):
|
||||
def __init__(self, mask: PreviewMask.Type, animated: bool=False, node: ComfyNodeV3=None, **kwargs):
|
||||
def __init__(self, mask: PreviewMask.Type, animated: bool=False, cls: ComfyNodeV3=None, **kwargs):
|
||||
preview = mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])).movedim(1, -1).expand(-1, -1, -1, 3)
|
||||
super().__init__(preview, animated, node, **kwargs)
|
||||
super().__init__(preview, animated, cls, **kwargs)
|
||||
|
||||
# class UILatent(_UIOutput):
|
||||
# def __init__(self, values: list[SavedResult | dict], **kwargs):
|
||||
|
@ -62,8 +62,8 @@ class V3TestNode(io.ComfyNodeV3):
|
||||
# ]]
|
||||
],
|
||||
outputs=[
|
||||
io.Int.Output("int_output"),
|
||||
io.Image.Output("img_output", display_name="img🖼️", tooltip="This is an image"),
|
||||
io.Int.Output(),
|
||||
io.Image.Output(display_name="img🖼️", tooltip="This is an image"),
|
||||
],
|
||||
hidden=[
|
||||
io.Hidden.prompt,
|
||||
@ -105,7 +105,7 @@ class V3TestNode(io.ComfyNodeV3):
|
||||
if hasattr(cls, "doohickey"):
|
||||
raise Exception("The 'cls' variable leaked state on class properties between runs!")
|
||||
cls.doohickey = "LOLJK"
|
||||
return io.NodeOutput(some_int, image, ui=ui.PreviewImage(image))
|
||||
return io.NodeOutput(some_int, image, ui=ui.PreviewImage(image, cls=cls))
|
||||
|
||||
|
||||
class V3LoraLoader(io.ComfyNodeV3):
|
||||
@ -142,8 +142,8 @@ class V3LoraLoader(io.ComfyNodeV3):
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.Model.Output("model_out"),
|
||||
io.Clip.Output("clip_out"),
|
||||
io.Model.Output(),
|
||||
io.Clip.Output(),
|
||||
],
|
||||
)
|
||||
|
||||
@ -169,7 +169,7 @@ class NInputsTest(io.ComfyNodeV3):
|
||||
io.AutogrowDynamic.Input("nmock2", template_input=io.Int.Input("int"), optional=True, min=1, max=4),
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output("image_out"),
|
||||
io.Image.Output(),
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -24,7 +24,6 @@ class SaveImage_V3(io.ComfyNodeV3):
|
||||
inputs=[
|
||||
io.Image.Input(
|
||||
"images",
|
||||
display_name="images",
|
||||
tooltip="The images to save.",
|
||||
),
|
||||
io.String.Input(
|
||||
@ -79,7 +78,6 @@ class PreviewImage_V3(io.ComfyNodeV3):
|
||||
inputs=[
|
||||
io.Image.Input(
|
||||
"images",
|
||||
display_name="images",
|
||||
tooltip="The images to preview.",
|
||||
),
|
||||
],
|
||||
@ -89,7 +87,7 @@ class PreviewImage_V3(io.ComfyNodeV3):
|
||||
|
||||
@classmethod
|
||||
def execute(cls, images):
|
||||
return io.NodeOutput(ui=ui.PreviewImage(images))
|
||||
return io.NodeOutput(ui=ui.PreviewImage(images, cls=cls))
|
||||
|
||||
|
||||
class LoadImage_V3(io.ComfyNodeV3):
|
||||
@ -102,7 +100,6 @@ class LoadImage_V3(io.ComfyNodeV3):
|
||||
inputs=[
|
||||
io.Combo.Input(
|
||||
"image",
|
||||
display_name="image",
|
||||
image_upload=True,
|
||||
image_folder=io.FolderType.input,
|
||||
content_types=["image"],
|
||||
@ -110,12 +107,8 @@ class LoadImage_V3(io.ComfyNodeV3):
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(
|
||||
"IMAGE",
|
||||
),
|
||||
io.Mask.Output(
|
||||
"MASK",
|
||||
),
|
||||
io.Image.Output(),
|
||||
io.Mask.Output(),
|
||||
],
|
||||
)
|
||||
|
||||
@ -199,7 +192,6 @@ class LoadImageOutput_V3(io.ComfyNodeV3):
|
||||
inputs=[
|
||||
io.Combo.Input(
|
||||
"image",
|
||||
display_name="image",
|
||||
image_upload=True,
|
||||
image_folder=io.FolderType.output,
|
||||
content_types=["image"],
|
||||
@ -211,12 +203,8 @@ class LoadImageOutput_V3(io.ComfyNodeV3):
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(
|
||||
"IMAGE",
|
||||
),
|
||||
io.Mask.Output(
|
||||
"MASK",
|
||||
),
|
||||
io.Image.Output(),
|
||||
io.Mask.Output(),
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -12,13 +12,10 @@ class MaskPreview_V3(io.ComfyNodeV3):
|
||||
def DEFINE_SCHEMA(cls):
|
||||
return io.SchemaV3(
|
||||
node_id="MaskPreview_V3",
|
||||
display_name="Convert Mask to Image _V3",
|
||||
display_name="Preview Mask _V3",
|
||||
category="mask",
|
||||
inputs=[
|
||||
io.Mask.Input(
|
||||
"masks",
|
||||
display_name="masks",
|
||||
),
|
||||
io.Mask.Input("masks"),
|
||||
],
|
||||
hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo],
|
||||
is_output_node=True,
|
||||
|
@ -21,13 +21,9 @@ class WebcamCapture_V3(io.ComfyNodeV3):
|
||||
display_name="Webcam Capture _V3",
|
||||
category="image",
|
||||
inputs=[
|
||||
io.Webcam.Input(
|
||||
"image",
|
||||
display_name="image",
|
||||
),
|
||||
io.Webcam.Input("image"),
|
||||
io.Int.Input(
|
||||
"width",
|
||||
display_name="width",
|
||||
default=0,
|
||||
min=0,
|
||||
max=MAX_RESOLUTION,
|
||||
@ -35,21 +31,15 @@ class WebcamCapture_V3(io.ComfyNodeV3):
|
||||
),
|
||||
io.Int.Input(
|
||||
"height",
|
||||
display_name="height",
|
||||
default=0,
|
||||
min=0,
|
||||
max=MAX_RESOLUTION,
|
||||
step=1,
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"capture_on_queue",
|
||||
default=True,
|
||||
),
|
||||
io.Boolean.Input("capture_on_queue", default=True),
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(
|
||||
"IMAGE",
|
||||
),
|
||||
io.Image.Output(),
|
||||
],
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user