mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-06-16 20:06:04 +08:00
Compare commits
13 Commits
comfyanony
...
cloud-open
| Author | SHA1 | Date | |
|---|---|---|---|
| c89cd46725 | |||
| 135abed8da | |||
| a439dcae07 | |||
| 5db51b76b4 | |||
| b13ca1ce7b | |||
| c47e21a3e0 | |||
| 2f4c4e983c | |||
| 83a3f03218 | |||
| ec4dec93d2 | |||
| 7d4194d984 | |||
| 4388eb781a | |||
| e1b9366898 | |||
| 5897d0c3ae |
@ -382,11 +382,7 @@ For AMD 7600 and maybe other RDNA3 cards: ```HSA_OVERRIDE_GFX_VERSION=11.0.0 pyt
|
|||||||
|
|
||||||
### AMD ROCm Tips
|
### AMD ROCm Tips
|
||||||
|
|
||||||
You can enable experimental memory efficient attention on recent pytorch in ComfyUI on some AMD GPUs using this command, it should already be enabled by default on RDNA3. If this improves speed for you on latest pytorch on your GPU please report it so that I can enable it by default.
|
You can try setting this env variable `PYTORCH_TUNABLEOP_ENABLED=1` which might speed things up at the cost of a very slow initial run.
|
||||||
|
|
||||||
```TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL=1 python main.py --use-pytorch-cross-attention```
|
|
||||||
|
|
||||||
You can also try setting this env variable `PYTORCH_TUNABLEOP_ENABLED=1` which might speed things up at the cost of a very slow initial run.
|
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
|
|
||||||
|
|||||||
@ -145,6 +145,7 @@ vram_group.add_argument("--novram", action="store_true", help="When lowvram isn'
|
|||||||
vram_group.add_argument("--cpu", action="store_true", help="To use the CPU for everything (slow).")
|
vram_group.add_argument("--cpu", action="store_true", help="To use the CPU for everything (slow).")
|
||||||
|
|
||||||
parser.add_argument("--reserve-vram", type=float, default=None, help="Set the amount of vram in GB you want to reserve for use by your OS/other software. By default some amount is reserved depending on your OS.")
|
parser.add_argument("--reserve-vram", type=float, default=None, help="Set the amount of vram in GB you want to reserve for use by your OS/other software. By default some amount is reserved depending on your OS.")
|
||||||
|
parser.add_argument("--vram-headroom", type=float, default=0, help="Set the amount of vram in GB for DynamicVRAM to maintain as extra headroom above default. ComfyUI will try and keep this much VRAM completely free and unused, even counting VRAM from other apps.")
|
||||||
|
|
||||||
parser.add_argument("--async-offload", nargs='?', const=2, type=int, default=None, metavar="NUM_STREAMS", help="Use async weight offloading. An optional argument controls the amount of offload streams. Default is 2. Enabled by default on Nvidia.")
|
parser.add_argument("--async-offload", nargs='?', const=2, type=int, default=None, metavar="NUM_STREAMS", help="Use async weight offloading. An optional argument controls the amount of offload streams. Default is 2. Enabled by default on Nvidia.")
|
||||||
parser.add_argument("--disable-async-offload", action="store_true", help="Disable async weight offloading.")
|
parser.add_argument("--disable-async-offload", action="store_true", help="Disable async weight offloading.")
|
||||||
|
|||||||
@ -325,21 +325,25 @@ class VideoFromFile(VideoInput):
|
|||||||
checked_alpha = True
|
checked_alpha = True
|
||||||
|
|
||||||
# Fix non-deterministic video decode when the video width is not a multiple of 32
|
# Fix non-deterministic video decode when the video width is not a multiple of 32
|
||||||
# For non-yuvj pixel formats (all H.264/H.265 video)
|
# For non-yuvj pixel formats: most H.264/H.265 video and static images (e.g. lossy WebP via LoadImage)
|
||||||
|
# Pad both axes to a multiple of 32 and smear the border so the alignment padding never bleeds into the cropped edges
|
||||||
if image_format in ('gbrpf32le', 'gbrapf32le') and frame.width % 32 != 0:
|
if image_format in ('gbrpf32le', 'gbrapf32le') and frame.width % 32 != 0:
|
||||||
if align_graph is None:
|
if align_graph is None:
|
||||||
pad_w = ((frame.width + 31) // 32) * 32
|
pad_w = ((frame.width + 31) // 32) * 32
|
||||||
|
pad_h = ((frame.height + 31) // 32) * 32
|
||||||
g = av.filter.Graph()
|
g = av.filter.Graph()
|
||||||
g_src = g.add_buffer(width=frame.width, height=frame.height,
|
g_src = g.add_buffer(width=frame.width, height=frame.height,
|
||||||
format=frame.format.name, time_base=video_stream.time_base)
|
format=frame.format.name, time_base=video_stream.time_base)
|
||||||
g_pad = g.add('pad', f'{pad_w}:{frame.height}:0:0')
|
g_pad = g.add('pad', f'{pad_w}:{pad_h}:0:0')
|
||||||
|
g_fill = g.add('fillborders', f'left=0:right={pad_w - frame.width}:top=0:bottom={pad_h - frame.height}:mode=smear')
|
||||||
g_sink = g.add('buffersink')
|
g_sink = g.add('buffersink')
|
||||||
g_src.link_to(g_pad)
|
g_src.link_to(g_pad)
|
||||||
g_pad.link_to(g_sink)
|
g_pad.link_to(g_fill)
|
||||||
|
g_fill.link_to(g_sink)
|
||||||
g.configure()
|
g.configure()
|
||||||
align_graph = (g, g_src, g_sink)
|
align_graph = (g, g_src, g_sink)
|
||||||
align_graph[1].push(frame)
|
align_graph[1].push(frame)
|
||||||
img = np.ascontiguousarray(align_graph[2].pull().to_ndarray(format=image_format)[:, :frame.width])
|
img = np.ascontiguousarray(align_graph[2].pull().to_ndarray(format=image_format)[:frame.height, :frame.width])
|
||||||
else:
|
else:
|
||||||
img = frame.to_ndarray(format=image_format)
|
img = frame.to_ndarray(format=image_format)
|
||||||
if frame.rotation != 0:
|
if frame.rotation != 0:
|
||||||
|
|||||||
@ -208,6 +208,10 @@ class TripoMultiviewToModelRequest(BaseModel):
|
|||||||
quad: bool | None = Field(False, description="Whether to apply quad to the generated model")
|
quad: bool | None = Field(False, description="Whether to apply quad to the generated model")
|
||||||
|
|
||||||
|
|
||||||
|
class TripoTexturePrompt(BaseModel):
|
||||||
|
text: str | None = Field(None, description="Text guidance for texture generation")
|
||||||
|
|
||||||
|
|
||||||
class TripoTextureModelRequest(BaseModel):
|
class TripoTextureModelRequest(BaseModel):
|
||||||
type: TripoTaskType = Field(TripoTaskType.TEXTURE_MODEL, description="Type of task")
|
type: TripoTaskType = Field(TripoTaskType.TEXTURE_MODEL, description="Type of task")
|
||||||
original_model_task_id: str = Field(..., description="The task ID of the original model")
|
original_model_task_id: str = Field(..., description="The task ID of the original model")
|
||||||
@ -219,6 +223,11 @@ class TripoTextureModelRequest(BaseModel):
|
|||||||
texture_alignment: TripoTextureAlignment | None = Field(
|
texture_alignment: TripoTextureAlignment | None = Field(
|
||||||
TripoTextureAlignment.ORIGINAL_IMAGE, description="The texture alignment method"
|
TripoTextureAlignment.ORIGINAL_IMAGE, description="The texture alignment method"
|
||||||
)
|
)
|
||||||
|
texture_prompt: TripoTexturePrompt | None = Field(
|
||||||
|
None,
|
||||||
|
description="Optional guidance for texturing. Required in practice for imported models, "
|
||||||
|
"which carry no source image to infer texture from.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TripoRefineModelRequest(BaseModel):
|
class TripoRefineModelRequest(BaseModel):
|
||||||
@ -307,6 +316,17 @@ class TripoP1MultiviewToModelRequest(TripoP1CommonRequest):
|
|||||||
orientation: str | None = None
|
orientation: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class TripoImportModelRequest(BaseModel):
|
||||||
|
"""Request for the comfy-api composite import endpoint (/proxy/tripo/v2/openapi/import).
|
||||||
|
|
||||||
|
The model file is uploaded to ComfyUI API storage first; the backend downloads it from
|
||||||
|
`url`, re-uploads it to Tripo's storage and creates the import_model task server-side.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url: str = Field(..., description="ComfyUI API storage download URL of the model file")
|
||||||
|
format: str = Field(..., description='File format: "glb", "fbx", "obj" or "stl"')
|
||||||
|
|
||||||
|
|
||||||
class TripoTaskOutput(BaseModel):
|
class TripoTaskOutput(BaseModel):
|
||||||
model: str | None = Field(None, description="URL to the model")
|
model: str | None = Field(None, description="URL to the model")
|
||||||
base_model: str | None = Field(None, description="URL to the base model")
|
base_model: str | None = Field(None, description="URL to the base model")
|
||||||
|
|||||||
@ -111,11 +111,10 @@ class SoniloTextToMusic(IO.ComfyNode):
|
|||||||
),
|
),
|
||||||
IO.Int.Input(
|
IO.Int.Input(
|
||||||
"duration",
|
"duration",
|
||||||
default=0,
|
default=30,
|
||||||
min=0,
|
min=1,
|
||||||
max=360,
|
max=360,
|
||||||
tooltip="Target duration in seconds. Set to 0 to let the model "
|
tooltip="Target duration in seconds. Maximum: 6 minutes.",
|
||||||
"infer the duration from the prompt. Maximum: 6 minutes.",
|
|
||||||
),
|
),
|
||||||
IO.Int.Input(
|
IO.Int.Input(
|
||||||
"seed",
|
"seed",
|
||||||
@ -150,14 +149,13 @@ class SoniloTextToMusic(IO.ComfyNode):
|
|||||||
async def execute(
|
async def execute(
|
||||||
cls,
|
cls,
|
||||||
prompt: str,
|
prompt: str,
|
||||||
duration: int = 0,
|
duration: int = 1,
|
||||||
seed: int = 0,
|
seed: int = 0,
|
||||||
) -> IO.NodeOutput:
|
) -> IO.NodeOutput:
|
||||||
validate_string(prompt, strip_whitespace=True, min_length=1)
|
validate_string(prompt, strip_whitespace=True, min_length=1, max_length=1000)
|
||||||
form = aiohttp.FormData()
|
form = aiohttp.FormData()
|
||||||
form.add_field("prompt", prompt)
|
form.add_field("prompt", prompt)
|
||||||
if duration > 0:
|
form.add_field("duration", str(duration))
|
||||||
form.add_field("duration", str(duration))
|
|
||||||
audio_bytes = await _stream_sonilo_music(
|
audio_bytes = await _stream_sonilo_music(
|
||||||
cls,
|
cls,
|
||||||
ApiEndpoint(path="/proxy/sonilo/t2m/generate", method="POST"),
|
ApiEndpoint(path="/proxy/sonilo/t2m/generate", method="POST"),
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from comfy_api.latest import IO, ComfyExtension, Input
|
from comfy_api.latest import IO, ComfyExtension, Input, Types
|
||||||
from comfy_api_nodes.apis.tripo import (
|
from comfy_api_nodes.apis.tripo import (
|
||||||
TripoAnimateRetargetRequest,
|
TripoAnimateRetargetRequest,
|
||||||
TripoAnimateRigRequest,
|
TripoAnimateRigRequest,
|
||||||
@ -8,6 +8,7 @@ from comfy_api_nodes.apis.tripo import (
|
|||||||
TripoFileEmptyReference,
|
TripoFileEmptyReference,
|
||||||
TripoFileReference,
|
TripoFileReference,
|
||||||
TripoImageToModelRequest,
|
TripoImageToModelRequest,
|
||||||
|
TripoImportModelRequest,
|
||||||
TripoModelVersion,
|
TripoModelVersion,
|
||||||
TripoMultiviewToModelRequest,
|
TripoMultiviewToModelRequest,
|
||||||
TripoOrientation,
|
TripoOrientation,
|
||||||
@ -21,6 +22,7 @@ from comfy_api_nodes.apis.tripo import (
|
|||||||
TripoTaskType,
|
TripoTaskType,
|
||||||
TripoTextToModelRequest,
|
TripoTextToModelRequest,
|
||||||
TripoTextureModelRequest,
|
TripoTextureModelRequest,
|
||||||
|
TripoTexturePrompt,
|
||||||
TripoUrlReference,
|
TripoUrlReference,
|
||||||
)
|
)
|
||||||
from comfy_api_nodes.util import (
|
from comfy_api_nodes.util import (
|
||||||
@ -28,6 +30,7 @@ from comfy_api_nodes.util import (
|
|||||||
download_url_to_file_3d,
|
download_url_to_file_3d,
|
||||||
poll_op,
|
poll_op,
|
||||||
sync_op,
|
sync_op,
|
||||||
|
upload_3d_model_to_comfyapi,
|
||||||
upload_images_to_comfyapi,
|
upload_images_to_comfyapi,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -538,6 +541,14 @@ class TripoTextureNode(IO.ComfyNode):
|
|||||||
optional=True,
|
optional=True,
|
||||||
advanced=True,
|
advanced=True,
|
||||||
),
|
),
|
||||||
|
IO.String.Input(
|
||||||
|
"texture_prompt",
|
||||||
|
default="",
|
||||||
|
multiline=True,
|
||||||
|
optional=True,
|
||||||
|
tooltip="Optional text guidance for texturing. Required in practice for imported "
|
||||||
|
"models (Tripo: Import Model), which carry no source image to infer colors from.",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
outputs=[
|
outputs=[
|
||||||
IO.String.Output(display_name="model_file"), # for backward compatibility only
|
IO.String.Output(display_name="model_file"), # for backward compatibility only
|
||||||
@ -571,6 +582,7 @@ class TripoTextureNode(IO.ComfyNode):
|
|||||||
texture_seed: int | None = None,
|
texture_seed: int | None = None,
|
||||||
texture_quality: str | None = None,
|
texture_quality: str | None = None,
|
||||||
texture_alignment: str | None = None,
|
texture_alignment: str | None = None,
|
||||||
|
texture_prompt: str = "",
|
||||||
) -> IO.NodeOutput:
|
) -> IO.NodeOutput:
|
||||||
response = await sync_op(
|
response = await sync_op(
|
||||||
cls,
|
cls,
|
||||||
@ -583,6 +595,7 @@ class TripoTextureNode(IO.ComfyNode):
|
|||||||
texture_seed=texture_seed,
|
texture_seed=texture_seed,
|
||||||
texture_quality=texture_quality,
|
texture_quality=texture_quality,
|
||||||
texture_alignment=texture_alignment,
|
texture_alignment=texture_alignment,
|
||||||
|
texture_prompt=TripoTexturePrompt(text=texture_prompt.strip()) if texture_prompt.strip() else None,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return await poll_until_finished(cls, response, average_duration=80)
|
return await poll_until_finished(cls, response, average_duration=80)
|
||||||
@ -915,6 +928,90 @@ class TripoConversionNode(IO.ComfyNode):
|
|||||||
return await poll_until_finished(cls, response, average_duration=30)
|
return await poll_until_finished(cls, response, average_duration=30)
|
||||||
|
|
||||||
|
|
||||||
|
class TripoImportModelNode(IO.ComfyNode):
|
||||||
|
"""Imports an external 3D model into Tripo, producing a MODEL_TASK_ID for post-processing nodes."""
|
||||||
|
|
||||||
|
SUPPORTED_FORMATS = ("glb", "fbx", "obj", "stl")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="TripoImportModelNode",
|
||||||
|
display_name="Tripo: Import Model",
|
||||||
|
category="partner/3d/Tripo",
|
||||||
|
description="Import an external 3D model (e.g. from Rodin, Hunyuan3D or a local file) into Tripo "
|
||||||
|
"to use it with Tripo's post-processing nodes: Texture, Rig, Convert. "
|
||||||
|
"GLB is recommended: textures survive import only when embedded in the file. "
|
||||||
|
"Note that texturing an imported model requires a texture prompt.",
|
||||||
|
inputs=[
|
||||||
|
IO.MultiType.Input(
|
||||||
|
"model_3d",
|
||||||
|
types=[IO.File3DGLB, IO.File3DFBX, IO.File3DOBJ, IO.File3DSTL, IO.File3DAny],
|
||||||
|
tooltip="3D model to import (GLB / FBX / OBJ / STL, up to 150 MB). "
|
||||||
|
"OBJ and STL files carry no embedded textures.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"),
|
||||||
|
],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
expr="""{"type":"text","text":"Free"}""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(cls, model_3d: Types.File3D) -> IO.NodeOutput:
|
||||||
|
file_format = (model_3d.format or "").lstrip(".").lower()
|
||||||
|
if file_format == "gltf":
|
||||||
|
raise ValueError(
|
||||||
|
"GLTF (.gltf) references external files and cannot be imported. Export a single-file GLB instead."
|
||||||
|
)
|
||||||
|
if file_format not in cls.SUPPORTED_FORMATS:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unsupported 3D format '{file_format or 'unknown'}'. "
|
||||||
|
f"Tripo import supports: {', '.join(f.upper() for f in cls.SUPPORTED_FORMATS)}."
|
||||||
|
)
|
||||||
|
size = len(model_3d.get_bytes())
|
||||||
|
if size > 150 * 1024 * 1024:
|
||||||
|
raise ValueError(f"Model file is {size / (1024 * 1024):.1f} MB; Tripo import allows up to 150 MB.")
|
||||||
|
|
||||||
|
url = await upload_3d_model_to_comfyapi(cls, model_3d, file_format)
|
||||||
|
response = await sync_op(
|
||||||
|
cls,
|
||||||
|
endpoint=ApiEndpoint(path="/proxy/tripo/v2/openapi/import", method="POST"),
|
||||||
|
response_model=TripoTaskResponse,
|
||||||
|
data=TripoImportModelRequest(url=url, format=file_format),
|
||||||
|
)
|
||||||
|
if response.code != 0:
|
||||||
|
raise RuntimeError(f"Failed to import model: {response.error}")
|
||||||
|
|
||||||
|
task_id = response.data.task_id
|
||||||
|
response_poll = await poll_op(
|
||||||
|
cls,
|
||||||
|
poll_endpoint=ApiEndpoint(path=f"/proxy/tripo/v2/openapi/task/{task_id}"),
|
||||||
|
response_model=TripoTaskResponse,
|
||||||
|
failed_statuses=[
|
||||||
|
TripoTaskStatus.FAILED,
|
||||||
|
TripoTaskStatus.CANCELLED,
|
||||||
|
TripoTaskStatus.UNKNOWN,
|
||||||
|
TripoTaskStatus.BANNED,
|
||||||
|
TripoTaskStatus.EXPIRED,
|
||||||
|
],
|
||||||
|
status_extractor=lambda x: x.data.status,
|
||||||
|
progress_extractor=lambda x: x.data.progress,
|
||||||
|
estimated_duration=10,
|
||||||
|
)
|
||||||
|
if response_poll.data.status != TripoTaskStatus.SUCCESS:
|
||||||
|
raise RuntimeError(f"Failed to import model: {response_poll}")
|
||||||
|
return IO.NodeOutput(task_id)
|
||||||
|
|
||||||
|
|
||||||
def _p1_price_expr(*, geometry_credits: int, textured_credits: int, detailed_credits: int) -> str:
|
def _p1_price_expr(*, geometry_credits: int, textured_credits: int, detailed_credits: int) -> str:
|
||||||
return (
|
return (
|
||||||
"("
|
"("
|
||||||
@ -1292,6 +1389,7 @@ class TripoExtension(ComfyExtension):
|
|||||||
TripoP1TextToModelNode,
|
TripoP1TextToModelNode,
|
||||||
TripoP1ImageToModelNode,
|
TripoP1ImageToModelNode,
|
||||||
TripoP1MultiviewToModelNode,
|
TripoP1MultiviewToModelNode,
|
||||||
|
TripoImportModelNode,
|
||||||
TripoTextureNode,
|
TripoTextureNode,
|
||||||
TripoRefineNode,
|
TripoRefineNode,
|
||||||
TripoRigNode,
|
TripoRigNode,
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class RTDETR_detect(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="RTDETR_detect",
|
node_id="RTDETR_detect",
|
||||||
display_name="RT-DETR Detect",
|
display_name="Run Real-Time Detection (RT-DETR)",
|
||||||
category="image/detection",
|
category="image/detection",
|
||||||
search_aliases=["bbox", "bounding box", "object detection", "coco"],
|
search_aliases=["bbox", "bounding box", "object detection", "coco"],
|
||||||
inputs=[
|
inputs=[
|
||||||
|
|||||||
@ -264,7 +264,7 @@ class SAM3_VideoTrack(io.ComfyNode):
|
|||||||
def define_schema(cls):
|
def define_schema(cls):
|
||||||
return io.Schema(
|
return io.Schema(
|
||||||
node_id="SAM3_VideoTrack",
|
node_id="SAM3_VideoTrack",
|
||||||
display_name="SAM3 Video Track",
|
display_name="Run SAM3 Video Track",
|
||||||
category="image/detection",
|
category="image/detection",
|
||||||
search_aliases=["sam3", "video", "track", "propagate"],
|
search_aliases=["sam3", "video", "track", "propagate"],
|
||||||
inputs=[
|
inputs=[
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
# This file is automatically generated by the build process when version is
|
# This file is automatically generated by the build process when version is
|
||||||
# updated in pyproject.toml.
|
# updated in pyproject.toml.
|
||||||
__version__ = "0.24.0"
|
__version__ = "0.25.0"
|
||||||
|
|||||||
45
main.py
45
main.py
@ -55,7 +55,11 @@ if __name__ == "__main__" and args.debug_hang:
|
|||||||
import comfy_aimdo.control
|
import comfy_aimdo.control
|
||||||
|
|
||||||
if enables_dynamic_vram():
|
if enables_dynamic_vram():
|
||||||
comfy_aimdo.control.init()
|
try:
|
||||||
|
comfy_aimdo.control.init(simple_vram_headroom=None if args.reserve_vram is None else int(args.reserve_vram * 1024 ** 3))
|
||||||
|
except TypeError:
|
||||||
|
# comfy-aimdo 0.4.9 protocol.
|
||||||
|
comfy_aimdo.control.init()
|
||||||
|
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
os.environ['MIMALLOC_PURGE_DELAY'] = '0'
|
os.environ['MIMALLOC_PURGE_DELAY'] = '0'
|
||||||
@ -231,23 +235,30 @@ import comfy.model_patcher
|
|||||||
if args.enable_dynamic_vram or (enables_dynamic_vram() and comfy.model_management.is_nvidia() and not comfy.model_management.is_wsl()):
|
if args.enable_dynamic_vram or (enables_dynamic_vram() and comfy.model_management.is_nvidia() and not comfy.model_management.is_wsl()):
|
||||||
if (not args.enable_dynamic_vram) and (comfy.model_management.torch_version_numeric < (2, 8)):
|
if (not args.enable_dynamic_vram) and (comfy.model_management.torch_version_numeric < (2, 8)):
|
||||||
logging.warning("Unsupported Pytorch detected. DynamicVRAM support requires Pytorch version 2.8 or later. Falling back to legacy ModelPatcher. VRAM estimates may be unreliable especially on Windows")
|
logging.warning("Unsupported Pytorch detected. DynamicVRAM support requires Pytorch version 2.8 or later. Falling back to legacy ModelPatcher. VRAM estimates may be unreliable especially on Windows")
|
||||||
elif comfy_aimdo.control.init_devices(d.index for d in comfy.model_management.get_all_torch_devices()):
|
|
||||||
if args.verbose == 'DEBUG':
|
|
||||||
comfy_aimdo.control.set_log_debug()
|
|
||||||
elif args.verbose == 'CRITICAL':
|
|
||||||
comfy_aimdo.control.set_log_critical()
|
|
||||||
elif args.verbose == 'ERROR':
|
|
||||||
comfy_aimdo.control.set_log_error()
|
|
||||||
elif args.verbose == 'WARNING':
|
|
||||||
comfy_aimdo.control.set_log_warning()
|
|
||||||
else: #INFO
|
|
||||||
comfy_aimdo.control.set_log_info()
|
|
||||||
|
|
||||||
comfy.model_patcher.CoreModelPatcher = comfy.model_patcher.ModelPatcherDynamic
|
|
||||||
comfy.memory_management.aimdo_enabled = True
|
|
||||||
logging.info("DynamicVRAM support detected and enabled")
|
|
||||||
else:
|
else:
|
||||||
logging.warning("No working comfy-aimdo install detected. DynamicVRAM support disabled. Falling back to legacy ModelPatcher. VRAM estimates may be unreliable especially on Windows")
|
try:
|
||||||
|
aimdo_initialized = comfy_aimdo.control.init_devices((d.index, int(args.vram_headroom * 1024 ** 3)) for d in comfy.model_management.get_all_torch_devices())
|
||||||
|
except TypeError:
|
||||||
|
# comfy-aimdo 0.4.9 protocol.
|
||||||
|
aimdo_initialized = comfy_aimdo.control.init_devices(d.index for d in comfy.model_management.get_all_torch_devices())
|
||||||
|
|
||||||
|
if aimdo_initialized:
|
||||||
|
if args.verbose == 'DEBUG':
|
||||||
|
comfy_aimdo.control.set_log_debug()
|
||||||
|
elif args.verbose == 'CRITICAL':
|
||||||
|
comfy_aimdo.control.set_log_critical()
|
||||||
|
elif args.verbose == 'ERROR':
|
||||||
|
comfy_aimdo.control.set_log_error()
|
||||||
|
elif args.verbose == 'WARNING':
|
||||||
|
comfy_aimdo.control.set_log_warning()
|
||||||
|
else: #INFO
|
||||||
|
comfy_aimdo.control.set_log_info()
|
||||||
|
|
||||||
|
comfy.model_patcher.CoreModelPatcher = comfy.model_patcher.ModelPatcherDynamic
|
||||||
|
comfy.memory_management.aimdo_enabled = True
|
||||||
|
logging.info("DynamicVRAM support detected and enabled")
|
||||||
|
else:
|
||||||
|
logging.warning("No working comfy-aimdo install detected. DynamicVRAM support disabled. Falling back to legacy ModelPatcher. VRAM estimates may be unreliable especially on Windows")
|
||||||
|
|
||||||
|
|
||||||
def cuda_malloc_warning():
|
def cuda_malloc_warning():
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
comfyui_manager==4.2.1
|
comfyui_manager==4.2.2
|
||||||
|
|||||||
5
nodes.py
5
nodes.py
@ -20,6 +20,8 @@ from PIL.PngImagePlugin import PngInfo
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import safetensors.torch
|
import safetensors.torch
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy"))
|
||||||
|
|
||||||
import comfy.diffusers_load
|
import comfy.diffusers_load
|
||||||
import comfy.samplers
|
import comfy.samplers
|
||||||
import comfy.sample
|
import comfy.sample
|
||||||
@ -2293,9 +2295,6 @@ async def init_external_custom_nodes():
|
|||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
# TODO: remove at some point when custom nodes don't break.
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy"))
|
|
||||||
|
|
||||||
base_node_names = set(NODE_CLASS_MAPPINGS.keys())
|
base_node_names = set(NODE_CLASS_MAPPINGS.keys())
|
||||||
node_paths = folder_paths.get_folder_paths("custom_nodes")
|
node_paths = folder_paths.get_folder_paths("custom_nodes")
|
||||||
node_import_times = []
|
node_import_times = []
|
||||||
|
|||||||
20
openapi.yaml
20
openapi.yaml
@ -896,11 +896,6 @@ components:
|
|||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
description: The workflow graph to execute
|
description: The workflow graph to execute
|
||||||
type: object
|
type: object
|
||||||
prompt_id:
|
|
||||||
description: Optional client-supplied job id. Must be a UUID in canonical lowercase hyphenated form; it is echoed back in the response. Omitted or null means the server generates one.
|
|
||||||
format: uuid
|
|
||||||
nullable: true
|
|
||||||
type: string
|
|
||||||
workflow_id:
|
workflow_id:
|
||||||
description: UUID identifying the cloud workflow entity to associate with this job
|
description: UUID identifying the cloud workflow entity to associate with this job
|
||||||
type: string
|
type: string
|
||||||
@ -1800,7 +1795,9 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ErrorResponse'
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
description: Invalid request (no fields provided)
|
description: |
|
||||||
|
Invalid request — no fields provided, or `preview_id` is the zero UUID
|
||||||
|
(`INVALID_PREVIEW_ID`).
|
||||||
"401":
|
"401":
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
@ -1812,7 +1809,10 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ErrorResponse'
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
description: Asset not found
|
description: |
|
||||||
|
Asset not found — returned both when the asset being updated does
|
||||||
|
not exist and when `preview_id` does not reference an asset
|
||||||
|
accessible to the caller.
|
||||||
"500":
|
"500":
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
@ -3050,6 +3050,12 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/PromptErrorResponse'
|
$ref: '#/components/schemas/PromptErrorResponse'
|
||||||
description: Payment required - Insufficient credits
|
description: Payment required - Insufficient credits
|
||||||
|
"413":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PromptErrorResponse'
|
||||||
|
description: Workflow JSON too large
|
||||||
"429":
|
"429":
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ComfyUI"
|
name = "ComfyUI"
|
||||||
version = "0.24.0"
|
version = "0.25.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { file = "LICENSE" }
|
license = { file = "LICENSE" }
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
comfyui-frontend-package==1.45.15
|
comfyui-frontend-package==1.45.15
|
||||||
comfyui-workflow-templates==0.9.98
|
comfyui-workflow-templates==0.10.0
|
||||||
comfyui-embedded-docs==0.5.3
|
comfyui-embedded-docs==0.5.4
|
||||||
torch
|
torch
|
||||||
torchsde
|
torchsde
|
||||||
torchvision
|
torchvision
|
||||||
@ -23,7 +23,7 @@ SQLAlchemy>=2.0.0
|
|||||||
filelock
|
filelock
|
||||||
av>=16.0.0
|
av>=16.0.0
|
||||||
comfy-kitchen==0.2.10
|
comfy-kitchen==0.2.10
|
||||||
comfy-aimdo==0.4.9
|
comfy-aimdo==0.4.10
|
||||||
requests
|
requests
|
||||||
simpleeval>=1.0.0
|
simpleeval>=1.0.0
|
||||||
blake3
|
blake3
|
||||||
|
|||||||
Reference in New Issue
Block a user