mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-10 01:02:56 +08:00
Update nodes categories and display names (CORE-89) (#13786)
This commit is contained in:
parent
c8673542f7
commit
594de378fe
@ -92,7 +92,7 @@ class SamplerEulerCFGpp(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="SamplerEulerCFGpp",
|
node_id="SamplerEulerCFGpp",
|
||||||
display_name="SamplerEulerCFG++",
|
display_name="SamplerEulerCFG++",
|
||||||
category="_for_testing", # "sampling/custom_sampling/samplers"
|
category="experimental", # "sampling/custom_sampling/samplers"
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Combo.Input("version", options=["regular", "alternative"], advanced=True),
|
io.Combo.Input("version", options=["regular", "alternative"], advanced=True),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class UNetSelfAttentionMultiply(io.ComfyNode):
|
|||||||
def define_schema(cls) -> io.Schema:
|
def define_schema(cls) -> io.Schema:
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="UNetSelfAttentionMultiply",
|
node_id="UNetSelfAttentionMultiply",
|
||||||
category="_for_testing/attention_experiments",
|
category="experimental/attention_experiments",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
||||||
@ -48,7 +48,7 @@ class UNetCrossAttentionMultiply(io.ComfyNode):
|
|||||||
def define_schema(cls) -> io.Schema:
|
def define_schema(cls) -> io.Schema:
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="UNetCrossAttentionMultiply",
|
node_id="UNetCrossAttentionMultiply",
|
||||||
category="_for_testing/attention_experiments",
|
category="experimental/attention_experiments",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
||||||
@ -72,7 +72,7 @@ class CLIPAttentionMultiply(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="CLIPAttentionMultiply",
|
node_id="CLIPAttentionMultiply",
|
||||||
search_aliases=["clip attention scale", "text encoder attention"],
|
search_aliases=["clip attention scale", "text encoder attention"],
|
||||||
category="_for_testing/attention_experiments",
|
category="experimental/attention_experiments",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Clip.Input("clip"),
|
io.Clip.Input("clip"),
|
||||||
io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
||||||
@ -106,7 +106,7 @@ class UNetTemporalAttentionMultiply(io.ComfyNode):
|
|||||||
def define_schema(cls) -> io.Schema:
|
def define_schema(cls) -> io.Schema:
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="UNetTemporalAttentionMultiply",
|
node_id="UNetTemporalAttentionMultiply",
|
||||||
category="_for_testing/attention_experiments",
|
category="experimental/attention_experiments",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Float.Input("self_structural", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
io.Float.Input("self_structural", default=1.0, min=0.0, max=10.0, step=0.01, advanced=True),
|
||||||
|
|||||||
@ -10,6 +10,7 @@ class AudioEncoderLoader(io.ComfyNode):
|
|||||||
def define_schema(cls) -> io.Schema:
|
def define_schema(cls) -> io.Schema:
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="AudioEncoderLoader",
|
node_id="AudioEncoderLoader",
|
||||||
|
display_name="Load Audio Encoder",
|
||||||
category="loaders",
|
category="loaders",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Combo.Input(
|
io.Combo.Input(
|
||||||
|
|||||||
@ -153,7 +153,7 @@ class WanCameraEmbedding(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="WanCameraEmbedding",
|
node_id="WanCameraEmbedding",
|
||||||
category="camera",
|
category="conditioning/video_models",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Combo.Input(
|
io.Combo.Input(
|
||||||
"camera_pose",
|
"camera_pose",
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class CLIPTextEncodeControlnet(io.ComfyNode):
|
|||||||
def define_schema(cls) -> io.Schema:
|
def define_schema(cls) -> io.Schema:
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="CLIPTextEncodeControlnet",
|
node_id="CLIPTextEncodeControlnet",
|
||||||
category="_for_testing/conditioning",
|
category="experimental/conditioning",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Clip.Input("clip"),
|
io.Clip.Input("clip"),
|
||||||
io.Conditioning.Input("conditioning"),
|
io.Conditioning.Input("conditioning"),
|
||||||
@ -35,7 +35,7 @@ class T5TokenizerOptions(io.ComfyNode):
|
|||||||
def define_schema(cls) -> io.Schema:
|
def define_schema(cls) -> io.Schema:
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="T5TokenizerOptions",
|
node_id="T5TokenizerOptions",
|
||||||
category="_for_testing/conditioning",
|
category="experimental/conditioning",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Clip.Input("clip"),
|
io.Clip.Input("clip"),
|
||||||
io.Int.Input("min_padding", default=0, min=0, max=10000, step=1, advanced=True),
|
io.Int.Input("min_padding", default=0, min=0, max=10000, step=1, advanced=True),
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class ContextWindowsManualNode(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="ContextWindowsManual",
|
node_id="ContextWindowsManual",
|
||||||
display_name="Context Windows (Manual)",
|
display_name="Context Windows (Manual)",
|
||||||
category="context",
|
category="model_patches",
|
||||||
description="Manually set context windows.",
|
description="Manually set context windows.",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model", tooltip="The model to apply context windows to during sampling."),
|
io.Model.Input("model", tooltip="The model to apply context windows to during sampling."),
|
||||||
|
|||||||
@ -984,7 +984,7 @@ class AddNoise(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="AddNoise",
|
node_id="AddNoise",
|
||||||
category="_for_testing/custom_sampling/noise",
|
category="experimental/custom_sampling/noise",
|
||||||
is_experimental=True,
|
is_experimental=True,
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
@ -1034,7 +1034,7 @@ class ManualSigmas(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="ManualSigmas",
|
node_id="ManualSigmas",
|
||||||
search_aliases=["custom noise schedule", "define sigmas"],
|
search_aliases=["custom noise schedule", "define sigmas"],
|
||||||
category="_for_testing/custom_sampling",
|
category="experimental/custom_sampling",
|
||||||
is_experimental=True,
|
is_experimental=True,
|
||||||
inputs=[
|
inputs=[
|
||||||
io.String.Input("sigmas", default="1, 0.5", multiline=False)
|
io.String.Input("sigmas", default="1, 0.5", multiline=False)
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class DifferentialDiffusion(io.ComfyNode):
|
|||||||
node_id="DifferentialDiffusion",
|
node_id="DifferentialDiffusion",
|
||||||
search_aliases=["inpaint gradient", "variable denoise strength"],
|
search_aliases=["inpaint gradient", "variable denoise strength"],
|
||||||
display_name="Differential Diffusion",
|
display_name="Differential Diffusion",
|
||||||
category="_for_testing",
|
category="experimental",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Float.Input(
|
io.Float.Input(
|
||||||
|
|||||||
@ -60,7 +60,7 @@ class FreSca(io.ComfyNode):
|
|||||||
node_id="FreSca",
|
node_id="FreSca",
|
||||||
search_aliases=["frequency guidance"],
|
search_aliases=["frequency guidance"],
|
||||||
display_name="FreSca",
|
display_name="FreSca",
|
||||||
category="_for_testing",
|
category="experimental",
|
||||||
description="Applies frequency-dependent scaling to the guidance",
|
description="Applies frequency-dependent scaling to the guidance",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
|
|||||||
@ -131,6 +131,8 @@ class HunyuanVideo15SuperResolution(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="HunyuanVideo15SuperResolution",
|
node_id="HunyuanVideo15SuperResolution",
|
||||||
|
display_name="Hunyuan Video 1.5 Super Resolution",
|
||||||
|
category="conditioning/video_models",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Conditioning.Input("positive"),
|
io.Conditioning.Input("positive"),
|
||||||
io.Conditioning.Input("negative"),
|
io.Conditioning.Input("negative"),
|
||||||
@ -381,6 +383,8 @@ class HunyuanRefinerLatent(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="HunyuanRefinerLatent",
|
node_id="HunyuanRefinerLatent",
|
||||||
|
display_name="Hunyuan Latent Refiner",
|
||||||
|
category="conditioning/video_models",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Conditioning.Input("positive"),
|
io.Conditioning.Input("positive"),
|
||||||
io.Conditioning.Input("negative"),
|
io.Conditioning.Input("negative"),
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class Hunyuan3Dv2Conditioning(IO.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return IO.Schema(
|
return IO.Schema(
|
||||||
node_id="Hunyuan3Dv2Conditioning",
|
node_id="Hunyuan3Dv2Conditioning",
|
||||||
category="conditioning/video_models",
|
category="conditioning/3d_models",
|
||||||
inputs=[
|
inputs=[
|
||||||
IO.ClipVisionOutput.Input("clip_vision_output"),
|
IO.ClipVisionOutput.Input("clip_vision_output"),
|
||||||
],
|
],
|
||||||
@ -65,7 +65,7 @@ class Hunyuan3Dv2ConditioningMultiView(IO.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return IO.Schema(
|
return IO.Schema(
|
||||||
node_id="Hunyuan3Dv2ConditioningMultiView",
|
node_id="Hunyuan3Dv2ConditioningMultiView",
|
||||||
category="conditioning/video_models",
|
category="conditioning/3d_models",
|
||||||
inputs=[
|
inputs=[
|
||||||
IO.ClipVisionOutput.Input("front", optional=True),
|
IO.ClipVisionOutput.Input("front", optional=True),
|
||||||
IO.ClipVisionOutput.Input("left", optional=True),
|
IO.ClipVisionOutput.Input("left", optional=True),
|
||||||
@ -424,6 +424,7 @@ class VoxelToMeshBasic(IO.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return IO.Schema(
|
return IO.Schema(
|
||||||
node_id="VoxelToMeshBasic",
|
node_id="VoxelToMeshBasic",
|
||||||
|
display_name="Voxel to Mesh (Basic)",
|
||||||
category="3d",
|
category="3d",
|
||||||
inputs=[
|
inputs=[
|
||||||
IO.Voxel.Input("voxel"),
|
IO.Voxel.Input("voxel"),
|
||||||
@ -453,6 +454,7 @@ class VoxelToMesh(IO.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return IO.Schema(
|
return IO.Schema(
|
||||||
node_id="VoxelToMesh",
|
node_id="VoxelToMesh",
|
||||||
|
display_name="Voxel to Mesh",
|
||||||
category="3d",
|
category="3d",
|
||||||
inputs=[
|
inputs=[
|
||||||
IO.Voxel.Input("voxel"),
|
IO.Voxel.Input("voxel"),
|
||||||
|
|||||||
@ -102,6 +102,7 @@ class HypernetworkLoader(IO.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return IO.Schema(
|
return IO.Schema(
|
||||||
node_id="HypernetworkLoader",
|
node_id="HypernetworkLoader",
|
||||||
|
display_name="Load Hypernetwork",
|
||||||
category="loaders",
|
category="loaders",
|
||||||
inputs=[
|
inputs=[
|
||||||
IO.Model.Input("model"),
|
IO.Model.Input("model"),
|
||||||
|
|||||||
@ -91,7 +91,7 @@ class LoraSave(io.ComfyNode):
|
|||||||
node_id="LoraSave",
|
node_id="LoraSave",
|
||||||
search_aliases=["export lora"],
|
search_aliases=["export lora"],
|
||||||
display_name="Extract and Save Lora",
|
display_name="Extract and Save Lora",
|
||||||
category="_for_testing",
|
category="experimental",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.String.Input("filename_prefix", default="loras/ComfyUI_extracted_lora"),
|
io.String.Input("filename_prefix", default="loras/ComfyUI_extracted_lora"),
|
||||||
io.Int.Input("rank", default=8, min=1, max=4096, step=1, advanced=True),
|
io.Int.Input("rank", default=8, min=1, max=4096, step=1, advanced=True),
|
||||||
|
|||||||
@ -594,7 +594,8 @@ class LTXVPreprocess(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="LTXVPreprocess",
|
node_id="LTXVPreprocess",
|
||||||
category="image",
|
display_name="LTXV Preprocess",
|
||||||
|
category="video/preprocessors",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Image.Input("image"),
|
io.Image.Input("image"),
|
||||||
io.Int.Input(
|
io.Int.Input(
|
||||||
|
|||||||
@ -11,7 +11,7 @@ class Mahiro(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="Mahiro",
|
node_id="Mahiro",
|
||||||
display_name="Positive-Biased Guidance",
|
display_name="Positive-Biased Guidance",
|
||||||
category="_for_testing",
|
category="experimental",
|
||||||
description="Modify the guidance to scale more on the 'direction' of the positive prompt rather than the difference between the negative prompt.",
|
description="Modify the guidance to scale more on the 'direction' of the positive prompt rather than the difference between the negative prompt.",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
|
|||||||
@ -70,7 +70,7 @@ class MathExpressionNode(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="ComfyMathExpression",
|
node_id="ComfyMathExpression",
|
||||||
display_name="Math Expression",
|
display_name="Math Expression",
|
||||||
category="math",
|
category="logic",
|
||||||
search_aliases=[
|
search_aliases=[
|
||||||
"expression", "formula", "calculate", "calculator",
|
"expression", "formula", "calculate", "calculator",
|
||||||
"eval", "math",
|
"eval", "math",
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class NumberConvertNode(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="ComfyNumberConvert",
|
node_id="ComfyNumberConvert",
|
||||||
display_name="Number Convert",
|
display_name="Number Convert",
|
||||||
category="math",
|
category="utils",
|
||||||
search_aliases=[
|
search_aliases=[
|
||||||
"int to float", "float to int", "number convert",
|
"int to float", "float to int", "number convert",
|
||||||
"int2float", "float2int", "cast", "parse number",
|
"int2float", "float2int", "cast", "parse number",
|
||||||
|
|||||||
@ -24,8 +24,8 @@ class PerpNeg(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="PerpNeg",
|
node_id="PerpNeg",
|
||||||
display_name="Perp-Neg (DEPRECATED by PerpNegGuider)",
|
display_name="Perp-Neg (DEPRECATED by Perp-Neg Guider)",
|
||||||
category="_for_testing",
|
category="experimental",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Conditioning.Input("empty_conditioning"),
|
io.Conditioning.Input("empty_conditioning"),
|
||||||
@ -127,7 +127,8 @@ class PerpNegGuider(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="PerpNegGuider",
|
node_id="PerpNegGuider",
|
||||||
category="_for_testing",
|
display_name="Perp-Neg Guider",
|
||||||
|
category="experimental",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Conditioning.Input("positive"),
|
io.Conditioning.Input("positive"),
|
||||||
|
|||||||
@ -123,7 +123,7 @@ class PhotoMakerLoader(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="PhotoMakerLoader",
|
node_id="PhotoMakerLoader",
|
||||||
category="_for_testing/photomaker",
|
category="experimental/photomaker",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Combo.Input("photomaker_model_name", options=folder_paths.get_filename_list("photomaker")),
|
io.Combo.Input("photomaker_model_name", options=folder_paths.get_filename_list("photomaker")),
|
||||||
],
|
],
|
||||||
@ -149,7 +149,7 @@ class PhotoMakerEncode(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="PhotoMakerEncode",
|
node_id="PhotoMakerEncode",
|
||||||
category="_for_testing/photomaker",
|
category="experimental/photomaker",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Photomaker.Input("photomaker"),
|
io.Photomaker.Input("photomaker"),
|
||||||
io.Image.Input("image"),
|
io.Image.Input("image"),
|
||||||
|
|||||||
@ -116,6 +116,7 @@ class Quantize(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="ImageQuantize",
|
node_id="ImageQuantize",
|
||||||
|
display_name="Quantize Image",
|
||||||
category="image/postprocessing",
|
category="image/postprocessing",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Image.Input("image"),
|
io.Image.Input("image"),
|
||||||
@ -181,6 +182,7 @@ class Sharpen(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="ImageSharpen",
|
node_id="ImageSharpen",
|
||||||
|
display_name="Sharpen Image",
|
||||||
category="image/postprocessing",
|
category="image/postprocessing",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Image.Input("image"),
|
io.Image.Input("image"),
|
||||||
@ -436,7 +438,7 @@ class ResizeImageMaskNode(io.ComfyNode):
|
|||||||
node_id="ResizeImageMaskNode",
|
node_id="ResizeImageMaskNode",
|
||||||
display_name="Resize Image/Mask",
|
display_name="Resize Image/Mask",
|
||||||
description="Resize an image or mask using various scaling methods.",
|
description="Resize an image or mask using various scaling methods.",
|
||||||
category="transform",
|
category="image/transform",
|
||||||
search_aliases=["resize", "resize image", "resize mask", "scale", "scale image", "scale mask", "image resize", "change size", "dimensions", "shrink", "enlarge"],
|
search_aliases=["resize", "resize image", "resize mask", "scale", "scale image", "scale mask", "image resize", "change size", "dimensions", "shrink", "enlarge"],
|
||||||
inputs=[
|
inputs=[
|
||||||
io.MatchType.Input("input", template=template),
|
io.MatchType.Input("input", template=template),
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class RTDETR_detect(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="RTDETR_detect",
|
node_id="RTDETR_detect",
|
||||||
display_name="RT-DETR Detect",
|
display_name="RT-DETR Detect",
|
||||||
category="detection/",
|
category="detection",
|
||||||
search_aliases=["bbox", "bounding box", "object detection", "coco"],
|
search_aliases=["bbox", "bounding box", "object detection", "coco"],
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model", display_name="model"),
|
io.Model.Input("model", display_name="model"),
|
||||||
@ -71,7 +71,7 @@ class DrawBBoxes(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="DrawBBoxes",
|
node_id="DrawBBoxes",
|
||||||
display_name="Draw BBoxes",
|
display_name="Draw BBoxes",
|
||||||
category="detection/",
|
category="detection",
|
||||||
search_aliases=["bbox", "bounding box", "object detection", "rt_detr", "visualize detections", "coco"],
|
search_aliases=["bbox", "bounding box", "object detection", "rt_detr", "visualize detections", "coco"],
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Image.Input("image", optional=True),
|
io.Image.Input("image", optional=True),
|
||||||
|
|||||||
@ -113,7 +113,7 @@ class SelfAttentionGuidance(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="SelfAttentionGuidance",
|
node_id="SelfAttentionGuidance",
|
||||||
display_name="Self-Attention Guidance",
|
display_name="Self-Attention Guidance",
|
||||||
category="_for_testing",
|
category="experimental",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Float.Input("scale", default=0.5, min=-2.0, max=5.0, step=0.01),
|
io.Float.Input("scale", default=0.5, min=-2.0, max=5.0, step=0.01),
|
||||||
|
|||||||
@ -93,7 +93,7 @@ class SAM3_Detect(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="SAM3_Detect",
|
node_id="SAM3_Detect",
|
||||||
display_name="SAM3 Detect",
|
display_name="SAM3 Detect",
|
||||||
category="detection/",
|
category="detection",
|
||||||
search_aliases=["sam3", "segment anything", "open vocabulary", "text detection", "segment"],
|
search_aliases=["sam3", "segment anything", "open vocabulary", "text detection", "segment"],
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model", display_name="model"),
|
io.Model.Input("model", display_name="model"),
|
||||||
@ -265,7 +265,7 @@ class SAM3_VideoTrack(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="SAM3_VideoTrack",
|
node_id="SAM3_VideoTrack",
|
||||||
display_name="SAM3 Video Track",
|
display_name="SAM3 Video Track",
|
||||||
category="detection/",
|
category="detection",
|
||||||
search_aliases=["sam3", "video", "track", "propagate"],
|
search_aliases=["sam3", "video", "track", "propagate"],
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Image.Input("images", display_name="images", tooltip="Video frames as batched images"),
|
io.Image.Input("images", display_name="images", tooltip="Video frames as batched images"),
|
||||||
@ -320,7 +320,7 @@ class SAM3_TrackPreview(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="SAM3_TrackPreview",
|
node_id="SAM3_TrackPreview",
|
||||||
display_name="SAM3 Track Preview",
|
display_name="SAM3 Track Preview",
|
||||||
category="detection/",
|
category="detection",
|
||||||
inputs=[
|
inputs=[
|
||||||
SAM3TrackData.Input("track_data", display_name="track_data"),
|
SAM3TrackData.Input("track_data", display_name="track_data"),
|
||||||
io.Image.Input("images", display_name="images", optional=True),
|
io.Image.Input("images", display_name="images", optional=True),
|
||||||
@ -478,7 +478,7 @@ class SAM3_TrackToMask(io.ComfyNode):
|
|||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="SAM3_TrackToMask",
|
node_id="SAM3_TrackToMask",
|
||||||
display_name="SAM3 Track to Mask",
|
display_name="SAM3 Track to Mask",
|
||||||
category="detection/",
|
category="detection",
|
||||||
inputs=[
|
inputs=[
|
||||||
SAM3TrackData.Input("track_data", display_name="track_data"),
|
SAM3TrackData.Input("track_data", display_name="track_data"),
|
||||||
io.String.Input("object_indices", display_name="object_indices", default="",
|
io.String.Input("object_indices", display_name="object_indices", default="",
|
||||||
|
|||||||
@ -119,7 +119,7 @@ class StableCascade_SuperResolutionControlnet(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="StableCascade_SuperResolutionControlnet",
|
node_id="StableCascade_SuperResolutionControlnet",
|
||||||
category="_for_testing/stable_cascade",
|
category="experimental/stable_cascade",
|
||||||
is_experimental=True,
|
is_experimental=True,
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Image.Input("image"),
|
io.Image.Input("image"),
|
||||||
|
|||||||
@ -26,7 +26,8 @@ class TextGenerate(io.ComfyNode):
|
|||||||
|
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="TextGenerate",
|
node_id="TextGenerate",
|
||||||
category="textgen",
|
display_name="Generate Text",
|
||||||
|
category="text",
|
||||||
search_aliases=["LLM", "gemma"],
|
search_aliases=["LLM", "gemma"],
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Clip.Input("clip"),
|
io.Clip.Input("clip"),
|
||||||
@ -157,6 +158,7 @@ class TextGenerateLTX2Prompt(TextGenerate):
|
|||||||
parent_schema = super().define_schema()
|
parent_schema = super().define_schema()
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="TextGenerateLTX2Prompt",
|
node_id="TextGenerateLTX2Prompt",
|
||||||
|
display_name="Generate LTX2 Prompt",
|
||||||
category=parent_schema.category,
|
category=parent_schema.category,
|
||||||
inputs=parent_schema.inputs,
|
inputs=parent_schema.inputs,
|
||||||
outputs=parent_schema.outputs,
|
outputs=parent_schema.outputs,
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class TorchCompileModel(io.ComfyNode):
|
|||||||
def define_schema(cls) -> io.Schema:
|
def define_schema(cls) -> io.Schema:
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="TorchCompileModel",
|
node_id="TorchCompileModel",
|
||||||
category="_for_testing",
|
category="experimental",
|
||||||
inputs=[
|
inputs=[
|
||||||
io.Model.Input("model"),
|
io.Model.Input("model"),
|
||||||
io.Combo.Input(
|
io.Combo.Input(
|
||||||
|
|||||||
@ -1361,7 +1361,7 @@ class SaveLoRA(io.ComfyNode):
|
|||||||
node_id="SaveLoRA",
|
node_id="SaveLoRA",
|
||||||
search_aliases=["export lora"],
|
search_aliases=["export lora"],
|
||||||
display_name="Save LoRA Weights",
|
display_name="Save LoRA Weights",
|
||||||
category="loaders",
|
category="advanced/model_merging",
|
||||||
is_experimental=True,
|
is_experimental=True,
|
||||||
is_output_node=True,
|
is_output_node=True,
|
||||||
inputs=[
|
inputs=[
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class ImageOnlyCheckpointLoader:
|
|||||||
RETURN_TYPES = ("MODEL", "CLIP_VISION", "VAE")
|
RETURN_TYPES = ("MODEL", "CLIP_VISION", "VAE")
|
||||||
FUNCTION = "load_checkpoint"
|
FUNCTION = "load_checkpoint"
|
||||||
|
|
||||||
CATEGORY = "loaders/video_models"
|
CATEGORY = "loaders"
|
||||||
|
|
||||||
def load_checkpoint(self, ckpt_name, output_vae=True, output_clip=True):
|
def load_checkpoint(self, ckpt_name, output_vae=True, output_clip=True):
|
||||||
ckpt_path = folder_paths.get_full_path_or_raise("checkpoints", ckpt_name)
|
ckpt_path = folder_paths.get_full_path_or_raise("checkpoints", ckpt_name)
|
||||||
|
|||||||
@ -22,7 +22,7 @@ class SaveImageWebsocket:
|
|||||||
|
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
CATEGORY = "api/image"
|
CATEGORY = "image"
|
||||||
|
|
||||||
def save_images(self, images):
|
def save_images(self, images):
|
||||||
pbar = comfy.utils.ProgressBar(images.shape[0])
|
pbar = comfy.utils.ProgressBar(images.shape[0])
|
||||||
@ -42,3 +42,7 @@ class SaveImageWebsocket:
|
|||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"SaveImageWebsocket": SaveImageWebsocket,
|
"SaveImageWebsocket": SaveImageWebsocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
"SaveImageWebsocket": "Save Image (Websocket)",
|
||||||
|
}
|
||||||
14
nodes.py
14
nodes.py
@ -330,7 +330,7 @@ class VAEDecodeTiled:
|
|||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "decode"
|
FUNCTION = "decode"
|
||||||
|
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
|
|
||||||
def decode(self, vae, samples, tile_size, overlap=64, temporal_size=64, temporal_overlap=8):
|
def decode(self, vae, samples, tile_size, overlap=64, temporal_size=64, temporal_overlap=8):
|
||||||
if tile_size < overlap * 4:
|
if tile_size < overlap * 4:
|
||||||
@ -377,7 +377,7 @@ class VAEEncodeTiled:
|
|||||||
RETURN_TYPES = ("LATENT",)
|
RETURN_TYPES = ("LATENT",)
|
||||||
FUNCTION = "encode"
|
FUNCTION = "encode"
|
||||||
|
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
|
|
||||||
def encode(self, vae, pixels, tile_size, overlap, temporal_size=64, temporal_overlap=8):
|
def encode(self, vae, pixels, tile_size, overlap, temporal_size=64, temporal_overlap=8):
|
||||||
t = vae.encode_tiled(pixels, tile_x=tile_size, tile_y=tile_size, overlap=overlap, tile_t=temporal_size, overlap_t=temporal_overlap)
|
t = vae.encode_tiled(pixels, tile_x=tile_size, tile_y=tile_size, overlap=overlap, tile_t=temporal_size, overlap_t=temporal_overlap)
|
||||||
@ -493,7 +493,7 @@ class SaveLatent:
|
|||||||
|
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
|
|
||||||
def save(self, samples, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
|
def save(self, samples, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
|
||||||
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir)
|
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir)
|
||||||
@ -538,7 +538,7 @@ class LoadLatent:
|
|||||||
files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f)) and f.endswith(".latent")]
|
files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f)) and f.endswith(".latent")]
|
||||||
return {"required": {"latent": [sorted(files), ]}, }
|
return {"required": {"latent": [sorted(files), ]}, }
|
||||||
|
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
|
|
||||||
RETURN_TYPES = ("LATENT", )
|
RETURN_TYPES = ("LATENT", )
|
||||||
FUNCTION = "load"
|
FUNCTION = "load"
|
||||||
@ -1443,7 +1443,7 @@ class LatentBlend:
|
|||||||
RETURN_TYPES = ("LATENT",)
|
RETURN_TYPES = ("LATENT",)
|
||||||
FUNCTION = "blend"
|
FUNCTION = "blend"
|
||||||
|
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
|
|
||||||
def blend(self, samples1, samples2, blend_factor:float, blend_mode: str="normal"):
|
def blend(self, samples1, samples2, blend_factor:float, blend_mode: str="normal"):
|
||||||
|
|
||||||
@ -2092,6 +2092,8 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"StyleModelLoader": "Load Style Model",
|
"StyleModelLoader": "Load Style Model",
|
||||||
"CLIPVisionLoader": "Load CLIP Vision",
|
"CLIPVisionLoader": "Load CLIP Vision",
|
||||||
"UNETLoader": "Load Diffusion Model",
|
"UNETLoader": "Load Diffusion Model",
|
||||||
|
"unCLIPCheckpointLoader": "Load unCLIP Checkpoint",
|
||||||
|
"GLIGENLoader": "Load GLIGEN Model",
|
||||||
# Conditioning
|
# Conditioning
|
||||||
"CLIPVisionEncode": "CLIP Vision Encode",
|
"CLIPVisionEncode": "CLIP Vision Encode",
|
||||||
"StyleModelApply": "Apply Style Model",
|
"StyleModelApply": "Apply Style Model",
|
||||||
@ -2140,7 +2142,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"ImageSharpen": "Sharpen Image",
|
"ImageSharpen": "Sharpen Image",
|
||||||
"ImageScaleToTotalPixels": "Scale Image to Total Pixels",
|
"ImageScaleToTotalPixels": "Scale Image to Total Pixels",
|
||||||
"GetImageSize": "Get Image Size",
|
"GetImageSize": "Get Image Size",
|
||||||
# _for_testing
|
# experimental
|
||||||
"VAEDecodeTiled": "VAE Decode (Tiled)",
|
"VAEDecodeTiled": "VAE Decode (Tiled)",
|
||||||
"VAEEncodeTiled": "VAE Encode (Tiled)",
|
"VAEEncodeTiled": "VAE Encode (Tiled)",
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class TestAsyncProgressUpdate(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "execute"
|
FUNCTION = "execute"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
async def execute(self, value, sleep_seconds):
|
async def execute(self, value, sleep_seconds):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
@ -51,7 +51,7 @@ class TestSyncProgressUpdate(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "execute"
|
FUNCTION = "execute"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
def execute(self, value, sleep_seconds):
|
def execute(self, value, sleep_seconds):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class TestAsyncValidation(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "process"
|
FUNCTION = "process"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def VALIDATE_INPUTS(cls, value, threshold):
|
async def VALIDATE_INPUTS(cls, value, threshold):
|
||||||
@ -53,7 +53,7 @@ class TestAsyncError(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "error_execution"
|
FUNCTION = "error_execution"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
async def error_execution(self, value, error_after):
|
async def error_execution(self, value, error_after):
|
||||||
await asyncio.sleep(error_after)
|
await asyncio.sleep(error_after)
|
||||||
@ -74,7 +74,7 @@ class TestAsyncValidationError(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "process"
|
FUNCTION = "process"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def VALIDATE_INPUTS(cls, value, max_value):
|
async def VALIDATE_INPUTS(cls, value, max_value):
|
||||||
@ -105,7 +105,7 @@ class TestAsyncTimeout(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "timeout_execution"
|
FUNCTION = "timeout_execution"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
async def timeout_execution(self, value, timeout, operation_time):
|
async def timeout_execution(self, value, timeout, operation_time):
|
||||||
try:
|
try:
|
||||||
@ -129,7 +129,7 @@ class TestSyncError(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "sync_error"
|
FUNCTION = "sync_error"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
def sync_error(self, value):
|
def sync_error(self, value):
|
||||||
raise RuntimeError("Intentional sync execution error for testing")
|
raise RuntimeError("Intentional sync execution error for testing")
|
||||||
@ -150,7 +150,7 @@ class TestAsyncLazyCheck(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "process"
|
FUNCTION = "process"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
async def check_lazy_status(self, condition, input1, input2):
|
async def check_lazy_status(self, condition, input1, input2):
|
||||||
# Simulate async checking (e.g., querying remote service)
|
# Simulate async checking (e.g., querying remote service)
|
||||||
@ -184,7 +184,7 @@ class TestDynamicAsyncGeneration(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "generate_async_workflow"
|
FUNCTION = "generate_async_workflow"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
def generate_async_workflow(self, image1, image2, num_async_nodes, sleep_duration):
|
def generate_async_workflow(self, image1, image2, num_async_nodes, sleep_duration):
|
||||||
g = GraphBuilder()
|
g = GraphBuilder()
|
||||||
@ -229,7 +229,7 @@ class TestAsyncResourceUser(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "use_resource"
|
FUNCTION = "use_resource"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
async def use_resource(self, value, resource_id, duration):
|
async def use_resource(self, value, resource_id, duration):
|
||||||
# Check if resource is already in use
|
# Check if resource is already in use
|
||||||
@ -265,7 +265,7 @@ class TestAsyncBatchProcessing(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "process_batch"
|
FUNCTION = "process_batch"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
async def process_batch(self, images, process_time_per_item, unique_id):
|
async def process_batch(self, images, process_time_per_item, unique_id):
|
||||||
batch_size = images.shape[0]
|
batch_size = images.shape[0]
|
||||||
@ -305,7 +305,7 @@ class TestAsyncConcurrentLimit(ComfyNodeABC):
|
|||||||
|
|
||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "limited_execution"
|
FUNCTION = "limited_execution"
|
||||||
CATEGORY = "_for_testing/async"
|
CATEGORY = "experimental/async"
|
||||||
|
|
||||||
async def limited_execution(self, value, duration, node_id):
|
async def limited_execution(self, value, duration, node_id):
|
||||||
async with self._semaphore:
|
async with self._semaphore:
|
||||||
|
|||||||
@ -409,7 +409,7 @@ class TestSleep(ComfyNodeABC):
|
|||||||
RETURN_TYPES = (IO.ANY,)
|
RETURN_TYPES = (IO.ANY,)
|
||||||
FUNCTION = "sleep"
|
FUNCTION = "sleep"
|
||||||
|
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
|
|
||||||
async def sleep(self, value, seconds, unique_id):
|
async def sleep(self, value, seconds, unique_id):
|
||||||
pbar = ProgressBar(seconds, node_id=unique_id)
|
pbar = ProgressBar(seconds, node_id=unique_id)
|
||||||
@ -440,7 +440,7 @@ class TestParallelSleep(ComfyNodeABC):
|
|||||||
}
|
}
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "parallel_sleep"
|
FUNCTION = "parallel_sleep"
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
def parallel_sleep(self, image1, image2, image3, sleep1, sleep2, sleep3, unique_id):
|
def parallel_sleep(self, image1, image2, image3, sleep1, sleep2, sleep3, unique_id):
|
||||||
@ -474,7 +474,7 @@ class TestOutputNodeWithSocketOutput:
|
|||||||
}
|
}
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "process"
|
FUNCTION = "process"
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "experimental"
|
||||||
OUTPUT_NODE = True
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
def process(self, image, value):
|
def process(self, image, value):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user