First commit

This commit is contained in:
niknah
2026-06-27 14:29:10 +10:00
parent c6f5ccf03f
commit a71c71cf04
5 changed files with 386 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
from typing import List, Union
import numpy as np
from comfy_api.latest import io
from PIL import Image
import torch
from diffusers import DiffusionPipeline
# import os
model_downloaded = False
class MiniT2ISampler(io.ComfyNode):
"""
An example node
Class methods
-------------
define_schema (io.Schema):
Tell the main program the metadata, input, output parameters of nodes.
fingerprint_inputs:
optional method to control when the node is re executed.
check_lazy_status:
optional method to control list of input names that need to be evaluated.
"""
@classmethod
def define_schema(cls) -> io.Schema:
"""
Return a schema which contains all information about the node.
Some types: "Model", "Vae", "Clip", "Conditioning", "Latent", "Image", "Int", "String", "Float", "Combo".
For outputs the "io.Model.Output" should be used, for inputs the "io.Model.Input" can be used.
The type can be a "Combo" - this will be a list for selection.
"""
return io.Schema(
node_id="MiniT2I",
display_name="MiniT2I Sampler",
category="MiniT2I",
inputs=[
io.String.Input("prompt", multiline=True, lazy=True),
io.Int.Input(
"steps",
default=10,
min=0,
max=4096,
step=1, # Slider's step
display_mode=io.NumberDisplay.number, # Cosmetic only: display as "number" or "slider"
lazy=True, # Will only be evaluated if check_lazy_status requires it
),
io.Float.Input(
"guidance",
default=2.5,
min=0.0,
max=100.0,
step=0.1,
round=0.001, #The value representing the precision to round to, will be set to the step value by default. Can be set to False to disable rounding.
display_mode=io.NumberDisplay.number,
lazy=True,
),
io.Combo.Input("model_type", options=["b16","l16"]),
io.Int.Input(
"seed",
default=1,
step=1,
lazy=True, # Will only be evaluated if check_lazy_status requires it
),
],
outputs=[
io.Image.Output(),
],
)
# @classmethod
# def check_lazy_status(cls, image, string_field, int_field, float_field, print_to_screen):
# """
# Return a list of input names that need to be evaluated.
#
# This function will be called if there are any lazy inputs which have not yet been
# evaluated. As long as you return at least one field which has not yet been evaluated
# (and more exist), this function will be called again once the value of the requested
# field is available.
#
# Any evaluated inputs will be passed as arguments to this function. Any unevaluated
# inputs will have the value None.
# """
# if print_to_screen == "enable":
# return ["int_field", "float_field", "string_field"]
# else:
# return []
@classmethod
def pil2tensor(cls, image: Union[Image.Image, List[Image.Image]]) -> torch.Tensor:
"""
Convert PIL image(s) to tensor, matching ComfyUI's implementation.
Args:
image: Single PIL Image or list of PIL Images
Returns:
torch.Tensor: Image tensor with values normalized to [0, 1]
"""
if isinstance(image, list):
if len(image) == 0:
return torch.empty(0)
return torch.cat([cls.pil2tensor(img) for img in image], dim=0)
# Convert PIL image to RGB if needed
if image.mode == 'RGBA':
image = image.convert('RGB')
elif image.mode != 'RGB':
image = image.convert('RGB')
# Convert to numpy array and normalize to [0, 1]
img_array = np.array(image).astype(np.float32) / 255.0
# Return tensor with shape [1, H, W, 3]
return torch.from_numpy(img_array)[None,]
@classmethod
def execute(cls, prompt, steps, guidance, model_type, seed) -> io.NodeOutput:
global model_downloaded
torch.manual_seed(seed)
HUB_MODEL_ID = "MiniT2I/MiniT2I"
pipe = DiffusionPipeline.from_pretrained(
HUB_MODEL_ID,
custom_pipeline=HUB_MODEL_ID,
local_files_only=model_downloaded,
trust_remote_code=True,
)
if pipe:
model_downloaded = True
output = pipe(
prompt,
model_type=model_type,
guidance_scale=guidance,
num_inference_steps=steps,
torch_dtype=torch.bfloat16,
)
return io.NodeOutput(cls.pil2tensor(output.images))
# return io.NodeOutput(image)
"""
The node will always be re executed if any of the inputs change but
this method can be used to force the node to execute again even when the inputs don't change.
You can make this node return a number or a string. This value will be compared to the one returned the last time the node was
executed, if it is different the node will be executed again.
This method is used in the core repo for the LoadImage node where they return the image hash as a string, if the image hash
changes between executions the LoadImage node is executed again.
"""
#@classmethod
#def fingerprint_inputs(s, image, string_field, int_field, float_field, print_to_screen):
# return ""
+9
View File
@@ -0,0 +1,9 @@
Sampler for MiniT2I
https://huggingface.co/MiniT2I/MiniT2I
Workflows are in the templates section.
Just a quickie. Bit slow cause the model is not cached in memory.
+16
View File
@@ -0,0 +1,16 @@
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io
from .MiniT2I import MiniT2ISampler
class MiniT2IExtension(ComfyExtension):
@override
async def get_node_list(self) -> list[type[io.ComfyNode]]:
return [
MiniT2ISampler,
]
async def comfy_entrypoint() -> MiniT2IExtension: # ComfyUI calls this to load your extension and its nodes.
return MiniT2IExtension()
+185
View File
@@ -0,0 +1,185 @@
{
"id": "e572e121-bf51-413f-bba1-ca525f710414",
"revision": 0,
"last_node_id": 4,
"last_link_id": 2,
"nodes": [
{
"id": 1,
"type": "PreviewImage",
"pos": [
1397.0351491908762,
-950.3260055448459
],
"size": [
140,
246
],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 1
}
],
"outputs": [
{
"name": "images",
"type": "IMAGE",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.26.0",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 4,
"type": "PreviewImage",
"pos": [
1416.1947412443299,
-549.015734080902
],
"size": [
140,
246
],
"flags": {},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 2
}
],
"outputs": [
{
"name": "images",
"type": "IMAGE",
"links": null
}
],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.26.0",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 2,
"type": "MiniT2I",
"pos": [
850.8583116297305,
-918.896001453913
],
"size": [
400,
208
],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
1
]
}
],
"properties": {
"Node name for S&R": "MiniT2I"
},
"widgets_values": [
"Purple monkey dishwasher",
100,
2.5,
"b16",
1,
"increment"
]
},
{
"id": 3,
"type": "MiniT2I",
"pos": [
820.5800443091753,
-530.5854576396309
],
"size": [
400,
208
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
2
]
}
],
"properties": {
"Node name for S&R": "MiniT2I"
},
"widgets_values": [
"Purple monkey dishwasher",
100,
6,
"l16",
1,
"increment"
]
}
],
"links": [
[
1,
2,
0,
1,
0,
"IMAGE"
],
[
2,
3,
0,
4,
0,
"IMAGE"
]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1.588548164722016,
"offset": [
-504.72890778875325,
878.5672286853679
]
},
"frontendVersion": "1.45.19",
"VHS_latentpreview": false,
"VHS_latentpreviewrate": 0,
"VHS_MetadataImage": true,
"VHS_KeepIntermediate": true
},
"version": 0.4
}
+20
View File
@@ -0,0 +1,20 @@
[project]
name = "MiniT2I-ComfyUI"
version = "1.0.0"
description = "MiniT2i for ComfyUI"
license = { file = "LICENSE" }
dependencies = [
]
classifiers = [
"Operating System :: OS Independent" # Works on all operating systems
]
dynamic = ["dependencies"]
[project.urls]
Repository = "https://github.com/niknah/MiniT2I-ComfyUI"
Documentation = "https://huggingface.co/MiniT2I/MiniT2I"
"Bug Tracker" = "https://github.com/niknah/MiniT2I-ComfyUI/issues"
[tool.comfy]
PublisherId = "niknah"
DisplayName = "MiniT2I"