Compare commits

...

11 Commits

Author SHA1 Message Date
zhaog100
b9dbe97cc9
Merge eea02607fc into b08debceca 2026-07-06 17:34:08 +08:00
Daxiong (Lin)
b08debceca
chore: update embedded docs to v0.5.7 (#14783)
Some checks failed
Detect Unreviewed Merge / detect (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Waiting to run
Execution Tests / test (macos-latest) (push) Waiting to run
Execution Tests / test (ubuntu-latest) (push) Waiting to run
Execution Tests / test (windows-latest) (push) Waiting to run
Test server launches without errors / test (push) Waiting to run
Unit Tests / test (macos-latest) (push) Waiting to run
Unit Tests / test (ubuntu-latest) (push) Waiting to run
Unit Tests / test (windows-2022) (push) Waiting to run
Build package / Build Test (3.10) (push) Has been cancelled
Build package / Build Test (3.11) (push) Has been cancelled
Build package / Build Test (3.12) (push) Has been cancelled
Build package / Build Test (3.13) (push) Has been cancelled
Build package / Build Test (3.14) (push) Has been cancelled
2026-07-06 09:56:09 +08:00
comfyanonymous
000c6b784e
Small speedup for text model sampling. (#14773) 2026-07-05 18:39:24 -07:00
Alexander Piskun
985fb9d6ad
[Partner Nodes] fix(logs-auth): mask authorization headers in logs (#14774)
Some checks failed
Detect Unreviewed Merge / detect (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Waiting to run
Execution Tests / test (macos-latest) (push) Waiting to run
Execution Tests / test (ubuntu-latest) (push) Waiting to run
Execution Tests / test (windows-latest) (push) Waiting to run
Test server launches without errors / test (push) Waiting to run
Unit Tests / test (macos-latest) (push) Waiting to run
Unit Tests / test (ubuntu-latest) (push) Waiting to run
Unit Tests / test (windows-2022) (push) Waiting to run
Generate Pydantic Stubs from api.comfy.org / generate-models (push) Has been cancelled
Signed-off-by: bigcat88 <bigcat88@icloud.com>
2026-07-05 13:55:29 +03:00
Alexis Rolland
7f287b705e
fix: Bug when setting transparency in color picker (#14764)
Some checks are pending
Detect Unreviewed Merge / detect (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Waiting to run
Execution Tests / test (macos-latest) (push) Waiting to run
Execution Tests / test (ubuntu-latest) (push) Waiting to run
Execution Tests / test (windows-latest) (push) Waiting to run
Test server launches without errors / test (push) Waiting to run
Unit Tests / test (macos-latest) (push) Waiting to run
Unit Tests / test (ubuntu-latest) (push) Waiting to run
Unit Tests / test (windows-2022) (push) Waiting to run
2026-07-04 19:13:38 -04:00
comfyanonymous
b7ba504e06
Try to make coderabbit enforce AGENTS.md (#14759)
Some checks are pending
Detect Unreviewed Merge / detect (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Waiting to run
Execution Tests / test (macos-latest) (push) Waiting to run
Execution Tests / test (ubuntu-latest) (push) Waiting to run
Execution Tests / test (windows-latest) (push) Waiting to run
Test server launches without errors / test (push) Waiting to run
Unit Tests / test (macos-latest) (push) Waiting to run
Unit Tests / test (ubuntu-latest) (push) Waiting to run
Unit Tests / test (windows-2022) (push) Waiting to run
2026-07-04 14:25:24 -04:00
Silver
6c62ca0b6b
fix: error when embedding is loaded with models using llama_template (#14744)
Some checks are pending
Detect Unreviewed Merge / detect (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Waiting to run
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Waiting to run
Execution Tests / test (macos-latest) (push) Waiting to run
Execution Tests / test (ubuntu-latest) (push) Waiting to run
Execution Tests / test (windows-latest) (push) Waiting to run
Test server launches without errors / test (push) Waiting to run
Unit Tests / test (macos-latest) (push) Waiting to run
Unit Tests / test (ubuntu-latest) (push) Waiting to run
Unit Tests / test (windows-2022) (push) Waiting to run
2026-07-04 17:06:09 +08:00
zhaog100
eea02607fc fix: relax JSON Schema constraints (same as #13094 fix)
- Remove strict node ID regex, allow any string key
- Change node additionalProperties to true

Addresses coderabbit Major review on #13095
2026-03-22 13:29:29 +08:00
zhaog100
2985bc933b fix: sanitize history items stored as tuple/list format
History items store prompt data as (output, inputs, extra_data, ...)
tuple/list format, not as a dict. The sanitizer now handles both
formats to properly strip SENSITIVE_EXTRA_DATA_KEYS.

Fixes coderabbit Critical review on #13095
2026-03-22 12:58:01 +08:00
zhaog100
87b7f4fcd6 fix: remove sensitive tokens from history items
Sanitize history items returned by get_history() to strip
auth_token_comfy_org and api_key_comfy_org from prompt inputs.
This prevents tokens from being exposed if history is ever
persisted to disk or accessed over open networks.

Closes #8889
2026-03-22 03:59:13 +08:00
zhaog100
bdead4bc04 Add JSON Schema for Prompt API Format
Closes #8899

- schemas/prompt.json: Draft-07 JSON Schema documenting the prompt format
  - Node objects with class_type (required), inputs (required), _meta (optional)
  - Node links as [source_id, output_index] arrays
  - Self-validating examples included in schema
- docs/api/prompt-schema.md: Documentation with validation rules, examples,
  and common error types

Based on analysis of execution.py:validate_prompt() and server.py
2026-03-22 03:53:01 +08:00
9 changed files with 330 additions and 28 deletions

View File

@ -4,12 +4,12 @@ early_access: false
tone_instructions: "Only comment on issues introduced by this PR's changes. Do not flag pre-existing problems in moved, re-indented, or reformatted code."
reviews:
profile: "chill"
request_changes_workflow: false
profile: "assertive"
request_changes_workflow: true
high_level_summary: false
poem: false
review_status: false
review_details: false
review_details: true
commit_status: true
collapse_walkthrough: true
changed_files_summary: false
@ -39,6 +39,14 @@ reviews:
- path: "**"
instructions: |
IMPORTANT: Only comment on issues directly introduced by this PR's code changes.
Treat AGENTS.md as mandatory repository policy, not optional style guidance.
Flag PR changes that violate AGENTS.md even when the code is otherwise functional.
In particular, enforce architecture boundaries, dtype/device/memory rules,
interface contracts, import style, no unnecessary try/except blocks, no inline
imports, no outbound internet paths in core ComfyUI, and narrow scoped fixes.
Prefer direct findings over suggestions when a rule is violated. Only ignore
AGENTS.md when it clearly conflicts with a newer explicit maintainer instruction
in the PR.
Do NOT flag pre-existing issues in code that was merely moved, re-indented,
de-indented, or reformatted without logic changes. If code appears in the diff
only due to whitespace or structural reformatting (e.g., removing a `with:` block),
@ -123,5 +131,10 @@ chat:
knowledge_base:
opt_out: false
code_guidelines:
enabled: true
filePatterns:
- files: "AGENTS.md"
applyTo: "**"
learnings:
scope: "auto"

View File

@ -543,18 +543,24 @@ class SDTokenizer:
def _try_get_embedding(self, embedding_name:str):
'''
Takes a potential embedding name and tries to retrieve it.
Returns a Tuple consisting of the embedding and any leftover string, embedding can be None.
Returns a Tuple consisting of the embedding, the cleaned embedding name, and any leftover string, embedding can be None.
'''
split_embed = embedding_name.split()
embedding_name = split_embed[0]
leftover = ' '.join(split_embed[1:])
match = re.search(r'[<\[]', embedding_name)
if match is not None:
leftover = embedding_name[match.start():] + (" " + leftover if leftover else "")
embedding_name = embedding_name[:match.start()]
embed = load_embed(embedding_name, self.embedding_directory, self.embedding_size, self.embedding_key)
if embed is None:
stripped = embedding_name.strip(',')
if len(stripped) < len(embedding_name):
embed = load_embed(stripped, self.embedding_directory, self.embedding_size, self.embedding_key)
return (embed, "{} {}".format(embedding_name[len(stripped):], leftover))
return (embed, leftover)
return (embed, embedding_name, "{} {}".format(embedding_name[len(stripped):], leftover))
return (embed, embedding_name, leftover)
def pad_tokens(self, tokens, amount):
if self.pad_left:
@ -585,7 +591,7 @@ class SDTokenizer:
tokens = []
for weighted_segment, weight in parsed_weights:
to_tokenize = unescape_important(weighted_segment)
split = re.split(' {0}|\n{0}'.format(self.embedding_identifier), to_tokenize)
split = re.split(r'(?<=\s){}'.format(re.escape(self.embedding_identifier)), to_tokenize)
to_tokenize = [split[0]]
for i in range(1, len(split)):
to_tokenize.append("{}{}".format(self.embedding_identifier, split[i]))
@ -595,7 +601,7 @@ class SDTokenizer:
# if we find an embedding, deal with the embedding
if word.startswith(self.embedding_identifier) and self.embedding_directory is not None:
embedding_name = word[len(self.embedding_identifier):].strip('\n')
embed, leftover = self._try_get_embedding(embedding_name)
embed, embedding_name, leftover = self._try_get_embedding(embedding_name)
if embed is None:
logging.warning(f"warning, embedding:{embedding_name} does not exist, ignoring")
else:

View File

@ -937,22 +937,41 @@ class BaseGenerate:
return torch.argmax(logits, dim=-1, keepdim=True)
# Sampling mode
if repetition_penalty != 1.0:
for i in range(logits.shape[0]):
for token_id in set(token_history):
logits[i, token_id] *= repetition_penalty if logits[i, token_id] < 0 else 1/repetition_penalty
if presence_penalty is not None and presence_penalty != 0.0:
for i in range(logits.shape[0]):
for token_id in set(token_history):
logits[i, token_id] -= presence_penalty
if len(token_history) > 0 and (repetition_penalty != 1.0 or (presence_penalty is not None and presence_penalty != 0.0)):
token_ids = torch.tensor(list(set(token_history)), device=logits.device)
token_logits = logits[:, token_ids]
if repetition_penalty != 1.0:
token_logits = torch.where(token_logits < 0, token_logits * repetition_penalty, token_logits / repetition_penalty)
if presence_penalty is not None and presence_penalty != 0.0:
token_logits = token_logits - presence_penalty
logits[:, token_ids] = token_logits
if temperature != 1.0:
logits = logits / temperature
if top_k > 0:
indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None]
logits[indices_to_remove] = torch.finfo(logits.dtype).min
top_k = min(top_k, logits.shape[-1])
logits, top_indices = torch.topk(logits, top_k)
if min_p > 0.0:
probs_before_filter = torch.nn.functional.softmax(logits, dim=-1)
top_probs, _ = probs_before_filter.max(dim=-1, keepdim=True)
min_threshold = min_p * top_probs
indices_to_remove = probs_before_filter < min_threshold
logits[indices_to_remove] = torch.finfo(logits.dtype).min
if top_p < 1.0:
sorted_logits, sorted_indices = torch.sort(logits, descending=True)
cumulative_probs = torch.cumsum(torch.nn.functional.softmax(sorted_logits, dim=-1), dim=-1)
sorted_indices_to_remove = cumulative_probs > top_p
sorted_indices_to_remove[..., 0] = False
indices_to_remove = torch.zeros_like(logits, dtype=torch.bool)
indices_to_remove.scatter_(1, sorted_indices, sorted_indices_to_remove)
logits[indices_to_remove] = torch.finfo(logits.dtype).min
probs = torch.nn.functional.softmax(logits, dim=-1)
next_token = torch.multinomial(probs, num_samples=1, generator=generator)
return top_indices.gather(1, next_token)
if min_p > 0.0:
probs_before_filter = torch.nn.functional.softmax(logits, dim=-1)

View File

@ -9,6 +9,7 @@ from typing import Any
import folder_paths
logger = logging.getLogger(__name__)
_SENSITIVE_HEADERS = {"authorization", "x-api-key"}
def get_log_directory():
@ -73,6 +74,10 @@ def _format_data_for_logging(data: Any) -> str:
return str(data)
def _redact_headers(headers: dict) -> dict:
return {k: ("***" if k.lower() in _SENSITIVE_HEADERS else v) for k, v in headers.items()}
def log_request_response(
operation_id: str,
request_method: str,
@ -101,7 +106,7 @@ def log_request_response(
log_content.append(f"Method: {request_method}")
log_content.append(f"URL: {request_url}")
if request_headers:
log_content.append(f"Headers:\n{_format_data_for_logging(request_headers)}")
log_content.append(f"Headers:\n{_format_data_for_logging(_redact_headers(request_headers))}")
if request_params:
log_content.append(f"Params:\n{_format_data_for_logging(request_params)}")
if request_data is not None:

View File

@ -16,23 +16,30 @@ class ColorToRGBInt(io.ComfyNode):
],
outputs=[
io.Int.Output(display_name="rgb_int"),
io.Color.Output(display_name="hex")
io.Color.Output(display_name="hex"),
io.Float.Output(display_name="alpha"),
],
)
@classmethod
def execute(cls, color: str) -> io.NodeOutput:
# expect format #RRGGBB
if len(color) != 7 or color[0] != "#":
raise ValueError("Color must be in format #RRGGBB")
# expect format #RRGGBB or #RRGGBBAA
if len(color) not in (7, 9) or color[0] != "#":
raise ValueError("Color must be in format #RRGGBB or #RRGGBBAA")
try:
int(color[1:], 16)
except ValueError:
raise ValueError("Color must be in format #RRGGBB") from None
raise ValueError("Color must be in format #RRGGBB or #RRGGBBAA") from None
alpha = 1.0
if len(color) == 9:
alpha = int(color[7:9], 16) / 255.0
color = color[:7]
r, g, b = hex_to_rgb(color)
rgb_int = r * 256 * 256 + g * 256 + b
return io.NodeOutput(rgb_int, color)
return io.NodeOutput(rgb_int, color, alpha)
class ColorExtension(ComfyExtension):

137
docs/api/prompt-schema.md Normal file
View File

@ -0,0 +1,137 @@
# ComfyUI Prompt API Schema
This document describes the JSON format used by the `/prompt` endpoint in ComfyUI.
## Overview
A ComfyUI prompt is a JSON object where:
- **Keys** are unique node IDs (arbitrary strings, typically numeric)
- **Values** are node objects containing `class_type`, `inputs`, and optional `_meta`
## Format Specification
### Node Object
```json
{
"class_type": "KSampler",
"inputs": {
"seed": 123456,
"steps": 20,
"model": ["4", 0]
},
"_meta": {
"title": "My KSampler"
}
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `class_type` | string | ✅ | Must match a registered node class in `NODE_CLASS_MAPPINGS` |
| `inputs` | object | ✅ | Input parameters for the node |
| `_meta` | object | ❌ | UI metadata (display title, position, etc.) |
### Input Values
Each input can be one of two types:
#### Direct Value
Any JSON-serializable value:
```json
{"seed": 123456, "steps": 20, "cfg": 7.0, "width": 512}
```
#### Node Link (Output Reference)
A 2-element array `[source_node_id, output_index]`:
```json
{"model": ["4", 0], "positive": ["6", 0]}
```
### Validation Rules
Based on `execution.py:validate_prompt()`:
1. Every node **must** have a `class_type` field
2. `class_type` **must** reference a registered node (existing in `NODE_CLASS_MAPPINGS`)
3. The prompt **must** contain at least one `OUTPUT_NODE`
4. All linked inputs must reference valid node IDs and output indices
5. Required inputs for each node class must be provided
### Common Error Types
| Type | Description |
|------|-------------|
| `missing_node_type` | Node has no `class_type` or class not found |
| `prompt_no_outputs` | No OUTPUT_NODE found in the prompt |
## Validation
Use the JSON Schema to validate prompts:
```bash
# Using ajv-cli
npx ajv validate -s schemas/prompt.json -d my_prompt.json
# Using Python
pip install jsonschema
python -c "
import json, jsonschema
with open('schemas/prompt.json') as f:
schema = json.load(f)
with open('my_prompt.json') as f:
prompt = json.load(f)
jsonschema.validate(prompt, schema)
print('Valid!')
"
```
## Minimal Example
```json
{
"1": {
"class_type": "CheckpointLoaderSimple",
"inputs": {"ckpt_name": "model.safetensors"}
},
"2": {
"class_type": "CLIPTextEncode",
"inputs": {"text": "hello world", "clip": ["1", 1]}
},
"3": {
"class_type": "EmptyLatentImage",
"inputs": {"width": 512, "height": 512, "batch_size": 1}
},
"4": {
"class_type": "KSampler",
"inputs": {
"seed": 0, "steps": 20, "cfg": 7,
"sampler_name": "euler", "scheduler": "normal",
"denoise": 1, "model": ["1", 0],
"positive": ["2", 0], "negative": ["2", 0],
"latent_image": ["3", 0]
}
},
"5": {
"class_type": "VAEDecode",
"inputs": {"samples": ["4", 0], "vae": ["1", 2]}
},
"6": {
"class_type": "SaveImage",
"inputs": {"filename_prefix": "test", "images": ["5", 0]}
}
}
```
## Workflow vs Prompt Format
The **prompt format** (this schema) is the compact API format used by `/prompt`.
The **workflow format** is the UI serialization format that includes additional layout data, group information, and node positions. Workflows are converted to prompts before execution.
## Future Enhancements
This schema documents the current static format. Future versions may include:
- Per-node schemas with required/optional input definitions
- Dynamic schema generation based on installed custom nodes
- LLM-friendly structured output definitions

View File

@ -1349,7 +1349,31 @@ class PromptQueue:
return True
return False
def _sanitize_history_item(self, item: dict) -> dict:
"""Remove sensitive keys from prompt inputs in history items.
Prevents tokens from being exposed if history is ever persisted to disk."""
item = copy.deepcopy(item)
prompt_item = item.get("prompt")
if isinstance(prompt_item, dict):
for node_id, node_data in prompt_item.items():
if isinstance(node_data, dict):
inputs = node_data.get("inputs", {})
if isinstance(inputs, dict):
for key in SENSITIVE_EXTRA_DATA_KEYS:
inputs.pop(key, None)
elif isinstance(prompt_item, (list, tuple)) and len(prompt_item) > 2:
prompt_graph = prompt_item[2] if isinstance(prompt_item[2], dict) else None
if isinstance(prompt_graph, dict):
for node_data in prompt_graph.values():
if isinstance(node_data, dict):
inputs = node_data.get("inputs")
if isinstance(inputs, dict):
for key in SENSITIVE_EXTRA_DATA_KEYS:
inputs.pop(key, None)
return item
def get_history(self, prompt_id=None, max_items=None, offset=-1, map_function=None):
sanitize = self._sanitize_history_item
with self.mutex:
if prompt_id is None:
out = {}
@ -1361,6 +1385,8 @@ class PromptQueue:
p = self.history[k]
if map_function is not None:
p = map_function(p)
else:
p = sanitize(p)
out[k] = p
if max_items is not None and len(out) >= max_items:
break
@ -1369,7 +1395,7 @@ class PromptQueue:
elif prompt_id in self.history:
p = self.history[prompt_id]
if map_function is None:
p = copy.deepcopy(p)
p = sanitize(p)
else:
p = map_function(p)
return {prompt_id: p}

View File

@ -1,6 +1,6 @@
comfyui-frontend-package==1.45.20
comfyui-workflow-templates==0.11.2
comfyui-embedded-docs==0.5.6
comfyui-embedded-docs==0.5.7
torch
torchsde
torchvision

89
schemas/prompt.json Normal file
View File

@ -0,0 +1,89 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://github.com/Comfy-Org/ComfyUI/blob/main/schemas/prompt.json",
"title": "ComfyUI Prompt Format",
"description": "JSON Schema for the ComfyUI /prompt endpoint. Each key is a unique node ID, and each value describes a node with its class_type, inputs, and optional metadata.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/node"
},
"definitions": {
"node": {
"type": "object",
"required": ["class_type", "inputs"],
"properties": {
"class_type": {
"type": "string",
"description": "The node class to instantiate. Must match a key in NODE_CLASS_MAPPINGS."
},
"inputs": {
"$ref": "#/definitions/inputs"
},
"_meta": {
"type": "object",
"description": "Optional UI metadata for a node.",
"properties": {
"title": {
"type": "string",
"description": "Display title for the node in the UI."
}
}
}
},
"additionalProperties": true
},
"inputs": {
"type": "object",
"description": "Node inputs. Keys are parameter names. Values are either direct values or node links [source_id, output_index].",
"additionalProperties": true
},
"node_link": {
"type": "array",
"description": "A link to another node's output.",
"items": [
{"type": "string", "description": "Source node ID"},
{"type": "integer", "description": "Output index of the source node"}
],
"minItems": 2,
"maxItems": 2
}
},
"examples": [
{
"4": {
"class_type": "CheckpointLoaderSimple",
"inputs": {"ckpt_name": "v1-5-pruned-emaonly.safetensors"}
},
"5": {
"class_type": "EmptyLatentImage",
"inputs": {"width": 512, "height": 512, "batch_size": 1}
},
"6": {
"class_type": "CLIPTextEncode",
"inputs": {"text": "a beautiful landscape", "clip": ["4", 1]}
},
"7": {
"class_type": "CLIPTextEncode",
"inputs": {"text": "ugly, blurry", "clip": ["4", 1]}
},
"3": {
"class_type": "KSampler",
"inputs": {
"seed": 123456, "steps": 20, "cfg": 7.0,
"sampler_name": "euler", "scheduler": "normal", "denoise": 1.0,
"model": ["4", 0], "positive": ["6", 0], "negative": ["7", 0],
"latent_image": ["5", 0]
}
},
"8": {
"class_type": "VAEDecode",
"inputs": {"samples": ["3", 0], "vae": ["4", 2]},
"_meta": {"title": "VAE Decode"}
},
"9": {
"class_type": "SaveImage",
"inputs": {"filename_prefix": "ComfyUI", "images": ["8", 0]}
}
}
]
}