From 8ab15c863c91bce1f9c3a32f947cb4ec659fd7fb Mon Sep 17 00:00:00 2001
From: comfyanonymous <121283862+comfyanonymous@users.noreply.github.com>
Date: Fri, 9 May 2025 01:52:47 -0700
Subject: [PATCH 1/5] Add --mmap-torch-files to enable use of mmap when loading
ckpt/pt (#8021)
---
comfy/cli_args.py | 2 ++
comfy/utils.py | 9 ++++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/comfy/cli_args.py b/comfy/cli_args.py
index 97b348f0d..de292d9b3 100644
--- a/comfy/cli_args.py
+++ b/comfy/cli_args.py
@@ -142,6 +142,8 @@ class PerformanceFeature(enum.Enum):
parser.add_argument("--fast", nargs="*", type=PerformanceFeature, help="Enable some untested and potentially quality deteriorating optimizations. --fast with no arguments enables everything. You can pass a list specific optimizations if you only want to enable specific ones. Current valid optimizations: fp16_accumulation fp8_matrix_mult cublas_ops")
+parser.add_argument("--mmap-torch-files", action="store_true", help="Use mmap when loading ckpt/pt files.")
+
parser.add_argument("--dont-print-server", action="store_true", help="Don't print server output.")
parser.add_argument("--quick-test-for-ci", action="store_true", help="Quick test for CI.")
parser.add_argument("--windows-standalone-build", action="store_true", help="Windows standalone build: Enable convenient things that most people using the standalone windows build will probably enjoy (like auto opening the page on startup).")
diff --git a/comfy/utils.py b/comfy/utils.py
index a826e41bf..561e1b858 100644
--- a/comfy/utils.py
+++ b/comfy/utils.py
@@ -28,6 +28,9 @@ import logging
import itertools
from torch.nn.functional import interpolate
from einops import rearrange
+from comfy.cli_args import args
+
+MMAP_TORCH_FILES = args.mmap_torch_files
ALWAYS_SAFE_LOAD = False
if hasattr(torch.serialization, "add_safe_globals"): # TODO: this was added in pytorch 2.4, the unsafe path should be removed once earlier versions are deprecated
@@ -67,8 +70,12 @@ def load_torch_file(ckpt, safe_load=False, device=None, return_metadata=False):
raise ValueError("{}\n\nFile path: {}\n\nThe safetensors file is corrupt/incomplete. Check the file size and make sure you have copied/downloaded it correctly.".format(message, ckpt))
raise e
else:
+ torch_args = {}
+ if MMAP_TORCH_FILES:
+ torch_args["mmap"] = True
+
if safe_load or ALWAYS_SAFE_LOAD:
- pl_sd = torch.load(ckpt, map_location=device, weights_only=True)
+ pl_sd = torch.load(ckpt, map_location=device, weights_only=True, **torch_args)
else:
pl_sd = torch.load(ckpt, map_location=device, pickle_module=comfy.checkpoint_pickle)
if "global_step" in pl_sd:
From 28f178a840aaa59971ecc6e0ce287bb40d275a89 Mon Sep 17 00:00:00 2001
From: thot experiment <94414189+thot-experiment@users.noreply.github.com>
Date: Fri, 9 May 2025 10:46:34 -0700
Subject: [PATCH 2/5] move SVG to core (#7982)
* move SVG to core
* fix workflow embedding w/ unicode characters
---
comfy_api_nodes/apis/recraft_api.py | 1 -
comfy_api_nodes/nodes_recraft.py | 110 ++--------------------------
comfy_extras/nodes_images.py | 102 ++++++++++++++++++++++++++
3 files changed, 107 insertions(+), 106 deletions(-)
diff --git a/comfy_api_nodes/apis/recraft_api.py b/comfy_api_nodes/apis/recraft_api.py
index c0ec9d0c8..c36d95f24 100644
--- a/comfy_api_nodes/apis/recraft_api.py
+++ b/comfy_api_nodes/apis/recraft_api.py
@@ -81,7 +81,6 @@ class RecraftStyle:
class RecraftIO:
STYLEV3 = "RECRAFT_V3_STYLE"
- SVG = "SVG" # TODO: if acceptable, move into ComfyUI's typing class
COLOR = "RECRAFT_COLOR"
CONTROLS = "RECRAFT_CONTROLS"
diff --git a/comfy_api_nodes/nodes_recraft.py b/comfy_api_nodes/nodes_recraft.py
index 994f377d1..5c89d21e9 100644
--- a/comfy_api_nodes/nodes_recraft.py
+++ b/comfy_api_nodes/nodes_recraft.py
@@ -1,6 +1,7 @@
from __future__ import annotations
from inspect import cleandoc
from comfy.utils import ProgressBar
+from comfy_extras.nodes_images import SVG # Added
from comfy.comfy_types.node_typing import IO
from comfy_api_nodes.apis.recraft_api import (
RecraftImageGenerationRequest,
@@ -28,9 +29,6 @@ from comfy_api_nodes.apinode_utils import (
resize_mask_to_image,
validate_string,
)
-import folder_paths
-import json
-import os
import torch
from io import BytesIO
from PIL import UnidentifiedImageError
@@ -162,102 +160,6 @@ class handle_recraft_image_output:
raise Exception("Received output data was not an image; likely an SVG. If you used style_id, make sure it is not a Vector art style.")
-class SVG:
- """
- Stores SVG representations via a list of BytesIO objects.
- """
- def __init__(self, data: list[BytesIO]):
- self.data = data
-
- def combine(self, other: SVG):
- return SVG(self.data + other.data)
-
- @staticmethod
- def combine_all(svgs: list[SVG]):
- all_svgs = []
- for svg in svgs:
- all_svgs.extend(svg.data)
- return SVG(all_svgs)
-
-
-class SaveSVGNode:
- """
- Save SVG files on disk.
- """
-
- def __init__(self):
- self.output_dir = folder_paths.get_output_directory()
- self.type = "output"
- self.prefix_append = ""
-
- RETURN_TYPES = ()
- DESCRIPTION = cleandoc(__doc__ or "") # Handle potential None value
- FUNCTION = "save_svg"
- CATEGORY = "api node/image/Recraft"
- OUTPUT_NODE = True
-
- @classmethod
- def INPUT_TYPES(s):
- return {
- "required": {
- "svg": (RecraftIO.SVG,),
- "filename_prefix": ("STRING", {"default": "svg/ComfyUI", "tooltip": "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes."})
- },
- "hidden": {
- "prompt": "PROMPT",
- "extra_pnginfo": "EXTRA_PNGINFO"
- }
- }
-
- def save_svg(self, svg: SVG, filename_prefix="svg/ComfyUI", prompt=None, extra_pnginfo=None):
- filename_prefix += self.prefix_append
- full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir)
- results = list()
-
- # Prepare metadata JSON
- metadata_dict = {}
- if prompt is not None:
- metadata_dict["prompt"] = prompt
- if extra_pnginfo is not None:
- metadata_dict.update(extra_pnginfo)
-
- # Convert metadata to JSON string
- metadata_json = json.dumps(metadata_dict, indent=2) if metadata_dict else None
-
- for batch_number, svg_bytes in enumerate(svg.data):
- filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
- file = f"{filename_with_batch_num}_{counter:05}_.svg"
-
- # Read SVG content
- svg_bytes.seek(0)
- svg_content = svg_bytes.read().decode('utf-8')
-
- # Inject metadata if available
- if metadata_json:
- # Create metadata element with CDATA section
- metadata_element = f"""
-
-
-"""
- # Insert metadata after opening svg tag using regex
- import re
- svg_content = re.sub(r'(