Added nodes TT_SdxlClipTextEncoderNode, TT_SdxlClipTextEncoderContextNode, TT_Flux1ClipTextEncoderNode, TT_Flux1ClipTextEncoderContextNode, minor bugfixes and refactoring, added docs, changed version
This commit is contained in:
+1
-1
@@ -9,7 +9,7 @@ __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
|
||||
print()
|
||||
SEP = f"{CYAN}{'=' * 60}{RESET}"
|
||||
print(SEP)
|
||||
print(f"{YELLOW}TenserTensor ComfyUI Nodes Pack (v1.6.12): {BRIGHT_GREEN}{NODES_COUNT} Nodes Loaded{RESET}")
|
||||
print(f"{YELLOW}TenserTensor ComfyUI Nodes Pack (v1.6.13): {BRIGHT_GREEN}{NODES_COUNT} Nodes Loaded{RESET}")
|
||||
print(SEP)
|
||||
print(f"{BRIGHT_CYAN}[V] Repository: https://github.com/tenser-tensor/ComfyUI-TenserTensor{RESET}")
|
||||
print(f"{BRIGHT_CYAN}[V] ComfyUI Registry: https://registry.comfy.org/publishers/tenser-tensor{RESET}")
|
||||
|
||||
@@ -20,7 +20,7 @@ class TT_ClipTextEncodeFlux():
|
||||
RETURN_TYPES = ("CONDITIONING", "CONDITIONING",)
|
||||
RETURN_NAMES = ("POSITIVE", "NEGATIVE",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "TenserTensor/Text Encoders/FLUX"
|
||||
CATEGORY = "TenserTensor/Deprecated/Text Encoders/FLUX"
|
||||
|
||||
def execute(self, **kwargs):
|
||||
return encode_prompts_flux(**kwargs)
|
||||
|
||||
@@ -15,7 +15,7 @@ class TT_ClipTextEncodeFluxContext():
|
||||
RETURN_TYPES = ("TT_CONTEXT", "CONDITIONING", "CONDITIONING",)
|
||||
RETURN_NAMES = ("CONTEXT", "POSITIVE", "NEGATIVE",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "TenserTensor/Text Encoders/FLUX"
|
||||
CATEGORY = "TenserTensor/Deprecated/Text Encoders/FLUX"
|
||||
|
||||
def execute(self, context):
|
||||
clip = context["clip"]
|
||||
|
||||
@@ -26,7 +26,7 @@ class TT_ClipTextEncodeSdxl():
|
||||
RETURN_TYPES = ("CONDITIONING", "CONDITIONING",)
|
||||
RETURN_NAMES = ("POSITIVE", "NEGATIVE",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "TenserTensor/Text Encoders/SDXL"
|
||||
CATEGORY = "TenserTensor/Deprecated/Text Encoders/SDXL"
|
||||
|
||||
def execute(self, **kwargs):
|
||||
return encode_prompts_sdxl(**kwargs)
|
||||
|
||||
@@ -15,7 +15,7 @@ class TT_ClipTextEncodeSdxlContext():
|
||||
RETURN_TYPES = ("TT_CONTEXT", "CONDITIONING", "CONDITIONING",)
|
||||
RETURN_NAMES = ("CONTEXT", "POSITIVE", "NEGATIVE",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "TenserTensor/Text Encoders/SDXL"
|
||||
CATEGORY = "TenserTensor/Deprecated/Text Encoders/SDXL"
|
||||
|
||||
def execute(self, context):
|
||||
clip = context["clip"]
|
||||
|
||||
@@ -16,7 +16,11 @@ def get_control_net_files():
|
||||
|
||||
def load_control_net(filename):
|
||||
cnet_path = folder_paths.get_full_path_or_raise("controlnet", filename)
|
||||
|
||||
print(f"CNET path: {cnet_path}")
|
||||
|
||||
cnet = controlnet.load_controlnet(cnet_path)
|
||||
|
||||
if cnet is None:
|
||||
raise RuntimeError("ERROR: ControlNet file is invalid or corrupted.")
|
||||
|
||||
|
||||
@@ -3,12 +3,192 @@
|
||||
from typing import override
|
||||
|
||||
from comfy_api.latest import io, ComfyExtension
|
||||
from nodes import MAX_RESOLUTION
|
||||
from .nodes_context import Context
|
||||
from .nodes_image import SingleCondCFGGuider
|
||||
|
||||
CATEGORY = "TenserTensor/Text Encoder"
|
||||
|
||||
|
||||
def encode_prompts_sdxl(**kwargs):
|
||||
clip = kwargs.get("clip")
|
||||
|
||||
if clip is None:
|
||||
raise ValueError("ERROR: CLIP is required for text encoder")
|
||||
|
||||
positive_tokens = clip.tokenize(kwargs.get("clip_g_positive"))
|
||||
positive_tokens["l"] = clip.tokenize(kwargs.get("clip_l_positive"))["l"]
|
||||
negative_tokens = clip.tokenize(kwargs.get("clip_g_negative"))
|
||||
negative_tokens["l"] = clip.tokenize(kwargs.get("clip_l_negative"))["l"]
|
||||
|
||||
cond_dict = {
|
||||
"aesthetic_score": kwargs.get("ascore_positive"),
|
||||
"width": kwargs.get("width"),
|
||||
"height": kwargs.get("height"),
|
||||
"target_width": kwargs.get("target_width"),
|
||||
"target_height": kwargs.get("target_height"),
|
||||
}
|
||||
|
||||
positive = clip.encode_from_tokens_scheduled(positive_tokens, add_dict=cond_dict)
|
||||
cond_dict["aesthetic_score"] = kwargs.get("ascore_negative")
|
||||
negative = clip.encode_from_tokens_scheduled(negative_tokens, add_dict=cond_dict)
|
||||
|
||||
return positive, negative
|
||||
|
||||
|
||||
class TT_SdxlClipTextEncoderNode(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="TT_SdxlClipTextEncoderNode",
|
||||
display_name="TT SDXL CLIP Text Encoder",
|
||||
category=CATEGORY,
|
||||
description="",
|
||||
inputs=[
|
||||
io.Clip.Input("clip"),
|
||||
io.String.Input("clip_l_positive", multiline=True, placeholder="CLIP_L Positive", dynamic_prompts=True),
|
||||
io.String.Input("clip_g_positive", multiline=True, placeholder="CLIP_G Positive", dynamic_prompts=True),
|
||||
io.String.Input("clip_l_negative", multiline=True, placeholder="CLIP_L Negative", dynamic_prompts=True),
|
||||
io.String.Input("clip_g_negative", multiline=True, placeholder="CLIP_G Negative", dynamic_prompts=True),
|
||||
io.Float.Input("ascore_positive", default=9.0, min=0.0, max=100.0, step=0.1),
|
||||
io.Float.Input("ascore_negative", default=6.0, min=0.0, max=100.0, step=0.1),
|
||||
io.Int.Input("width", default=512, min=64, max=MAX_RESOLUTION, step=8),
|
||||
io.Int.Input("height", default=512, min=64, max=MAX_RESOLUTION, step=8),
|
||||
io.Int.Input("target_width", default=512, min=64, max=MAX_RESOLUTION, step=8),
|
||||
io.Int.Input("target_height", default=512, min=64, max=MAX_RESOLUTION, step=8),
|
||||
],
|
||||
outputs=[
|
||||
io.Conditioning.Output("POSITIVE"),
|
||||
io.Conditioning.Output("NEGATIVE"),
|
||||
]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, **kwargs) -> io.NodeOutput:
|
||||
positive, negative = encode_prompts_sdxl(**kwargs)
|
||||
|
||||
return io.NodeOutput(positive, negative)
|
||||
|
||||
|
||||
class TT_SdxlClipTextEncoderContextNode(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="TT_SdxlClipTextEncoderContextNode",
|
||||
display_name="TT SDXL CLIP Text Encoder (Context)",
|
||||
category=CATEGORY,
|
||||
description="",
|
||||
inputs=[
|
||||
Context.Input("context")
|
||||
],
|
||||
outputs=[
|
||||
Context.Output("CONTEXT"),
|
||||
io.Conditioning.Output("POSITIVE"),
|
||||
io.Conditioning.Output("NEGATIVE"),
|
||||
]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, **kwargs) -> io.NodeOutput:
|
||||
context = kwargs.get("context")
|
||||
|
||||
args = {}
|
||||
for key in (
|
||||
"clip", "clip_l_positive", "clip_g_positive", "clip_l_negative", "clip_g_negative",
|
||||
"ascore_positive", "ascore_negative", "width", "height", "target_width", "target_height",
|
||||
):
|
||||
args[key] = context.get_attr(key)
|
||||
|
||||
positive, negative = encode_prompts_sdxl(**args)
|
||||
context.set_attr("positive", positive)
|
||||
context.set_attr("negative", negative)
|
||||
|
||||
return io.NodeOutput(context, positive, negative)
|
||||
|
||||
|
||||
def encode_prompts_flux(**kwargs):
|
||||
clip = kwargs.get("clip")
|
||||
|
||||
if clip is None:
|
||||
raise ValueError("ERROR: CLIP is required for text encoder")
|
||||
|
||||
positive_tokens = clip.tokenize(kwargs.get("clip_l_positive"))
|
||||
positive_tokens["t5xxl"] = clip.tokenize(kwargs.get("t5xxl_positive"))["t5xxl"]
|
||||
negative_tokens = clip.tokenize(kwargs.get("clip_l_negative"))
|
||||
negative_tokens["t5xxl"] = clip.tokenize(kwargs.get("t5xxl_negative"))["t5xxl"]
|
||||
|
||||
guidance = kwargs.get("guidance")
|
||||
positive = clip.encode_from_tokens_scheduled(positive_tokens, add_dict={"guidance": guidance, })
|
||||
negative = clip.encode_from_tokens_scheduled(negative_tokens, add_dict={"guidance": guidance, })
|
||||
|
||||
return positive, negative
|
||||
|
||||
|
||||
class TT_Flux1ClipTextEncoderNode(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="TT_Flux1ClipTextEncoderNode",
|
||||
display_name="TT FLUX1 CLIP Text Encoder",
|
||||
category=CATEGORY,
|
||||
description="",
|
||||
inputs=[
|
||||
io.Clip.Input("clip"),
|
||||
io.String.Input("clip_l_positive", multiline=True, placeholder="CLIP_L Positive", dynamic_prompts=True),
|
||||
io.String.Input("t5xxl_positive", multiline=True, placeholder="T5XXL Positive", dynamic_prompts=True),
|
||||
io.String.Input("clip_l_negative", multiline=True, placeholder="CLIP_L Negative", dynamic_prompts=True),
|
||||
io.String.Input("t5xxl_negative", multiline=True, placeholder="T5XXL Negative", dynamic_prompts=True),
|
||||
io.Float.Input("guidance", default=9.0, min=0.0, max=100.0, step=0.1),
|
||||
],
|
||||
outputs=[
|
||||
io.Conditioning.Output("POSITIVE"),
|
||||
io.Conditioning.Output("NEGATIVE"),
|
||||
]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, **kwargs) -> io.NodeOutput:
|
||||
positive, negative = encode_prompts_flux(**kwargs)
|
||||
|
||||
return io.NodeOutput(positive, negative)
|
||||
|
||||
|
||||
class TT_Flux1ClipTextEncoderContextNode(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="TT_Flux1ClipTextEncoderContextNode",
|
||||
display_name="TT FLUX1 CLIP Text Encoder (Context)",
|
||||
category=CATEGORY,
|
||||
description="",
|
||||
inputs=[
|
||||
Context.Input("context")
|
||||
],
|
||||
outputs=[
|
||||
Context.Output("CONTEXT"),
|
||||
io.Conditioning.Output("POSITIVE"),
|
||||
io.Conditioning.Output("NEGATIVE"),
|
||||
]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, **kwargs) -> io.NodeOutput:
|
||||
context = kwargs.get("context")
|
||||
|
||||
args = {}
|
||||
for key in (
|
||||
"clip", "clip_l_positive", "t5xxl_positive", "clip_l_negative", "t5xxl_negative",
|
||||
"guidance",
|
||||
):
|
||||
args[key] = context.get_attr(key)
|
||||
|
||||
positive, negative = encode_prompts_flux(**args)
|
||||
context.set_attr("positive", positive)
|
||||
context.set_attr("negative", negative)
|
||||
|
||||
return io.NodeOutput(context, positive, negative)
|
||||
|
||||
|
||||
def encode_prompts_flux2(**kwargs):
|
||||
clip = kwargs.get("clip")
|
||||
model = kwargs.get("model")
|
||||
@@ -103,6 +283,10 @@ class TextEncodeNodesExtension(ComfyExtension):
|
||||
@override
|
||||
async def get_node_list(self) -> list[type[io.ComfyNode]]:
|
||||
return [
|
||||
TT_SdxlClipTextEncoderNode,
|
||||
TT_SdxlClipTextEncoderContextNode,
|
||||
TT_Flux1ClipTextEncoderNode,
|
||||
TT_Flux1ClipTextEncoderContextNode,
|
||||
TT_Flux2TextEncoderNode,
|
||||
TT_Flux2TextEncoderContextNode,
|
||||
]
|
||||
@@ -117,6 +301,10 @@ async def comfy_entrypoint() -> TextEncodeNodesExtension:
|
||||
# ==============================================================================
|
||||
|
||||
__all__ = [
|
||||
"TT_SdxlClipTextEncoderNode",
|
||||
"TT_SdxlClipTextEncoderContextNode",
|
||||
"TT_Flux1ClipTextEncoderNode",
|
||||
"TT_Flux1ClipTextEncoderContextNode",
|
||||
"TT_Flux2TextEncoderNode",
|
||||
"TT_Flux2TextEncoderContextNode",
|
||||
]
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
[project]
|
||||
name = "ComfyUI-TenserTensor"
|
||||
description = "A collection of custom nodes for ComfyUI that streamline common workflows. Includes all-in-one model loaders (checkpoint/unet, LoRA, CLIP, VAE), GGUF quantized model support (FLUX, FLUX2, SDXL), workflow settings nodes, latent factory (aspect ratio, megapixels, FLUX/SDXL), context nodes, CLIP text encoders, KSamplers (context, advanced, two-stage - draft/refine), VAE encoders/decoders (context, tiled), and post-production tools (brightness, contrast, LUT color grading, film grain, upscaler)."
|
||||
version = "1.6.12"
|
||||
version = "1.6.13"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = ["gguf", "kornia"]
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
## TT FLUX1 CLIP Text Encoder (Context) *TT_Flux1ClipTextEncoderContextNode*
|
||||
|
||||
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
|
||||
|
||||
Context-based variant of the FLUX1 CLIP text encoder. Reads all required parameters from a Context object and writes the resulting conditioning back
|
||||
into it.
|
||||
|
||||
### Inputs
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------------|----------|-----------------------------------------------------------|
|
||||
| `context` | TT_CONTEXT | Yes | Context object carrying CLIP, prompts, and guidance scale |
|
||||
|
||||
### Outputs
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|------------|--------------|-----------------------------------------------------------------------|
|
||||
| `CONTEXT` | TT_CONTEXT | Updated Context with positive and negative conditioning stored inside |
|
||||
| `POSITIVE` | CONDITIONING | Positive conditioning |
|
||||
| `NEGATIVE` | CONDITIONING | Negative conditioning |
|
||||
|
||||
### Usage
|
||||
|
||||
Drop-in replacement for [TT FLUX1 CLIP Text Encoder](TT_Flux1ClipTextEncoderNode.md) in Context-based workflows. The Context must have `clip`,
|
||||
`clip_l_positive`, `t5xxl_positive`, `clip_l_negative`, `t5xxl_negative`, and `guidance` set before reaching this node.
|
||||
|
||||
---
|
||||
|
||||
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
|
||||
@@ -0,0 +1,32 @@
|
||||
## TT FLUX1 CLIP Text Encoder *TT_Flux1ClipTextEncoderNode*
|
||||
|
||||
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
|
||||
|
||||
Encodes positive and negative text prompts for FLUX1 models using dual text encoders (CLIP-L and T5-XXL) with guidance scale conditioning.
|
||||
|
||||
### Inputs
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-------------------|--------|----------|-------------------------------------------|
|
||||
| `clip` | CLIP | Yes | Dual text encoder model (CLIP-L + T5-XXL) |
|
||||
| `clip_l_positive` | STRING | Yes | CLIP-L positive prompt |
|
||||
| `t5xxl_positive` | STRING | Yes | T5-XXL positive prompt |
|
||||
| `clip_l_negative` | STRING | Yes | CLIP-L negative prompt |
|
||||
| `t5xxl_negative` | STRING | Yes | T5-XXL negative prompt |
|
||||
| `guidance` | FLOAT | Yes | Guidance scale, default 9.0 |
|
||||
|
||||
### Outputs
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|------------|--------------|-----------------------|
|
||||
| `POSITIVE` | CONDITIONING | Positive conditioning |
|
||||
| `NEGATIVE` | CONDITIONING | Negative conditioning |
|
||||
|
||||
### Usage
|
||||
|
||||
Connect `POSITIVE` and `NEGATIVE` outputs to a sampler. CLIP-L handles short, structured descriptions; T5-XXL understands longer, more complex
|
||||
prompts — you can use the same text in both or tailor each separately.
|
||||
|
||||
---
|
||||
|
||||
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
|
||||
@@ -0,0 +1,30 @@
|
||||
## TT SDXL CLIP Text Encoder (Context) *TT_SdxlClipTextEncoderContextNode*
|
||||
|
||||
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
|
||||
|
||||
Context-based variant of the SDXL CLIP text encoder. Reads all required parameters from a Context object and writes the resulting conditioning back
|
||||
into it.
|
||||
|
||||
### Inputs
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------------|----------|------------------------------------------------------------------------------------|
|
||||
| `context` | TT_CONTEXT | Yes | Context object carrying CLIP, prompts, aesthetic scores, and resolution parameters |
|
||||
|
||||
### Outputs
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|------------|--------------|-----------------------------------------------------------------------|
|
||||
| `CONTEXT` | TT_CONTEXT | Updated Context with positive and negative conditioning stored inside |
|
||||
| `POSITIVE` | CONDITIONING | Positive conditioning |
|
||||
| `NEGATIVE` | CONDITIONING | Negative conditioning |
|
||||
|
||||
### Usage
|
||||
|
||||
Drop-in replacement for [TT SDXL CLIP Text Encoder](TT_SdxlClipTextEncoderNode.md) in Context-based workflows. The Context must have `clip`,
|
||||
`clip_l_positive`, `clip_g_positive`, `clip_l_negative`, `clip_g_negative`, `ascore_positive`, `ascore_negative`, `width`, `height`, `target_width`,
|
||||
and `target_height` set before reaching this node.
|
||||
|
||||
---
|
||||
|
||||
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
|
||||
@@ -0,0 +1,39 @@
|
||||
## TT SDXL CLIP Text Encoder *TT_SdxlClipTextEncoderNode*
|
||||
|
||||
*This description was generated with AI assistance. If you spot any errors, please create an issue on GitHub.*
|
||||
|
||||
Encodes positive and negative text prompts for SDXL models using dual CLIP encoders (CLIP-L and CLIP-G) with aesthetic score and resolution
|
||||
conditioning.
|
||||
|
||||
### Inputs
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-------------------|--------|----------|--------------------------------------------------------|
|
||||
| `clip` | CLIP | Yes | Dual CLIP model (CLIP-L + CLIP-G) |
|
||||
| `clip_l_positive` | STRING | Yes | CLIP-L positive prompt |
|
||||
| `clip_g_positive` | STRING | Yes | CLIP-G positive prompt |
|
||||
| `clip_l_negative` | STRING | Yes | CLIP-L negative prompt |
|
||||
| `clip_g_negative` | STRING | Yes | CLIP-G negative prompt |
|
||||
| `ascore_positive` | FLOAT | Yes | Aesthetic score for positive conditioning, default 9.0 |
|
||||
| `ascore_negative` | FLOAT | Yes | Aesthetic score for negative conditioning, default 6.0 |
|
||||
| `width` | INT | Yes | Source image width |
|
||||
| `height` | INT | Yes | Source image height |
|
||||
| `target_width` | INT | Yes | Target output width |
|
||||
| `target_height` | INT | Yes | Target output height |
|
||||
|
||||
### Outputs
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|------------|--------------|-----------------------|
|
||||
| `POSITIVE` | CONDITIONING | Positive conditioning |
|
||||
| `NEGATIVE` | CONDITIONING | Negative conditioning |
|
||||
|
||||
### Usage
|
||||
|
||||
Connect `POSITIVE` and `NEGATIVE` outputs to a sampler. Set `width`/`height` to match your source image dimensions and `target_width`/`target_height`
|
||||
to your desired output resolution. Higher `ascore_positive` (8–10) steers generation toward higher aesthetic quality; lower `ascore_negative` (4–6)
|
||||
pushes away from low-quality outputs.
|
||||
|
||||
---
|
||||
|
||||
[View on GitHub](https://github.com/tenser-tensor/ComfyUI-TenserTensor)
|
||||
Reference in New Issue
Block a user