mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into bugfix/prevent-cli-crash
This commit is contained in:
commit
8334757af9
19
.github/stale.yaml
vendored
Normal file
19
.github/stale.yaml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 28
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 14
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- pinned
|
||||||
|
- security
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: stale
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Please
|
||||||
|
update the ticket if this is still a problem on the latest release.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: >
|
||||||
|
Due to inactivity, this issue has been automatically closed. If this is
|
||||||
|
still a problem on the latest release, please recreate the issue.
|
@ -268,7 +268,7 @@ model is so good at inpainting, a good substitute is to use the `clipseg` text
|
|||||||
masking option:
|
masking option:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
invoke> a fluffy cat eating a hotdot
|
invoke> a fluffy cat eating a hotdog
|
||||||
Outputs:
|
Outputs:
|
||||||
[1010] outputs/000025.2182095108.png: a fluffy cat eating a hotdog
|
[1010] outputs/000025.2182095108.png: a fluffy cat eating a hotdog
|
||||||
invoke> a smiling dog eating a hotdog -I 000025.2182095108.png -tm cat
|
invoke> a smiling dog eating a hotdog -I 000025.2182095108.png -tm cat
|
||||||
|
@ -561,7 +561,7 @@ class Args(object):
|
|||||||
"--autoimport",
|
"--autoimport",
|
||||||
default=None,
|
default=None,
|
||||||
type=str,
|
type=str,
|
||||||
help="Check the indicated directory for .ckpt/.safetensors weights files at startup and import directly",
|
help="(DEPRECATED - NONFUNCTIONAL). Check the indicated directory for .ckpt/.safetensors weights files at startup and import directly",
|
||||||
)
|
)
|
||||||
model_group.add_argument(
|
model_group.add_argument(
|
||||||
"--autoconvert",
|
"--autoconvert",
|
||||||
|
@ -67,7 +67,6 @@ def install_requested_models(
|
|||||||
scan_directory: Path = None,
|
scan_directory: Path = None,
|
||||||
external_models: List[str] = None,
|
external_models: List[str] = None,
|
||||||
scan_at_startup: bool = False,
|
scan_at_startup: bool = False,
|
||||||
convert_to_diffusers: bool = False,
|
|
||||||
precision: str = "float16",
|
precision: str = "float16",
|
||||||
purge_deleted: bool = False,
|
purge_deleted: bool = False,
|
||||||
config_file_path: Path = None,
|
config_file_path: Path = None,
|
||||||
@ -113,7 +112,6 @@ def install_requested_models(
|
|||||||
try:
|
try:
|
||||||
model_manager.heuristic_import(
|
model_manager.heuristic_import(
|
||||||
path_url_or_repo,
|
path_url_or_repo,
|
||||||
convert=convert_to_diffusers,
|
|
||||||
commit_to_conf=config_file_path,
|
commit_to_conf=config_file_path,
|
||||||
)
|
)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
@ -122,7 +120,7 @@ def install_requested_models(
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if scan_at_startup and scan_directory.is_dir():
|
if scan_at_startup and scan_directory.is_dir():
|
||||||
argument = "--autoconvert" if convert_to_diffusers else "--autoimport"
|
argument = "--autoconvert"
|
||||||
initfile = Path(Globals.root, Globals.initfile)
|
initfile = Path(Globals.root, Globals.initfile)
|
||||||
replacement = Path(Globals.root, f"{Globals.initfile}.new")
|
replacement = Path(Globals.root, f"{Globals.initfile}.new")
|
||||||
directory = str(scan_directory).replace("\\", "/")
|
directory = str(scan_directory).replace("\\", "/")
|
||||||
|
@ -8,3 +8,4 @@ from .convert_ckpt_to_diffusers import (
|
|||||||
from .model_manager import ModelManager,SDModelComponent
|
from .model_manager import ModelManager,SDModelComponent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import transformers
|
|||||||
from diffusers import (
|
from diffusers import (
|
||||||
AutoencoderKL,
|
AutoencoderKL,
|
||||||
UNet2DConditionModel,
|
UNet2DConditionModel,
|
||||||
|
SchedulerMixin,
|
||||||
logging as dlogging,
|
logging as dlogging,
|
||||||
)
|
)
|
||||||
from huggingface_hub import scan_cache_dir
|
from huggingface_hub import scan_cache_dir
|
||||||
@ -169,7 +170,55 @@ class ModelManager(object):
|
|||||||
"hash": hash,
|
"hash": hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_sub_model(
|
def get_model_vae(self, model_name: str=None)->AutoencoderKL:
|
||||||
|
"""Given a model name identified in models.yaml, load the model into
|
||||||
|
GPU if necessary and return its assigned VAE as an
|
||||||
|
AutoencoderKL object. If no model name is provided, return the
|
||||||
|
vae from the model currently in the GPU.
|
||||||
|
"""
|
||||||
|
return self._get_sub_model(model_name, SDModelComponent.vae)
|
||||||
|
|
||||||
|
def get_model_tokenizer(self, model_name: str=None)->CLIPTokenizer:
|
||||||
|
"""Given a model name identified in models.yaml, load the model into
|
||||||
|
GPU if necessary and return its assigned CLIPTokenizer. If no
|
||||||
|
model name is provided, return the tokenizer from the model
|
||||||
|
currently in the GPU.
|
||||||
|
"""
|
||||||
|
return self._get_sub_model(model_name, SDModelComponent.tokenizer)
|
||||||
|
|
||||||
|
def get_model_unet(self, model_name: str=None)->UNet2DConditionModel:
|
||||||
|
"""Given a model name identified in models.yaml, load the model into
|
||||||
|
GPU if necessary and return its assigned UNet2DConditionModel. If no model
|
||||||
|
name is provided, return the UNet from the model
|
||||||
|
currently in the GPU.
|
||||||
|
"""
|
||||||
|
return self._get_sub_model(model_name, SDModelComponent.unet)
|
||||||
|
|
||||||
|
def get_model_text_encoder(self, model_name: str=None)->CLIPTextModel:
|
||||||
|
"""Given a model name identified in models.yaml, load the model into
|
||||||
|
GPU if necessary and return its assigned CLIPTextModel. If no
|
||||||
|
model name is provided, return the text encoder from the model
|
||||||
|
currently in the GPU.
|
||||||
|
"""
|
||||||
|
return self._get_sub_model(model_name, SDModelComponent.text_encoder)
|
||||||
|
|
||||||
|
def get_model_feature_extractor(self, model_name: str=None)->CLIPFeatureExtractor:
|
||||||
|
"""Given a model name identified in models.yaml, load the model into
|
||||||
|
GPU if necessary and return its assigned CLIPFeatureExtractor. If no
|
||||||
|
model name is provided, return the text encoder from the model
|
||||||
|
currently in the GPU.
|
||||||
|
"""
|
||||||
|
return self._get_sub_model(model_name, SDModelComponent.feature_extractor)
|
||||||
|
|
||||||
|
def get_model_scheduler(self, model_name: str=None)->SchedulerMixin:
|
||||||
|
"""Given a model name identified in models.yaml, load the model into
|
||||||
|
GPU if necessary and return its assigned scheduler. If no
|
||||||
|
model name is provided, return the text encoder from the model
|
||||||
|
currently in the GPU.
|
||||||
|
"""
|
||||||
|
return self._get_sub_model(model_name, SDModelComponent.scheduler)
|
||||||
|
|
||||||
|
def _get_sub_model(
|
||||||
self,
|
self,
|
||||||
model_name: str=None,
|
model_name: str=None,
|
||||||
model_part: SDModelComponent=SDModelComponent.vae,
|
model_part: SDModelComponent=SDModelComponent.vae,
|
||||||
@ -181,7 +230,7 @@ class ModelManager(object):
|
|||||||
CLIPTextModel,
|
CLIPTextModel,
|
||||||
StableDiffusionSafetyChecker,
|
StableDiffusionSafetyChecker,
|
||||||
]:
|
]:
|
||||||
"""Given a model named identified in models.yaml, and the part of the
|
"""Given a model name identified in models.yaml, and the part of the
|
||||||
model you wish to retrieve, return that part. Parts are in an Enum
|
model you wish to retrieve, return that part. Parts are in an Enum
|
||||||
class named SDModelComponent, and consist of:
|
class named SDModelComponent, and consist of:
|
||||||
SDModelComponent.vae
|
SDModelComponent.vae
|
||||||
@ -190,7 +239,7 @@ class ModelManager(object):
|
|||||||
SDModelComponent.unet
|
SDModelComponent.unet
|
||||||
SDModelComponent.scheduler
|
SDModelComponent.scheduler
|
||||||
SDModelComponent.safety_checker
|
SDModelComponent.safety_checker
|
||||||
SDModelComponent.feature_etractor
|
SDModelComponent.feature_extractor
|
||||||
"""
|
"""
|
||||||
model_dict = self.get_model(model_name)
|
model_dict = self.get_model(model_name)
|
||||||
model = model_dict["model"]
|
model = model_dict["model"]
|
||||||
|
@ -158,11 +158,6 @@ def main():
|
|||||||
report_model_error(opt, e)
|
report_model_error(opt, e)
|
||||||
|
|
||||||
# try to autoconvert new models
|
# try to autoconvert new models
|
||||||
if path := opt.autoimport:
|
|
||||||
gen.model_manager.heuristic_import(
|
|
||||||
str(path), commit_to_conf=opt.conf
|
|
||||||
)
|
|
||||||
|
|
||||||
if path := opt.autoconvert:
|
if path := opt.autoconvert:
|
||||||
gen.model_manager.heuristic_import(
|
gen.model_manager.heuristic_import(
|
||||||
str(path), commit_to_conf=opt.conf
|
str(path), commit_to_conf=opt.conf
|
||||||
@ -581,6 +576,7 @@ def do_command(command: str, gen, opt: Args, completer) -> tuple:
|
|||||||
|
|
||||||
elif command.startswith("!replay"):
|
elif command.startswith("!replay"):
|
||||||
file_path = command.replace("!replay", "", 1).strip()
|
file_path = command.replace("!replay", "", 1).strip()
|
||||||
|
file_path = os.path.join(opt.outdir, file_path)
|
||||||
if infile is None and os.path.isfile(file_path):
|
if infile is None and os.path.isfile(file_path):
|
||||||
infile = open(file_path, "r", encoding="utf-8")
|
infile = open(file_path, "r", encoding="utf-8")
|
||||||
completer.add_history(command)
|
completer.add_history(command)
|
||||||
|
@ -199,17 +199,6 @@ class addModelsForm(npyscreen.FormMultiPage):
|
|||||||
relx=4,
|
relx=4,
|
||||||
scroll_exit=True,
|
scroll_exit=True,
|
||||||
)
|
)
|
||||||
self.nextrely += 1
|
|
||||||
self.convert_models = self.add_widget_intelligent(
|
|
||||||
npyscreen.TitleSelectOne,
|
|
||||||
name="== CONVERT IMPORTED MODELS INTO DIFFUSERS==",
|
|
||||||
values=["Keep original format", "Convert to diffusers"],
|
|
||||||
value=0,
|
|
||||||
begin_entry_at=4,
|
|
||||||
max_height=4,
|
|
||||||
hidden=True, # will appear when imported models box is edited
|
|
||||||
scroll_exit=True,
|
|
||||||
)
|
|
||||||
self.cancel = self.add_widget_intelligent(
|
self.cancel = self.add_widget_intelligent(
|
||||||
npyscreen.ButtonPress,
|
npyscreen.ButtonPress,
|
||||||
name="CANCEL",
|
name="CANCEL",
|
||||||
@ -244,8 +233,6 @@ class addModelsForm(npyscreen.FormMultiPage):
|
|||||||
self.show_directory_fields.addVisibleWhenSelected(i)
|
self.show_directory_fields.addVisibleWhenSelected(i)
|
||||||
|
|
||||||
self.show_directory_fields.when_value_edited = self._clear_scan_directory
|
self.show_directory_fields.when_value_edited = self._clear_scan_directory
|
||||||
self.import_model_paths.when_value_edited = self._show_hide_convert
|
|
||||||
self.autoload_directory.when_value_edited = self._show_hide_convert
|
|
||||||
|
|
||||||
def resize(self):
|
def resize(self):
|
||||||
super().resize()
|
super().resize()
|
||||||
@ -256,13 +243,6 @@ class addModelsForm(npyscreen.FormMultiPage):
|
|||||||
if not self.show_directory_fields.value:
|
if not self.show_directory_fields.value:
|
||||||
self.autoload_directory.value = ""
|
self.autoload_directory.value = ""
|
||||||
|
|
||||||
def _show_hide_convert(self):
|
|
||||||
model_paths = self.import_model_paths.value or ""
|
|
||||||
autoload_directory = self.autoload_directory.value or ""
|
|
||||||
self.convert_models.hidden = (
|
|
||||||
len(model_paths) == 0 and len(autoload_directory) == 0
|
|
||||||
)
|
|
||||||
|
|
||||||
def _get_starter_model_labels(self) -> List[str]:
|
def _get_starter_model_labels(self) -> List[str]:
|
||||||
window_width, window_height = get_terminal_size()
|
window_width, window_height = get_terminal_size()
|
||||||
label_width = 25
|
label_width = 25
|
||||||
@ -322,7 +302,6 @@ class addModelsForm(npyscreen.FormMultiPage):
|
|||||||
.scan_directory: Path to a directory of models to scan and import
|
.scan_directory: Path to a directory of models to scan and import
|
||||||
.autoscan_on_startup: True if invokeai should scan and import at startup time
|
.autoscan_on_startup: True if invokeai should scan and import at startup time
|
||||||
.import_model_paths: list of URLs, repo_ids and file paths to import
|
.import_model_paths: list of URLs, repo_ids and file paths to import
|
||||||
.convert_to_diffusers: if True, convert legacy checkpoints into diffusers
|
|
||||||
"""
|
"""
|
||||||
# we're using a global here rather than storing the result in the parentapp
|
# we're using a global here rather than storing the result in the parentapp
|
||||||
# due to some bug in npyscreen that is causing attributes to be lost
|
# due to some bug in npyscreen that is causing attributes to be lost
|
||||||
@ -359,7 +338,6 @@ class addModelsForm(npyscreen.FormMultiPage):
|
|||||||
|
|
||||||
# URLs and the like
|
# URLs and the like
|
||||||
selections.import_model_paths = self.import_model_paths.value.split()
|
selections.import_model_paths = self.import_model_paths.value.split()
|
||||||
selections.convert_to_diffusers = self.convert_models.value[0] == 1
|
|
||||||
|
|
||||||
|
|
||||||
class AddModelApplication(npyscreen.NPSAppManaged):
|
class AddModelApplication(npyscreen.NPSAppManaged):
|
||||||
@ -372,7 +350,6 @@ class AddModelApplication(npyscreen.NPSAppManaged):
|
|||||||
scan_directory=None,
|
scan_directory=None,
|
||||||
autoscan_on_startup=None,
|
autoscan_on_startup=None,
|
||||||
import_model_paths=None,
|
import_model_paths=None,
|
||||||
convert_to_diffusers=None,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def onStart(self):
|
def onStart(self):
|
||||||
@ -393,7 +370,6 @@ def process_and_execute(opt: Namespace, selections: Namespace):
|
|||||||
directory_to_scan = selections.scan_directory
|
directory_to_scan = selections.scan_directory
|
||||||
scan_at_startup = selections.autoscan_on_startup
|
scan_at_startup = selections.autoscan_on_startup
|
||||||
potential_models_to_install = selections.import_model_paths
|
potential_models_to_install = selections.import_model_paths
|
||||||
convert_to_diffusers = selections.convert_to_diffusers
|
|
||||||
|
|
||||||
install_requested_models(
|
install_requested_models(
|
||||||
install_initial_models=models_to_install,
|
install_initial_models=models_to_install,
|
||||||
@ -401,7 +377,6 @@ def process_and_execute(opt: Namespace, selections: Namespace):
|
|||||||
scan_directory=Path(directory_to_scan) if directory_to_scan else None,
|
scan_directory=Path(directory_to_scan) if directory_to_scan else None,
|
||||||
external_models=potential_models_to_install,
|
external_models=potential_models_to_install,
|
||||||
scan_at_startup=scan_at_startup,
|
scan_at_startup=scan_at_startup,
|
||||||
convert_to_diffusers=convert_to_diffusers,
|
|
||||||
precision="float32"
|
precision="float32"
|
||||||
if opt.full_precision
|
if opt.full_precision
|
||||||
else choose_precision(torch.device(choose_torch_device())),
|
else choose_precision(torch.device(choose_torch_device())),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user