Files
jakechai 49ce520567 v2.7.4
1. Fix Scene Cuts node bug.
2. Fix Cuts video gen workflows bug: loop count = 2 when segment frame count < loop frame count.
3. Add Audio Switch node.
2026-03-06 23:27:44 +08:00

589 lines
29 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import configparser
import os
import re
import folder_paths
import sys
import nodes
from typing import Dict, Type, Any
# WEB directory settings
WEB_DIR_NAME = "ComfyUI-JakeUpgrade"
WEB_JS_DIR = 'web/js'
nodes.EXTENSION_WEB_DIRS[WEB_DIR_NAME] = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
WEB_JS_DIR
)
# Path settings
jakeupgrade_path = os.path.dirname(__file__)
jakeupgrade_nodes_path = os.path.join(jakeupgrade_path, "nodes")
# 直接修改 sys.path 来支持相对导入
sys.path.insert(0, jakeupgrade_path)
print(f"--------------------- Jake Upgrade Nodes ---------------------")
def get_version_from_pyproject():
"""从 pyproject.toml 读取版本信息"""
try:
# 获取当前文件所在目录
current_dir = os.path.dirname(os.path.abspath(__file__))
pyproject_path = os.path.join(current_dir, 'pyproject.toml')
# 读取 pyproject.toml 文件
with open(pyproject_path, 'r', encoding='utf-8') as f:
content = f.read()
# 使用正则表达式匹配版本号
version_match = re.search(r'version\s*=\s*["\']([^"\']+)["\']', content)
if version_match:
return version_match.group(1)
else:
print("⚠️ Version info not found")
return "unknown"
except Exception as e:
print(f"❌ Failed to read version: {e}")
return "unknown"
__version__ = get_version_from_pyproject()
print(f"🔶 Version {__version__}")
def load_config():
"""从 config.ini 加载配置 / Load configuration from config.ini"""
config = configparser.ConfigParser()
# 获取配置文件路径
current_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(current_dir, 'config.ini')
# 如果配置文件存在,读取它
if os.path.exists(config_path):
try:
config.read(config_path, encoding='utf-8')
print("🔶 Config file loaded successfully")
except Exception as e:
print(f"❌ Config file read error: {e}")
# 使用默认值创建新的配置文件
create_default_config(config_path)
else:
# 创建默认配置文件
create_default_config(config_path)
# 获取配置值
try:
load_deprecated = config.getboolean('JakeUpgrade', 'LOAD_DEPRECATED_NODES', fallback=False)
enabled_modules_str = config.get('JakeUpgrade', 'ENABLED_MODULES', fallback='')
random_prompter_abc = config.getboolean('JakeUpgrade', 'RANDOM_PROMPTER_ABC', fallback=False)
except Exception as e:
print(f"❌ Config parsing error: {e}")
load_deprecated = False
enabled_modules_str = ''
random_prompter_abc = False
# 处理启用的模块列表
if enabled_modules_str.strip().lower() == 'all':
# 如果设置为 'all',启用所有模块
enabled_modules = []
elif enabled_modules_str.strip():
# 否则按逗号分割
enabled_modules = [m.strip().lower() for m in enabled_modules_str.split(',') if m.strip()]
else:
# 如果为空,也启用所有模块
enabled_modules = []
return load_deprecated, enabled_modules, random_prompter_abc
def create_default_config(config_path):
"""创建默认配置文件 / Create default config file"""
try:
config_content = """; JakeUpgrade 配置文件 / JakeUpgrade Configuration File
; 注意: 修改配置后需要重启 ComfyUI / Note: Restart ComfyUI after modifying config
[JakeUpgrade]
; 设置为 True 来加载已弃用的节点,False不加载。
; Set to True to load deprecated nodes, False to unload.
LOAD_DEPRECATED_NODES = False
; 启用模块列表 (留空或填写all表示全读取,指定读取模块用逗号分隔)
; Enabled modules list (Leave it blank or fill in "all" to load all modules, and specify the modules separated by commas.)
; 3d,audio,controlnet,lora,experimental,image,latent,mask,math,misc,prompt,switch,video
ENABLED_MODULES = all
; True表示使用ABC Stratagy架构的RandomPrompter节点,False不使用。
; Should we use the ABC Stratagy architecture's RandomPrompter node? True indicates use, False indicates not use.
RANDOM_PROMPTER_ABC = false
[RandomPrompterConfig]
; 提示词数据目录
; Prompt data directory
PROMPT_DATA_DIR = prompt_data
; 目录映射配置 (格式: 内部名称:目录名称)
; Directory mapping configuration (format: internal name: directory name)
DIRECTORY_MAPPING_scene = scenes
DIRECTORY_MAPPING_motion = motions
DIRECTORY_MAPPING_facial_action = facial_actions
DIRECTORY_MAPPING_exp_str = exp_strs
DIRECTORY_MAPPING_expression = expressions
DIRECTORY_MAPPING_audio = audios
DIRECTORY_MAPPING_lighting = lightings
DIRECTORY_MAPPING_camera = cameras
DIRECTORY_MAPPING_style = styles
DIRECTORY_MAPPING_style_artist = 1-artists
DIRECTORY_MAPPING_style_form = 2-forms
DIRECTORY_MAPPING_description = descriptions
; 概率参数配置
; Probability parameter configuration
RANDOM_EMPTY_PROB = 0.10
CUSTOM_FIELD_PROB = 0.05
EXP_STR_RANDOM_PROB = 0.80
STRUCTURED_SELECT_PROB = 0.50
; 参考图像数量 (QWen)
; Number of reference images (QWen)
REF_IMAGE_COUNT = 3
; 随机计算时排除的文件记号 (900 表示文件开头字符数字 >=900 的所有文件)
; File identifiers excluded during randomization (900 indicates all files whose first digits are >= 900).
EXCLUSION_MARK = 900
"""
with open(config_path, 'w', encoding='utf-8') as f:
f.write(config_content)
print(f"🔶 Default config file created: {config_path}")
except Exception as e:
print(f"❌ Failed to create config file: {e}")
# 获取配置
LOAD_DEPRECATED_NODES, ENABLED_MODULES, RANDOM_PROMPTER_ABC = load_config()
BASE_PROMPT_FILE = "jake_node_prompt"
# 根据配置选择提示词节点文件
if RANDOM_PROMPTER_ABC:
PROMPT_NODE_FILE = "jake_node_prompt_random_ABC"
print("🔶 Using ABC Strategy version of RandomPrompter")
else:
PROMPT_NODE_FILE = "jake_node_prompt_random"
print("🔶 Using standard version of RandomPrompter")
# Main node mappings
NODE_CLASS_MAPPINGS: Dict[str, Type[Any]] = {}
NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = {}
# 模块映射定义
MODULE_MAPPING = {
'3d': ('jake_node_3d', '3D Nodes'),
'audio': ('jake_node_audio', 'Audio Nodes'),
'controlnet': ('jake_node_controlnet', 'ControlNet Nodes'),
'lora': ('jake_node_lora', 'LoRA Nodes'),
'experimental': ('jake_node_experimental', 'Experimental Nodes'),
'image': ('jake_node_image', 'Image Nodes'),
'latent': ('jake_node_latent', 'Latent Nodes'),
'mask': ('jake_node_mask', 'Mask Nodes'),
'math': ('jake_node_math', 'Math Nodes'),
'misc': ('jake_node_misc', 'Misc Nodes'),
'prompt': (PROMPT_NODE_FILE, 'Prompt Nodes'),
'switch': ('jake_node_switch', 'Switch Nodes'),
'video': ('jake_node_video', 'Video Nodes')
}
def load_modules():
"""根据配置动态加载模块"""
loaded_modules = []
# 构建导入命令字符串
import_commands = []
# 如果没有指定模块,默认加载所有
if not ENABLED_MODULES:
# print("🔶 Loading all main modules.")
for module_key, (module_file, module_name) in MODULE_MAPPING.items():
import_commands.append(f"from .nodes.{module_file} import *")
import_commands.append(f"from .nodes.{BASE_PROMPT_FILE} import *")
import_commands.append(f"from .nodes.jake_node_3d_viewer import *")
import_commands.append(f"from .nodes.jake_node_3d_sam3dseq import *")
loaded_modules.append(module_key)
else:
# 加载指定的模块
# print("🔶 Loading specified main modules.")
for module_key in ENABLED_MODULES:
if module_key in MODULE_MAPPING:
module_file, module_name = MODULE_MAPPING[module_key]
# 特殊处理3d模块:先加载基础文件(不记录到loaded_modules)
if module_key == '3d':
import_commands.append(f"from .nodes.jake_node_3d_viewer import *")
import_commands.append(f"from .nodes.jake_node_3d_sam3dseq import *")
# 特殊处理prompt模块:先加载基础文件(不记录到loaded_modules)
if module_key == 'prompt':
import_commands.append(f"from .nodes.{BASE_PROMPT_FILE} import *")
# print(f"🔶 Attempting to import: {module_file}")
import_commands.append(f"from .nodes.{module_file} import *")
loaded_modules.append(module_key)
else:
print(f"⚠️ Unknown module: {module_key}")
# 一次性执行所有导入命令
if import_commands:
try:
import_statement = "\n".join(import_commands)
exec(import_statement, globals())
if not ENABLED_MODULES:
print("🔶 All main modules loaded")
else:
print(f"🔶 Loaded modules: {', '.join(loaded_modules) if loaded_modules else 'None'}")
except ImportError as e:
print(f"❌ Failed to load modules: {e}")
return loaded_modules
# 加载模块
loaded_modules = load_modules()
if LOAD_DEPRECATED_NODES:
try:
from .nodes.jake_node_deprecated import *
print("🔶 All deprecated nodes loaded")
except ImportError as e:
print(f"❌ Failed to load deprecated nodes: {e}")
else:
print("🔶 No deprecated nodes loaded")
# 根据实际加载的模块动态创建节点映射
def create_node_mappings() -> Dict[str, Type[Any]]:
"""创建节点映射字典"""
node_mappings = {}
# 使用全局符号表来检查已导入的类
global_symbols = globals()
# 使用lambda函数延迟求值
module_mappings = {
### 3D Nodes
'3d': lambda: {
"Adv3DViewer_JK": lambda: global_symbols.get("Adv3DViewer_JK"),
"SAM3D From Video JK": lambda: global_symbols.get("SAM3DMeshSequenceFromVideo_JK"),
"Orbit Poses JK": lambda: global_symbols.get("OrbitPoses_JK"),
"OrbitLists to OrbitPoses JK": lambda: global_symbols.get("OrbitLists_to_OrbitPoses_JK"),
"OrbitPoses to OrbitLists JK": lambda: global_symbols.get("OrbitPoses_to_OrbitLists_JK"),
"Get OrbitPoses From List JK": lambda: global_symbols.get("Get_OrbitPoses_From_List_JK"),
},
### Audio Nodes
'audio': lambda: {
"Cut Audio JK": lambda: global_symbols.get("CutAudio_JK"),
"Cut Audio Index JK": lambda: global_symbols.get("CutAudioIndex_JK"),
"Cut Audio Cuts JK": lambda: global_symbols.get("CutAudioCuts_JK"),
"Cut Audio Loop JK": lambda: global_symbols.get("CutAudioLoop_JK"),
},
### ControlNet Nodes
'controlnet': lambda: {
"CR ControlNet Loader JK": lambda: global_symbols.get("CR_ControlNetLoader_JK"),
"CR Multi-ControlNet Param Stack JK": lambda: global_symbols.get("CR_ControlNetParamStack_JK"),
"CR Apply ControlNet JK": lambda: global_symbols.get("CR_ApplyControlNet_JK"),
"CR Apply Multi-ControlNet Adv JK": lambda: global_symbols.get("CR_ApplyControlNetStackAdv_JK"),
},
### LoRA Nodes
'lora': lambda: {
"CR LoRA Stack JK": lambda: global_symbols.get("CR_LoRAStack_JK"),
"CR Apply LoRA Stack JK": lambda: global_symbols.get("CR_ApplyLoRAStack_JK"),
"CR LoRA Stack Model Only JK": lambda: global_symbols.get("CR_LoRAStack_ModelOnly_JK"),
"CR Apply LoRA Stack Model Only JK": lambda: global_symbols.get("CR_ApplyLoRAStack_ModelOnly_JK"),
},
### Experimental Nodes
'experimental': lambda: {
"Random Beats JK": lambda: global_symbols.get("RandomBeats_JK"),
},
### Image Nodes
'image': lambda: {
"Rough Outline JK": lambda: global_symbols.get("RoughOutline_JK"),
"OpenDWPose_JK": lambda: global_symbols.get("OpenDWPose_JK"),
"Make Image Grid JK": lambda: global_symbols.get("MakeImageGrid_JK"),
"Split Image Grid JK": lambda: global_symbols.get("SplitImageGrid_JK"),
"Image Remove Alpha JK": lambda: global_symbols.get("ImageRemoveAlpha_JK"),
"Color Grading JK": lambda: global_symbols.get("ColorGrading_JK"),
"Get Size JK": lambda: global_symbols.get("GetSize_JK"),
"Image Crop By Mask Resolution Grp JK": lambda: global_symbols.get("ImageCropByMaskResolutionGrp_JK"),
"Image Crop by Mask Params JK": lambda: global_symbols.get("ImageCropByMaskParams_JK"),
"Scale To Resolution JK": lambda: global_symbols.get("ScaleToResolution_JK"),
"HintImageEnchance JK": lambda: global_symbols.get("HintImageEnchance_JK"),
},
### Latent Nodes
'latent': lambda: {
"Empty Latent Color JK": lambda: global_symbols.get("EmptyLatentColor_JK"),
"Latent Crop Offset JK": lambda: global_symbols.get("LatentCropOffset_JK"),
},
### Mask Nodes
'mask': lambda: {
"Is Mask Empty JK": lambda: global_symbols.get("IsMaskEmpty_JK"),
},
### Math Nodes
'math': lambda: {
"CM_BoolToInt JK": lambda: global_symbols.get("BoolToInt_JK"),
"CM_IntToBool JK": lambda: global_symbols.get("IntToBool_JK"),
"CM_BoolUnaryOperation JK": lambda: global_symbols.get("BoolUnaryOperation_JK"),
"CM_BoolBinaryOperation JK": lambda: global_symbols.get("BoolBinaryOperation_JK"),
"Bool Binary And JK": lambda: global_symbols.get("BoolBinaryAnd_JK"),
"Bool Binary OR JK": lambda: global_symbols.get("BoolBinaryOR_JK"),
"CM_StringBinaryCondition_JK": lambda: global_symbols.get("StringBinaryCondition_JK"),
"CM_FloatUnaryCondition JK": lambda: global_symbols.get("FloatUnaryCondition_JK"),
"CM_FloatBinaryCondition JK": lambda: global_symbols.get("FloatBinaryCondition_JK"),
"CM_IntUnaryCondition JK": lambda: global_symbols.get("IntUnaryCondition_JK"),
"CM_IntBinaryCondition JK": lambda: global_symbols.get("IntBinaryCondition_JK"),
"CM_FloatToInt JK": lambda: global_symbols.get("FloatToInt_JK"),
"CM_IntToFloat JK": lambda: global_symbols.get("IntToFloat_JK"),
"CM_FloatUnaryOperation JK": lambda: global_symbols.get("FloatUnaryOperation_JK"),
"CM_FloatBinaryOperation JK": lambda: global_symbols.get("FloatBinaryOperation_JK"),
"CM_IntUnaryOperation JK": lambda: global_symbols.get("IntUnaryOperation_JK"),
"CM_IntBinaryOperation JK": lambda: global_symbols.get("IntBinaryOperation_JK"),
"Int Sub Operation JK": lambda: global_symbols.get("IntSubOperation_JK"),
"Evaluate Ints JK": lambda: global_symbols.get("EvaluateInts_JK"),
"Evaluate Floats JK": lambda: global_symbols.get("EvaluateFloats_JK"),
"Evaluate Strings JK": lambda: global_symbols.get("EvaluateStrs_JK"),
"Evaluate Examples JK": lambda: global_symbols.get("EvalExamples_JK"),
},
### Misc Nodes
'misc': lambda: {
"Project Setting JK": lambda: global_symbols.get("ProjectSetting_JK"),
"Ksampler Parameters Default JK": lambda: global_symbols.get("KsamplerParametersDefault_JK"),
"Ksampler Adv Parameters Default JK": lambda: global_symbols.get("KsamplerAdvParametersDefault_JK"),
"Base Model Parameters SD3API JK": lambda: global_symbols.get("BaseModelParametersSD3API_JK"),
"Inject Noise Params JK": lambda: global_symbols.get("Inject_Noise_Params_JK"),
"SD3 Prompts Switch JK": lambda: global_symbols.get("SD3_Prompts_Switch_JK"),
"SDXL Target Res JK": lambda: global_symbols.get("SDXL_TargetRes_JK"),
"Guidance Default JK": lambda: global_symbols.get("GuidanceDefault_JK"),
"Image Resize Mode JK": lambda: global_symbols.get("ImageResizeMode_JK"),
"Sampler Loader JK": lambda: global_symbols.get("SamplerLoader_JK"),
"Upscale Method JK": lambda: global_symbols.get("UpscaleMethod_JK"),
"CR Aspect Ratio JK": lambda: global_symbols.get("CR_AspectRatio_JK"),
"String To Combo JK": lambda: global_symbols.get("StringToCombo_JK"),
"Get Nth String JK": lambda: global_symbols.get("GetNthString_JK"),
"Save String List To JSON JK": lambda: global_symbols.get("SaveStringListToJSON_JK"),
"Load String List From JSON JK": lambda: global_symbols.get("LoadStringListFromJSON_JK"),
"Tiling Mode JK": lambda: global_symbols.get("TilingMode_JK"),
"Remove Input JK": lambda: global_symbols.get("RemoveInput_JK"),
},
### Prompt Nodes
'prompt': lambda: {
"RandomPrompter_JK": lambda: global_symbols.get("RandomPrompter_JK"),
"RandomPrompterGeek_JK": lambda: global_symbols.get("RandomPrompterGeek_JK"),
"SystemPrompter_JK": lambda: global_symbols.get("SystemPrompter_JK"),
"ShotScriptCombiner_JK": lambda: global_symbols.get("ShotScriptCombiner_JK"),
"ShotScriptExtractor_JK": lambda: global_symbols.get("ShotScriptExtractor_JK"),
"CM_PromptCombine_JK": lambda: global_symbols.get("PromptCombine_JK"),
},
### Switch Nodes
'switch': lambda: {
"CR Boolean JK": lambda: global_symbols.get("CR_Boolean_JK"),
"CR Int Input Switch JK": lambda: global_symbols.get("CR_IntInputSwitch_JK"),
"CR Float Input Switch JK": lambda: global_symbols.get("CR_FloatInputSwitch_JK"),
"CR Image Input Switch JK": lambda: global_symbols.get("CR_ImageInputSwitch_JK"),
"CR Mask Input Switch JK": lambda: global_symbols.get("CR_MaskInputSwitch_JK"),
"CR Audio Input Switch JK": lambda: global_symbols.get("CR_AudioInputSwitch_JK"),
"CR Latent Input Switch JK": lambda: global_symbols.get("CR_LatentInputSwitch_JK"),
"CR Conditioning Input Switch JK": lambda: global_symbols.get("CR_ConditioningInputSwitch_JK"),
"CR Clip Input Switch JK": lambda: global_symbols.get("CR_ClipInputSwitch_JK"),
"CR Model Input Switch JK": lambda: global_symbols.get("CR_ModelInputSwitch_JK"),
"CR ControlNet Input Switch JK": lambda: global_symbols.get("CR_ControlNetInputSwitch_JK"),
"CR ControlNet Stack Input Switch JK": lambda: global_symbols.get("CR_ControlNetStackInputSwitch_JK"),
"CR Text Input Switch JK": lambda: global_symbols.get("CR_TextInputSwitch_JK"),
"CR VAE Input Switch JK": lambda: global_symbols.get("CR_VAEInputSwitch_JK"),
"CR Noise Input Switch JK": lambda: global_symbols.get("CR_NoiseInputSwitch_JK"),
"CR Guider Input Switch JK": lambda: global_symbols.get("CR_GuiderInputSwitch_JK"),
"CR Sampler Input Switch JK": lambda: global_symbols.get("CR_SamplerInputSwitch_JK"),
"CR Sigmas Input Switch JK": lambda: global_symbols.get("CR_SigmasInputSwitch_JK"),
"CR Mesh Input Switch JK": lambda: global_symbols.get("CR_MeshInputSwitch_JK"),
"CR Ply Input Switch JK": lambda: global_symbols.get("CR_PlyInputSwitch_JK"),
"CR Orbit Pose Input Switch JK": lambda: global_symbols.get("CR_OrbitPoseInputSwitch_JK"),
"CR TriMesh Input Switch JK": lambda: global_symbols.get("CR_TriMeshInputSwitch_JK"),
"CR Impact Pipe Input Switch JK": lambda: global_symbols.get("CR_ImpactPipeInputSwitch_JK"),
},
### Video Nodes
'video': lambda: {
"Scene Cuts JK": lambda: global_symbols.get("SceneCuts_JK"),
"Create Loop Schedule List": lambda: global_symbols.get("CreateLoopScheduleList"),
"Wan Frame Count JK": lambda: global_symbols.get("WanFrameCount_JK"),
"LTXV2 Frame Count JK": lambda: global_symbols.get("LtxV2FrameCount_JK"),
"Wan22 cfg Scheduler List JK": lambda: global_symbols.get("Wan22cfgSchedulerList_JK"),
"Wan Wrapper Sampler Default JK": lambda: global_symbols.get("WanWrapperSamplerDefault_JK"),
}
}
# 高效处理:根据是否指定模块选择不同策略
if not ENABLED_MODULES:
# 加载所有模块
for module_key, node_dict_func in module_mappings.items():
node_dict = node_dict_func() # 调用lambda函数获取字典
for display_name, class_func in node_dict.items():
node_class = class_func() # 调用lambda函数获取类
if node_class is not None and isinstance(node_class, type):
node_mappings[display_name] = node_class
# print(f"✅ Found node: {display_name}")
else:
print(f"⚠️ Node class not found: {display_name}")
else:
# 只加载指定模块
for module_key in ENABLED_MODULES:
if module_key in module_mappings:
node_dict_func = module_mappings[module_key]
node_dict = node_dict_func() # 调用lambda函数获取字典
for display_name, class_func in node_dict.items():
node_class = class_func() # 调用lambda函数获取类
if node_class is not None and isinstance(node_class, type):
node_mappings[display_name] = node_class
# print(f"✅ Found node: {display_name}")
else:
print(f"⚠️ Node class not found: {display_name}")
else:
print(f"⚠️ Module mapping not found for: {module_key}")
return node_mappings
def create_deprecated_node_mappings() -> Dict[str, Type[Any]]:
"""创建已弃用节点映射字典"""
return {
### 3D Nodes [Deprecated]
"Hy3D Cam Config 20to21 JK": Hy3DCamConfig20to21_JK,
### Animation Nodes [Deprecated]
"Animation Prompt JK": AnimPrompt_JK,
"Animation Value JK": AnimValue_JK,
### ControlNet Nodes [Deprecated]
"CR Multi-ControlNet Stack JK": CR_ControlNetStack_JK,
"CR Apply Multi-ControlNet JK": CR_ApplyControlNetStack_JK,
### Embedding Nodes [Deprecated]
"Embedding Picker JK": EmbeddingPicker_JK,
"Embedding Picker Multi JK": EmbeddingPicker_Multi_JK,
### Image Nodes [Deprecated]
"Image Crop by Mask Resolution JK": ImageCropByMaskResolution_JK,
### Loader Nodes [Deprecated]
"Ckpt Loader JK": CkptLoader_JK,
"Vae Loader JK": VaeLoader_JK,
"Upscale Model Loader JK": UpscaleModelLoader_JK,
### LoRA Nodes [Deprecated]
"CR Load LoRA JK": CR_LoraLoader_JK,
### Math Nodes [Deprecated]
"CM_NumberUnaryCondition JK": NumberUnaryCondition_JK,
"CM_NumberBinaryCondition JK": NumberBinaryCondition_JK,
"CM_Vec2UnaryCondition JK": Vec2UnaryCondition_JK,
"CM_Vec2BinaryCondition JK": Vec2BinaryCondition_JK,
"CM_Vec2ToFloatUnaryOperation JK": Vec2ToFloatUnaryOperation_JK,
"CM_Vec2ToFloatBinaryOperation JK": Vec2ToFloatBinaryOperation_JK,
"CM_Vec2FloatOperation_JK": Vec2FloatOperation_JK,
"CM_Vec3UnaryCondition JK": Vec3UnaryCondition_JK,
"CM_Vec3BinaryCondition JK": Vec3BinaryCondition_JK,
"CM_Vec3ToFloatUnaryOperation JK": Vec3ToFloatUnaryOperation_JK,
"CM_Vec3ToFloatBinaryOperation JK": Vec3ToFloatBinaryOperation_JK,
"CM_Vec3FloatOperation_JK": Vec3FloatOperation_JK,
"CM_Vec4UnaryCondition JK": Vec4UnaryCondition_JK,
"CM_Vec4BinaryCondition JK": Vec4BinaryCondition_JK,
"CM_Vec4ToFloatUnaryOperation JK": Vec4ToFloatUnaryOperation_JK,
"CM_Vec4ToFloatBinaryOperation JK": Vec4ToFloatBinaryOperation_JK,
"CM_Vec4FloatOperation_JK": Vec4FloatOperation_JK,
"CM_IntToNumber JK": IntToNumber_JK,
"CM_NumberToInt JK": NumberToInt_JK,
"CM_FloatToNumber JK": FloatToNumber_JK,
"CM_NumberToFloat JK": NumberToFloat_JK,
"CM_NumberUnaryOperation JK": NumberUnaryOperation_JK,
"CM_NumberBinaryOperation JK": NumberBinaryOperation_JK,
"CM_ComposeVec2 JK": ComposeVec2_JK,
"CM_ComposeVec3 JK": ComposeVec3_JK,
"CM_ComposeVec4 JK": ComposeVec4_JK,
"CM_BreakoutVec2 JK": BreakoutVec2_JK,
"CM_BreakoutVec3 JK": BreakoutVec3_JK,
"CM_BreakoutVec4 JK": BreakoutVec4_JK,
"CM_FillVec2 JK": FillVec2_JK,
"CM_FillVec3 JK": FillVec3_JK,
"CM_FillVec4 JK": FillVec4_JK,
"CM_Vec2UnaryOperation JK": Vec2UnaryOperation_JK,
"CM_Vec2BinaryOperation JK": Vec2BinaryOperation_JK,
"CM_Vec3UnaryOperation JK": Vec3UnaryOperation_JK,
"CM_Vec3BinaryOperation JK": Vec3BinaryOperation_JK,
"CM_Vec4UnaryOperation JK": Vec4UnaryOperation_JK,
"CM_Vec4BinaryOperation JK": Vec4BinaryOperation_JK,
### Misc Nodes [Deprecated]
"CR SD1.5 Aspect Ratio JK": CR_AspectRatioSD15_JK,
"CR SDXL Aspect Ratio JK": CR_AspectRatioSDXL_JK,
"CR SD3 Aspect Ratio JK": CR_AspectRatioSD3_JK,
### Pipe Nodes [Deprecated]
"Pipe End JK": PipeEnd_JK,
"NodesState JK": NodesState_JK,
"Ksampler Parameters JK": KsamplerParameters_JK,
"Base Model Parameters JK": BaseModelParameters_JK,
"Base Model Parameters Extract JK": BaseModelParametersExtract_JK,
"Base Image Parameters Extract JK": BaseImageParametersExtract_JK,
"Base Model Pipe JK": BaseModelPipe_JK,
"Base Model Pipe Extract JK": BaseModelPipeExtract_JK,
"Noise Injection Parameters JK": NoiseInjectionParameters_JK,
"Noise Injection Pipe Extract JK": NoiseInjectionPipeExtract_JK,
"Refine Model Parameters JK": RefineModelParameters_JK,
"Refine 1 Parameters Extract JK": Refine1ParametersExtract_JK,
"Refine 2 Parameters Extract JK": Refine2ParametersExtract_JK,
"Refine Pipe JK": RefinePipe_JK,
"Refine Pipe Extract JK": RefinePipeExtract_JK,
"Upscale Model Parameters JK": UpscaleModelParameters_JK,
"Image Upscale Parameters Extract JK": ImageUpscaleParametersExtract_JK,
"Latent Upscale Parameters Extract JK": LatentUpscaleParametersExtract_JK,
"Upscale Model Parameters Extract JK": UpscaleModelParametersExtract_JK,
"Detailer Parameters JK": DetailerParameters_JK,
"Metadata Pipe JK": MetadataPipe_JK,
"Metadata Pipe Extract JK": MetadataPipeExtract_JK,
"Save Image with Metadata JK": ImageSaveWithMetadata_JK,
"Save Image with Metadata Flow JK": ImageSaveWithMetadata_Flow_JK,
"Load Image With Metadata JK": LoadImageWithMetadata_JK,
"Load Image With Alpha JK": LoadImageWithAlpha_JK,
### Reroute Nodes [Deprecated]
"Reroute List JK": RerouteList_JK,
"Reroute Ckpt JK": RerouteCkpt_JK,
"Reroute Vae JK": RerouteVae_JK,
"Reroute Sampler JK": RerouteSampler_JK,
"Reroute Upscale JK": RerouteUpscale_JK,
"Reroute Resize JK": RerouteResize_JK,
"Reroute String JK": RerouteString_JK,
### Switch Nodes [Deprecated]
"CR Pipe Input Switch JK": CR_PipeInputSwitch_JK,
}
def filter_valid_mappings(mappings: Dict[str, Type[Any]]) -> Dict[str, Type[Any]]:
"""过滤掉None值(未成功导入的类)"""
return {k: v for k, v in mappings.items() if v is not None}
def add_dragon_emoji(name: str) -> str:
"""为节点名称添加龙表情符号"""
# 使用正则表达式移除 CR 或 CM_ 前缀
name = re.sub(r'^(CR |CM_)', '', name)
# 将下划线替换为空格
name = name.replace('_', ' ')
# 在符合"小写英文字母+大写英文字母+小写英文字母"模式的大写字母前添加空格
name = re.sub(r'(?<=[a-z])([A-Z])(?=[a-z])', r' \1', name)
return f"{name}🐉"
# 构建主节点映射
node_mappings = create_node_mappings()
valid_node_mappings = filter_valid_mappings(node_mappings)
NODE_CLASS_MAPPINGS.update(valid_node_mappings)
NODE_DISPLAY_NAME_MAPPINGS.update({k: add_dragon_emoji(k) for k in NODE_CLASS_MAPPINGS.keys()})
# 处理已弃用节点
if LOAD_DEPRECATED_NODES:
deprecated_node_mappings = create_deprecated_node_mappings()
valid_deprecated_node_mappings = filter_valid_mappings(deprecated_node_mappings)
NODE_CLASS_MAPPINGS.update(valid_deprecated_node_mappings)
NODE_DISPLAY_NAME_MAPPINGS.update({k: add_dragon_emoji(k) for k in valid_deprecated_node_mappings.keys()})
# 导出配置
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
# 加载统计
active_nodes_count = len(NODE_CLASS_MAPPINGS)
print(f"🔶 Total nodes: {active_nodes_count}")
print("--------------------------------------------------------------")