Added nodes TT_SdxlModelsLoaderNode, TT_SdxlModelsLoaderAdvancedNode, TT_FluxModelsLoaderNode, TT_FluxModelsLoaderAdvancedNode, minor bugfixes and refactoring, added docs, changed version

This commit is contained in:
TenserTensor
2026-03-09 11:20:22 +03:00
parent 52f93f889b
commit 6f7452ac15
9 changed files with 456 additions and 5 deletions
+4
View File
@@ -178,6 +178,8 @@ NODE_CLASS_MAPPINGS = {
"TT_SdxlModelsLoaderAdvancedNode": TT_SdxlModelsLoaderAdvancedNode,
"TT_FluxModelsLoaderNode": TT_FluxModelsLoaderNode,
"TT_FluxModelsLoaderAdvancedNode": TT_FluxModelsLoaderAdvancedNode,
"TT_GgufModelsLoaderNode": TT_GgufModelsLoaderNode,
"TT_GgufModelsLoaderAdvancedNode": TT_GgufModelsLoaderAdvancedNode,
# Postproduction
"TT_ApplyLut": TT_ApplyLut,
"TT_AddFilmGrain": TT_AddFilmGrain,
@@ -278,6 +280,8 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"TT_SdxlModelsLoaderAdvancedNode": "TT SDXL Models Loader (Advanced)",
"TT_FluxModelsLoaderNode": "TT FLUX Models Loader",
"TT_FluxModelsLoaderAdvancedNode": "TT FLUX Models Loader (Advanced)",
"TT_GgufModelsLoaderNode": "TT GGUF Models Loader",
"TT_GgufModelsLoaderAdvancedNode": "TT GGUF Models Loader (Advanced)",
# Postproduction
"TT_ApplyLut": "TT Apply LUT",
"TT_AddFilmGrain": "TT Add Film Grain",
+1 -1
View File
@@ -28,7 +28,7 @@ class TT_Flux2GgufModelsLoader():
RETURN_TYPES = ("MODEL", "CLIP", "VAE",)
RETURN_NAMES = ("MODEL", "CLIP", "VAE",)
FUNCTION = "load_models"
CATEGORY = "TenserTensor/Loaders/FLUX2 GGUF"
CATEGORY = "TenserTensor/Deprecated/Loaders/FLUX2 GGUF"
VAE_DEVICE = "cpu"
VAE_DTYPE = "bfloat16"
+1 -1
View File
@@ -55,7 +55,7 @@ class TT_Flux2GgufModelsLoaderAdvanced():
RETURN_TYPES = ("MODEL", "CLIP", "VAE",)
RETURN_NAMES = ("MODEL", "CLIP", "VAE",)
FUNCTION = "load_models"
CATEGORY = "TenserTensor/Loaders/FLUX2 GGUF"
CATEGORY = "TenserTensor/Deprecated/Loaders/FLUX2 GGUF"
def load_models(self, **kwargs):
model = load_unet(
+282 -1
View File
@@ -1,13 +1,26 @@
# (c) TenserTensor <tenser.tensor@proton.me> || Apache-2.0 (apache.org/licenses/LICENSE-2.0)
# Contains slightly modified code by City96
# (c) City96 || Apache-2.0 (apache.org/licenses/LICENSE-2.0)
# Modified by TenserTensor
# (c) TenserTensor || Apache-2.0 (apache.org/licenses/LICENSE-2.0)
import collections
import inspect
import logging
import os
from typing import override
import torch
from torch import bfloat16, float16, float32, float8_e4m3fn, float8_e5m2, device, tensor
import folder_paths
from comfy import sd, model_management, utils, model_sampling
from comfy import sd, model_management, utils, model_sampling, model_patcher, lora, float
from comfy_api.latest import io, ComfyExtension
from nodes import VAELoader, MAX_RESOLUTION
from .gguf.dequant import is_quantized, is_torch_compatible
from .gguf.loader import gguf_sd_loader, gguf_clip_loader
from .gguf.ops import GGMLOps, move_patch_to_device
CATEGORY = "TenserTensor/Loaders"
TORCH_DEVICES = ["default", "cpu"]
@@ -27,10 +40,22 @@ def get_diffusion_models_files():
return folder_paths.get_filename_list("diffusion_models")
def get_gguf_diffusion_models_files():
update_folder_names_and_paths("unet_gguf", ["diffusion_models", "unet"])
return [f for f in folder_paths.get_filename_list("unet_gguf")]
def get_text_encoder_files():
return folder_paths.get_filename_list("text_encoders")
def get_gguf_text_encoder_files():
update_folder_names_and_paths("clip_gguf", ["text_encoders", "clip"])
return [x for x in folder_paths.get_filename_list("clip_gguf")]
def get_vae_files():
return VAELoader.vae_list(VAELoader)
@@ -380,6 +405,258 @@ class TT_FluxModelsLoaderAdvancedNode(io.ComfyNode):
return io.NodeOutput(model, clip, vae)
def update_folder_names_and_paths(key, targets=[]):
base = folder_paths.folder_names_and_paths.get(key, ([], {}))
base = base[0] if isinstance(base[0], (list, set, tuple)) else []
target = next((x for x in targets if x in folder_paths.folder_names_and_paths), targets[0])
orig, _ = folder_paths.folder_names_and_paths.get(target, ([], {}))
folder_paths.folder_names_and_paths[key] = (orig or base, {".gguf"})
if base and base != orig:
logging.warning(f"Unknown file list already present on key {key}: {base}")
WeightBackup = collections.namedtuple('WeightBackup', ['weight', 'inplace_update'])
class GGUFModelPatcher(model_patcher.ModelPatcher):
patch_on_device = False
def patch_weight_to_device(self, key, device_to=None, inplace_update=False):
if key not in self.patches:
return
weight = utils.get_attr(self.model, key)
patches = self.patches[key]
if is_quantized(weight):
out_weight = weight.to(device_to)
patches = move_patch_to_device(patches, self.load_device if self.patch_on_device else self.offload_device)
# TODO: do we ever have legitimate duplicate patches? (i.e. patch on top of patched weight)
out_weight.patches = [(patches, key)]
else:
inplace_update = self.weight_inplace_update or inplace_update
if key not in self.backup:
self.backup[key] = WeightBackup(
weight.to(device=self.offload_device, copy=inplace_update), inplace_update
)
if device_to is not None:
temp_weight = model_management.cast_to_device(weight, device_to, torch.float32, copy=True)
else:
temp_weight = weight.to(torch.float32, copy=True)
out_weight = lora.calculate_weight(patches, temp_weight, key)
out_weight = float.stochastic_rounding(out_weight, weight.dtype)
if inplace_update:
utils.copy_to_param(self.model, key, out_weight)
else:
utils.set_attr_param(self.model, key, out_weight)
def unpatch_model(self, device_to=None, unpatch_weights=True):
if unpatch_weights:
for p in self.model.parameters():
if is_torch_compatible(p):
continue
patches = getattr(p, "patches", [])
if len(patches) > 0:
p.patches = []
# TODO: Find another way to not unload after patches
return super().unpatch_model(device_to=device_to, unpatch_weights=unpatch_weights)
def get_dtype(dtype):
match dtype:
case None | "default":
return None
case "target":
return dtype
case _:
return getattr(torch, dtype)
def load_clip_data(ckpt_paths):
clip_data = []
for path in ckpt_paths:
if path.endswith(".gguf"):
state_dict = gguf_clip_loader(path)
else:
state_dict = utils.load_torch_file(path, safe_load=True)
# NOTE: Scaled FP8 would require different custom ops, but only one can be active
if "scaled_fp8" in state_dict:
raise NotImplementedError(
f"Mixing scaled FP8 with GGUF is not supported! Use regular CLIP loader or switch model(s)\n({path})")
clip_data.append(state_dict)
return clip_data
def load_clip_patcher(clip_name, type="flux2"):
clip_path = folder_paths.get_full_path("clip_gguf", clip_name)
clip_type = getattr(sd.CLIPType, type.upper(), sd.CLIPType.FLUX2)
clip_data = load_clip_data([clip_path])
clip = sd.load_text_encoder_state_dicts(
clip_type=clip_type,
state_dicts=clip_data,
model_options={
"custom_operations": GGMLOps,
"initial_device": model_management.text_encoder_offload_device()
},
embedding_directory=folder_paths.get_folder_paths("embeddings"),
)
clip.patcher = GGUFModelPatcher.clone(clip.patcher)
return clip
def apply_bypass_lora_for_models(loaded_lora, model, clip, lora_name, strength):
if loaded_lora == None:
lora_path = folder_paths.get_full_path_or_raise("loras", lora_name)
lora = utils.load_torch_file(lora_path, safe_load=True)
else:
lora = loaded_lora
patched_model, patched_clip = sd.load_bypass_lora_for_models(model, clip, lora, strength, strength)
return (patched_model, patched_clip, lora,)
def load_gguf_pipeline(cls, **kwargs):
ops = GGMLOps()
ops.Linear.dequant_dtype = get_dtype(kwargs.get("dequant_dtype", None))
ops.Linear.patch_dtype = get_dtype(kwargs.get("patch_dtype", None))
gguf_full_path = folder_paths.get_full_path("unet_gguf", kwargs.get("diffusion_model"))
state_dict, extra = gguf_sd_loader(gguf_full_path)
args = {}
valid_params = inspect.signature(sd.load_diffusion_model_state_dict).parameters
if "metadata" in valid_params:
args["metadata"] = extra.get("metadata", {})
model = sd.load_diffusion_model_state_dict(state_dict, model_options={"custom_operations": ops}, **args, )
if model is None:
raise RuntimeError("ERROR: Could not detect model type of: {}".format(gguf_full_path))
model = GGUFModelPatcher.clone(model)
model.patch_on_device = kwargs.get("patch_on_device", None)
apply_sampling = kwargs.get("apply_sampling")
if apply_sampling:
args = {
"model": model,
"base_sampling_shift": kwargs.get("base_sampling_shift"),
"max_sampling_shift": kwargs.get("max_sampling_shift"),
"sampling_width": kwargs.get("sampling_width"),
"sampling_height": kwargs.get("sampling_height"),
}
model = patch_flux_sampling(**args)
clip = load_clip_patcher(kwargs.get("clip"), kwargs.get("clip_type", "flux2"))
if kwargs.get("apply_bypass_lora"):
loras = [
(kwargs.get("lora_name_1"), kwargs.get("strength_1"), 'loaded_lora_1'),
(kwargs.get("lora_name_2"), kwargs.get("strength_2"), 'loaded_lora_2'),
(kwargs.get("lora_name_3"), kwargs.get("strength_3"), 'loaded_lora_3'),
(kwargs.get("lora_name_4"), kwargs.get("strength_4"), 'loaded_lora_4'),
]
for name, strength, attr in loras:
if name != "None" and strength != 0:
cached = getattr(cls, attr)
model, clip, lora = apply_bypass_lora_for_models(cached, model, clip, name, strength)
setattr(cls, attr, lora)
vae = load_vae(
kwargs.get("vae_name"),
kwargs.get("vae_device", "default"),
kwargs.get("vae_dtype", "bfloat16"),
)
return model, clip, vae
class TT_GgufModelsLoaderNode(io.ComfyNode):
@classmethod
def define_schema(cls) -> io.Schema:
return io.Schema(
node_id="TT_GgufModelsLoaderNode",
display_name="TT GGUF Models Loader",
category=CATEGORY,
description="",
inputs=[
io.Combo.Input("diffusion_model", options=get_gguf_diffusion_models_files()),
io.Combo.Input("clip", options=get_gguf_text_encoder_files()),
io.Combo.Input("vae_name", options=get_vae_files()),
],
outputs=[
io.Model.Output("MODEL"),
io.Clip.Output("CLIP"),
io.Vae.Output("VAE"),
]
)
@classmethod
def execute(cls, **kwargs) -> io.NodeOutput:
kwargs["apply_bypass_lora"] = False
model, clip, vae = load_gguf_pipeline(cls, apply_loras=True, **kwargs)
return io.NodeOutput(model, clip, vae)
class TT_GgufModelsLoaderAdvancedNode(io.ComfyNode):
@classmethod
def define_schema(cls) -> io.Schema:
return io.Schema(
node_id="TT_GgufModelsLoaderAdvancedNode",
display_name="TT GGUF Models Loader (Advanced)",
category=CATEGORY,
description="",
inputs=[
io.Combo.Input("diffusion_model", options=get_gguf_diffusion_models_files()),
io.Combo.Input("dequant_dtype", options=list(DTYPES.keys()), default="bfloat16", advanced=True),
io.Combo.Input("patch_dtype", options=list(DTYPES.keys()), default="bfloat16", advanced=True),
io.Boolean.Input("apply_sampling", default=True, label_on="Flux Shift", label_off="No Shift"),
io.Float.Input("base_sampling_shift", default=0.5, min=0.0, max=100.0, step=0.01, advanced=True),
io.Float.Input("max_sampling_shift", default=1.15, min=0.0, max=100.0, step=0.01, advanced=True),
io.Int.Input("sampling_width", default=1024, min=16, max=MAX_RESOLUTION, step=8, advanced=True),
io.Int.Input("sampling_height", default=1024, min=16, max=MAX_RESOLUTION, step=8, advanced=True),
io.Combo.Input("clip", options=get_gguf_text_encoder_files()),
io.Combo.Input("clip_device", options=TORCH_DEVICES, default="default", advanced=True),
io.Combo.Input("lora_name_1", options=get_lora_files()),
io.Float.Input("strength_1", default=1.0, min=-10.0, max=10.0, step=0.1),
io.Combo.Input("lora_name_2", options=get_lora_files()),
io.Float.Input("strength_2", default=1.0, min=-10.0, max=10.0, step=0.1),
io.Combo.Input("lora_name_3", options=get_lora_files()),
io.Float.Input("strength_3", default=1.0, min=-10.0, max=10.0, step=0.1),
io.Combo.Input("lora_name_4", options=get_lora_files()),
io.Float.Input("strength_4", default=1.0, min=-10.0, max=10.0, step=0.1),
io.Combo.Input("vae_name", options=get_vae_files()),
io.Combo.Input("vae_device", options=TORCH_DEVICES, default="default", advanced=True),
io.Combo.Input("vae_dtype", options=list(DTYPES.keys()), advanced=True),
],
outputs=[
io.Model.Output("MODEL"),
io.Clip.Output("CLIP"),
io.Vae.Output("VAE"),
]
)
@classmethod
def execute(cls, **kwargs) -> io.NodeOutput:
kwargs["apply_bypass_lora"] = False
model, clip, vae = load_gguf_pipeline(cls, apply_loras=True, **kwargs)
return io.NodeOutput(model, clip, vae)
# ==============================================================================
# V3 entrypoint — registers context nodes with ComfyUI
# ==============================================================================
@@ -392,6 +669,8 @@ class LoaderNodesExtension(ComfyExtension):
TT_SdxlModelsLoaderAdvancedNode,
TT_FluxModelsLoaderNode,
TT_FluxModelsLoaderAdvancedNode,
TT_GgufModelsLoaderNode,
TT_GgufModelsLoaderAdvancedNode,
]
@@ -408,4 +687,6 @@ __all__ = [
"TT_SdxlModelsLoaderAdvancedNode",
"TT_FluxModelsLoaderNode",
"TT_FluxModelsLoaderAdvancedNode",
"TT_GgufModelsLoaderNode",
"TT_GgufModelsLoaderAdvancedNode",
]
+4 -2
View File
@@ -11,6 +11,8 @@ from comfy.samplers import KSampler, sampler_object, Sampler
from comfy_api.latest import io, ComfyExtension
from nodes import MAX_RESOLUTION
CATEGORY = "TenserTensor/Workflow"
@dataclass
class TTWorkflowSettings():
@@ -128,7 +130,7 @@ class TT_Flux2WorkflowSettingsNode(io.ComfyNode):
return io.Schema(
node_id="TT_Flux2WorkflowSettingsNode",
display_name="TT FLUX2 Workflow Settings",
category="TenserTensor/Workflow",
category=CATEGORY,
description="",
inputs=[
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
@@ -190,7 +192,7 @@ class TT_Flux2WorkflowSettingsAdvancedNode(io.ComfyNode):
return io.Schema(
node_id="TT_Flux2WorkflowSettingsAdvancedNode",
display_name="TT FLUX2 Workflow Settings (Advanced)",
category="TenserTensor/Workflow",
category=CATEGORY,
description="",
inputs=[
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
@@ -0,0 +1,49 @@
## TT FLUX Models Loader (Advanced) *TT_FluxModelsLoaderAdvancedNode*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Extended FLUX pipeline loader with sampling shift control, up to 4 LoRA slots, and advanced device/dtype configuration.
### Inputs
| Parameter | Type | Required | Description |
|---------------------|---------|----------|--------------------------------------------------------------------------------------------------|
| `diffusion_model` | COMBO | Yes | FLUX diffusion model checkpoint file |
| `apply_sampling` | BOOLEAN | Yes | Enable resolution-based sampling shift ("Flux Shift" / "No Shift", default: enabled) |
| `base_sampling_shift` | FLOAT | Yes | Base shift value for sampling schedule (0.0–100.0, default: 0.5) *(advanced)* |
| `max_sampling_shift` | FLOAT | Yes | Maximum shift value for sampling schedule (0.0–100.0, default: 1.15) *(advanced)* |
| `sampling_width` | INT | Yes | Reference width for shift calculation (16–MAX, step: 8, default: 1024) *(advanced)* |
| `sampling_height` | INT | Yes | Reference height for shift calculation (16–MAX, step: 8, default: 1024) *(advanced)* |
| `clip_l` | COMBO | Yes | CLIP-L text encoder file |
| `t5xxl` | COMBO | Yes | T5-XXL text encoder file |
| `clip_device` | COMBO | Yes | Device for CLIP/T5 inference (default: "default") *(advanced)* |
| `lora_name_1` | COMBO | Yes | LoRA file for slot 1 |
| `strength_1` | FLOAT | Yes | Strength for LoRA slot 1 (-10.0–10.0, default: 1.0) |
| `lora_name_2` | COMBO | Yes | LoRA file for slot 2 |
| `strength_2` | FLOAT | Yes | Strength for LoRA slot 2 (-10.0–10.0, default: 1.0) |
| `lora_name_3` | COMBO | Yes | LoRA file for slot 3 |
| `strength_3` | FLOAT | Yes | Strength for LoRA slot 3 (-10.0–10.0, default: 1.0) |
| `lora_name_4` | COMBO | Yes | LoRA file for slot 4 |
| `strength_4` | FLOAT | Yes | Strength for LoRA slot 4 (-10.0–10.0, default: 1.0) |
| `vae_name` | COMBO | Yes | VAE model file for image encoding/decoding |
| `vae_device` | COMBO | Yes | Device for VAE inference (default: "default") *(advanced)* |
| `vae_dtype` | COMBO | Yes | Data type for VAE computation *(advanced)* |
### Outputs
| Parameter | Type | Description |
|-----------|-------|----------------------------------|
| `MODEL` | MODEL | Loaded FLUX diffusion model |
| `CLIP` | CLIP | Loaded CLIP+T5 text encoder |
| `VAE` | VAE | Loaded VAE |
### Usage
Advanced version of the FLUX pipeline loader with full control over all loading parameters. Supports up to
4 simultaneous LoRAs applied at load time. Enable "Flux Shift" to apply resolution-aware sampling shift —
adjust `base_sampling_shift`, `max_sampling_shift`, and the reference resolution to tune the shift curve.
Use advanced device/dtype options to offload components to specific devices or reduce memory usage.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+33
View File
@@ -0,0 +1,33 @@
## TT FLUX Models Loader *TT_FluxModelsLoaderNode*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Loads all components of the FLUX pipeline (diffusion model, text encoders, and VAE) in a single node.
### Inputs
| Parameter | Type | Required | Description |
|-------------------|-------|----------|------------------------------------------------|
| `diffusion_model` | COMBO | Yes | FLUX diffusion model checkpoint file |
| `clip_l` | COMBO | Yes | CLIP-L text encoder file |
| `t5xxl` | COMBO | Yes | T5-XXL text encoder file |
| `clip_device` | COMBO | Yes | Device for CLIP inference (default: "default") |
| `vae_name` | COMBO | Yes | VAE model file for image encoding/decoding |
### Outputs
| Parameter | Type | Description |
|-----------|-------|-----------------------------|
| `MODEL` | MODEL | Loaded FLUX diffusion model |
| `CLIP` | CLIP | Loaded CLIP+T5 text encoder |
| `VAE` | VAE | Loaded VAE |
### Usage
Convenience node for loading the complete FLUX pipeline in one step. Select the diffusion model,
both text encoders (CLIP-L and T5-XXL), and VAE from their respective dropdowns. Use `clip_device`
to offload text encoders to a specific device if needed. LoRA loading is not applied at this stage.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
@@ -0,0 +1,51 @@
## TT GGUF Models Loader (Advanced) *TT_GgufModelsLoaderAdvancedNode*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Extended GGUF pipeline loader with dequantization control, sampling shift, up to 4 LoRA slots, and advanced device/dtype configuration.
### Inputs
| Parameter | Type | Required | Description |
|-----------------------|---------|----------|--------------------------------------------------------------------------------------|
| `diffusion_model` | COMBO | Yes | GGUF-quantized diffusion model file |
| `dequant_dtype` | COMBO | Yes | Data type for dequantization (default: "bfloat16") *(advanced)* |
| `patch_dtype` | COMBO | Yes | Data type for model patches (default: "bfloat16") *(advanced)* |
| `apply_sampling` | BOOLEAN | Yes | Enable resolution-based sampling shift ("Flux Shift" / "No Shift", default: enabled) |
| `base_sampling_shift` | FLOAT | Yes | Base shift value for sampling schedule (0.0–100.0, default: 0.5) *(advanced)* |
| `max_sampling_shift` | FLOAT | Yes | Maximum shift value for sampling schedule (0.0–100.0, default: 1.15) *(advanced)* |
| `sampling_width` | INT | Yes | Reference width for shift calculation (16–MAX, step: 8, default: 1024) *(advanced)* |
| `sampling_height` | INT | Yes | Reference height for shift calculation (16–MAX, step: 8, default: 1024) *(advanced)* |
| `clip` | COMBO | Yes | GGUF-quantized text encoder file |
| `clip_device` | COMBO | Yes | Device for CLIP inference (default: "default") *(advanced)* |
| `lora_name_1` | COMBO | Yes | LoRA file for slot 1 |
| `strength_1` | FLOAT | Yes | Strength for LoRA slot 1 (-10.0–10.0, default: 1.0) |
| `lora_name_2` | COMBO | Yes | LoRA file for slot 2 |
| `strength_2` | FLOAT | Yes | Strength for LoRA slot 2 (-10.0–10.0, default: 1.0) |
| `lora_name_3` | COMBO | Yes | LoRA file for slot 3 |
| `strength_3` | FLOAT | Yes | Strength for LoRA slot 3 (-10.0–10.0, default: 1.0) |
| `lora_name_4` | COMBO | Yes | LoRA file for slot 4 |
| `strength_4` | FLOAT | Yes | Strength for LoRA slot 4 (-10.0–10.0, default: 1.0) |
| `vae_name` | COMBO | Yes | VAE model file for image encoding/decoding |
| `vae_device` | COMBO | Yes | Device for VAE inference (default: "default") *(advanced)* |
| `vae_dtype` | COMBO | Yes | Data type for VAE computation *(advanced)* |
### Outputs
| Parameter | Type | Description |
|-----------|-------|-----------------------------|
| `MODEL` | MODEL | Loaded GGUF diffusion model |
| `CLIP` | CLIP | Loaded GGUF text encoder |
| `VAE` | VAE | Loaded VAE |
### Usage
Advanced GGUF pipeline loader with full control over quantization and loading parameters. Use `dequant_dtype`
and `patch_dtype` to balance precision and VRAM usage during dequantization. Supports up to 4 simultaneous
LoRAs applied at load time. Enable "Flux Shift" to apply resolution-aware sampling shift — adjust
`base_sampling_shift`, `max_sampling_shift`, and the reference resolution to tune the shift curve.
Use advanced device options to offload components as needed.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
+31
View File
@@ -0,0 +1,31 @@
## TT GGUF Models Loader *TT_GgufModelsLoaderNode*
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
Loads a complete GGUF-quantized pipeline (diffusion model, text encoder, and VAE) in a single node.
### Inputs
| Parameter | Type | Required | Description |
|-------------------|-------|----------|---------------------------------------------|
| `diffusion_model` | COMBO | Yes | GGUF-quantized diffusion model file |
| `clip` | COMBO | Yes | GGUF-quantized text encoder file |
| `vae_name` | COMBO | Yes | VAE model file for image encoding/decoding |
### Outputs
| Parameter | Type | Description |
|-----------|-------|-------------------------------------|
| `MODEL` | MODEL | Loaded GGUF diffusion model |
| `CLIP` | CLIP | Loaded GGUF text encoder |
| `VAE` | VAE | Loaded VAE |
### Usage
Convenience node for loading a GGUF-quantized pipeline in one step. Designed for use with quantized model
files that reduce VRAM requirements. Select the GGUF diffusion model, GGUF text encoder, and VAE from
their respective dropdowns. LoRA loading is supported at this stage; bypass LoRA is not applied.
---
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)