mirror of
https://github.com/hanzoui/mixlab-nodes.git
synced 2026-10-30 20:48:06 +00:00
1009 lines
28 KiB
Python
1009 lines
28 KiB
Python
import os,platform
|
||
import re,random,json
|
||
from PIL import Image
|
||
import numpy as np
|
||
# FONT_PATH= os.path.abspath(os.path.join(os.path.dirname(__file__),'../assets/王汉宗颜楷体繁.ttf'))
|
||
import folder_paths
|
||
import matplotlib.font_manager as fm
|
||
import torch
|
||
import importlib.util
|
||
|
||
def create_incrementing_list(min_value, max_value, step, count):
|
||
l1 = [int(min_value + i * step) for i in range(count) if min_value + i * step <= max_value]
|
||
l2 = [float(min_value + i * step) for i in range(count) if min_value + i * step <= max_value]
|
||
return (l1,l2)
|
||
|
||
def split_list(lst, chunk_size, transition_size):
|
||
result = []
|
||
for i in range(0, len(lst), chunk_size):
|
||
start = i - transition_size
|
||
end = i + chunk_size + transition_size
|
||
result.append(lst[max(start, 0):end])
|
||
return result
|
||
|
||
def recursive_search(directory, excluded_dir_names=None):
|
||
if not os.path.isdir(directory):
|
||
return [], {}
|
||
|
||
if excluded_dir_names is None:
|
||
excluded_dir_names = []
|
||
|
||
result = []
|
||
dirs = {directory: os.path.getmtime(directory)}
|
||
for dirpath, subdirs, filenames in os.walk(directory, followlinks=True, topdown=True):
|
||
subdirs[:] = [d for d in subdirs if d not in excluded_dir_names]
|
||
for file_name in filenames:
|
||
relative_path = os.path.relpath(os.path.join(dirpath, file_name), directory)
|
||
result.append(relative_path)
|
||
for d in subdirs:
|
||
path = os.path.join(dirpath, d)
|
||
dirs[path] = os.path.getmtime(path)
|
||
return result, dirs
|
||
|
||
def filter_files_extensions(files, extensions):
|
||
return sorted(list(filter(lambda a: os.path.splitext(a)[-1].lower() in extensions or len(extensions) == 0, files)))
|
||
|
||
|
||
def get_system_font_path():
|
||
ps=[]
|
||
system = platform.system()
|
||
if system == "Windows":
|
||
ps.append(os.path.join(os.environ["WINDIR"], "Fonts"))
|
||
elif system == "Darwin":
|
||
ps.append(os.path.join("/Library", "Fonts"))
|
||
elif system == "Linux":
|
||
ps.append(os.path.join("/usr", "share", "fonts"))
|
||
ps.append(os.path.join("/usr", "local", "share", "fonts"))
|
||
ps=[p for p in ps if os.path.exists(p)]
|
||
file_paths=[]
|
||
for f in ps:
|
||
result, dirs=recursive_search(f)
|
||
for r in result:
|
||
file_paths.append(r)
|
||
file_paths=filter_files_extensions(file_paths,[".otf", ".ttf"])
|
||
|
||
return file_paths
|
||
|
||
|
||
|
||
# import json
|
||
# import hashlib
|
||
|
||
|
||
# def get_json_hash(json_content):
|
||
# json_string = json.dumps(json_content, sort_keys=True)
|
||
# hash_object = hashlib.sha256(json_string.encode())
|
||
# hash_value = hash_object.hexdigest()
|
||
# return hash_value
|
||
|
||
|
||
|
||
def tensor2pil(image):
|
||
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
|
||
|
||
|
||
def create_temp_file(image):
|
||
output_dir = folder_paths.get_temp_directory()
|
||
|
||
(
|
||
full_output_folder,
|
||
filename,
|
||
counter,
|
||
subfolder,
|
||
_,
|
||
) = folder_paths.get_save_image_path('tmp', output_dir)
|
||
|
||
|
||
im=tensor2pil(image)
|
||
|
||
image_file = f"{filename}_{counter:05}.png"
|
||
|
||
image_path=os.path.join(full_output_folder, image_file)
|
||
|
||
im.save(image_path,compress_level=4)
|
||
|
||
return [{
|
||
"filename": image_file,
|
||
"subfolder": subfolder,
|
||
"type": "temp"
|
||
}]
|
||
|
||
def get_font_files(directory):
|
||
font_files = {}
|
||
|
||
# 从指定目录加载字体
|
||
for file in os.listdir(directory):
|
||
if file.endswith('.ttf') or file.endswith('.otf'):
|
||
font_name = os.path.splitext(file)[0]
|
||
font_path = os.path.join(directory, file)
|
||
font_files[font_name] = os.path.abspath(font_path)
|
||
|
||
# 尝试获取系统字体
|
||
try:
|
||
font_paths = get_system_font_path()
|
||
for file in font_paths:
|
||
try:
|
||
font_name = os.path.splitext(file)[0]
|
||
font_path = file
|
||
font_files[font_name] = os.path.abspath(font_path)
|
||
except Exception as e:
|
||
print(f"Error processing font {file}: {e}")
|
||
except Exception as e:
|
||
print(f"Error finding system fonts: {e}")
|
||
|
||
return font_files
|
||
|
||
r_directory = os.path.join(os.path.dirname(__file__), '..','assets','/')
|
||
|
||
font_files = get_font_files(r_directory)
|
||
# print(font_files)
|
||
|
||
|
||
def flatten_list(nested_list):
|
||
flat_list = []
|
||
for item in nested_list:
|
||
if isinstance(item, list):
|
||
flat_list.extend(flatten_list(item))
|
||
else:
|
||
if torch.is_tensor(item):
|
||
print('item.shape',item.shape)
|
||
for i in range(item.shape[0]):
|
||
flat_list.append(item[i:i + 1, ...])
|
||
else:
|
||
flat_list.append(item)
|
||
return flat_list
|
||
|
||
|
||
class ColorInput:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"color":("TCOLOR",),
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("STRING","INT","INT","INT","FLOAT",)
|
||
RETURN_NAMES = ("hex","r","g","b","a",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Color"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,False,False,False,False,)
|
||
|
||
def run(self,color):
|
||
h=color['hex']
|
||
r=color['r']
|
||
g=color['g']
|
||
b=color['b']
|
||
a=color['a']
|
||
return (h,r,g,b,a,)
|
||
|
||
|
||
class KeyInput:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"key":("KEY",),
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("STRING",)
|
||
RETURN_NAMES = ("key",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Input"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self,key):
|
||
return (key,)
|
||
|
||
|
||
|
||
class FontInput:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
|
||
"font": (list(font_files.keys()),),
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("STRING",)
|
||
# RETURN_NAMES = ("WIDTH","HEIGHT","X","Y",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Input"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self,font):
|
||
|
||
return (font_files[font],)
|
||
|
||
class TextToNumber:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"text": ("STRING",{"multiline": False,"default": "1"}),
|
||
"random_number": (["enable", "disable"],),
|
||
"max_num":("INT", {
|
||
"default": 10,
|
||
"min":2, #Minimum value
|
||
"max": 10000000000, #Maximum value
|
||
"step": 1, #Slider's step
|
||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||
}),
|
||
},
|
||
"optional":{
|
||
"seed": (any_type, {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = ("INT",)
|
||
# RETURN_NAMES = ("WIDTH","HEIGHT","X","Y",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Text"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self,text,random_number,max_num,seed=0):
|
||
|
||
numbers = re.findall(r'\d+', text)
|
||
result=0
|
||
for n in numbers:
|
||
result = int(n)
|
||
# print(result)
|
||
|
||
if random_number=='enable' and result>0:
|
||
result= random.randint(1, max_num)
|
||
return {"ui": {"text": [text],"num":[result]}, "result": (result,)}
|
||
|
||
|
||
|
||
class FloatSlider:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"number":("FLOAT", {
|
||
"default": 0,
|
||
"min": 0, #Minimum value
|
||
"max": 0xffffffffffffffff, #Maximum value
|
||
"step": 0.001, #Slider's step
|
||
"display": "slider" # Cosmetic only: display as "number" or "slider"
|
||
}),
|
||
"min_value":("FLOAT", {
|
||
"default": 0,
|
||
"min": -0xffffffffffffffff,
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.001,
|
||
"display": "number"
|
||
}),
|
||
"max_value":("FLOAT", {
|
||
"default": 1,
|
||
"min": -0xffffffffffffffff,
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.001,
|
||
"display": "number"
|
||
}),
|
||
"step":("FLOAT", {
|
||
"default": 0.001,
|
||
"min": -0xffffffffffffffff,
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.001,
|
||
"display": "number"
|
||
}),
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("FLOAT",)
|
||
RETURN_NAMES = ('FLOAT',)
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Input"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self, number, min_value, max_value, step):
|
||
if number < min_value:
|
||
number = min_value
|
||
elif number > max_value:
|
||
number = max_value
|
||
return (number,)
|
||
|
||
class IntNumber:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"number":("INT", {
|
||
"default": 0,
|
||
"min": -1, #Minimum value
|
||
"max": 0xffffffffffffffff,
|
||
"step": 1,
|
||
"display": "number"
|
||
}),
|
||
"min_value":("INT", {
|
||
"default": 0,
|
||
"min": -0xffffffffffffffff,
|
||
"max": 0xffffffffffffffff,
|
||
"step": 1,
|
||
"display": "number"
|
||
}),
|
||
"max_value":("INT", {
|
||
"default": 1,
|
||
"min": -0xffffffffffffffff,
|
||
"max": 0xffffffffffffffff,
|
||
"step": 1,
|
||
"display": "number"
|
||
}),
|
||
"step":("INT", {
|
||
"default": 1,
|
||
"min": -0xffffffffffffffff,
|
||
"max": 0xffffffffffffffff,
|
||
"step":1,
|
||
"display": "number"
|
||
}),
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("INT",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Input"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self,number,min_value,max_value,step):
|
||
if number < min_value:
|
||
number= min_value
|
||
elif number > max_value:
|
||
number= max_value
|
||
return (number,)
|
||
|
||
class MultiplicationNode:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"numberA":(any_type,),
|
||
"multiply_by":("FLOAT", {
|
||
"default": 1,
|
||
"min": -2, #Minimum value
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.01, #Slider's step
|
||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||
}),
|
||
"add_by":("FLOAT", {
|
||
"default": 0,
|
||
"min": -2000, #Minimum value
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.01, #Slider's step
|
||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||
})
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("FLOAT","INT",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Utils"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,False,)
|
||
|
||
def run(self,numberA,multiply_by,add_by):
|
||
b=int(numberA*multiply_by+add_by)
|
||
a=float(numberA*multiply_by+add_by)
|
||
return (a,b,)
|
||
|
||
class TextInput:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"text": ("STRING",{"multiline": True,"default": ""})
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("STRING",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Input"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self,text):
|
||
|
||
return (text,)
|
||
|
||
|
||
class IncrementingListNode:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"min_value": ("FLOAT", {
|
||
"default": 0,
|
||
"min": -2000, #Minimum value
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.01, #Slider's step
|
||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||
}),
|
||
"max_value": ("FLOAT", {
|
||
"default": 10,
|
||
"min": -2000, #Minimum value
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.01, #Slider's step
|
||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||
}),
|
||
"step": ("FLOAT", {
|
||
"default": 0,
|
||
"min": -2000, #Minimum value
|
||
"max": 0xffffffffffffffff,
|
||
"step": 0.01, #Slider's step
|
||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||
}),
|
||
"count": ("INT", {
|
||
"default": 1,
|
||
"min": 1, #Minimum value
|
||
"max": 0xffffffffffffffff,
|
||
"step":1, #Slider's step
|
||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||
})
|
||
},
|
||
"optional":{
|
||
"seed":("INT", {"default": -1, "min": -1, "max": 1000000}),
|
||
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("INT","FLOAT",)
|
||
RETURN_NAMES = ('int_list','float_list',)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Video"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (True,True,)
|
||
|
||
def run(self,min_value,max_value,step,count,seed):
|
||
print('create_incrementing_list',seed)
|
||
l1,l2=create_incrementing_list(min_value,max_value,step,count)
|
||
return (l1,l2,)
|
||
|
||
# 接收一个值,然后根据字符串或数值长度计算延迟时间,用户可以自定义延迟"字/s",延迟之后将转化
|
||
|
||
import comfy.samplers
|
||
import folder_paths
|
||
|
||
# import time
|
||
|
||
|
||
class AnyType(str):
|
||
"""A special class that is always equal in not equal comparisons. Credit to pythongosssss"""
|
||
|
||
def __ne__(self, __value: object) -> bool:
|
||
return False
|
||
|
||
any_type = AnyType("*")
|
||
import time
|
||
|
||
class DynamicDelayProcessor:
|
||
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
# print("print INPUT_TYPES",cls)
|
||
return {
|
||
"required":{
|
||
"delay_seconds":("INT",{
|
||
"default":1,
|
||
"min": 0,
|
||
"max": 1000000,
|
||
}),
|
||
},
|
||
"optional":{
|
||
"any_input":(any_type,),
|
||
"delay_by_text":("STRING",{"multiline":True,"dynamicPrompts": False,}),
|
||
"words_per_seconds":("FLOAT",{ "default":1.50,"min": 0.0,"max": 1000.00,"display":"Chars per second?"}),
|
||
"replace_output": (["disable","enable"],),
|
||
"replace_value":("INT",{ "default":-1,"min": 0,"max": 1000000,"display":"Replacement value"})
|
||
}
|
||
}
|
||
|
||
@classmethod
|
||
def calculate_words_length(cls,text):
|
||
chinese_char_pattern = re.compile(r'[\u4e00-\u9fff]')
|
||
english_word_pattern = re.compile(r'\b[a-zA-Z]+\b')
|
||
number_pattern = re.compile(r'\b[0-9]+\b')
|
||
|
||
words_length = 0
|
||
for segment in text.split():
|
||
if chinese_char_pattern.search(segment):
|
||
# 中文字符,每个字符计为 1
|
||
words_length += len(segment)
|
||
elif number_pattern.match(segment):
|
||
# 数字,每个字符计为 1
|
||
words_length += len(segment)
|
||
elif english_word_pattern.match(segment):
|
||
# 英文单词,整个单词计为 1
|
||
words_length += 1
|
||
|
||
return words_length
|
||
|
||
|
||
|
||
FUNCTION = "run"
|
||
RETURN_TYPES = (any_type,)
|
||
RETURN_NAMES = ('output',)
|
||
|
||
CATEGORY = "♾️Mixlab/Utils"
|
||
def run(self,any_input,delay_seconds,delay_by_text,words_per_seconds,replace_output,replace_value):
|
||
# print(f"Delay text:",delay_by_text )
|
||
# 获取开始时间戳
|
||
start_time = time.time()
|
||
|
||
# 计算延迟时间
|
||
delay_time = delay_seconds
|
||
if delay_by_text and isinstance(delay_by_text, str) and words_per_seconds > 0:
|
||
words_length = self.calculate_words_length(delay_by_text)
|
||
print(f"Delay text: {delay_by_text}, Length: {words_length}")
|
||
delay_time += words_length / words_per_seconds
|
||
|
||
# 延迟执行
|
||
print(f"延迟执行: {delay_time}")
|
||
time.sleep(delay_time)
|
||
|
||
# 获取结束时间戳并计算间隔
|
||
end_time = time.time()
|
||
elapsed_time = end_time - start_time
|
||
print(f"实际延迟时间: {elapsed_time} 秒")
|
||
|
||
# 根据 replace_output 决定输出值
|
||
return (max(0, replace_value),) if replace_output == "enable" else (any_input,)
|
||
|
||
|
||
|
||
|
||
# app 配置节点
|
||
class AppInfo:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"name": ("STRING",{"multiline": False,"default": "Mixlab-App","dynamicPrompts": False}),
|
||
"input_ids":("STRING",{"multiline": True,"default": "\n".join(["1","2","3"]),"dynamicPrompts": False}),
|
||
"output_ids":("STRING",{"multiline": True,"default": "\n".join(["5","9"]),"dynamicPrompts": False}),
|
||
},
|
||
|
||
"optional":{
|
||
"image": ("IMAGE",),
|
||
"description":("STRING",{"multiline": True,"default": "","dynamicPrompts": False}),
|
||
"version":("INT", {
|
||
"default": 1,
|
||
"min": 1,
|
||
"max": 10000,
|
||
"step": 1,
|
||
"display": "number"
|
||
}),
|
||
"share_prefix":("STRING",{"multiline": False,"default": "","dynamicPrompts": False}),
|
||
"link":("STRING",{"multiline": False,"default": "https://","dynamicPrompts": False}),
|
||
"category":("STRING",{"multiline": False,"default": "","dynamicPrompts": False}),
|
||
"auto_save": (["enable","disable"],),
|
||
}
|
||
|
||
}
|
||
|
||
RETURN_TYPES = ()
|
||
# RETURN_NAMES = ("IMAGE",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab"
|
||
|
||
OUTPUT_NODE = True
|
||
INPUT_IS_LIST = True
|
||
# OUTPUT_IS_LIST = (True,)
|
||
|
||
def run(self,name,input_ids,output_ids,image,description,version,share_prefix,link,category,auto_save):
|
||
name=name[0]
|
||
|
||
im=None
|
||
if image:
|
||
im=image[0][0]
|
||
#TODO batch 的方式需要处理
|
||
im=create_temp_file(im)
|
||
# image [img,] img[batch,w,h,a] 列表里面是batch,
|
||
|
||
input_ids=input_ids[0]
|
||
output_ids=output_ids[0]
|
||
description=description[0]
|
||
version=version[0]
|
||
share_prefix=share_prefix[0]
|
||
link=link[0]
|
||
category=category[0]
|
||
|
||
# id=get_json_hash([name,im,input_ids,output_ids,description,version])
|
||
|
||
return {"ui": {"json": [name,im,input_ids,output_ids,description,version,share_prefix,link,category]}, "result": ()}
|
||
|
||
|
||
|
||
|
||
|
||
class SwitchByIndex:
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
return {
|
||
"optional":{
|
||
"A":(any_type,),
|
||
"B":(any_type,),
|
||
},
|
||
"required": {
|
||
"index":("INT", {
|
||
"default": -1,
|
||
"min": -1,
|
||
"max": 1000,
|
||
"step": 1,
|
||
"display": "number"
|
||
}),
|
||
"flat": (['off',"on"],),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = (any_type,"INT",)
|
||
RETURN_NAMES = ("list", "count",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Utils"
|
||
|
||
INPUT_IS_LIST = True
|
||
OUTPUT_IS_LIST = (True, False,)
|
||
|
||
def run(self, A=[],B=[],index=-1,flat='on'):
|
||
|
||
flat=flat[0]
|
||
|
||
C=[]
|
||
index=index[0]
|
||
|
||
for a in A:
|
||
C.append(a)
|
||
for b in B:
|
||
C.append(b)
|
||
|
||
if flat=='on':
|
||
C=flatten_list(C)
|
||
|
||
if index>-1:
|
||
try:
|
||
C=[C[index]]
|
||
except Exception as e:
|
||
C=[C[-1]] #最后一个
|
||
|
||
return (C, len(C),)
|
||
|
||
class ListSplit:
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
return {
|
||
"optional":{
|
||
"A":(any_type,),
|
||
},
|
||
"required": {
|
||
"chunk_size": ("INT", {"default": 10, "min": 1, "step": 1}),
|
||
"transition_size": ("INT", {"default": 0, "min": 0, "step": 1}),
|
||
"index": ("INT", {"default": -1, "min": -1, "step": 1}),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = (any_type,)
|
||
RETURN_NAMES = ("B",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Utils"
|
||
|
||
INPUT_IS_LIST = True
|
||
OUTPUT_IS_LIST = (True,)
|
||
|
||
def run(self, A=[],chunk_size=[10],transition_size=[0],index=[-1]):
|
||
# print(len(A))
|
||
B=split_list(A,chunk_size[0],transition_size[0])
|
||
|
||
if index[0]>-1:
|
||
B=B[index[0]]
|
||
|
||
return (B,)
|
||
|
||
|
||
|
||
class LimitNumber:
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
return {
|
||
"required": {
|
||
"number":(any_type,),
|
||
"min_value":("INT", {
|
||
"default": 0,
|
||
"min": 0,
|
||
"max": 0xffffffffffffffff,
|
||
"step": 1,
|
||
"display": "number"
|
||
}),
|
||
"max_value":("INT", {
|
||
"default": 1,
|
||
"min": 1,
|
||
"max": 0xffffffffffffffff,
|
||
"step": 1,
|
||
"display": "number"
|
||
}),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = (any_type,)
|
||
RETURN_NAMES = ("number",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Input"
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self, number, min_value, max_value):
|
||
nn=number
|
||
|
||
if isinstance(number, int):
|
||
min_value=int(min_value)
|
||
max_value=int(max_value)
|
||
if isinstance(number, float):
|
||
min_value=float(min_value)
|
||
max_value=float(max_value)
|
||
|
||
if number < min_value:
|
||
nn= min_value
|
||
elif number > max_value:
|
||
nn= max_value
|
||
|
||
return (nn,)
|
||
|
||
|
||
|
||
class ListStatistics:
|
||
@staticmethod
|
||
def count_types(lst):
|
||
type_count = {}
|
||
|
||
for item in lst:
|
||
item_type = type(item).__name__
|
||
if item_type not in type_count:
|
||
type_count[item_type] = []
|
||
|
||
if item_type in ['dict', 'str', 'int', 'float']:
|
||
type_count[item_type].append(item)
|
||
|
||
return type_count
|
||
|
||
# # 示例列表
|
||
# my_list = [1, 'hello', {'name': 'John'}, 3.14, {'age': 25}, 'world', 10]
|
||
|
||
# # 创建ListStatistics对象
|
||
# list_stats = ListStatistics()
|
||
|
||
# # 调用count_types方法进行统计
|
||
# result = list_stats.count_types(my_list)
|
||
|
||
# # 输出结果
|
||
# for item_type, values in result.items():
|
||
# print(item_type + ':')
|
||
# for value in values:
|
||
# print(value)
|
||
# print('---')
|
||
|
||
class TESTNODE_:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"ANY":(any_type,),
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = (any_type,)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Test"
|
||
|
||
OUTPUT_NODE = True
|
||
INPUT_IS_LIST = True
|
||
OUTPUT_IS_LIST = (True,)
|
||
|
||
def run(self,ANY):
|
||
print(type(ANY))
|
||
try:
|
||
print(ANY[0].shape)
|
||
img= tensor2pil(ANY[0])
|
||
print(img.size)
|
||
except:
|
||
print('')
|
||
|
||
# data=ANY
|
||
list_stats = ListStatistics()
|
||
|
||
# 调用count_types方法进行统计
|
||
result = list_stats.count_types(ANY)
|
||
|
||
|
||
# 假设我们有一个模块文件名为 my_module.py,它位于 'importables' 目录下
|
||
module_path = os.path.join(os.path.dirname(__file__),'test.py')
|
||
|
||
# 使用 spec_from_file_location 获取模块的元数据(名称、定义等)
|
||
spec = importlib.util.spec_from_file_location('test', module_path)
|
||
|
||
module = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(module)
|
||
|
||
functions = getattr(module, 'run') # 获取函数
|
||
|
||
functions(ANY)
|
||
|
||
|
||
return {"ui": {"data": result,"type":[str(type(ANY[0]))]}, "result": (ANY,)}
|
||
|
||
|
||
class TESTNODE_TOKEN:
|
||
@classmethod
|
||
def INPUT_TYPES(s):
|
||
return {"required": {
|
||
"text":("STRING", {"forceInput": True,}),
|
||
"clip": ("CLIP", )
|
||
},
|
||
}
|
||
|
||
RETURN_TYPES = ("STRING",)
|
||
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Test"
|
||
|
||
OUTPUT_NODE = True
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (False,)
|
||
|
||
def run(self,text,clip=None):
|
||
# print(text)
|
||
|
||
tokens = clip.tokenize(text)
|
||
|
||
tokens=[v for v in tokens.values()][0][0]
|
||
|
||
tokens=json.dumps(tokens)
|
||
|
||
return (tokens,)
|
||
|
||
|
||
|
||
class CreateSeedNode:
|
||
def __init__(self):
|
||
pass
|
||
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
return {
|
||
"required": {
|
||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = ("INT",)
|
||
RETURN_NAMES = ("seed",)
|
||
|
||
OUTPUT_NODE = True
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Experiment"
|
||
|
||
def run(self, seed):
|
||
return (seed,)
|
||
|
||
|
||
class CreateCkptNames:
|
||
def __init__(self):
|
||
pass
|
||
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
return {
|
||
"required": {
|
||
"ckpt_names": ("STRING",{"multiline": True,"default": "\n".join(folder_paths.get_filename_list("checkpoints")),"dynamicPrompts": False}),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = (any_type,)
|
||
RETURN_NAMES = ("ckpt_names",)
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (True,)
|
||
|
||
# OUTPUT_NODE = True
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Experiment"
|
||
|
||
def run(self, ckpt_names):
|
||
ckpt_names=ckpt_names.split('\n')
|
||
ckpt_names = [name for name in ckpt_names if name.strip()]
|
||
return (ckpt_names,)
|
||
|
||
|
||
class CreateLoraNames:
|
||
def __init__(self):
|
||
pass
|
||
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
return {
|
||
"required": {
|
||
"lora_names": ("STRING",{"multiline": True,"default": "\n".join(folder_paths.get_filename_list("loras")),"dynamicPrompts": False}),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = (any_type,"STRING",)
|
||
RETURN_NAMES = ("lora_names","prompt",)
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (True,True,)
|
||
|
||
# OUTPUT_NODE = True
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Experiment"
|
||
|
||
def run(self, lora_names):
|
||
lora_names=lora_names.split('\n')
|
||
lora_names = [name for name in lora_names if name.strip()]
|
||
prompts=[os.path.splitext(n)[0] for n in lora_names]
|
||
return (lora_names,prompts,)
|
||
|
||
|
||
|
||
class CreateSampler_names:
|
||
def __init__(self):
|
||
pass
|
||
|
||
@classmethod
|
||
def INPUT_TYPES(cls):
|
||
return {
|
||
"required": {
|
||
"sampler_names": ("STRING",{"multiline": True,"default": "\n".join(comfy.samplers.KSampler.SAMPLERS),"dynamicPrompts": False}),
|
||
}
|
||
}
|
||
|
||
RETURN_TYPES = (any_type,)
|
||
RETURN_NAMES = ("sampler_names",)
|
||
|
||
INPUT_IS_LIST = False
|
||
OUTPUT_IS_LIST = (True,)
|
||
|
||
# OUTPUT_NODE = True
|
||
FUNCTION = "run"
|
||
|
||
CATEGORY = "♾️Mixlab/Experiment"
|
||
|
||
def run(self, sampler_names):
|
||
sampler_names=sampler_names.split('\n')
|
||
sampler_names = [name for name in sampler_names if name.strip()]
|
||
return (sampler_names,) |