Improve and expand extra_model_paths.yaml

This commit is contained in:
Vladimir Vukicevic 2024-12-02 08:39:43 +01:00
parent 497db6212f
commit c5271fe73f
3 changed files with 178 additions and 44 deletions

View File

@ -1,47 +1,111 @@
#Rename this to extra_model_paths.yaml and ComfyUI will load it
# Copy this to extra_model_paths.yaml and ComfyUI will load it, or pass
# --extra-model-paths-config file.yaml
# Config for ComfyUI
#
# In all paths below:
# - ~ will expand out to the current user's home directory (typically C:\Users\username on Windows,
# /home/username on Linux, /Users/username on MacOS).
# - $ENV_VAR will expand out to the value of the environment variable ENV_VAR. However, if
# ENV_VAR is not set, the path will be ignored ($ENV_VAR will not expand out to an empty string).
# - environment variables are expanded before ~, so ENV_VAR=~/foo will work properly
# - if a path beings with @ it is treated as an explicit path, and no base_path will be
# prepended to it (but environment variable and ~ expansion still apply)
#
comfyui:
# If is_default is set to true, all the directories below will be prepended
# instead of appended to the default ComfyUI lists.
# instead of appending
is_default: true
#config for a1111 ui
#all you have to do is change the base_path to where yours is installed
a111:
base_path: path/to/stable-diffusion-webui/
# If base_path is specified, all the directories referenced below will be
# relative to this path. For example, if you want to move comfy's models etc
# to ~/comfy_data, set base_path to ~/comfy_data
#base_path: ~/comfy_data
checkpoints: models/Stable-diffusion
configs: models/Stable-diffusion
vae: models/VAE
loras: |
models/Lora
models/LyCORIS
upscale_models: |
models/ESRGAN
models/RealESRGAN
models/SwinIR
embeddings: embeddings
hypernetworks: models/hypernetworks
controlnet: models/ControlNet
# If base_paths is specified, it's treated as a multiple set of base_paths. Each
# path in following entries is appended to each element of base_paths. If base_path is
# also present, it will be included as the first element.
#
# This is useful to be able to easily specify multiple roots -- for example,
# you could have one /shared_comfy_data that is a large network mount with
# models shared amongst many users/machines, and then ~/local_comfy_data
# where you can place models you're locally experimenting with. Specifying
# base_paths: ~/local_comfy_data /shared_comfy_data
# will let Comfy search both paths.
#
#base_paths: |
# $LOCAL_COMFY_ROOT
# $COMFY_ROOT
#config for comfyui
#your base path should be either an existing comfy install or a central folder where you store all of your models, loras, etc.
# The singular models/output/temp/input/user directories can be overriden as well.
# These are single paths; they can't be a list. Base path handling still applies, but the
# first directory that exists will be used. If none exist, the value isn't touched.
#
# For example, if base_paths is set to "~/local_comfy_data /shared_comfy_data",
# and output_directory is set to "output", Comfy will look for for ~/local_comfy_data/output
# first. If it exists, it will be used as the output directory. If models_dir is set to "models",
# Comfy will look for ~/local_comfy_data/models -- if that doesn't exist, it will look for
# /shared_comfy_data/models next.
#comfyui:
# base_path: path/to/comfyui/
# # You can use is_default to mark that these folders should be listed first, and used as the default dirs for eg downloads
# #is_default: true
# checkpoints: models/checkpoints/
# clip: models/clip/
# clip_vision: models/clip_vision/
# configs: models/configs/
# controlnet: models/controlnet/
# diffusion_models: |
# models/diffusion_models
# models/unet
# embeddings: models/embeddings/
# loras: models/loras/
# upscale_models: models/upscale_models/
# vae: models/vae/
# The `models_dir`. This is used by some custom nodes to find the "models" directory
# into which to place downloads (e.g. CogVideoX does this).
#models_dir: models
#output_directory: output
#temp_directory: temp
#input_directory: input
#user_directory: user
# Where to look for custom nodes. The @custom_nodes ensures that the custom_nodes
# directory relative to the comfy install will be searched. The custom_nodes without
# the @ means a directory called custom_nodes will also be searched in each of the base
# paths.
custom_nodes: |
@custom_nodes
custom_nodes
# Different model types in use by Comfy. These are the defaults.
# If you want the "base path" handling you _must_ respecify these here,
# even if you want to keep the default suffix values. Specifying
# just base_path (or base_paths) is not enough.
#
# Other model types can be added to this list, and some Comfy custom
# nodes may add their own model types.
checkpoints: models/checkpoints
clip: models/clip
text_encodings: models/text_encodings
clip_vision: models/clip_vision
configs: models/configs
controlnet: models/controlnet
diffusion_models: |
models/diffusion_models
models/unet
embeddings: models/embeddings
loras: models/loras
upscale_models: models/upscale_models
vae: models/vae
#other_ui:
# base_path: path/to/ui
# checkpoints: models/checkpoints
# gligen: models/gligen
# custom_nodes: path/custom_nodes
#config for a1111 ui
#all you have to do is change the base_path to where yours is installed
#a111:
# base_path: path/to/stable-diffusion-webui/
#
# checkpoints: models/Stable-diffusion
# configs: models/Stable-diffusion
# vae: models/VAE
# loras: |
# models/Lora
# models/LyCORIS
# upscale_models: |
# models/ESRGAN
# models/RealESRGAN
# models/SwinIR
# embeddings: embeddings
# hypernetworks: models/hypernetworks
# controlnet: models/ControlNet
#

View File

@ -2061,6 +2061,9 @@ def init_external_custom_nodes():
node_paths = folder_paths.get_folder_paths("custom_nodes")
node_import_times = []
for custom_node_path in node_paths:
if not os.path.isdir(custom_node_path):
logging.warning(f"Custom node path {custom_node_path} not found or is not a directory, ignoring")
continue
possible_modules = os.listdir(os.path.realpath(custom_node_path))
if "__pycache__" in possible_modules:
possible_modules.remove("__pycache__")

View File

@ -10,19 +10,86 @@ def load_extra_path_config(yaml_path):
conf = config[c]
if conf is None:
continue
base_path = None
base_paths = []
if "base_path" in conf:
base_path = conf.pop("base_path")
base_path = conf.pop("base_path").strip()
base_path = os.path.expandvars(os.path.expanduser(base_path))
if len(base_path) > 0:
base_paths.append(base_path)
if "base_paths" in conf:
base_paths_str = conf.pop("base_paths").strip()
for bp in base_paths_str.split("\n"):
bp = os.path.expanduser(os.path.expandvars(bp))
if bp.find("$") >= 0:
logging.warning(f"Skipping base path {bp} as it contains an undefined variable")
continue
if len(bp) > 0:
base_paths.append(bp)
# simplify the logic below. os.path.join("", foo) == foo
if len(base_paths) == 0:
base_paths.append("")
# allow overriding paths that are not normally overriden.
# these can only be overriden to just one path (not a set).
# the first one that exists wins.
override_list = [ "models_dir", "output_directory", "temp_directory", "input_directory", "user_directory" ]
for okey in override_list:
if okey in conf:
opath = conf.pop(okey).strip()
is_absolute = False
if opath[0] == '@':
opath = opath[1:]
is_absolute = True
opath = os.path.expanduser(os.path.expandvars(opath))
if is_absolute:
setattr(folder_paths, okey, opath)
logging.info(f"Set {okey} tp {opath}")
continue
for bp in base_paths:
path = os.path.join(bp, opath)
if os.path.isdir(path):
setattr(folder_paths, okey, path)
logging.info(f"Set {okey} tp {path}")
break
is_default = False
if "is_default" in conf:
is_default = conf.pop("is_default")
for x in conf:
for y in conf[x].split("\n"):
if len(y) == 0:
if len(y.strip()) == 0:
continue
full_path = y
if base_path is not None:
full_path = os.path.join(base_path, full_path)
logging.info("Adding extra search path {} {}".format(x, full_path))
folder_paths.add_model_folder_path(x, full_path, is_default)
is_absolute = False
if y[0] == '@':
y = y[1:]
is_absolute = True
path = os.path.expanduser(os.path.expandvars(y))
if path.find("$") >= 0:
logging.warning(f"Skipping path {path} for {x} as it contains an undefined variable")
continue
if is_absolute:
all_paths = [path]
else:
all_paths = [os.path.join(bp, path) for bp in base_paths]
# pull out only unique elements in order. Do this so that we don't add the same dir twice,
# if for example two undefined variables are used, e.g. "$X/foo" and "$Y/foo",
# both will evaluate to "/foo" if neither is set
all_paths = [x for i, x in enumerate(all_paths) if x not in all_paths[:i]]
# custom_nodes is special; it's the root directory of custom nodes, and Comfy calls listdir
# on it assuming it exists which throws otherwise
if x == "custom_nodes":
all_paths = [x for x in all_paths if os.path.isdir(x)]
if is_default:
# if we're using is_default, the add_model_folder_path inserts at 0.
# so reverse this list, so that the (original) first element that the user
# specifies in the extra paths file actually ends up at 0
all_paths.reverse()
for p in all_paths:
logging.info("Adding extra search path {} {}".format(x, p))
folder_paths.add_model_folder_path(x, p, is_default)