From 593fb95213624833a46c900025cd68951a25113b Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Sun, 24 Sep 2023 19:00:21 -0400 Subject: [PATCH] ip_adapter_sd15 & its encoder will now be installed by default during headless install --- .../backend/install/model_install_backend.py | 39 +++++++++++++------ invokeai/configs/INITIAL_MODELS.yaml | 25 +++++++----- invokeai/frontend/install/model_install.py | 35 +++++++++-------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/invokeai/backend/install/model_install_backend.py b/invokeai/backend/install/model_install_backend.py index 6133a26ec1..cfb1477744 100644 --- a/invokeai/backend/install/model_install_backend.py +++ b/invokeai/backend/install/model_install_backend.py @@ -69,14 +69,6 @@ LEGACY_CONFIGS = { } -@dataclass -class ModelInstallList: - """Class for listing models to be installed/removed""" - - install_models: List[str] = field(default_factory=list) - remove_models: List[str] = field(default_factory=list) - - @dataclass class InstallSelections: install_models: List[str] = field(default_factory=list) @@ -94,7 +86,7 @@ class ModelLoadInfo: installed: bool = False recommended: bool = False default: bool = False - + requires: Optional[List[str]] = field(default_factory=list) class ModelInstall(object): def __init__( @@ -131,8 +123,6 @@ class ModelInstall(object): # supplement with entries in models.yaml installed_models = [x for x in self.mgr.list_models()] - # suppresses autoloaded models - # installed_models = [x for x in self.mgr.list_models() if not self._is_autoloaded(x)] for md in installed_models: base = md["base_model"] @@ -164,9 +154,12 @@ class ModelInstall(object): def list_models(self, model_type): installed = self.mgr.list_models(model_type=model_type) + print() print(f"Installed models of type `{model_type}`:") + print(f"{'Model Key':50} Model Path") for i in installed: - print(f"{i['model_name']}\t{i['base_model']}\t{i['path']}") + print(f"{'/'.join([i['base_model'],i['model_type'],i['model_name']]):50} {i['path']}") + print() # logic here a little reversed to maintain backward compatibility def starter_models(self, all_models: bool = False) -> Set[str]: @@ -204,6 +197,8 @@ class ModelInstall(object): job += 1 # add requested models + self._remove_installed(selections.install_models) + self._add_required_models(selections.install_models) for path in selections.install_models: logger.info(f"Installing {path} [{job}/{jobs}]") try: @@ -263,6 +258,26 @@ class ModelInstall(object): return models_installed + def _remove_installed(self, model_list: List[str]): + all_models = self.all_models() + for path in model_list: + key = self.reverse_paths.get(path) + if key and all_models[key].installed: + logger.warning(f"{path} already installed. Skipping.") + model_list.remove(path) + + def _add_required_models(self, model_list: List[str]): + additional_models = [] + all_models = self.all_models() + for path in model_list: + if not(key := self.reverse_paths.get(path)): + continue + for requirement in all_models[key].requires: + requirement_key = self.reverse_paths.get(requirement) + if not all_models[requirement_key].installed: + additional_models.append(requirement) + model_list.extend(additional_models) + # install a model from a local path. The optional info parameter is there to prevent # the model from being probed twice in the event that it has already been probed. def _install_path(self, path: Path, info: ModelProbeInfo = None) -> AddModelResult: diff --git a/invokeai/configs/INITIAL_MODELS.yaml b/invokeai/configs/INITIAL_MODELS.yaml index d806b001ab..f3dbc11c2a 100644 --- a/invokeai/configs/INITIAL_MODELS.yaml +++ b/invokeai/configs/INITIAL_MODELS.yaml @@ -103,28 +103,35 @@ sd-1/lora/LowRA: recommended: True sd-1/lora/Ink scenery: path: https://civitai.com/api/download/models/83390 -# any/clip_vision/ip_adapter_sd_image_encoder: -# repo_id: InvokeAI/ip_adapter_sd_image_encoder -# recommended: True -# description: Required model for using IP-Adapters with SD-1/2 models -# any/clip_vision/ip_adapter_sdxl_image_encoder: -# repo_id: InvokeAI/ip_adapter_sdxl_image_encoder -# recommended: True -# description: Required model for using IP-Adapters with SDXL models sd-1/ip_adapter/ip_adapter_sd15: repo_id: InvokeAI/ip_adapter_sd15 recommended: True + requires: + - InvokeAI/ip_adapter_sd_image_encoder description: IP-Adapter for SD 1.5 models sd-1/ip_adapter/ip_adapter_plus_sd15: repo_id: InvokeAI/ip_adapter_plus_sd15 recommended: False + requires: + - InvokeAI/ip_adapter_sd_image_encoder description: Refined IP-Adapter for SD 1.5 models sd-1/ip_adapter/ip_adapter_plus_face_sd15: repo_id: InvokeAI/ip_adapter_plus_face_sd15 recommended: False + requires: + - InvokeAI/ip_adapter_sd_image_encoder description: Refined IP-Adapter for SD 1.5 models, adapted for faces sdxl/ip_adapter/ip_adapter_sdxl: repo_id: InvokeAI/ip_adapter_sdxl recommended: False + requires: + - InvokeAI/ip_adapter_sdxl_image_encoder description: IP-Adapter for SDXL models - +any/clip_vision/ip_adapter_sd_image_encoder: + repo_id: InvokeAI/ip_adapter_sd_image_encoder + recommended: False + description: Required model for using IP-Adapters with SD-1/2 models +any/clip_vision/ip_adapter_sdxl_image_encoder: + repo_id: InvokeAI/ip_adapter_sdxl_image_encoder + recommended: False + description: Required model for using IP-Adapters with SDXL models diff --git a/invokeai/frontend/install/model_install.py b/invokeai/frontend/install/model_install.py index a76706311a..b8a44ae089 100644 --- a/invokeai/frontend/install/model_install.py +++ b/invokeai/frontend/install/model_install.py @@ -563,23 +563,24 @@ class addModelsForm(CyclingForm, npyscreen.FormMultiPage): if downloads := section.get("download_ids"): selections.install_models.extend(downloads.value.split()) - # special case for the ipadapter_models. If any of the adapters are - # chosen, then we add the corresponding encoder(s) to the install list. - section = self.ipadapter_models - if section.get("models_selected"): - selected_adapters = [ - self.all_models[section["models"][x]].name for x in section.get("models_selected").value - ] - encoders = [] - if any(["sdxl" in x for x in selected_adapters]): - encoders.append("ip_adapter_sdxl_image_encoder") - if any(["sd15" in x for x in selected_adapters]): - encoders.append("ip_adapter_sd_image_encoder") - for encoder in encoders: - key = f"any/clip_vision/{encoder}" - repo_id = f"InvokeAI/{encoder}" - if key not in self.all_models: - selections.install_models.append(repo_id) + # NOT NEEDED - DONE IN BACKEND NOW + # # special case for the ipadapter_models. If any of the adapters are + # # chosen, then we add the corresponding encoder(s) to the install list. + # section = self.ipadapter_models + # if section.get("models_selected"): + # selected_adapters = [ + # self.all_models[section["models"][x]].name for x in section.get("models_selected").value + # ] + # encoders = [] + # if any(["sdxl" in x for x in selected_adapters]): + # encoders.append("ip_adapter_sdxl_image_encoder") + # if any(["sd15" in x for x in selected_adapters]): + # encoders.append("ip_adapter_sd_image_encoder") + # for encoder in encoders: + # key = f"any/clip_vision/{encoder}" + # repo_id = f"InvokeAI/{encoder}" + # if key not in self.all_models: + # selections.install_models.append(repo_id) class AddModelApplication(npyscreen.NPSAppManaged):