380 lines
8.4 KiB
Markdown
380 lines
8.4 KiB
Markdown
# Node Interface Reference
|
|
|
|
## Complete Node API
|
|
|
|
This reference covers all attributes and methods available when creating custom nodes in ComfyUI.
|
|
|
|
## Required Components
|
|
|
|
### Class Definition
|
|
|
|
Every custom node must be a Python class. The class name will be used internally, while the display name can be customized.
|
|
|
|
```python
|
|
class YourNodeClassName:
|
|
"""Docstring describing what your node does"""
|
|
```
|
|
|
|
### INPUT_TYPES (Required)
|
|
|
|
A class method that returns a dictionary defining the node's inputs.
|
|
|
|
```python
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
# Required inputs must be connected
|
|
"input_name": ("TYPE", options_dict),
|
|
},
|
|
"optional": {
|
|
# Optional inputs can be left unconnected
|
|
"optional_name": ("TYPE", options_dict),
|
|
},
|
|
"hidden": {
|
|
# Hidden inputs not shown in UI
|
|
"unique_id": "UNIQUE_ID",
|
|
"prompt": "PROMPT",
|
|
"extra_pnginfo": "EXTRA_PNGINFO",
|
|
}
|
|
}
|
|
```
|
|
|
|
### RETURN_TYPES (Required)
|
|
|
|
A tuple defining the types of outputs the node produces.
|
|
|
|
```python
|
|
RETURN_TYPES = ("IMAGE", "MASK")
|
|
```
|
|
|
|
### FUNCTION (Required)
|
|
|
|
The name of the method to call when the node executes.
|
|
|
|
```python
|
|
FUNCTION = "process"
|
|
```
|
|
|
|
### Execution Method (Required)
|
|
|
|
The method that performs the node's computation.
|
|
|
|
```python
|
|
def process(self, **kwargs):
|
|
# All inputs from INPUT_TYPES are passed as keyword arguments
|
|
# Must return a tuple matching RETURN_TYPES
|
|
return (output1, output2)
|
|
```
|
|
|
|
## Optional Components
|
|
|
|
### CATEGORY
|
|
|
|
Where the node appears in the add node menu. Use "/" for submenu organization.
|
|
|
|
```python
|
|
CATEGORY = "image/filters"
|
|
```
|
|
|
|
### RETURN_NAMES
|
|
|
|
Human-readable names for outputs (must match RETURN_TYPES length).
|
|
|
|
```python
|
|
RETURN_NAMES = ("processed_image", "generated_mask")
|
|
```
|
|
|
|
### OUTPUT_NODE
|
|
|
|
Set to `True` if this node produces final outputs (like Save Image).
|
|
|
|
```python
|
|
OUTPUT_NODE = True
|
|
```
|
|
|
|
### OUTPUT_TOOLTIPS
|
|
|
|
Tooltips for each output socket.
|
|
|
|
```python
|
|
OUTPUT_TOOLTIPS = ("The processed image", "The generated mask")
|
|
```
|
|
|
|
### DESCRIPTION
|
|
|
|
A description shown in the UI when hovering over the node.
|
|
|
|
```python
|
|
DESCRIPTION = "Applies advanced filtering to images"
|
|
```
|
|
|
|
## Input Type Options
|
|
|
|
### Basic Input Options
|
|
|
|
All input types support these options:
|
|
|
|
```python
|
|
{
|
|
"default": value, # Default value
|
|
"forceInput": True, # Force connection (no widget)
|
|
"lazy": True, # Enable lazy evaluation
|
|
"tooltip": "Help text", # Tooltip on hover
|
|
}
|
|
```
|
|
|
|
### Numeric Inputs (INT, FLOAT)
|
|
|
|
```python
|
|
"number": ("FLOAT", {
|
|
"default": 1.0,
|
|
"min": 0.0,
|
|
"max": 10.0,
|
|
"step": 0.01,
|
|
"round": 0.001, # Round to this precision
|
|
"display": "slider", # or "number"
|
|
})
|
|
```
|
|
|
|
### String Inputs
|
|
|
|
```python
|
|
"text": ("STRING", {
|
|
"default": "Enter text",
|
|
"multiline": True, # Multi-line text box
|
|
"dynamicPrompts": True, # Enable dynamic prompts
|
|
"placeholder": "Type here..."
|
|
})
|
|
```
|
|
|
|
### Boolean Inputs
|
|
|
|
```python
|
|
"enable": ("BOOLEAN", {
|
|
"default": True,
|
|
"label_on": "Enabled", # Label when True
|
|
"label_off": "Disabled" # Label when False
|
|
})
|
|
```
|
|
|
|
### Combo Box (Dropdown)
|
|
|
|
```python
|
|
"mode": (["option1", "option2", "option3"], {
|
|
"default": "option1"
|
|
})
|
|
```
|
|
|
|
### Image Upload
|
|
|
|
```python
|
|
"image": ("IMAGE", {
|
|
"image_upload": True, # Enable upload button
|
|
})
|
|
```
|
|
|
|
## Advanced Features
|
|
|
|
### IS_CHANGED Method
|
|
|
|
Control when the node is re-executed:
|
|
|
|
```python
|
|
@classmethod
|
|
def IS_CHANGED(cls, **kwargs):
|
|
# Return a value that changes when node should re-execute
|
|
# Can return hash, timestamp, random value, etc.
|
|
return float("nan") # Always re-execute
|
|
```
|
|
|
|
### VALIDATE_INPUTS Method
|
|
|
|
Custom validation before execution:
|
|
|
|
```python
|
|
@classmethod
|
|
def VALIDATE_INPUTS(cls, **kwargs):
|
|
# Return True if inputs are valid
|
|
# Return error message string if invalid
|
|
if kwargs.get("value", 0) < 0:
|
|
return "Value must be non-negative"
|
|
return True
|
|
```
|
|
|
|
### Hidden Inputs
|
|
|
|
Access special system information:
|
|
|
|
```python
|
|
"hidden": {
|
|
"unique_id": "UNIQUE_ID", # Node's unique ID
|
|
"prompt": "PROMPT", # Full workflow prompt
|
|
"extra_pnginfo": "EXTRA_PNGINFO", # PNG metadata dict
|
|
"dynprompt": "DYNPROMPT" # Dynamic prompt object
|
|
}
|
|
```
|
|
|
|
### Lazy Evaluation
|
|
|
|
Enable on-demand execution:
|
|
|
|
```python
|
|
"input": ("TYPE", {"lazy": True})
|
|
|
|
# In execution method:
|
|
def process(self, input):
|
|
# Input might be a lazy object
|
|
if hasattr(input, '__call__'):
|
|
actual_value = input() # Evaluate lazy input
|
|
```
|
|
|
|
## Type System
|
|
|
|
### Built-in Types
|
|
|
|
```python
|
|
# Basic types
|
|
"STRING" # Text strings
|
|
"INT" # Integers
|
|
"FLOAT" # Floating point numbers
|
|
"BOOLEAN" # True/False values
|
|
|
|
# Image types
|
|
"IMAGE" # Image tensor [B,H,W,C]
|
|
"MASK" # Mask tensor [H,W] or [B,H,W]
|
|
"LATENT" # Latent representation
|
|
|
|
# Model types
|
|
"MODEL" # Diffusion model
|
|
"CLIP" # CLIP text encoder
|
|
"VAE" # Variational autoencoder
|
|
"CONDITIONING" # Text conditioning
|
|
"CONTROL_NET" # ControlNet model
|
|
|
|
# Advanced types
|
|
"SAMPLER" # Sampling method
|
|
"SIGMAS" # Sigma schedule
|
|
"GUIDER" # Guidance model
|
|
"NOISE" # Noise tensor
|
|
|
|
# Special types
|
|
"*" # ANY type (matches anything)
|
|
"STRING,FLOAT,INT" # Union types
|
|
```
|
|
|
|
### Custom Types
|
|
|
|
You can define custom types:
|
|
|
|
```python
|
|
class MY_CUSTOM_TYPE:
|
|
def __init__(self, data):
|
|
self.data = data
|
|
|
|
# Use in node:
|
|
RETURN_TYPES = ("MY_CUSTOM_TYPE",)
|
|
```
|
|
|
|
## Complete Example
|
|
|
|
```python
|
|
class AdvancedImageProcessor:
|
|
"""
|
|
Processes images with multiple effects and options.
|
|
Demonstrates most node interface features.
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.type = "AdvancedImageProcessor"
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"image": ("IMAGE", {
|
|
"tooltip": "Input image to process"
|
|
}),
|
|
"mode": (["blur", "sharpen", "edge_detect"], {
|
|
"default": "blur"
|
|
}),
|
|
"strength": ("FLOAT", {
|
|
"default": 1.0,
|
|
"min": 0.0,
|
|
"max": 10.0,
|
|
"step": 0.1,
|
|
"display": "slider"
|
|
}),
|
|
},
|
|
"optional": {
|
|
"mask": ("MASK", {
|
|
"tooltip": "Optional mask for selective processing"
|
|
}),
|
|
"seed": ("INT", {
|
|
"default": 0,
|
|
"min": 0,
|
|
"max": 0xffffffffffffffff
|
|
}),
|
|
},
|
|
"hidden": {
|
|
"unique_id": "UNIQUE_ID"
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE", "MASK")
|
|
RETURN_NAMES = ("processed", "effect_mask")
|
|
OUTPUT_TOOLTIPS = ("Processed image", "Mask showing affected areas")
|
|
|
|
FUNCTION = "process_image"
|
|
CATEGORY = "image/processing"
|
|
DESCRIPTION = "Advanced image processing with multiple effects"
|
|
|
|
def process_image(self, image, mode, strength, mask=None, seed=0, unique_id=None):
|
|
# Processing implementation
|
|
processed = apply_effect(image, mode, strength)
|
|
effect_mask = generate_effect_mask(image, processed)
|
|
|
|
return (processed, effect_mask)
|
|
|
|
@classmethod
|
|
def IS_CHANGED(cls, **kwargs):
|
|
# Re-execute if seed changes
|
|
return kwargs.get("seed", 0)
|
|
|
|
@classmethod
|
|
def VALIDATE_INPUTS(cls, **kwargs):
|
|
if kwargs.get("strength", 0) < 0:
|
|
return "Strength must be non-negative"
|
|
return True
|
|
|
|
# Register the node
|
|
NODE_CLASS_MAPPINGS = {
|
|
"AdvancedImageProcessor": AdvancedImageProcessor
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"AdvancedImageProcessor": "Advanced Image Processor"
|
|
}
|
|
```
|
|
|
|
## Server Communication
|
|
|
|
For advanced use cases, communicate with the frontend:
|
|
|
|
```python
|
|
from server import PromptServer
|
|
|
|
def process_image(self, image):
|
|
# Send message to frontend
|
|
PromptServer.instance.send_sync(
|
|
"my_node.message",
|
|
{"text": "Processing complete", "node_id": unique_id}
|
|
)
|
|
return (image,)
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
- Learn about [Data Types and Type Conversion](./03-data-types.md)
|
|
- Explore [Advanced Features](./04-advanced-features.md)
|
|
- See [Example Implementations](./05-examples.md) |