177 lines
5.1 KiB
Python
177 lines
5.1 KiB
Python
import os
|
|
from aiohttp import web
|
|
|
|
import folder_paths
|
|
from server import PromptServer
|
|
|
|
|
|
def _get_supported_checkpoint_extensions():
|
|
default_extensions = {".ckpt", ".pt", ".bin", ".pth", ".safetensors"}
|
|
extensions = getattr(folder_paths, "supported_pt_extensions", None)
|
|
if not extensions:
|
|
return default_extensions
|
|
return {str(ext).lower() for ext in extensions}
|
|
|
|
|
|
def _clear_checkpoint_filename_cache():
|
|
cache = getattr(folder_paths, "filename_list_cache", None)
|
|
if isinstance(cache, dict):
|
|
cache.pop("checkpoints", None)
|
|
|
|
|
|
def _scan_registered_checkpoint_folders():
|
|
results = set()
|
|
extensions = _get_supported_checkpoint_extensions()
|
|
|
|
try:
|
|
roots = folder_paths.get_folder_paths("checkpoints")
|
|
except Exception:
|
|
roots = []
|
|
|
|
for root in roots:
|
|
if not root or not os.path.isdir(root):
|
|
continue
|
|
|
|
for dirpath, _dirnames, filenames in os.walk(root):
|
|
for filename in filenames:
|
|
_, ext = os.path.splitext(filename)
|
|
if ext.lower() not in extensions:
|
|
continue
|
|
|
|
full_path = os.path.join(dirpath, filename)
|
|
rel_path = os.path.relpath(full_path, root)
|
|
rel_path = rel_path.replace("\\", "/")
|
|
results.add(rel_path)
|
|
|
|
return sorted(results, key=lambda value: value.lower())
|
|
|
|
|
|
def _get_fresh_checkpoints():
|
|
_clear_checkpoint_filename_cache()
|
|
|
|
results = set()
|
|
|
|
try:
|
|
results.update(folder_paths.get_filename_list("checkpoints"))
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
results.update(_scan_registered_checkpoint_folders())
|
|
except Exception:
|
|
pass
|
|
|
|
return sorted(results, key=lambda value: value.lower())
|
|
|
|
|
|
def _patch_backend_checkpoint_classes(checkpoints):
|
|
patched = []
|
|
|
|
try:
|
|
import nodes as comfy_nodes
|
|
except Exception:
|
|
return patched
|
|
|
|
mappings = getattr(comfy_nodes, "NODE_CLASS_MAPPINGS", {})
|
|
checkpoint_values = list(checkpoints)
|
|
|
|
for class_name, node_class in list(mappings.items()):
|
|
name = str(class_name)
|
|
|
|
try:
|
|
if "CheckpointNameSelector" in name:
|
|
def selector_input_types(cls, _checkpoint_values=checkpoint_values):
|
|
return {
|
|
"required": {
|
|
"ckpt_name": (list(_checkpoint_values),),
|
|
},
|
|
}
|
|
|
|
node_class.INPUT_TYPES = classmethod(selector_input_types)
|
|
node_class.RETURN_TYPES = (list(checkpoint_values), "STRING")
|
|
patched.append(name)
|
|
continue
|
|
|
|
if name == "CheckpointLoaderSimple":
|
|
def loader_input_types(cls, _checkpoint_values=checkpoint_values):
|
|
return {
|
|
"required": {
|
|
"ckpt_name": (list(_checkpoint_values),),
|
|
},
|
|
}
|
|
|
|
node_class.INPUT_TYPES = classmethod(loader_input_types)
|
|
patched.append(name)
|
|
continue
|
|
|
|
if name == "CheckpointNameCycler":
|
|
def cycler_input_types(cls, _checkpoint_values=checkpoint_values):
|
|
values = list(_checkpoint_values) or [""]
|
|
return {
|
|
"required": {
|
|
"start_checkpoint": (values,),
|
|
"mode": (["fixed", "increment", "randomize", "shuffle_once"], {"default": "increment"}),
|
|
"change_every": ("INT", {"default": 1, "min": 1, "max": 999999}),
|
|
},
|
|
"hidden": {
|
|
"unique_id": "UNIQUE_ID",
|
|
},
|
|
}
|
|
|
|
node_class.INPUT_TYPES = classmethod(cycler_input_types)
|
|
node_class.RETURN_TYPES = (
|
|
list(checkpoint_values),
|
|
"STRING",
|
|
"STRING",
|
|
"INT",
|
|
"INT",
|
|
"INT",
|
|
)
|
|
patched.append(name)
|
|
continue
|
|
|
|
except Exception as exc:
|
|
print(f"[CheckpointWidgetRefresh] failed to patch {name}: {exc}")
|
|
|
|
return patched
|
|
|
|
|
|
routes = PromptServer.instance.routes
|
|
|
|
|
|
@routes.get("/checkpoint_widget_refresh/checkpoints")
|
|
async def checkpoint_widget_refresh_checkpoints(_request):
|
|
checkpoints = _get_fresh_checkpoints()
|
|
patched = _patch_backend_checkpoint_classes(checkpoints)
|
|
|
|
return web.json_response({
|
|
"checkpoints": checkpoints,
|
|
"count": len(checkpoints),
|
|
"patched_classes": patched,
|
|
"patched_class_count": len(patched),
|
|
})
|
|
|
|
|
|
class CheckpointWidgetRefreshPanel:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {},
|
|
}
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "noop"
|
|
CATEGORY = "utils/model"
|
|
|
|
def noop(self):
|
|
return ()
|
|
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"CheckpointWidgetRefreshPanel": CheckpointWidgetRefreshPanel,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"CheckpointWidgetRefreshPanel": "Checkpoint Widget Refresh",
|
|
}
|