mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-07-20 21:38:30 +08:00
Merge branch 'master' into fix/3d-advanced-api-mode
This commit is contained in:
commit
0ba1243492
@ -15,24 +15,24 @@ def make_two_pass_attention(ar_len: int, transformer_options=None):
|
|||||||
The AR pass goes through SDPA directand bypasses wrappers, it is only ~1% of T at typical edit sizes.
|
The AR pass goes through SDPA directand bypasses wrappers, it is only ~1% of T at typical edit sizes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def two_pass_attention(q, k, v, heads, **kwargs):
|
def two_pass_attention(q, k, v, heads, enable_gqa=False, **kwargs):
|
||||||
B, H, T, D = q.shape
|
B, H, T, D = q.shape
|
||||||
|
|
||||||
if T < k.shape[2]: # KV-cache hot path: Q is shorter than K/V (cached AR prefix is in K/V only), all fresh Q positions are in the gen region, single full-attention call
|
if T < k.shape[2]: # KV-cache hot path: Q is shorter than K/V (cached AR prefix is in K/V only), all fresh Q positions are in the gen region, single full-attention call
|
||||||
out = optimized_attention(q, k, v, heads, mask=None, skip_reshape=True, skip_output_reshape=True, transformer_options=transformer_options)
|
out = optimized_attention(q, k, v, heads, mask=None, skip_reshape=True, skip_output_reshape=True, transformer_options=transformer_options, enable_gqa=enable_gqa)
|
||||||
elif ar_len >= T:
|
elif ar_len >= T:
|
||||||
out = comfy.ops.scaled_dot_product_attention(q, k, v, attn_mask=None, dropout_p=0.0, is_causal=True)
|
out = comfy.ops.scaled_dot_product_attention(q, k, v, attn_mask=None, dropout_p=0.0, is_causal=True, enable_gqa=enable_gqa)
|
||||||
elif ar_len <= 0:
|
elif ar_len <= 0:
|
||||||
out = optimized_attention(q, k, v, heads, mask=None, skip_reshape=True, skip_output_reshape=True, transformer_options=transformer_options)
|
out = optimized_attention(q, k, v, heads, mask=None, skip_reshape=True, skip_output_reshape=True, transformer_options=transformer_options, enable_gqa=enable_gqa)
|
||||||
else:
|
else:
|
||||||
out_ar = comfy.ops.scaled_dot_product_attention(
|
out_ar = comfy.ops.scaled_dot_product_attention(
|
||||||
q[:, :, :ar_len], k[:, :, :ar_len], v[:, :, :ar_len],
|
q[:, :, :ar_len], k[:, :, :ar_len], v[:, :, :ar_len],
|
||||||
attn_mask=None, dropout_p=0.0, is_causal=True,
|
attn_mask=None, dropout_p=0.0, is_causal=True, enable_gqa=enable_gqa,
|
||||||
)
|
)
|
||||||
out_gen = optimized_attention(
|
out_gen = optimized_attention(
|
||||||
q[:, :, ar_len:], k, v, heads,
|
q[:, :, ar_len:], k, v, heads,
|
||||||
mask=None, skip_reshape=True, skip_output_reshape=True,
|
mask=None, skip_reshape=True, skip_output_reshape=True,
|
||||||
transformer_options=transformer_options,
|
transformer_options=transformer_options, enable_gqa=enable_gqa,
|
||||||
)
|
)
|
||||||
out = torch.cat([out_ar, out_gen], dim=2)
|
out = torch.cat([out_ar, out_gen], dim=2)
|
||||||
|
|
||||||
|
|||||||
@ -1133,7 +1133,9 @@ class GeminiImage2(IO.ComfyNode):
|
|||||||
) -> IO.NodeOutput:
|
) -> IO.NodeOutput:
|
||||||
validate_string(prompt, strip_whitespace=True, min_length=1)
|
validate_string(prompt, strip_whitespace=True, min_length=1)
|
||||||
if model == "Nano Banana 2 (Gemini 3.1 Flash Image)":
|
if model == "Nano Banana 2 (Gemini 3.1 Flash Image)":
|
||||||
model = "gemini-3.1-flash-image-preview"
|
model = "gemini-3.1-flash-image"
|
||||||
|
elif model == "gemini-3-pro-image-preview":
|
||||||
|
model = "gemini-3-pro-image"
|
||||||
|
|
||||||
parts: list[GeminiPart] = [GeminiPart(text=prompt)]
|
parts: list[GeminiPart] = [GeminiPart(text=prompt)]
|
||||||
if images is not None:
|
if images is not None:
|
||||||
@ -1507,7 +1509,7 @@ class GeminiNanoBanana2V2(IO.ComfyNode):
|
|||||||
validate_string(prompt, strip_whitespace=True, min_length=1)
|
validate_string(prompt, strip_whitespace=True, min_length=1)
|
||||||
model_choice = model["model"]
|
model_choice = model["model"]
|
||||||
if model_choice == "Nano Banana 2 (Gemini 3.1 Flash Image)":
|
if model_choice == "Nano Banana 2 (Gemini 3.1 Flash Image)":
|
||||||
model_id = "gemini-3.1-flash-image-preview"
|
model_id = "gemini-3.1-flash-image"
|
||||||
elif model_choice == "Nano Banana 2 Lite":
|
elif model_choice == "Nano Banana 2 Lite":
|
||||||
model_id = "gemini-3.1-flash-lite-image"
|
model_id = "gemini-3.1-flash-lite-image"
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -15,6 +15,7 @@ from comfy.comfy_api_env import normalize_comfy_api_base
|
|||||||
from comfy.deploy_environment import get_deploy_environment
|
from comfy.deploy_environment import get_deploy_environment
|
||||||
from comfy.model_management import processing_interrupted
|
from comfy.model_management import processing_interrupted
|
||||||
from comfy_api.latest import IO
|
from comfy_api.latest import IO
|
||||||
|
from comfyui_version import __version__ as comfyui_version
|
||||||
|
|
||||||
from .common_exceptions import ProcessingInterrupted
|
from .common_exceptions import ProcessingInterrupted
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ def get_comfy_api_headers(node_cls: type[IO.ComfyNode]) -> dict[str, str]:
|
|||||||
**get_auth_header(node_cls),
|
**get_auth_header(node_cls),
|
||||||
"Comfy-Env": get_deploy_environment(),
|
"Comfy-Env": get_deploy_environment(),
|
||||||
"Comfy-Usage-Source": get_usage_source(node_cls),
|
"Comfy-Usage-Source": get_usage_source(node_cls),
|
||||||
|
"Comfy-Core-Version": comfyui_version,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -844,15 +844,18 @@ class ImageMergeTileList(IO.ComfyNode):
|
|||||||
# Format specifications
|
# Format specifications
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
# Maps (file_format, bit_depth, has_alpha) -> (numpy dtype scale, av pixel format,
|
# Maps (file_format, bit_depth, num_channels) -> (quantization scale, numpy dtype,
|
||||||
# stream pix_fmt). Keeps the encode path declarative instead of branchy.
|
# av frame pix_fmt, stream pix_fmt). Keeps the encode path declarative instead of branchy.
|
||||||
_FORMAT_SPECS = {
|
_FORMAT_SPECS = {
|
||||||
("png", "8-bit", False): {"scale": 255.0, "dtype": np.uint8, "frame_fmt": "rgb24", "stream_fmt": "rgb24"},
|
("png", "8-bit", 1): {"scale": 255.0, "dtype": np.uint8, "frame_fmt": "gray", "stream_fmt": "gray"},
|
||||||
("png", "8-bit", True): {"scale": 255.0, "dtype": np.uint8, "frame_fmt": "rgba", "stream_fmt": "rgba"},
|
("png", "8-bit", 3): {"scale": 255.0, "dtype": np.uint8, "frame_fmt": "rgb24", "stream_fmt": "rgb24"},
|
||||||
("png", "16-bit", False): {"scale": 65535.0, "dtype": np.uint16, "frame_fmt": "rgb48le", "stream_fmt": "rgb48be"},
|
("png", "8-bit", 4): {"scale": 255.0, "dtype": np.uint8, "frame_fmt": "rgba", "stream_fmt": "rgba"},
|
||||||
("png", "16-bit", True): {"scale": 65535.0, "dtype": np.uint16, "frame_fmt": "rgba64le", "stream_fmt": "rgba64be"},
|
("png", "16-bit", 1): {"scale": 65535.0, "dtype": np.uint16, "frame_fmt": "gray16le", "stream_fmt": "gray16be"},
|
||||||
("exr", "32-bit float", False): {"scale": 1.0, "dtype": np.float32, "frame_fmt": "gbrpf32le", "stream_fmt": "gbrpf32le"},
|
("png", "16-bit", 3): {"scale": 65535.0, "dtype": np.uint16, "frame_fmt": "rgb48le", "stream_fmt": "rgb48be"},
|
||||||
("exr", "32-bit float", True): {"scale": 1.0, "dtype": np.float32, "frame_fmt": "gbrapf32le", "stream_fmt": "gbrapf32le"},
|
("png", "16-bit", 4): {"scale": 65535.0, "dtype": np.uint16, "frame_fmt": "rgba64le", "stream_fmt": "rgba64be"},
|
||||||
|
("exr", "32-bit float", 1): {"scale": 1.0, "dtype": np.float32, "frame_fmt": "grayf32le", "stream_fmt": "grayf32le"},
|
||||||
|
("exr", "32-bit float", 3): {"scale": 1.0, "dtype": np.float32, "frame_fmt": "gbrpf32le", "stream_fmt": "gbrpf32le"},
|
||||||
|
("exr", "32-bit float", 4): {"scale": 1.0, "dtype": np.float32, "frame_fmt": "gbrapf32le", "stream_fmt": "gbrapf32le"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -891,10 +894,11 @@ def hlg_to_linear(t: torch.Tensor) -> torch.Tensor:
|
|||||||
return torch.cat([hlg_to_linear(rgb), alpha], dim=-1)
|
return torch.cat([hlg_to_linear(rgb), alpha], dim=-1)
|
||||||
|
|
||||||
# Piecewise: sqrt branch below 0.5, log branch above.
|
# Piecewise: sqrt branch below 0.5, log branch above.
|
||||||
# Clamp inside the log branch so negative / out-of-range values don't blow up;
|
# Clamp the log branch at the 0.5 branch point (not above it) so the
|
||||||
|
# unselected lane stays finite in exp() without altering selected values;
|
||||||
# values above 1.0 are allowed and extrapolate naturally.
|
# values above 1.0 are allowed and extrapolate naturally.
|
||||||
low = (t ** 2) / 3.0
|
low = (t ** 2) / 3.0
|
||||||
high = (torch.exp((t.clamp(min=_HLG_C) - _HLG_C) / _HLG_A) + _HLG_B) / 12.0
|
high = (torch.exp((t.clamp(min=0.5) - _HLG_C) / _HLG_A) + _HLG_B) / 12.0
|
||||||
return torch.where(t <= 0.5, low, high)
|
return torch.where(t <= 0.5, low, high)
|
||||||
|
|
||||||
|
|
||||||
@ -1087,7 +1091,8 @@ def _encode_image(
|
|||||||
bit_depth: str,
|
bit_depth: str,
|
||||||
colorspace: str,
|
colorspace: str,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
"""Encode a single HxWxC tensor to PNG or EXR bytes in memory.
|
"""Encode a single HxWxC (or channel-less HxW grayscale) tensor to PNG or
|
||||||
|
EXR bytes in memory. Grayscale is written as single-channel PNG / Y-only EXR.
|
||||||
|
|
||||||
For EXR the input is interpreted according to `colorspace` and converted
|
For EXR the input is interpreted according to `colorspace` and converted
|
||||||
to scene-linear (EXR's convention) before writing:
|
to scene-linear (EXR's convention) before writing:
|
||||||
@ -1101,10 +1106,16 @@ def _encode_image(
|
|||||||
For PNG, colorspace selection does not modify pixels — PNG is delivered
|
For PNG, colorspace selection does not modify pixels — PNG is delivered
|
||||||
sRGB-encoded and there is no PNG path for wide-gamut HDR in this node.
|
sRGB-encoded and there is no PNG path for wide-gamut HDR in this node.
|
||||||
"""
|
"""
|
||||||
|
if img_tensor.ndim == 2:
|
||||||
|
img_tensor = img_tensor.unsqueeze(-1) # Some nodes emit grayscale as (H, W) with no channel dim, mask-style.
|
||||||
height, width, num_channels = img_tensor.shape
|
height, width, num_channels = img_tensor.shape
|
||||||
has_alpha = num_channels == 4
|
|
||||||
|
|
||||||
spec = _FORMAT_SPECS[(file_format, bit_depth, has_alpha)]
|
spec = _FORMAT_SPECS.get((file_format, bit_depth, num_channels))
|
||||||
|
if spec is None:
|
||||||
|
raise ValueError(
|
||||||
|
f"No {file_format}/{bit_depth} encoder for {num_channels}-channel images: "
|
||||||
|
"supported channel counts are 1 (grayscale), 3 (RGB) and 4 (RGBA)."
|
||||||
|
)
|
||||||
|
|
||||||
if spec["dtype"] == np.float32:
|
if spec["dtype"] == np.float32:
|
||||||
# EXR path: preserve full range, no clamp.
|
# EXR path: preserve full range, no clamp.
|
||||||
|
|||||||
45
openapi.yaml
45
openapi.yaml
@ -7,18 +7,18 @@ components:
|
|||||||
description: Timestamp when the asset was created
|
description: Timestamp when the asset was created
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
|
display_name:
|
||||||
|
description: Display name of the asset. Mirrors name for backwards compatibility.
|
||||||
|
nullable: true
|
||||||
|
type: string
|
||||||
|
file_path:
|
||||||
|
description: Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors")
|
||||||
|
nullable: true
|
||||||
|
type: string
|
||||||
hash:
|
hash:
|
||||||
description: Blake3 hash of the asset content.
|
description: Blake3 hash of the asset content.
|
||||||
pattern: ^blake3:[a-f0-9]{64}$
|
pattern: ^blake3:[a-f0-9]{64}$
|
||||||
type: string
|
type: string
|
||||||
loader_path:
|
|
||||||
description: The value a loader consumes to load this asset. Null when no loader can resolve the file.
|
|
||||||
nullable: true
|
|
||||||
type: string
|
|
||||||
display_name:
|
|
||||||
description: Human-facing label for the asset. Not unique.
|
|
||||||
nullable: true
|
|
||||||
type: string
|
|
||||||
id:
|
id:
|
||||||
description: Unique identifier for the asset
|
description: Unique identifier for the asset
|
||||||
format: uuid
|
format: uuid
|
||||||
@ -144,6 +144,14 @@ components:
|
|||||||
AssetUpdated:
|
AssetUpdated:
|
||||||
description: Response returned when an existing asset is successfully updated.
|
description: Response returned when an existing asset is successfully updated.
|
||||||
properties:
|
properties:
|
||||||
|
display_name:
|
||||||
|
description: Display name of the asset. Mirrors name for backwards compatibility.
|
||||||
|
nullable: true
|
||||||
|
type: string
|
||||||
|
file_path:
|
||||||
|
description: Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors")
|
||||||
|
nullable: true
|
||||||
|
type: string
|
||||||
hash:
|
hash:
|
||||||
description: Blake3 hash of the asset content.
|
description: Blake3 hash of the asset content.
|
||||||
pattern: ^blake3:[a-f0-9]{64}$
|
pattern: ^blake3:[a-f0-9]{64}$
|
||||||
@ -775,14 +783,6 @@ components:
|
|||||||
ModelFolder:
|
ModelFolder:
|
||||||
description: Represents a folder containing models
|
description: Represents a folder containing models
|
||||||
properties:
|
properties:
|
||||||
extensions:
|
|
||||||
description: The folder's registered file-extension allowlist. An empty array means the folder accepts any extension (match-all).
|
|
||||||
example:
|
|
||||||
- .ckpt
|
|
||||||
- .safetensors
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
folders:
|
folders:
|
||||||
description: List of paths where models of this type are stored
|
description: List of paths where models of this type are stored
|
||||||
example:
|
example:
|
||||||
@ -1644,7 +1644,7 @@ paths:
|
|||||||
format: uuid
|
format: uuid
|
||||||
type: string
|
type: string
|
||||||
tags:
|
tags:
|
||||||
description: JSON-encoded array of tag strings. For new byte uploads, include exactly one destination role (`input`, `output`, or `models`); `models` uploads also require exactly one `model_type:<folder_name>` tag. Extra tags are stored as labels and do not create path components.
|
description: JSON-encoded array of freeform tag strings, e.g. '["models","checkpoint"]'. Common types include "models", "input", "output", and "temp", but any tag can be used in any order.
|
||||||
type: string
|
type: string
|
||||||
user_metadata:
|
user_metadata:
|
||||||
description: Custom JSON metadata as a string
|
description: Custom JSON metadata as a string
|
||||||
@ -1829,7 +1829,7 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/Asset'
|
$ref: '#/components/schemas/AssetUpdated'
|
||||||
description: Asset updated successfully
|
description: Asset updated successfully
|
||||||
"400":
|
"400":
|
||||||
content:
|
content:
|
||||||
@ -2470,9 +2470,6 @@ paths:
|
|||||||
supports_preview_metadata:
|
supports_preview_metadata:
|
||||||
description: Whether the server supports preview metadata
|
description: Whether the server supports preview metadata
|
||||||
type: boolean
|
type: boolean
|
||||||
supports_model_type_tags:
|
|
||||||
description: Whether the server supports namespaced model type asset tags
|
|
||||||
type: boolean
|
|
||||||
type: object
|
type: object
|
||||||
description: Success
|
description: Success
|
||||||
headers:
|
headers:
|
||||||
@ -3300,6 +3297,12 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ErrorResponse'
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
description: Invalid request parameters
|
description: Invalid request parameters
|
||||||
|
"401":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
description: Unauthorized - Authentication required
|
||||||
"500":
|
"500":
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
comfyui-frontend-package==1.45.20
|
comfyui-frontend-package==1.45.20
|
||||||
comfyui-workflow-templates==0.11.6
|
comfyui-workflow-templates==0.11.9
|
||||||
comfyui-embedded-docs==0.5.7
|
comfyui-embedded-docs==0.5.8
|
||||||
torch
|
torch
|
||||||
torchsde
|
torchsde
|
||||||
torchvision
|
torchvision
|
||||||
@ -22,7 +22,7 @@ alembic
|
|||||||
SQLAlchemy>=2.0.0
|
SQLAlchemy>=2.0.0
|
||||||
filelock
|
filelock
|
||||||
av>=16.0.0
|
av>=16.0.0
|
||||||
comfy-kitchen==0.2.18
|
comfy-kitchen==0.2.19
|
||||||
comfy-aimdo==0.4.10
|
comfy-aimdo==0.4.10
|
||||||
requests
|
requests
|
||||||
simpleeval>=1.0.0
|
simpleeval>=1.0.0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user