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.
589 lines
29 KiB
Python
589 lines
29 KiB
Python
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("--------------------------------------------------------------")
|