Files
dengdong 3f509b6f09 feat: support z-image-turbo (#713)
* [feat] add nodes for z-image

* updates for fp4 state dict loading

* unit test case for z-image-turbo text-to-image workflow

* update documentation templates for z-image

* minor fix: remove some warnings and invalid attribute access during model loading

* drop down res4lyf test case

* style: make linter happy

* modify test case metrics

* add notes for maintenance

* add github url in notes

* simplify the notes
2025-12-23 22:00:01 -05:00

167 lines
6.1 KiB
Python

import logging
import os
from pathlib import Path
import torch
import yaml
from packaging.version import InvalidVersion, Version
# vanilla and LTS compatibility snippet
try:
from comfy_compatibility.vanilla import prepare_vanilla_environment
prepare_vanilla_environment()
from comfy.model_downloader import add_known_models
from comfy.model_downloader_types import HuggingFile
capability = torch.cuda.get_device_capability(0 if torch.cuda.is_available() else None)
sm = f"{capability[0]}{capability[1]}"
precision = "fp4" if sm == "120" else "int4"
# add known models
models_yaml_path = Path(__file__).parent / "test_data" / "models.yaml"
with open(models_yaml_path, "r") as f:
nunchaku_models_yaml = yaml.safe_load(f)
NUNCHAKU_SVDQ_MODELS = []
for model in nunchaku_models_yaml["models"]:
filename = model["filename"]
if not filename.startswith("svdq-"):
continue
if "{precision}" in filename:
filename = filename.format(precision=precision)
NUNCHAKU_SVDQ_MODELS.append(HuggingFile(repo_id=model["repo_id"], filename=filename))
NUNCHAKU_SVDQ_TEXT_ENCODER_MODELS = [
HuggingFile(repo_id="nunchaku-tech/nunchaku-t5", filename="awq-int4-flux.1-t5xxl.safetensors"),
]
add_known_models("diffusion_models", *NUNCHAKU_SVDQ_MODELS)
add_known_models("text_encoders", *NUNCHAKU_SVDQ_TEXT_ENCODER_MODELS)
except (ImportError, ModuleNotFoundError):
pass
# Get log level from environment variable (default to INFO)
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
# Configure logging
logging.basicConfig(level=getattr(logging, log_level, logging.INFO), format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
logger.info("=" * 40 + " ComfyUI-nunchaku Initialization " + "=" * 40)
from .utils import get_package_version, get_plugin_version
nunchaku_full_version = get_package_version("nunchaku").split("+")[0].strip()
logger.info(f"Nunchaku version: {nunchaku_full_version}")
logger.info(f"ComfyUI-nunchaku version: {get_plugin_version()}")
min_nunchaku_version = "1.0.0"
nunchaku_version = nunchaku_full_version.split("+")[0].strip()
nunchaku_major_minor_patch_version = ".".join(nunchaku_version.split(".")[:3])
try:
if Version(nunchaku_major_minor_patch_version) < Version(min_nunchaku_version):
logger.warning(
f"ComfyUI-nunchaku {get_plugin_version()} requires nunchaku >= v{min_nunchaku_version}, "
f"but found nunchaku {nunchaku_full_version}. Please update nunchaku."
)
except InvalidVersion:
logger.warning(
f"Could not parse nunchaku version: {nunchaku_full_version}. "
f"Please ensure you have at least v{min_nunchaku_version}."
)
NODE_CLASS_MAPPINGS = {}
try:
from .nodes.models.flux import NunchakuFluxDiTLoader
NODE_CLASS_MAPPINGS["NunchakuFluxDiTLoader"] = NunchakuFluxDiTLoader
except ImportError:
logger.exception("Node `NunchakuFluxDiTLoader` import failed:")
try:
from .nodes.models.qwenimage import NunchakuQwenImageDiTLoader
NODE_CLASS_MAPPINGS["NunchakuQwenImageDiTLoader"] = NunchakuQwenImageDiTLoader
except ImportError:
logger.exception("Node `NunchakuQwenImageDiTLoader` import failed:")
try:
from .nodes.lora.flux import NunchakuFluxLoraLoader, NunchakuFluxLoraStack
NODE_CLASS_MAPPINGS["NunchakuFluxLoraLoader"] = NunchakuFluxLoraLoader
NODE_CLASS_MAPPINGS["NunchakuFluxLoraStack"] = NunchakuFluxLoraStack
except ImportError:
logger.exception("Nodes `NunchakuFluxLoraLoader` and `NunchakuFluxLoraStack` import failed:")
try:
from .nodes.models.text_encoder import NunchakuTextEncoderLoader, NunchakuTextEncoderLoaderV2
NODE_CLASS_MAPPINGS["NunchakuTextEncoderLoader"] = NunchakuTextEncoderLoader
NODE_CLASS_MAPPINGS["NunchakuTextEncoderLoaderV2"] = NunchakuTextEncoderLoaderV2
except ImportError:
logger.exception("Nodes `NunchakuTextEncoderLoader` and `NunchakuTextEncoderLoaderV2` import failed:")
try:
from .nodes.preprocessors.depth import FluxDepthPreprocessor
NODE_CLASS_MAPPINGS["NunchakuDepthPreprocessor"] = FluxDepthPreprocessor
except ImportError:
logger.exception("Node `NunchakuDepthPreprocessor` import failed:")
try:
from .nodes.models.pulid import (
NunchakuFluxPuLIDApplyV2,
NunchakuPulidApply,
NunchakuPulidLoader,
NunchakuPuLIDLoaderV2,
)
NODE_CLASS_MAPPINGS["NunchakuPulidApply"] = NunchakuPulidApply
NODE_CLASS_MAPPINGS["NunchakuPulidLoader"] = NunchakuPulidLoader
NODE_CLASS_MAPPINGS["NunchakuPuLIDLoaderV2"] = NunchakuPuLIDLoaderV2
NODE_CLASS_MAPPINGS["NunchakuFluxPuLIDApplyV2"] = NunchakuFluxPuLIDApplyV2
except ImportError:
logger.exception(
"Nodes `NunchakuPulidApply`,`NunchakuPulidLoader`, "
"`NunchakuPuLIDLoaderV2` and `NunchakuFluxPuLIDApplyV2` import failed:"
)
try:
from .nodes.models.ipadapter import NunchakuFluxIPAdapterApply, NunchakuIPAdapterLoader
NODE_CLASS_MAPPINGS["NunchakuFluxIPAdapterApply"] = NunchakuFluxIPAdapterApply
NODE_CLASS_MAPPINGS["NunchakuIPAdapterLoader"] = NunchakuIPAdapterLoader
except ImportError:
logger.exception("Nodes `NunchakuFluxIPAdapterApply` and `NunchakuIPAdapterLoader` import failed:")
try:
from .nodes.models.zimage import NunchakuZImageDiTLoader
NODE_CLASS_MAPPINGS["NunchakuZImageDiTLoader"] = NunchakuZImageDiTLoader
except ImportError:
logger.exception("Nodes `NunchakuZImageDiTLoader` import failed:")
try:
from .nodes.tools.merge_safetensors import NunchakuModelMerger
NODE_CLASS_MAPPINGS["NunchakuModelMerger"] = NunchakuModelMerger
except ImportError:
logger.exception("Node `NunchakuModelMerger` import failed:")
try:
from .nodes.tools.installers import NunchakuWheelInstaller
NODE_CLASS_MAPPINGS["NunchakuWheelInstaller"] = NunchakuWheelInstaller
except ImportError:
logger.exception("Node `NunchakuWheelInstaller` import failed:")
NODE_DISPLAY_NAME_MAPPINGS = {k: v.TITLE for k, v in NODE_CLASS_MAPPINGS.items()}
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
logger.info("=" * (80 + len(" ComfyUI-nunchaku Initialization ")))