Files
T
2026-05-19 14:02:35 +08:00

148 lines
4.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
LLS / ModelLoader
=================
功能域:模型加载与管理(对应功能分类总览第 1 节)
CATEGORY = "LLS/Model Loader"
"""
from __future__ import annotations
# ---------- 防御性导入 ----------
try:
import folder_paths
except Exception as exc:
folder_paths = None
_FOLDER_PATHS_ERR = exc
else:
_FOLDER_PATHS_ERR = None
try:
import comfy.sd as comfy_sd
except Exception as exc:
comfy_sd = None
_COMFY_SD_ERR = exc
else:
_COMFY_SD_ERR = None
# 注:comfy.utils 在本模块未使用,无需导入
# ---------- 工具函数 ----------
def _get_checkpoint_names() -> list[str]:
if folder_paths is None:
return ["(ComfyUI not available)"]
try:
names = folder_paths.get_filename_list("checkpoints")
return names if names else ["(no checkpoints found)"]
except Exception:
return ["(no checkpoints found)"]
def _detect_family(ckpt_name: str, model_family: str) -> str:
"""根据 model_family 参数或文件名推断模型家族。"""
if model_family in ("SD1.5", "SDXL"):
return model_family
# Auto:通过文件名关键词简单判断
name_lower = ckpt_name.lower()
if any(kw in name_lower for kw in ("sdxl", "_xl", "-xl", "xl_")):
return "SDXL"
return "SD1.5"
# ---------- 节点类 ----------
class LLSSimpleCheckpointLoader:
"""
简化版 Checkpoint 加载器,支持 SD1.5 / SDXL 基础流程。
自动识别模型家族,输出 MODEL / CLIP / VAE 以及模型信息字符串。
内部复用 ComfyUI 原生 load_checkpoint_guess_config,已自动适配两种架构。
"""
CATEGORY = "LLS/Model Loader"
FUNCTION = "load_checkpoint"
RETURN_TYPES = ("MODEL", "CLIP", "VAE", "STRING")
RETURN_NAMES = ("model", "clip", "vae", "model_info")
DESCRIPTION = "Load a SD1.5 or SDXL checkpoint. Outputs MODEL, CLIP, VAE and a model_info string."
_FAMILY_CHOICES = ["Auto", "SD1.5", "SDXL"]
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"ckpt_name": (_get_checkpoint_names(),),
"model_family": (cls._FAMILY_CHOICES, {"default": "Auto"}),
}
}
def load_checkpoint(self, ckpt_name: str, model_family: str):
if folder_paths is None:
raise RuntimeError(
"[LLS] folder_paths is not available. "
"Make sure this node runs inside a ComfyUI environment."
) from _FOLDER_PATHS_ERR
if comfy_sd is None:
raise RuntimeError(
"[LLS] comfy.sd is not available. "
"Make sure this node runs inside a ComfyUI environment."
) from _COMFY_SD_ERR
# 解析模型路径(使用 ComfyUI 原生方法,自动抛出文件不存在异常)
try:
ckpt_path = folder_paths.get_full_path_or_raise("checkpoints", ckpt_name)
except (AttributeError, TypeError):
# get_full_path_or_raise 在旧版 ComfyUI 中可能不存在,回退到 get_full_path
ckpt_path = folder_paths.get_full_path("checkpoints", ckpt_name)
if not ckpt_path:
raise RuntimeError(
f"[LLS] Checkpoint '{ckpt_name}' not found in ComfyUI checkpoints directories. "
f"Please add the file to models/checkpoints/ and restart ComfyUI."
)
except FileNotFoundError as exc:
raise RuntimeError(
f"[LLS] Checkpoint '{ckpt_name}' not found: {exc}"
) from exc
# 加载 checkpoint(复用 ComfyUI 原生加载逻辑,自动适配 SD1.5 / SDXL)
try:
out = comfy_sd.load_checkpoint_guess_config(
ckpt_path,
output_vae=True,
output_clip=True,
embedding_directory=folder_paths.get_folder_paths("embeddings"),
)
except Exception as exc:
raise RuntimeError(
f"[LLS] Failed to load checkpoint '{ckpt_name}': {exc}"
) from exc
model, clip, vae = out[0], out[1], out[2]
if model is None:
raise RuntimeError(f"[LLS] Checkpoint '{ckpt_name}' did not produce a valid MODEL.")
if clip is None:
raise RuntimeError(f"[LLS] Checkpoint '{ckpt_name}' did not produce a valid CLIP.")
if vae is None:
raise RuntimeError(f"[LLS] Checkpoint '{ckpt_name}' did not produce a valid VAE.")
detected_family = _detect_family(ckpt_name, model_family)
model_info = (
f"ckpt={ckpt_name} | family={detected_family}"
)
return (model, clip, vae, model_info)
# ---------- 注册表 ----------
NODE_CLASS_MAPPINGS: dict[str, type] = {
"LLSSimpleCheckpointLoader": LLSSimpleCheckpointLoader,
}
NODE_DISPLAY_NAME_MAPPINGS: dict[str, str] = {
"LLSSimpleCheckpointLoader": "LLS Simple Checkpoint Loader",
}