mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-07-29 17:26:34 +00:00
Merge pull request #9036 from comfyanonymous/v3-definition-wip
V3 update - refactored v3/io.py+ui.py+resources.py to get closer to Core API support
This commit is contained in:
commit
ed95d603df
@ -36,6 +36,13 @@ class _ComfyNodeInternal:
|
|||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class _NodeOutputInternal:
|
||||||
|
"""Class that all V3-based APIs inherit from for NodeOutput.
|
||||||
|
|
||||||
|
This is intended to only be referenced within execution.py, as it has to handle all V3 APIs going forward."""
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
def as_pruned_dict(dataclass_obj):
|
def as_pruned_dict(dataclass_obj):
|
||||||
'''Return dict of dataclass object with pruned None values.'''
|
'''Return dict of dataclass object with pruned None values.'''
|
||||||
return prune_dict(asdict(dataclass_obj))
|
return prune_dict(asdict(dataclass_obj))
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
from comfy_api.v3._io import _IO
|
||||||
|
from comfy_api.v3._ui import _UI
|
||||||
|
from comfy_api.v3._resources import _RESOURCES
|
||||||
|
|
||||||
|
io = _IO
|
||||||
|
ui = _UI
|
||||||
|
resources = _RESOURCES
|
||||||
|
|
||||||
|
__all__ = ["io", "ui", "resources"]
|
@ -22,14 +22,13 @@ from comfy.samplers import CFGGuider, Sampler
|
|||||||
from comfy.sd import CLIP, VAE
|
from comfy.sd import CLIP, VAE
|
||||||
from comfy.sd import StyleModel as StyleModel_
|
from comfy.sd import StyleModel as StyleModel_
|
||||||
from comfy_api.input import VideoInput
|
from comfy_api.input import VideoInput
|
||||||
from comfy_api.internal import (_ComfyNodeInternal, classproperty, copy_class, first_real_override, is_class,
|
from comfy_api.internal import (_ComfyNodeInternal, _NodeOutputInternal, classproperty, copy_class, first_real_override, is_class,
|
||||||
prune_dict, shallow_clone_class)
|
prune_dict, shallow_clone_class)
|
||||||
from comfy_api.v3.resources import Resources, ResourcesLocal
|
from comfy_api.v3._resources import Resources, ResourcesLocal
|
||||||
from comfy_execution.graph import ExecutionBlocker
|
from comfy_execution.graph import ExecutionBlocker
|
||||||
|
|
||||||
# from comfy_extras.nodes_images import SVG as SVG_ # NOTE: needs to be moved before can be imported due to circular reference
|
# from comfy_extras.nodes_images import SVG as SVG_ # NOTE: needs to be moved before can be imported due to circular reference
|
||||||
|
|
||||||
|
|
||||||
class FolderType(str, Enum):
|
class FolderType(str, Enum):
|
||||||
input = "input"
|
input = "input"
|
||||||
output = "output"
|
output = "output"
|
||||||
@ -157,7 +156,7 @@ class _IO_V3:
|
|||||||
def Type(self):
|
def Type(self):
|
||||||
return self.Parent.Type
|
return self.Parent.Type
|
||||||
|
|
||||||
class InputV3(_IO_V3):
|
class Input(_IO_V3):
|
||||||
'''
|
'''
|
||||||
Base class for a V3 Input.
|
Base class for a V3 Input.
|
||||||
'''
|
'''
|
||||||
@ -181,7 +180,7 @@ class InputV3(_IO_V3):
|
|||||||
def get_io_type(self):
|
def get_io_type(self):
|
||||||
return _StringIOType(self.io_type)
|
return _StringIOType(self.io_type)
|
||||||
|
|
||||||
class WidgetInputV3(InputV3):
|
class WidgetInput(Input):
|
||||||
'''
|
'''
|
||||||
Base class for a V3 Input with widget.
|
Base class for a V3 Input with widget.
|
||||||
'''
|
'''
|
||||||
@ -206,7 +205,7 @@ class WidgetInputV3(InputV3):
|
|||||||
return self.widget_type if self.widget_type is not None else super().get_io_type()
|
return self.widget_type if self.widget_type is not None else super().get_io_type()
|
||||||
|
|
||||||
|
|
||||||
class OutputV3(_IO_V3):
|
class Output(_IO_V3):
|
||||||
def __init__(self, id: str=None, display_name: str=None, tooltip: str=None,
|
def __init__(self, id: str=None, display_name: str=None, tooltip: str=None,
|
||||||
is_output_list=False):
|
is_output_list=False):
|
||||||
self.id = id
|
self.id = id
|
||||||
@ -227,12 +226,12 @@ class OutputV3(_IO_V3):
|
|||||||
|
|
||||||
class ComfyTypeI(_ComfyType):
|
class ComfyTypeI(_ComfyType):
|
||||||
'''ComfyType subclass that only has a default Input class - intended for types that only have Inputs.'''
|
'''ComfyType subclass that only has a default Input class - intended for types that only have Inputs.'''
|
||||||
class Input(InputV3):
|
class Input(Input):
|
||||||
...
|
...
|
||||||
|
|
||||||
class ComfyTypeIO(ComfyTypeI):
|
class ComfyTypeIO(ComfyTypeI):
|
||||||
'''ComfyType subclass that has default Input and Output classes; useful for types with both Inputs and Outputs.'''
|
'''ComfyType subclass that has default Input and Output classes; useful for types with both Inputs and Outputs.'''
|
||||||
class Output(OutputV3):
|
class Output(Output):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
@ -240,7 +239,7 @@ class ComfyTypeIO(ComfyTypeI):
|
|||||||
class Boolean(ComfyTypeIO):
|
class Boolean(ComfyTypeIO):
|
||||||
Type = bool
|
Type = bool
|
||||||
|
|
||||||
class Input(WidgetInputV3):
|
class Input(WidgetInput):
|
||||||
'''Boolean input.'''
|
'''Boolean input.'''
|
||||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
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,
|
default: bool=None, label_on: str=None, label_off: str=None,
|
||||||
@ -260,7 +259,7 @@ class Boolean(ComfyTypeIO):
|
|||||||
class Int(ComfyTypeIO):
|
class Int(ComfyTypeIO):
|
||||||
Type = int
|
Type = int
|
||||||
|
|
||||||
class Input(WidgetInputV3):
|
class Input(WidgetInput):
|
||||||
'''Integer input.'''
|
'''Integer input.'''
|
||||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
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,
|
default: int=None, min: int=None, max: int=None, step: int=None, control_after_generate: bool=None,
|
||||||
@ -286,7 +285,7 @@ class Int(ComfyTypeIO):
|
|||||||
class Float(ComfyTypeIO):
|
class Float(ComfyTypeIO):
|
||||||
Type = float
|
Type = float
|
||||||
|
|
||||||
class Input(WidgetInputV3):
|
class Input(WidgetInput):
|
||||||
'''Float input.'''
|
'''Float input.'''
|
||||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
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,
|
default: float=None, min: float=None, max: float=None, step: float=None, round: float=None,
|
||||||
@ -312,7 +311,7 @@ class Float(ComfyTypeIO):
|
|||||||
class String(ComfyTypeIO):
|
class String(ComfyTypeIO):
|
||||||
Type = str
|
Type = str
|
||||||
|
|
||||||
class Input(WidgetInputV3):
|
class Input(WidgetInput):
|
||||||
'''String input.'''
|
'''String input.'''
|
||||||
def __init__(self, id: str, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
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, dynamic_prompts: bool=None,
|
multiline=False, placeholder: str=None, default: str=None, dynamic_prompts: bool=None,
|
||||||
@ -333,7 +332,7 @@ class String(ComfyTypeIO):
|
|||||||
@comfytype(io_type="COMBO")
|
@comfytype(io_type="COMBO")
|
||||||
class Combo(ComfyTypeI):
|
class Combo(ComfyTypeI):
|
||||||
Type = str
|
Type = str
|
||||||
class Input(WidgetInputV3):
|
class Input(WidgetInput):
|
||||||
"""Combo input (dropdown)."""
|
"""Combo input (dropdown)."""
|
||||||
Type = str
|
Type = str
|
||||||
def __init__(self, id: str, options: list[str]=None, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
def __init__(self, id: str, options: list[str]=None, display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None,
|
||||||
@ -398,7 +397,7 @@ class WanCameraEmbedding(ComfyTypeIO):
|
|||||||
class Webcam(ComfyTypeIO):
|
class Webcam(ComfyTypeIO):
|
||||||
Type = str
|
Type = str
|
||||||
|
|
||||||
class Input(WidgetInputV3):
|
class Input(WidgetInput):
|
||||||
"""Webcam input."""
|
"""Webcam input."""
|
||||||
Type = str
|
Type = str
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -715,14 +714,14 @@ class AnyType(ComfyTypeIO):
|
|||||||
@comfytype(io_type="COMFY_MULTITYPED_V3")
|
@comfytype(io_type="COMFY_MULTITYPED_V3")
|
||||||
class MultiType:
|
class MultiType:
|
||||||
Type = Any
|
Type = Any
|
||||||
class Input(InputV3):
|
class Input(Input):
|
||||||
'''
|
'''
|
||||||
Input that permits more than one input type; if `id` is an instance of `ComfyType.Input`, then that input will be used to create a widget (if applicable) with overridden values.
|
Input that permits more than one input type; if `id` is an instance of `ComfyType.Input`, then that input will be used to create a widget (if applicable) with overridden values.
|
||||||
'''
|
'''
|
||||||
def __init__(self, id: str | InputV3, types: list[type[_ComfyType] | _ComfyType], display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None, extra_dict=None):
|
def __init__(self, id: str | Input, types: list[type[_ComfyType] | _ComfyType], display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None, extra_dict=None):
|
||||||
# if id is an Input, then use that Input with overridden values
|
# if id is an Input, then use that Input with overridden values
|
||||||
self.input_override = None
|
self.input_override = None
|
||||||
if isinstance(id, InputV3):
|
if isinstance(id, Input):
|
||||||
self.input_override = copy.copy(id)
|
self.input_override = copy.copy(id)
|
||||||
optional = id.optional if id.optional is True else optional
|
optional = id.optional if id.optional is True else optional
|
||||||
tooltip = id.tooltip if id.tooltip is not None else tooltip
|
tooltip = id.tooltip if id.tooltip is not None else tooltip
|
||||||
@ -730,13 +729,13 @@ class MultiType:
|
|||||||
lazy = id.lazy if id.lazy is not None else lazy
|
lazy = id.lazy if id.lazy is not None else lazy
|
||||||
id = id.id
|
id = id.id
|
||||||
# if is a widget input, make sure widget_type is set appropriately
|
# if is a widget input, make sure widget_type is set appropriately
|
||||||
if isinstance(self.input_override, WidgetInputV3):
|
if isinstance(self.input_override, WidgetInput):
|
||||||
self.input_override.widget_type = self.input_override.get_io_type()
|
self.input_override.widget_type = self.input_override.get_io_type()
|
||||||
super().__init__(id, display_name, optional, tooltip, lazy, extra_dict)
|
super().__init__(id, display_name, optional, tooltip, lazy, extra_dict)
|
||||||
self._io_types = types
|
self._io_types = types
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def io_types(self) -> list[type[InputV3]]:
|
def io_types(self) -> list[type[Input]]:
|
||||||
'''
|
'''
|
||||||
Returns list of InputV3 class types permitted.
|
Returns list of InputV3 class types permitted.
|
||||||
'''
|
'''
|
||||||
@ -761,15 +760,15 @@ class MultiType:
|
|||||||
else:
|
else:
|
||||||
return super().as_dict()
|
return super().as_dict()
|
||||||
|
|
||||||
class DynamicInput(InputV3, ABC):
|
class DynamicInput(Input, ABC):
|
||||||
'''
|
'''
|
||||||
Abstract class for dynamic input registration.
|
Abstract class for dynamic input registration.
|
||||||
'''
|
'''
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_dynamic(self) -> list[InputV3]:
|
def get_dynamic(self) -> list[Input]:
|
||||||
...
|
...
|
||||||
|
|
||||||
class DynamicOutput(OutputV3, ABC):
|
class DynamicOutput(Output, ABC):
|
||||||
'''
|
'''
|
||||||
Abstract class for dynamic output registration.
|
Abstract class for dynamic output registration.
|
||||||
'''
|
'''
|
||||||
@ -778,7 +777,7 @@ class DynamicOutput(OutputV3, ABC):
|
|||||||
super().__init__(id, display_name, tooltip, is_output_list)
|
super().__init__(id, display_name, tooltip, is_output_list)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_dynamic(self) -> list[OutputV3]:
|
def get_dynamic(self) -> list[Output]:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
@ -786,7 +785,7 @@ class DynamicOutput(OutputV3, ABC):
|
|||||||
class AutogrowDynamic(ComfyTypeI):
|
class AutogrowDynamic(ComfyTypeI):
|
||||||
Type = list[Any]
|
Type = list[Any]
|
||||||
class Input(DynamicInput):
|
class Input(DynamicInput):
|
||||||
def __init__(self, id: str, template_input: InputV3, min: int=1, max: int=None,
|
def __init__(self, id: str, template_input: Input, min: int=1, max: int=None,
|
||||||
display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None, extra_dict=None):
|
display_name: str=None, optional=False, tooltip: str=None, lazy: bool=None, extra_dict=None):
|
||||||
super().__init__(id, display_name, optional, tooltip, lazy, extra_dict)
|
super().__init__(id, display_name, optional, tooltip, lazy, extra_dict)
|
||||||
self.template_input = template_input
|
self.template_input = template_input
|
||||||
@ -797,7 +796,7 @@ class AutogrowDynamic(ComfyTypeI):
|
|||||||
self.min = min
|
self.min = min
|
||||||
self.max = max
|
self.max = max
|
||||||
|
|
||||||
def get_dynamic(self) -> list[InputV3]:
|
def get_dynamic(self) -> list[Input]:
|
||||||
curr_count = 1
|
curr_count = 1
|
||||||
new_inputs = []
|
new_inputs = []
|
||||||
for i in range(self.min):
|
for i in range(self.min):
|
||||||
@ -806,7 +805,7 @@ class AutogrowDynamic(ComfyTypeI):
|
|||||||
if new_input.display_name is not None:
|
if new_input.display_name is not None:
|
||||||
new_input.display_name = f"{new_input.display_name}{curr_count}"
|
new_input.display_name = f"{new_input.display_name}{curr_count}"
|
||||||
new_input.optional = self.optional or new_input.optional
|
new_input.optional = self.optional or new_input.optional
|
||||||
if isinstance(self.template_input, WidgetInputV3):
|
if isinstance(self.template_input, WidgetInput):
|
||||||
new_input.force_input = True
|
new_input.force_input = True
|
||||||
new_inputs.append(new_input)
|
new_inputs.append(new_input)
|
||||||
curr_count += 1
|
curr_count += 1
|
||||||
@ -817,17 +816,17 @@ class AutogrowDynamic(ComfyTypeI):
|
|||||||
if new_input.display_name is not None:
|
if new_input.display_name is not None:
|
||||||
new_input.display_name = f"{new_input.display_name}{curr_count}"
|
new_input.display_name = f"{new_input.display_name}{curr_count}"
|
||||||
new_input.optional = True
|
new_input.optional = True
|
||||||
if isinstance(self.template_input, WidgetInputV3):
|
if isinstance(self.template_input, WidgetInput):
|
||||||
new_input.force_input = True
|
new_input.force_input = True
|
||||||
new_inputs.append(new_input)
|
new_inputs.append(new_input)
|
||||||
curr_count += 1
|
curr_count += 1
|
||||||
return new_inputs
|
return new_inputs
|
||||||
|
|
||||||
# io_type="COMFY_COMBODYNAMIC_V3"
|
@comfytype(io_type="COMFY_COMBODYNAMIC_V3")
|
||||||
class ComboDynamicInput(DynamicInput):
|
class ComboDynamic(ComfyTypeI):
|
||||||
def __init__(self, id: str):
|
class Input(DynamicInput):
|
||||||
pass
|
def __init__(self, id: str):
|
||||||
|
pass
|
||||||
|
|
||||||
@comfytype(io_type="COMFY_MATCHTYPE_V3")
|
@comfytype(io_type="COMFY_MATCHTYPE_V3")
|
||||||
class MatchType(ComfyTypeIO):
|
class MatchType(ComfyTypeIO):
|
||||||
@ -848,7 +847,7 @@ class MatchType(ComfyTypeIO):
|
|||||||
super().__init__(id, display_name, optional, tooltip, lazy, extra_dict)
|
super().__init__(id, display_name, optional, tooltip, lazy, extra_dict)
|
||||||
self.template = template
|
self.template = template
|
||||||
|
|
||||||
def get_dynamic(self) -> list[InputV3]:
|
def get_dynamic(self) -> list[Input]:
|
||||||
return [self]
|
return [self]
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
@ -862,7 +861,7 @@ class MatchType(ComfyTypeIO):
|
|||||||
super().__init__(id, display_name, tooltip, is_output_list)
|
super().__init__(id, display_name, tooltip, is_output_list)
|
||||||
self.template = template
|
self.template = template
|
||||||
|
|
||||||
def get_dynamic(self) -> list[OutputV3]:
|
def get_dynamic(self) -> list[Output]:
|
||||||
return [self]
|
return [self]
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
@ -966,8 +965,8 @@ class Schema:
|
|||||||
"""Display name of node."""
|
"""Display name of node."""
|
||||||
category: str = "sd"
|
category: str = "sd"
|
||||||
"""The category of the node, as per the "Add Node" menu."""
|
"""The category of the node, as per the "Add Node" menu."""
|
||||||
inputs: list[InputV3]=None
|
inputs: list[Input]=None
|
||||||
outputs: list[OutputV3]=None
|
outputs: list[Output]=None
|
||||||
hidden: list[Hidden]=None
|
hidden: list[Hidden]=None
|
||||||
description: str=""
|
description: str=""
|
||||||
"""Node description, shown as a tooltip when hovering over the node."""
|
"""Node description, shown as a tooltip when hovering over the node."""
|
||||||
@ -1129,14 +1128,14 @@ class Schema:
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
def add_to_dict_v1(i: InputV3, input: dict):
|
def add_to_dict_v1(i: Input, input: dict):
|
||||||
key = "optional" if i.optional else "required"
|
key = "optional" if i.optional else "required"
|
||||||
as_dict = i.as_dict()
|
as_dict = i.as_dict()
|
||||||
# for v1, we don't want to include the optional key
|
# for v1, we don't want to include the optional key
|
||||||
as_dict.pop("optional", None)
|
as_dict.pop("optional", None)
|
||||||
input.setdefault(key, {})[i.id] = (i.get_io_type(), as_dict)
|
input.setdefault(key, {})[i.id] = (i.get_io_type(), as_dict)
|
||||||
|
|
||||||
def add_to_dict_v3(io: InputV3 | OutputV3, d: dict):
|
def add_to_dict_v3(io: Input | Output, d: dict):
|
||||||
d[io.id] = (io.get_io_type(), io.as_dict())
|
d[io.id] = (io.get_io_type(), io.as_dict())
|
||||||
|
|
||||||
|
|
||||||
@ -1487,7 +1486,7 @@ class ComfyNode(_ComfyNodeBaseInternal):
|
|||||||
return ComfyNode
|
return ComfyNode
|
||||||
|
|
||||||
|
|
||||||
class NodeOutput:
|
class NodeOutput(_NodeOutputInternal):
|
||||||
'''
|
'''
|
||||||
Standardized output of a node; can pass in any number of args and/or a UIOutput into 'ui' kwarg.
|
Standardized output of a node; can pass in any number of args and/or a UIOutput into 'ui' kwarg.
|
||||||
'''
|
'''
|
||||||
@ -1527,3 +1526,78 @@ class _UIOutput(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class _IO:
|
||||||
|
FolderType = FolderType
|
||||||
|
UploadType = UploadType
|
||||||
|
RemoteOptions = RemoteOptions
|
||||||
|
NumberDisplay = NumberDisplay
|
||||||
|
|
||||||
|
comfytype = staticmethod(comfytype)
|
||||||
|
Custom = staticmethod(Custom)
|
||||||
|
Input = Input
|
||||||
|
WidgetInput = WidgetInput
|
||||||
|
Output = Output
|
||||||
|
ComfyTypeI = ComfyTypeI
|
||||||
|
ComfyTypeIO = ComfyTypeIO
|
||||||
|
#---------------------------------
|
||||||
|
# Supported Types
|
||||||
|
Boolean = Boolean
|
||||||
|
Int = Int
|
||||||
|
Float = Float
|
||||||
|
String = String
|
||||||
|
Combo = Combo
|
||||||
|
MultiCombo = MultiCombo
|
||||||
|
Image = Image
|
||||||
|
WanCameraEmbedding = WanCameraEmbedding
|
||||||
|
Webcam = Webcam
|
||||||
|
Mask = Mask
|
||||||
|
Latent = Latent
|
||||||
|
Conditioning = Conditioning
|
||||||
|
Sampler = Sampler
|
||||||
|
Sigmas = Sigmas
|
||||||
|
Noise = Noise
|
||||||
|
Guider = Guider
|
||||||
|
Clip = Clip
|
||||||
|
ControlNet = ControlNet
|
||||||
|
Vae = Vae
|
||||||
|
Model = Model
|
||||||
|
ClipVision = ClipVision
|
||||||
|
ClipVisionOutput = ClipVisionOutput
|
||||||
|
StyleModel = StyleModel
|
||||||
|
Gligen = Gligen
|
||||||
|
UpscaleModel = UpscaleModel
|
||||||
|
Audio = Audio
|
||||||
|
Video = Video
|
||||||
|
SVG = SVG
|
||||||
|
LoraModel = LoraModel
|
||||||
|
LossMap = LossMap
|
||||||
|
Voxel = Voxel
|
||||||
|
Mesh = Mesh
|
||||||
|
Hooks = Hooks
|
||||||
|
HookKeyframes = HookKeyframes
|
||||||
|
TimestepsRange = TimestepsRange
|
||||||
|
LatentOperation = LatentOperation
|
||||||
|
FlowControl = FlowControl
|
||||||
|
Accumulation = Accumulation
|
||||||
|
Load3DCamera = Load3DCamera
|
||||||
|
Load3D = Load3D
|
||||||
|
Load3DAnimation = Load3DAnimation
|
||||||
|
Photomaker = Photomaker
|
||||||
|
Point = Point
|
||||||
|
FaceAnalysis = FaceAnalysis
|
||||||
|
BBOX = BBOX
|
||||||
|
SEGS = SEGS
|
||||||
|
AnyType = AnyType
|
||||||
|
MultiType = MultiType
|
||||||
|
#---------------------------------
|
||||||
|
HiddenHolder = HiddenHolder
|
||||||
|
Hidden = Hidden
|
||||||
|
NodeInfoV1 = NodeInfoV1
|
||||||
|
NodeInfoV3 = NodeInfoV3
|
||||||
|
Schema = Schema
|
||||||
|
ComfyNode = ComfyNode
|
||||||
|
NodeOutput = NodeOutput
|
||||||
|
add_to_dict_v1 = staticmethod(add_to_dict_v1)
|
||||||
|
add_to_dict_v3 = staticmethod(add_to_dict_v3)
|
@ -63,3 +63,10 @@ class ResourcesLocal(Resources):
|
|||||||
if default is not ...:
|
if default is not ...:
|
||||||
return default
|
return default
|
||||||
raise Exception(f"Unsupported resource key type: {type(key)}")
|
raise Exception(f"Unsupported resource key type: {type(key)}")
|
||||||
|
|
||||||
|
|
||||||
|
class _RESOURCES:
|
||||||
|
ResourceKey = ResourceKey
|
||||||
|
TorchDictFolderFilename = TorchDictFolderFilename
|
||||||
|
Resources = Resources
|
||||||
|
ResourcesLocal = ResourcesLocal
|
@ -17,7 +17,7 @@ import folder_paths
|
|||||||
|
|
||||||
# used for image preview
|
# used for image preview
|
||||||
from comfy.cli_args import args
|
from comfy.cli_args import args
|
||||||
from comfy_api.v3.io import ComfyNode, FolderType, Image, _UIOutput
|
from comfy_api.v3._io import ComfyNode, FolderType, Image, _UIOutput
|
||||||
|
|
||||||
|
|
||||||
class SavedResult(dict):
|
class SavedResult(dict):
|
||||||
@ -489,3 +489,17 @@ class PreviewText(_UIOutput):
|
|||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
return {"text": (self.value,)}
|
return {"text": (self.value,)}
|
||||||
|
|
||||||
|
|
||||||
|
class _UI:
|
||||||
|
SavedResult = SavedResult
|
||||||
|
SavedImages = SavedImages
|
||||||
|
SavedAudios = SavedAudios
|
||||||
|
ImageSaveHelper = ImageSaveHelper
|
||||||
|
AudioSaveHelper = AudioSaveHelper
|
||||||
|
PreviewImage = PreviewImage
|
||||||
|
PreviewMask = PreviewMask
|
||||||
|
PreviewAudio = PreviewAudio
|
||||||
|
PreviewVideo = PreviewVideo
|
||||||
|
PreviewUI3D = PreviewUI3D
|
||||||
|
PreviewText = PreviewText
|
@ -1,13 +1,12 @@
|
|||||||
import torch
|
import torch
|
||||||
import time
|
import time
|
||||||
from comfy_api.v3 import io, ui, resources
|
from comfy_api.v3 import io, ui, resources, _io
|
||||||
import logging # noqa
|
import logging # noqa
|
||||||
import folder_paths
|
import folder_paths
|
||||||
import comfy.utils
|
import comfy.utils
|
||||||
import comfy.sd
|
import comfy.sd
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
@io.comfytype(io_type="XYZ")
|
@io.comfytype(io_type="XYZ")
|
||||||
class XYZ(io.ComfyTypeIO):
|
class XYZ(io.ComfyTypeIO):
|
||||||
Type = tuple[int,str]
|
Type = tuple[int,str]
|
||||||
@ -144,8 +143,8 @@ class NInputsTest(io.ComfyNode):
|
|||||||
node_id="V3_NInputsTest",
|
node_id="V3_NInputsTest",
|
||||||
display_name="V3 N Inputs Test",
|
display_name="V3 N Inputs Test",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.AutogrowDynamic.Input("nmock", template_input=io.Image.Input("image"), min=1, max=3),
|
_io.AutogrowDynamic.Input("nmock", template_input=io.Image.Input("image"), min=1, max=3),
|
||||||
io.AutogrowDynamic.Input("nmock2", template_input=io.Int.Input("int"), optional=True, min=1, max=4),
|
_io.AutogrowDynamic.Input("nmock2", template_input=io.Int.Input("int"), optional=True, min=1, max=4),
|
||||||
],
|
],
|
||||||
outputs=[
|
outputs=[
|
||||||
io.Image.Output(),
|
io.Image.Output(),
|
||||||
|
23
execution.py
23
execution.py
@ -32,8 +32,8 @@ from comfy_execution.graph_utils import GraphBuilder, is_link
|
|||||||
from comfy_execution.validation import validate_node_input
|
from comfy_execution.validation import validate_node_input
|
||||||
from comfy_execution.progress import get_progress_state, reset_progress_state, add_progress_handler, WebUIProgressHandler
|
from comfy_execution.progress import get_progress_state, reset_progress_state, add_progress_handler, WebUIProgressHandler
|
||||||
from comfy_execution.utils import CurrentNodeContext
|
from comfy_execution.utils import CurrentNodeContext
|
||||||
from comfy_api.internal import _ComfyNodeInternal, first_real_override, is_class, make_locked_method_func
|
from comfy_api.internal import _ComfyNodeInternal, _NodeOutputInternal, first_real_override, is_class, make_locked_method_func
|
||||||
from comfy_api.v3 import io
|
from comfy_api.v3 import io, resources
|
||||||
|
|
||||||
|
|
||||||
class ExecutionResult(Enum):
|
class ExecutionResult(Enum):
|
||||||
@ -256,26 +256,11 @@ async def _async_map_node_over_list(prompt_id, unique_id, obj, input_data_all, f
|
|||||||
type_obj = type(obj)
|
type_obj = type(obj)
|
||||||
type_obj.VALIDATE_CLASS()
|
type_obj.VALIDATE_CLASS()
|
||||||
class_clone = type_obj.PREPARE_CLASS_CLONE(hidden_inputs)
|
class_clone = type_obj.PREPARE_CLASS_CLONE(hidden_inputs)
|
||||||
# NOTE: this is a mock of state management; for local, just stores NodeStateLocal on node instance
|
|
||||||
if hasattr(obj, "local_state"):
|
|
||||||
if obj.local_state is None:
|
|
||||||
obj.local_state = io.NodeStateLocal(class_clone.hidden.unique_id)
|
|
||||||
class_clone.state = obj.local_state
|
|
||||||
# NOTE: this is a mock of resource management; for local, just stores ResourcesLocal on node instance
|
# NOTE: this is a mock of resource management; for local, just stores ResourcesLocal on node instance
|
||||||
if hasattr(obj, "local_resources"):
|
if hasattr(obj, "local_resources"):
|
||||||
if obj.local_resources is None:
|
if obj.local_resources is None:
|
||||||
obj.local_resources = io.ResourcesLocal()
|
obj.local_resources = resources.ResourcesLocal()
|
||||||
class_clone.resources = obj.local_resources
|
class_clone.resources = obj.local_resources
|
||||||
# TODO: delete this when done testing mocking dynamic inputs
|
|
||||||
for si in obj.SCHEMA.inputs:
|
|
||||||
if isinstance(si, io.AutogrowDynamic.Input):
|
|
||||||
add_key = si.id
|
|
||||||
dynamic_list = []
|
|
||||||
real_inputs = {k: v for k, v in inputs.items()}
|
|
||||||
for d in si.get_dynamic():
|
|
||||||
dynamic_list.append(real_inputs.pop(d.id, None))
|
|
||||||
dynamic_list = [x for x in dynamic_list if x is not None]
|
|
||||||
inputs = {**real_inputs, add_key: dynamic_list}
|
|
||||||
f = make_locked_method_func(type_obj, func, class_clone)
|
f = make_locked_method_func(type_obj, func, class_clone)
|
||||||
# V1
|
# V1
|
||||||
else:
|
else:
|
||||||
@ -363,7 +348,7 @@ def get_output_from_returns(return_values, obj):
|
|||||||
result = tuple([result] * len(obj.RETURN_TYPES))
|
result = tuple([result] * len(obj.RETURN_TYPES))
|
||||||
results.append(result)
|
results.append(result)
|
||||||
subgraph_results.append((None, result))
|
subgraph_results.append((None, result))
|
||||||
elif isinstance(r, io.NodeOutput):
|
elif isinstance(r, _NodeOutputInternal):
|
||||||
# V3
|
# V3
|
||||||
if r.ui is not None:
|
if r.ui is not None:
|
||||||
if isinstance(r.ui, dict):
|
if isinstance(r.ui, dict):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user