mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-05 23:02:49 +08:00
- Implement VerifierSelectionNode for creating quality verifiers - Implement InferenceScalingNode that wraps KSampler with quality checks - Add VAE decoding during sampling steps for quality assessment - Include quality verification logic using variance and edge detection - Fix noise/latent handling to match ComfyUI patterns - Add comprehensive error handling and logging - Include documentation and debugging notes
181 lines
4.9 KiB
Python
181 lines
4.9 KiB
Python
"""
|
|
Template example node file.
|
|
Copy this file and modify it to create your own custom nodes.
|
|
"""
|
|
|
|
from typing import Optional
|
|
from typing_extensions import override
|
|
from inspect import cleandoc
|
|
import torch
|
|
import numpy as np
|
|
from PIL import Image
|
|
|
|
from comfy_api.latest import IO, ComfyExtension
|
|
|
|
|
|
class ExampleNode(IO.ComfyNode):
|
|
"""
|
|
This is an example node that demonstrates the basic structure.
|
|
Replace this docstring with a description of what your node does.
|
|
"""
|
|
|
|
@classmethod
|
|
def define_schema(cls):
|
|
return IO.Schema(
|
|
node_id="ExampleNode",
|
|
display_name="Example Node",
|
|
category="example",
|
|
description=cleandoc(cls.__doc__ or ""),
|
|
inputs=[
|
|
IO.String.Input(
|
|
"text_input",
|
|
default="Hello, ComfyUI!",
|
|
multiline=False,
|
|
tooltip="A text input field",
|
|
),
|
|
IO.Int.Input(
|
|
"number_input",
|
|
default=42,
|
|
min=0,
|
|
max=100,
|
|
step=1,
|
|
display_mode=IO.NumberDisplay.slider,
|
|
tooltip="A number input with slider",
|
|
),
|
|
IO.Image.Input(
|
|
"image_input",
|
|
tooltip="An optional image input",
|
|
optional=True,
|
|
),
|
|
],
|
|
outputs=[
|
|
IO.String.Output(),
|
|
IO.Int.Output(),
|
|
IO.Image.Output(),
|
|
],
|
|
)
|
|
|
|
@classmethod
|
|
async def execute(
|
|
cls,
|
|
text_input: str,
|
|
number_input: int,
|
|
image_input: Optional[torch.Tensor] = None,
|
|
) -> IO.NodeOutput:
|
|
"""
|
|
Execute the node logic.
|
|
|
|
Args:
|
|
text_input: The text input value
|
|
number_input: The number input value
|
|
image_input: Optional image tensor [B, H, W, C]
|
|
|
|
Returns:
|
|
NodeOutput with processed results
|
|
"""
|
|
# Process text
|
|
processed_text = f"Processed: {text_input}"
|
|
|
|
# Process number
|
|
processed_number = number_input * 2
|
|
|
|
# Process image if provided
|
|
if image_input is not None:
|
|
# Ensure batch dimension exists
|
|
if len(image_input.shape) == 3:
|
|
image_input = image_input.unsqueeze(0)
|
|
|
|
# Example: invert the image
|
|
processed_image = 1.0 - image_input
|
|
else:
|
|
# Create a default image if none provided
|
|
# Create a simple 256x256 RGBA image
|
|
default_image = torch.ones(1, 256, 256, 4) * 0.5
|
|
processed_image = default_image
|
|
|
|
# Return multiple outputs
|
|
return IO.NodeOutput(
|
|
string=processed_text,
|
|
int=processed_number,
|
|
image=processed_image,
|
|
)
|
|
|
|
|
|
class SimpleImageNode(IO.ComfyNode):
|
|
"""
|
|
A simpler example with just image input/output.
|
|
"""
|
|
|
|
@classmethod
|
|
def define_schema(cls):
|
|
return IO.Schema(
|
|
node_id="SimpleImageNode",
|
|
display_name="Simple Image Node",
|
|
category="example/image",
|
|
description=cleandoc(cls.__doc__ or ""),
|
|
inputs=[
|
|
IO.Image.Input(
|
|
"image",
|
|
tooltip="Input image",
|
|
),
|
|
IO.Float.Input(
|
|
"multiplier",
|
|
default=1.0,
|
|
min=0.0,
|
|
max=2.0,
|
|
step=0.1,
|
|
tooltip="Brightness multiplier",
|
|
),
|
|
],
|
|
outputs=[
|
|
IO.Image.Output(),
|
|
],
|
|
)
|
|
|
|
@classmethod
|
|
async def execute(
|
|
cls,
|
|
image: torch.Tensor,
|
|
multiplier: float = 1.0,
|
|
) -> IO.NodeOutput:
|
|
"""
|
|
Multiply image brightness.
|
|
|
|
Args:
|
|
image: Input image tensor [B, H, W, C]
|
|
multiplier: Brightness multiplier
|
|
|
|
Returns:
|
|
Adjusted image
|
|
"""
|
|
# Ensure batch dimension
|
|
if len(image.shape) == 3:
|
|
image = image.unsqueeze(0)
|
|
|
|
# Apply multiplier and clamp to valid range
|
|
result = torch.clamp(image * multiplier, 0.0, 1.0)
|
|
|
|
return IO.NodeOutput(result)
|
|
|
|
|
|
class ExampleExtension(ComfyExtension):
|
|
"""
|
|
Extension class that registers all your nodes.
|
|
"""
|
|
|
|
@override
|
|
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
|
|
return [
|
|
ExampleNode,
|
|
SimpleImageNode,
|
|
# Add more nodes here as you create them
|
|
]
|
|
|
|
|
|
async def comfy_entrypoint() -> ExampleExtension:
|
|
"""
|
|
Entry point function that ComfyUI calls to load your extension.
|
|
This function name must be exactly 'comfy_entrypoint'.
|
|
"""
|
|
return ExampleExtension()
|