Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d54a90e
[diffusion] comfyui: fix hardcoded 300s timeout on image generate/edi…
OnePunchMonk Oct 10, 2026
2395b34
[diffusion] comfyui: fix batched image inputs silently truncated to t…
OnePunchMonk Oct 10, 2026
0ea0a54
[diffusion] comfyui: fix LoRA strength not settable in server mode
OnePunchMonk Oct 10, 2026
a5ac1ba
[diffusion] comfyui: fix SGLDVideoInput's broken VideoInput contract …
OnePunchMonk Oct 10, 2026
3267040
[diffusion] comfyui: fix server-mode nodes sending local paths a remo…
OnePunchMonk Oct 10, 2026
b85cf52
[diffusion] comfyui: show progress and honour Cancel for server-mode …
OnePunchMonk Oct 10, 2026
b876b40
[diffusion] lint: apply ruff format
OnePunchMonk Oct 13, 2026
68765f8
Merge remote-tracking branch 'upstream/main' into fix-server
OnePunchMonk Oct 14, 2026
3cc5709
[diffusion] comfyui: upload a local video-to-video source instead of …
OnePunchMonk Oct 14, 2026
6059f4c
Merge origin/main into fix/comfyui-sgld-server-mode
OnePunchMonk Oct 15, 2026
d9d94e4
stub comfy modules in lora node test
OnePunchMonk Oct 15, 2026
c0da458
[diffusion] comfyui: return cloud-storage video urls instead of polli…
OnePunchMonk Oct 18, 2026
14d35f9
[diffusion] comfyui: json-encode multipart video fields and pass file…
OnePunchMonk Oct 18, 2026
67bbb2c
Harden video download, local server check, batch image input
OnePunchMonk Oct 20, 2026
12e8f4b
[diffusion] comfyui: compare resolved paths in video download test
OnePunchMonk Oct 20, 2026
22fb84d
[Fix] comfyui: fold server-mode tests into test_h3_request, trim comm…
OnePunchMonk Oct 22, 2026
8220c63
Merge branch 'main' into fix/comfyui-sgld-server-mode
OnePunchMonk Oct 22, 2026
eacc02e
[Fix] comfyui: make server-mode tests independent of an installed Com…
OnePunchMonk Oct 22, 2026
9234665
Merge main into fix/comfyui-sgld-server-mode
OnePunchMonk Oct 23, 2026
9a6a96a
Merge branch 'main' into fix/comfyui-sgld-server-mode
OnePunchMonk Oct 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ def __init__(
base_url: Base URL of the SGLang Diffusion server (e.g., "http://localhost:30010/v1")
api_key: API key for authentication (default: "sk-proj-1234567890")
image_timeout: Seconds to wait for an image generate/edit request
before timing out. A large job (big size, or a first request
that triggers torch.compile/warmup) can need more than the
previous hardcoded 300s.
"""
self.image_timeout = image_timeout
# Ensure base_url doesn't end with /v1 if it's already there
Expand Down Expand Up @@ -289,12 +286,8 @@ def generate_video(
else:
size = "720x1280"

# Prepare request fields shared by the JSON and multipart paths.
# `output_path` is deliberately never sent: it used to be the
# ComfyUI node's own temp directory, which only exists on this
# machine and breaks as soon as the server runs elsewhere. Letting
# the server pick its own output location and fetching the result
# (see below) works for both the local and remote case.
# output_path is not sent: it is a local dir a remote server cannot use;
# the result is fetched back instead (_localize_video_result).
fields: Dict[str, Any] = {
"prompt": prompt,
"size": size,
Expand Down Expand Up @@ -322,10 +315,7 @@ def generate_video(
if extra_fields:
fields.update(extra_fields)

# Upload local files instead of sending their paths: a server on
# another machine cannot read this machine's filesystem (the images
# endpoint already does this for image_path). The server takes an
# uploaded source clip as `video_reference`.
# Upload local files: a remote server cannot read this machine's paths.
string_fields: Dict[str, Any] = {}
uploads: Dict[str, str] = {}
for form_key, json_key, path in (
Expand All @@ -341,8 +331,7 @@ def generate_video(

try:
if uploads:
# JSON, not repr: the server json-decodes form values, so a
# nested dict or False must not arrive as Python's repr
# the server json-decodes form values
data = {
key: (
value if isinstance(value, (str, bytes)) else json.dumps(value)
Expand Down Expand Up @@ -402,8 +391,7 @@ def generate_video(
progress_callback(int(status["progress"]))

if status.get("status") == "completed":
# Localize outside this try, so a failed download
# fails fast instead of being retried as a poll error.
# download outside this try so a failure is not retried
break
elif status.get("status") == "failed":
error = status.get("error", {})
Expand Down Expand Up @@ -445,14 +433,9 @@ def generate_video(
def _localize_video_result(
self, status: Dict[str, Any], video_id: str, output_path: Optional[str]
) -> Dict[str, Any]:
"""Make sure ``file_path`` in a completed job points at a local file.

The server's own ``file_path`` is only readable when the server runs
on this machine. When it isn't (no such local file), download the
result through ``GET /videos/{id}/content`` instead of trusting a
path that belongs to a different filesystem. A job uploaded to cloud
storage has no file_path and a ``url`` instead; ``/content`` refuses
those, so it is returned as is and the node fetches the url.
"""Download the result via /videos/{id}/content when file_path is not local.

Cloud jobs (url, no file_path) are returned as is; the node fetches the url.
"""
file_path = status.get("file_path")
if file_path and os.path.exists(file_path):
Expand Down Expand Up @@ -594,8 +577,7 @@ def set_lora(
- "transformer": Apply only to the primary transformer (high noise for Wan2.2)
- "transformer_2": Apply only to transformer_2 (low noise for Wan2.2)
- "critic": Apply only to the critic model
strength: LoRA merge strength. The server defaults to 1.0 when
not given; values < 1.0 reduce the effect.
strength: LoRA merge strength (server default 1.0)

Returns:
Dictionary containing the API response with status and message
Expand Down
29 changes: 6 additions & 23 deletions python/sglang/multimodal_gen/apps/ComfyUI_SGLDiffusion/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,7 @@ def INPUT_TYPES(cls):
"default": 300,
"min": 1,
"max": 3600,
"tooltip": "Seconds to wait for an image "
"generate/edit request (e.g. a large job, or "
"torch.compile warmup on the first request, can "
"need more than 300s)",
"tooltip": "Seconds to wait for an image request",
},
),
},
Expand Down Expand Up @@ -644,8 +641,7 @@ def generate_video(
video_path = resolve_video_path(
response.get("file_path"), response.get("url")
)
# The server may have resolved a different size than requested
# (e.g. to match an image-to-video input's aspect ratio).
# the server may resolve a different size (e.g. I2V aspect ratio)
resolved_size = response.get("size", "")
if resolved_size:
width, height = (int(v) for v in resolved_size.split("x"))
Expand Down Expand Up @@ -744,13 +740,7 @@ def INPUT_TYPES(cls):

@staticmethod
def _image_material_uri(image: torch.Tensor) -> str:
"""Embed the image inline as a base64 data URI.

A `file://` path only works when the SGLD server runs on this same
machine; the server's H3 material loader accepts `data:` URIs
directly (no upload endpoint needed), so this works locally and
remotely alike.
"""
"""Inline data: URI, so a remote server can read it (file:// cannot)."""
path = get_image_path(image)
try:
with open(path, "rb") as fh:
Expand Down Expand Up @@ -780,14 +770,8 @@ def _is_local_server(base_url: str) -> bool:

@classmethod
def _remote_material_uri(cls, value: str, kind: str, base_url: str) -> str:
"""Remote URLs pass through. A local path only works when the SGLD
server is also on this machine: H3's server-side `/v1/videos`
endpoint has no multipart slot for the video/audio conditions this
node sends through `extra_fields.conditions`, unlike the image
conditions above (which sidestep that by embedding bytes inline).
Raise clearly instead of building a `file://` URI that will
silently fail against any server that isn't local.
"""
"""URLs pass through; a local path only works with a server on this machine,
since H3 conditions have no upload slot."""
# file:// already names a server-side path
if value.startswith(("http://", "https://", "file://")):
return value
Expand Down Expand Up @@ -978,8 +962,7 @@ def INPUT_TYPES(cls):
"min": 0.0,
"max": 10.0,
"step": 0.01,
"tooltip": "LoRA merge strength; the server's own "
"default is 1.0",
"tooltip": "LoRA merge strength",
},
),
},
Expand Down
Loading
Loading