mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-03-07 10:17:31 +08:00
feat: add placeholder support for empty model dropdowns
Add get_model_placeholder() helper function to folder_paths.py that
generates user-friendly placeholder text for empty model dropdowns.
Update model loader nodes to include placeholder in INPUT_TYPES:
- CheckpointLoaderSimple
- unCLIPCheckpointLoader
- LoraLoader
- LoraLoaderModelOnly
- VAELoader
- ControlNetLoader
- DiffControlNetLoader
- UNETLoader
- CLIPLoader
- DualCLIPLoader
- CLIPVisionLoader
The placeholder text shows 'No models found in ComfyUI/models/{folder} folder . . .'
when the options list is empty, helping users understand where to place models.
Amp-Thread-ID: https://ampcode.com/threads/T-019c2bd5-472a-73a1-842b-4e05cba5d12c
This commit is contained in:
parent
e721e24136
commit
6c8c6f2d52
@ -472,6 +472,18 @@ def get_save_image_path(filename_prefix: str, output_dir: str, image_width=0, im
|
|||||||
counter = 1
|
counter = 1
|
||||||
return full_output_folder, filename, counter, subfolder, filename_prefix
|
return full_output_folder, filename, counter, subfolder, filename_prefix
|
||||||
|
|
||||||
|
def get_model_placeholder(folder_name: str) -> str:
|
||||||
|
"""Generate placeholder text for empty model dropdowns.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
folder_name: The name of the model folder (e.g., "checkpoints", "loras").
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A user-friendly placeholder string indicating where models should be placed.
|
||||||
|
"""
|
||||||
|
return f"No models found in ComfyUI/models/{folder_name} folder . . ."
|
||||||
|
|
||||||
|
|
||||||
def get_input_subfolders() -> list[str]:
|
def get_input_subfolders() -> list[str]:
|
||||||
"""Returns a list of all subfolder paths in the input directory, recursively.
|
"""Returns a list of all subfolder paths in the input directory, recursively.
|
||||||
|
|
||||||
|
|||||||
50
nodes.py
50
nodes.py
@ -589,7 +589,10 @@ class CheckpointLoaderSimple:
|
|||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"ckpt_name": (folder_paths.get_filename_list("checkpoints"), {"tooltip": "The name of the checkpoint (model) to load."}),
|
"ckpt_name": (folder_paths.get_filename_list("checkpoints"), {
|
||||||
|
"tooltip": "The name of the checkpoint (model) to load.",
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("checkpoints")
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RETURN_TYPES = ("MODEL", "CLIP", "VAE")
|
RETURN_TYPES = ("MODEL", "CLIP", "VAE")
|
||||||
@ -639,7 +642,9 @@ class DiffusersLoader:
|
|||||||
class unCLIPCheckpointLoader:
|
class unCLIPCheckpointLoader:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "ckpt_name": (folder_paths.get_filename_list("checkpoints"), ),
|
return {"required": { "ckpt_name": (folder_paths.get_filename_list("checkpoints"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("checkpoints")
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
RETURN_TYPES = ("MODEL", "CLIP", "VAE", "CLIP_VISION")
|
RETURN_TYPES = ("MODEL", "CLIP", "VAE", "CLIP_VISION")
|
||||||
FUNCTION = "load_checkpoint"
|
FUNCTION = "load_checkpoint"
|
||||||
@ -679,7 +684,10 @@ class LoraLoader:
|
|||||||
"required": {
|
"required": {
|
||||||
"model": ("MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}),
|
"model": ("MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}),
|
||||||
"clip": ("CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}),
|
"clip": ("CLIP", {"tooltip": "The CLIP model the LoRA will be applied to."}),
|
||||||
"lora_name": (folder_paths.get_filename_list("loras"), {"tooltip": "The name of the LoRA."}),
|
"lora_name": (folder_paths.get_filename_list("loras"), {
|
||||||
|
"tooltip": "The name of the LoRA.",
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("loras")
|
||||||
|
}),
|
||||||
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}),
|
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}),
|
||||||
"strength_clip": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}),
|
"strength_clip": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the CLIP model. This value can be negative."}),
|
||||||
}
|
}
|
||||||
@ -716,7 +724,9 @@ class LoraLoaderModelOnly(LoraLoader):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "model": ("MODEL",),
|
return {"required": { "model": ("MODEL",),
|
||||||
"lora_name": (folder_paths.get_filename_list("loras"), ),
|
"lora_name": (folder_paths.get_filename_list("loras"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("loras")
|
||||||
|
}),
|
||||||
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}),
|
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01}),
|
||||||
}}
|
}}
|
||||||
RETURN_TYPES = ("MODEL",)
|
RETURN_TYPES = ("MODEL",)
|
||||||
@ -806,7 +816,9 @@ class VAELoader:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "vae_name": (s.vae_list(s), )}}
|
return {"required": { "vae_name": (s.vae_list(s), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("vae")
|
||||||
|
})}}
|
||||||
RETURN_TYPES = ("VAE",)
|
RETURN_TYPES = ("VAE",)
|
||||||
FUNCTION = "load_vae"
|
FUNCTION = "load_vae"
|
||||||
|
|
||||||
@ -833,7 +845,9 @@ class VAELoader:
|
|||||||
class ControlNetLoader:
|
class ControlNetLoader:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "control_net_name": (folder_paths.get_filename_list("controlnet"), )}}
|
return {"required": { "control_net_name": (folder_paths.get_filename_list("controlnet"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("controlnet")
|
||||||
|
})}}
|
||||||
|
|
||||||
RETURN_TYPES = ("CONTROL_NET",)
|
RETURN_TYPES = ("CONTROL_NET",)
|
||||||
FUNCTION = "load_controlnet"
|
FUNCTION = "load_controlnet"
|
||||||
@ -852,7 +866,9 @@ class DiffControlNetLoader:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "model": ("MODEL",),
|
return {"required": { "model": ("MODEL",),
|
||||||
"control_net_name": (folder_paths.get_filename_list("controlnet"), )}}
|
"control_net_name": (folder_paths.get_filename_list("controlnet"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("controlnet")
|
||||||
|
})}}
|
||||||
|
|
||||||
RETURN_TYPES = ("CONTROL_NET",)
|
RETURN_TYPES = ("CONTROL_NET",)
|
||||||
FUNCTION = "load_controlnet"
|
FUNCTION = "load_controlnet"
|
||||||
@ -950,7 +966,9 @@ class ControlNetApplyAdvanced:
|
|||||||
class UNETLoader:
|
class UNETLoader:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "unet_name": (folder_paths.get_filename_list("diffusion_models"), ),
|
return {"required": { "unet_name": (folder_paths.get_filename_list("diffusion_models"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("diffusion_models")
|
||||||
|
}),
|
||||||
"weight_dtype": (["default", "fp8_e4m3fn", "fp8_e4m3fn_fast", "fp8_e5m2"],)
|
"weight_dtype": (["default", "fp8_e4m3fn", "fp8_e4m3fn_fast", "fp8_e5m2"],)
|
||||||
}}
|
}}
|
||||||
RETURN_TYPES = ("MODEL",)
|
RETURN_TYPES = ("MODEL",)
|
||||||
@ -975,7 +993,9 @@ class UNETLoader:
|
|||||||
class CLIPLoader:
|
class CLIPLoader:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "clip_name": (folder_paths.get_filename_list("text_encoders"), ),
|
return {"required": { "clip_name": (folder_paths.get_filename_list("text_encoders"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("text_encoders")
|
||||||
|
}),
|
||||||
"type": (["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis"], ),
|
"type": (["stable_diffusion", "stable_cascade", "sd3", "stable_audio", "mochi", "ltxv", "pixart", "cosmos", "lumina2", "wan", "hidream", "chroma", "ace", "omnigen2", "qwen_image", "hunyuan_image", "flux2", "ovis"], ),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
@ -1002,8 +1022,12 @@ class CLIPLoader:
|
|||||||
class DualCLIPLoader:
|
class DualCLIPLoader:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "clip_name1": (folder_paths.get_filename_list("text_encoders"), ),
|
return {"required": { "clip_name1": (folder_paths.get_filename_list("text_encoders"), {
|
||||||
"clip_name2": (folder_paths.get_filename_list("text_encoders"), ),
|
"placeholder": folder_paths.get_model_placeholder("text_encoders")
|
||||||
|
}),
|
||||||
|
"clip_name2": (folder_paths.get_filename_list("text_encoders"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("text_encoders")
|
||||||
|
}),
|
||||||
"type": (["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"], ),
|
"type": (["sdxl", "sd3", "flux", "hunyuan_video", "hidream", "hunyuan_image", "hunyuan_video_15", "kandinsky5", "kandinsky5_image", "ltxv", "newbie", "ace"], ),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
@ -1032,7 +1056,9 @@ class DualCLIPLoader:
|
|||||||
class CLIPVisionLoader:
|
class CLIPVisionLoader:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "clip_name": (folder_paths.get_filename_list("clip_vision"), ),
|
return {"required": { "clip_name": (folder_paths.get_filename_list("clip_vision"), {
|
||||||
|
"placeholder": folder_paths.get_model_placeholder("clip_vision")
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
RETURN_TYPES = ("CLIP_VISION",)
|
RETURN_TYPES = ("CLIP_VISION",)
|
||||||
FUNCTION = "load_clip"
|
FUNCTION = "load_clip"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user