removed invalidate cache and added async

This commit is contained in:
Inoland
2026-04-14 23:56:51 +04:00
parent 7a2bbb0ed0
commit 8fabb2d56f
8 changed files with 61 additions and 66 deletions
@@ -1,3 +1,4 @@
import asyncio
from pathlib import Path
from inopyutils import InoFileHelper
@@ -374,7 +375,7 @@ class InoGetLastFile(io.ComfyNode):
return io.NodeOutput(False, "Node is disabled", "", "")
_, abs_path = resolve_comfy_path(parent_folder, folder)
res = InoFileHelper.get_last_file(path=Path(abs_path))
res = await asyncio.to_thread(InoFileHelper.get_last_file, path=Path(abs_path))
if not res["success"]:
return io.NodeOutput(False, res["msg"], "", "")
return io.NodeOutput(True, res["msg"], res.get("file_name", ""), res.get("file_path", ""))
@@ -1,3 +1,4 @@
import asyncio
import os
from inopyutils import InoJsonHelper, InoOpenAIHelper
@@ -5,10 +6,10 @@ from openai import OpenAI
from comfy_api.latest import io
from ..node_helper import ino_print_log, FailureInvalidatesCacheMixin
from ..node_helper import ino_print_log
class InoOpenaiResponses(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoOpenaiResponses(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -60,7 +61,7 @@ class InoOpenaiResponses(FailureInvalidatesCacheMixin, io.ComfyNode):
}
]
response = client.responses.create(model=model, input=response_input)
response = await asyncio.to_thread(client.responses.create, model=model, input=response_input)
error_message = response.error.message if response.error else "none"
response_output = InoJsonHelper.dict_to_string(response.output)["data"] if response.output else "empty"
@@ -69,11 +70,10 @@ class InoOpenaiResponses(FailureInvalidatesCacheMixin, io.ComfyNode):
return io.NodeOutput(True, response.id, response.status, error_message, response_text, response_output)
except Exception as e:
ino_print_log("InoOpenaiResponses", "", e)
cls._bump_failure()
return io.NodeOutput(False, "", "Openai response failed", str(e), "", "")
class InoOpenaiChatCompletions(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoOpenaiChatCompletions(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -124,11 +124,9 @@ class InoOpenaiChatCompletions(FailureInvalidatesCacheMixin, io.ComfyNode):
else:
error_msg = result.get("message", "unknown error")
ino_print_log("InoOpenaiChatCompletions", "", error_msg)
cls._bump_failure()
return io.NodeOutput(False, "", "", error_msg)
except Exception as e:
ino_print_log("InoOpenaiChatCompletions", "", e)
cls._bump_failure()
return io.NodeOutput(False, "", "", str(e))
@@ -1,3 +1,4 @@
import asyncio
import base64
import io as std_io
import torch
@@ -79,7 +80,7 @@ class InoSaveImages(io.ComfyNode):
)
@classmethod
def execute(cls, images, parent_folder, folder, filename_prefix) -> io.NodeOutput:
async def execute(cls, images, parent_folder, folder, filename_prefix) -> io.NodeOutput:
time_now = datetime.now(timezone.utc).isoformat()
rel_path, abs_path = resolve_comfy_path(parent_folder, folder)
@@ -96,20 +97,23 @@ class InoSaveImages(io.ComfyNode):
from comfy.cli_args import args
from PIL.PngImagePlugin import PngInfo
results = []
for (batch_number, image) in enumerate(images):
i = 255. * image.cpu().numpy()
img = PILImage.fromarray(np.clip(i, 0, 255).astype(np.uint8))
metadata = None
if not args.disable_metadata:
metadata = PngInfo()
images_cpu = [img.cpu().numpy() for img in images]
include_metadata = not args.disable_metadata
filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
file = f"{filename_with_batch_num}_{counter:05}_.png"
full_path = os.path.join(full_output_folder, file)
img.save(full_path, pnginfo=metadata, compress_level=4)
results.append({"filename": file, "subfolder": subfolder, "type": parent_folder})
counter += 1
def _save_all():
saved = []
local_counter = counter
for batch_number, arr in enumerate(images_cpu):
pil_img = PILImage.fromarray(np.clip(255. * arr, 0, 255).astype(np.uint8))
metadata = PngInfo() if include_metadata else None
filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
file = f"{filename_with_batch_num}_{local_counter:05}_.png"
pil_img.save(os.path.join(full_output_folder, file), pnginfo=metadata, compress_level=4)
saved.append({"filename": file, "subfolder": subfolder, "type": parent_folder})
local_counter += 1
return saved
results = await asyncio.to_thread(_save_all)
if len(results) == 0:
return io.NodeOutput(False, "No images saved", rel_path, abs_path, 0, time_now)
@@ -1,3 +1,4 @@
import asyncio
import re
import hashlib
import base64
@@ -8,6 +9,12 @@ from comfy_api.latest import io
from ..node_helper import PARENT_FOLDER_OPTIONS, resolve_comfy_path
def _write_text_sync(abs_path, text):
Path(abs_path).parent.mkdir(parents=True, exist_ok=True)
with open(abs_path, "w", encoding="utf-8") as f:
f.write(text)
class InoStringToggleCase(io.ComfyNode):
@classmethod
def define_schema(cls):
@@ -168,15 +175,13 @@ class InoSaveText(io.ComfyNode):
)
@classmethod
def execute(cls, enabled, text, parent_folder, folder, filename) -> io.NodeOutput:
async def execute(cls, enabled, text, parent_folder, folder, filename) -> io.NodeOutput:
rel_path, abs_path = resolve_comfy_path(parent_folder, folder, filename)
if not enabled:
return io.NodeOutput(False, "not enabled", rel_path, abs_path)
try:
Path(abs_path).parent.mkdir(parents=True, exist_ok=True)
with open(abs_path, "w", encoding="utf-8") as f:
f.write(text)
await asyncio.to_thread(_write_text_sync, abs_path, text)
return io.NodeOutput(True, "saved", rel_path, abs_path)
except Exception as e:
return io.NodeOutput(False, str(e), rel_path, abs_path)
@@ -1,3 +1,4 @@
import asyncio
import os
import random
import string
@@ -27,7 +28,7 @@ class InoPreviewVideo(io.ComfyNode):
)
@classmethod
def execute(cls, enabled, video: Input.Video, format="mp4", codec="h264") -> io.NodeOutput:
async def execute(cls, enabled, video: Input.Video, format="mp4", codec="h264") -> io.NodeOutput:
if not enabled:
return io.NodeOutput(ui=ui.PreviewVideo([]).as_dict())
@@ -37,7 +38,8 @@ class InoPreviewVideo(io.ComfyNode):
)
file = f"{filename}_{counter:05}_.{Types.VideoContainer.get_extension(format)}"
video.save_to(
await asyncio.to_thread(
video.save_to,
os.path.join(full_output_folder, file),
format=Types.VideoContainer(format),
codec=Types.VideoCodec(codec),
@@ -1,3 +1,4 @@
import asyncio
import os
from pathlib import Path
@@ -6,10 +7,10 @@ from inopyutils import ino_is_err
from comfy_api.latest import io
from .s3_helper import S3Helper, S3_EMPTY_CONFIG_STRING
from ..node_helper import PARENT_FOLDER_OPTIONS, resolve_comfy_path, FailureInvalidatesCacheMixin
from ..node_helper import PARENT_FOLDER_OPTIONS, resolve_comfy_path
class InoS3UploadFile(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoS3UploadFile(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -64,12 +65,11 @@ class InoS3UploadFile(FailureInvalidatesCacheMixin, io.ComfyNode):
s3_instance = S3Helper.get_instance(s3_config)
if ino_is_err(s3_instance):
cls._bump_failure()
return io.NodeOutput(False, s3_instance["msg"], "")
s3_instance = s3_instance["instance"]
s3_result = await s3_instance.upload_file(s3_key=s3_full_key, local_file_path=abs_path)
if s3_result["success"] and delete_local:
os.remove(abs_path)
await asyncio.to_thread(os.remove, abs_path)
return io.NodeOutput(cls._track(s3_result["success"]), s3_result["msg"], s3_full_key)
return io.NodeOutput(s3_result["success"], s3_result["msg"], s3_full_key)
@@ -1,3 +1,4 @@
import asyncio
import shutil
from pathlib import Path
@@ -6,10 +7,10 @@ from inopyutils import ino_is_err
from comfy_api.latest import io
from .s3_helper import S3Helper, S3_EMPTY_CONFIG_STRING
from ..node_helper import PARENT_FOLDER_OPTIONS, resolve_comfy_path, FailureInvalidatesCacheMixin
from ..node_helper import PARENT_FOLDER_OPTIONS, resolve_comfy_path
class InoS3UploadFolder(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoS3UploadFolder(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -60,12 +61,11 @@ class InoS3UploadFolder(FailureInvalidatesCacheMixin, io.ComfyNode):
s3_instance = S3Helper.get_instance(s3_config)
if ino_is_err(s3_instance):
cls._bump_failure()
return io.NodeOutput(False, s3_instance["msg"], rel_path, abs_path, 0, 0, 0, "")
s3_instance = s3_instance["instance"]
s3_result = await s3_instance.upload_folder(s3_folder_key=s3_key, local_folder_path=abs_path, max_concurrent=max_concurrent, verify=verify_with_s3)
if s3_result["success"] and delete_local:
shutil.rmtree(Path(abs_path))
await asyncio.to_thread(shutil.rmtree, Path(abs_path))
return io.NodeOutput(cls._track(s3_result["success"]), s3_result["msg"], rel_path, abs_path, s3_result["total_files"], s3_result["uploaded_successfully"], s3_result["failed_uploads"], str(s3_result["errors"]))
return io.NodeOutput(s3_result["success"], s3_result["msg"], rel_path, abs_path, s3_result["total_files"], s3_result["uploaded_successfully"], s3_result["failed_uploads"], str(s3_result["errors"]))
@@ -1,3 +1,4 @@
import asyncio
import os
import shutil
@@ -10,7 +11,7 @@ import folder_paths
from comfy_api.latest import io
from ..s3_helper.s3_helper import S3Helper, S3_EMPTY_CONFIG_STRING
from ..node_helper import ino_print_log, MODEL_TYPES, FailureInvalidatesCacheMixin
from ..node_helper import ino_print_log, MODEL_TYPES
from ..node_helper import get_list_from_csv, get_model_from_csv
@@ -227,7 +228,7 @@ class InoGetLoraDownloadConfig(io.ComfyNode):
return io.NodeOutput(data)
class InoHttpDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoHttpDownloadModel(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -286,18 +287,16 @@ class InoHttpDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
allow_redirects=True, mkdirs=True, connection=6
)
if ino_is_err(http_result):
cls._bump_failure()
return io.NodeOutput(False, "failed to download", model_type, str(model_path), str(rel_path))
ino_print_log("InoHttpDownloadModel", "file downloaded successfully")
return io.NodeOutput(cls._track(http_result["success"]), http_result["msg"], model_type, str(model_path), str(rel_path))
return io.NodeOutput(http_result["success"], http_result["msg"], model_type, str(model_path), str(rel_path))
except Exception as e:
ino_print_log("InoHttpDownloadModel", "", e)
cls._bump_failure()
return io.NodeOutput(False, f"Error: {e}", "", "", "")
class InoS3DownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoS3DownloadModel(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -359,21 +358,19 @@ class InoS3DownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
s3_instance = S3Helper.get_instance(s3_config)
if ino_is_err(s3_instance):
cls._bump_failure()
return io.NodeOutput(False, s3_instance["msg"], "", "", "")
s3_instance = s3_instance["instance"]
s3_result = await s3_instance.download_file(s3_key=s3_key, local_file_path=model_path)
ino_print_log("InoS3DownloadModel", "file downloaded successfully")
return io.NodeOutput(cls._track(s3_result["success"]), s3_result["msg"], model_type, str(model_path), str(rel_path))
return io.NodeOutput(s3_result["success"], s3_result["msg"], model_type, str(model_path), str(rel_path))
except Exception as e:
ino_print_log("InoS3DownloadModel", "", e)
cls._bump_failure()
return io.NodeOutput(False, f"Error: {e}", "", "", "")
class InoHuggingFaceDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoHuggingFaceDownloadModel(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -442,24 +439,22 @@ class InoHuggingFaceDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
args["local_dir"] = model_path
except Exception as e:
ino_print_log("InoHuggingFaceDownloadModel", "", e)
cls._bump_failure()
return io.NodeOutput(False, f"Error: {e}", "", "", "")
try:
result = hf_hub_download(repo_id, filename, **args)
result = await asyncio.to_thread(hf_hub_download, repo_id, filename, **args)
if ignore_repo_dir:
shutil.move(result, model_path)
await asyncio.to_thread(shutil.move, result, model_path)
result = f"{model_path}/{Path(result).name}"
rel_path = Path(result).relative_to(model_path_base)
ino_print_log("InoHuggingFaceDownloadModel", "file downloaded successfully")
return io.NodeOutput(True, "Successful", model_type, str(result), str(rel_path))
except Exception as e:
ino_print_log("InoHuggingFaceDownloadModel", "", e)
cls._bump_failure()
return io.NodeOutput(False, f"Error: {e}", "", "", "")
class InoHuggingFaceDownloadRepo(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoHuggingFaceDownloadRepo(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -521,21 +516,19 @@ class InoHuggingFaceDownloadRepo(FailureInvalidatesCacheMixin, io.ComfyNode):
args["local_dir"] = model_path
except Exception as e:
ino_print_log("InoHuggingFaceDownloadRepo", "", e)
cls._bump_failure()
return io.NodeOutput(False, f"Error: {e}", "", "", "")
try:
result = snapshot_download(repo_id, **args)
result = await asyncio.to_thread(snapshot_download, repo_id, **args)
rel_path = Path(result).relative_to(model_path_base)
ino_print_log("InoHuggingFaceDownloadRepo", "file downloaded successfully")
return io.NodeOutput(True, "Successful", model_type, str(result), str(rel_path))
except Exception as e:
ino_print_log("InoHuggingFaceDownloadRepo", "", e)
cls._bump_failure()
return io.NodeOutput(False, f"Error: {e}", "", "", "")
class InoCivitaiDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoCivitaiDownloadModel(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -599,7 +592,6 @@ class InoCivitaiDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
file_id=file_id,
)
if ino_is_err(download_model):
cls._bump_failure()
return io.NodeOutput(False, download_model["msg"], model_type, "", "")
await civit_client.close()
@@ -610,11 +602,10 @@ class InoCivitaiDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
return io.NodeOutput(True, download_model["msg"], model_type, str(abs_path), str(rel_path))
except Exception as e:
ino_print_log("InoCivitaiDownloadModel", "", e)
cls._bump_failure()
return io.NodeOutput(False, str(e), "", "", "")
class InoHandleDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
class InoHandleDownloadModel(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
@@ -661,12 +652,6 @@ class InoHandleDownloadModel(FailureInvalidatesCacheMixin, io.ComfyNode):
result = await loader.execute(enabled=True, model_config=config)
ino_print_log("InoHandleDownloadModel", "delegated to loader completed")
# Propagate failure to the outer class's cache-invalidation nonce
try:
inner_success = result.args[0]
except (AttributeError, IndexError):
inner_success = False
cls._track(inner_success)
return result