From e43e198102db6d347f80034b3c2202896335e21c Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Tue, 25 Jul 2023 11:25:26 -0400 Subject: [PATCH 1/2] rework configure/install TUI to require less space --- .../backend/install/invokeai_configure.py | 103 ++++++------------ invokeai/configs/INITIAL_MODELS.yaml | 8 -- invokeai/frontend/install/model_install.py | 27 ++--- invokeai/frontend/install/widgets.py | 10 +- 4 files changed, 55 insertions(+), 93 deletions(-) diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index 1f0e39961b..fa22376ab4 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -44,6 +44,7 @@ from invokeai.app.services.config import ( from invokeai.backend.util.logging import InvokeAILogger from invokeai.frontend.install.model_install import addModelsForm, process_and_execute from invokeai.frontend.install.widgets import ( + SingleSelectColumns, CenteredButtonPress, FileBox, IntTitleSlider, @@ -288,44 +289,10 @@ Use cursor arrows to make a checkbox selection, and space to toggle. ) self.nextrely += 1 - self.add_widget_intelligent( - npyscreen.TitleFixedText, - name="== BASIC OPTIONS ==", - begin_entry_at=0, - editable=False, - color="CONTROL", - scroll_exit=True, - ) - self.nextrely -= 1 - self.add_widget_intelligent( - npyscreen.FixedText, - value="Select an output directory for images:", - editable=False, - color="CONTROL", - ) - self.outdir = self.add_widget_intelligent( - npyscreen.TitleFilename, - name="( autocompletes, ctrl-N advances):", - value=str(default_output_dir()), - select_dir=True, - must_exist=False, - use_two_lines=False, - labelColor="GOOD", - begin_entry_at=40, - scroll_exit=True, - ) - self.nextrely += 1 - self.add_widget_intelligent( - npyscreen.FixedText, - value="Activate the NSFW checker to blur images showing potential sexual imagery:", - editable=False, - color="CONTROL", - ) self.nsfw_checker = self.add_widget_intelligent( npyscreen.Checkbox, - name="NSFW checker", + name="Activate the NSFW checker to blur images showing potential sexual imagery", value=old_opts.nsfw_checker, - relx=5, scroll_exit=True, ) self.nextrely += 1 @@ -347,15 +314,6 @@ Use cursor arrows to make a checkbox selection, and space to toggle. scroll_exit=True, ) self.nextrely += 1 - self.add_widget_intelligent( - npyscreen.TitleFixedText, - name="== ADVANCED OPTIONS ==", - begin_entry_at=0, - editable=False, - color="CONTROL", - scroll_exit=True, - ) - self.nextrely -= 1 self.add_widget_intelligent( npyscreen.TitleFixedText, name="GPU Management", @@ -369,34 +327,49 @@ Use cursor arrows to make a checkbox selection, and space to toggle. npyscreen.Checkbox, name="Free GPU memory after each generation", value=old_opts.free_gpu_mem, + max_width=45, relx=5, scroll_exit=True, ) + self.nextrely -= 1 self.xformers_enabled = self.add_widget_intelligent( npyscreen.Checkbox, - name="Enable xformers support if available", + name="Enable xformers support", value=old_opts.xformers_enabled, - relx=5, + max_width=30, + relx=50, scroll_exit=True, ) + self.nextrely -=1 self.always_use_cpu = self.add_widget_intelligent( npyscreen.Checkbox, name="Force CPU to be used on GPU systems", value=old_opts.always_use_cpu, - relx=5, + relx=80, scroll_exit=True, ) precision = old_opts.precision or ( "float32" if program_opts.full_precision else "auto" ) + self.nextrely +=1 + self.add_widget_intelligent( + npyscreen.TitleFixedText, + name="Floating Point Precision", + begin_entry_at=0, + editable=False, + color="CONTROL", + scroll_exit=True, + ) + self.nextrely -=1 self.precision = self.add_widget_intelligent( - npyscreen.TitleSelectOne, - columns = 2, + SingleSelectColumns, + columns = 3, name="Precision", values=PRECISION_CHOICES, value=PRECISION_CHOICES.index(precision), begin_entry_at=3, - max_height=len(PRECISION_CHOICES) + 1, + max_height=2, + max_width=80, scroll_exit=True, ) self.max_cache_size = self.add_widget_intelligent( @@ -409,16 +382,22 @@ Use cursor arrows to make a checkbox selection, and space to toggle. scroll_exit=True, ) self.nextrely += 1 - self.add_widget_intelligent( - npyscreen.FixedText, - value="Folder to recursively scan for new checkpoints, ControlNets, LoRAs and TI models ( autocompletes, ctrl-N advances):", - editable=False, - color="CONTROL", + self.outdir = self.add_widget_intelligent( + FileBox, + name="Output directory for images ( autocompletes, ctrl-N advances):", + value=str(default_output_dir()), + select_dir=True, + must_exist=False, + use_two_lines=False, + labelColor="GOOD", + begin_entry_at=68, + max_height=3, + scroll_exit=True, ) self.autoimport_dirs = {} self.autoimport_dirs['autoimport_dir'] = self.add_widget_intelligent( FileBox, - name=f'Autoimport Folder', + name=f'Folder to recursively scan for new checkpoints, ControlNets, LoRAs and TI models', value=str(config.root_path / config.autoimport_dir), select_dir=True, must_exist=False, @@ -429,15 +408,6 @@ Use cursor arrows to make a checkbox selection, and space to toggle. scroll_exit=True ) self.nextrely += 1 - self.add_widget_intelligent( - npyscreen.TitleFixedText, - name="== LICENSE ==", - begin_entry_at=0, - editable=False, - color="CONTROL", - scroll_exit=True, - ) - self.nextrely -= 1 label = """BY DOWNLOADING THE STABLE DIFFUSION WEIGHT FILES, YOU AGREE TO HAVE READ AND ACCEPTED THE CREATIVEML RESPONSIBLE AI LICENSE LOCATED AT https://huggingface.co/spaces/CompVis/stable-diffusion-license @@ -466,7 +436,6 @@ https://huggingface.co/spaces/CompVis/stable-diffusion-license CenteredButtonPress, name=label, relx=(window_width - len(label)) // 2, - rely=-3, when_pressed_function=self.on_ok, ) @@ -542,7 +511,7 @@ class EditOptApplication(npyscreen.NPSAppManaged): "MAIN", editOptsForm, name="InvokeAI Startup Options", - cycle_widgets=True, + cycle_widgets=False, ) if not (self.program_opts.skip_sd_weights or self.program_opts.default_only): self.model_select = self.addForm( diff --git a/invokeai/configs/INITIAL_MODELS.yaml b/invokeai/configs/INITIAL_MODELS.yaml index e148ee9b55..1a785cac13 100644 --- a/invokeai/configs/INITIAL_MODELS.yaml +++ b/invokeai/configs/INITIAL_MODELS.yaml @@ -48,10 +48,6 @@ sd-1/main/openjourney: description: An SD 1.5 model fine tuned on Midjourney; prompt with "mdjrny-v4 style" (2.13 GB) repo_id: prompthero/openjourney recommended: False -sd-1/main/portraitplus: - description: An SD-1.5 model trained on close range portraits of people; prompt with "portrait+" (2.13 GB) - repo_id: wavymulder/portraitplus - recommended: False sd-1/main/seek.art_MEGA: repo_id: coreco/seek.art_MEGA description: A general use SD-1.5 "anything" model that supports multiple styles (2.1 GB) @@ -60,10 +56,6 @@ sd-1/main/trinart_stable_diffusion_v2: description: An SD-1.5 model finetuned with ~40K assorted high resolution manga/anime-style images (2.13 GB) repo_id: naclbit/trinart_stable_diffusion_v2 recommended: False -sd-1/main/waifu-diffusion: - description: An SD-1.5 model trained on 680k anime/manga-style images (2.13 GB) - repo_id: hakurei/waifu-diffusion - recommended: False sd-1/controlnet/canny: repo_id: lllyasviel/control_v11p_sd15_canny recommended: True diff --git a/invokeai/frontend/install/model_install.py b/invokeai/frontend/install/model_install.py index c4b19157a4..448ded6318 100644 --- a/invokeai/frontend/install/model_install.py +++ b/invokeai/frontend/install/model_install.py @@ -93,13 +93,7 @@ class addModelsForm(CyclingForm, npyscreen.FormMultiPage): self.nextrely -= 1 self.add_widget_intelligent( npyscreen.FixedText, - value="Use ctrl-N and ctrl-P to move to the ext and

revious fields,", - editable=False, - color="CAUTION", - ) - self.add_widget_intelligent( - npyscreen.FixedText, - value="Use cursor arrows to make a selection, and space to toggle checkboxes.", + value="Use ctrl-N and ctrl-P to move to the ext and

revious fields. Cursor keys navigate, and selects.", editable=False, color="CAUTION", ) @@ -161,33 +155,40 @@ class addModelsForm(CyclingForm, npyscreen.FormMultiPage): BufferBox, name='Log Messages', editable=False, - max_height = 10, + max_height = 8, ) self.nextrely += 1 done_label = "APPLY CHANGES" back_label = "BACK" + cancel_label = "CANCEL" + current_position = self.nextrely if self.multipage: self.back_button = self.add_widget_intelligent( npyscreen.ButtonPress, name=back_label, - rely=-3, when_pressed_function=self.on_back, ) else: + self.nextrely = current_position + self.cancel_button = self.add_widget_intelligent( + npyscreen.ButtonPress, + name=cancel_label, + when_pressed_function=self.on_cancel + ) + self.nextrely = current_position self.ok_button = self.add_widget_intelligent( npyscreen.ButtonPress, name=done_label, relx=(window_width - len(done_label)) // 2, - rely=-3, - when_pressed_function=self.on_execute + when_pressed_function=self.on_execute ) label = "APPLY CHANGES & EXIT" + self.nextrely = current_position self.done = self.add_widget_intelligent( npyscreen.ButtonPress, name=label, - rely=-3, relx=window_width-len(label)-15, when_pressed_function=self.on_done, ) @@ -553,7 +554,7 @@ class AddModelApplication(npyscreen.NPSAppManaged): def onStart(self): npyscreen.setTheme(npyscreen.Themes.DefaultTheme) self.main_form = self.addForm( - "MAIN", addModelsForm, name="Install Stable Diffusion Models", cycle_widgets=True, + "MAIN", addModelsForm, name="Install Stable Diffusion Models", cycle_widgets=False, ) class StderrToMessage(): diff --git a/invokeai/frontend/install/widgets.py b/invokeai/frontend/install/widgets.py index 82d3753eb4..65f1589589 100644 --- a/invokeai/frontend/install/widgets.py +++ b/invokeai/frontend/install/widgets.py @@ -17,8 +17,8 @@ from shutil import get_terminal_size from curses import BUTTON2_CLICKED,BUTTON3_CLICKED # minimum size for UIs -MIN_COLS = 136 -MIN_LINES = 45 +MIN_COLS = 130 +MIN_LINES = 38 # ------------------------------------- def set_terminal_size(columns: int, lines: int): @@ -38,13 +38,13 @@ def set_terminal_size(columns: int, lines: int): ts = get_terminal_size() pause = False if ts.columns < columns: - print('\033[1mThis window is too narrow for the user interface. Please make it wider.\033[0m') + print('\033[1mThis window is too narrow for the user interface.\033[0m') pause = True if ts.lines < lines: - print('\033[1mThis window is too short for the user interface. Please make it taller.\033[0m') + print('\033[1mThis window is too short for the user interface.\033[0m') pause = True if pause: - input('Press any key to continue..') + input('Maximize the window then press any key to continue..') def _set_terminal_size_powershell(width: int, height: int): script=f''' From 451b8c96e5f2667b7967f34c3624718cf83df2b5 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Wed, 26 Jul 2023 22:29:39 -0400 Subject: [PATCH 2/2] do not overwrite models.yaml if it is well formed --- invokeai/backend/install/invokeai_configure.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index 0d3f98155c..98b92858e7 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -13,8 +13,8 @@ import os import shutil import textwrap import traceback -import warnings import yaml +import warnings from argparse import Namespace from pathlib import Path from shutil import get_terminal_size @@ -56,7 +56,6 @@ from invokeai.frontend.install.widgets import ( from invokeai.backend.install.legacy_arg_parsing import legacy_parser from invokeai.backend.install.model_install_backend import ( hf_download_from_pretrained, - hf_download_with_resume, InstallSelections, ModelInstall, ) @@ -391,7 +390,7 @@ Use cursor arrows to make a checkbox selection, and space to toggle. self.autoimport_dirs = {} self.autoimport_dirs['autoimport_dir'] = self.add_widget_intelligent( FileBox, - name=f'Autoimport Folder', + name='Autoimport Folder', value=str(config.root_path / config.autoimport_dir), select_dir=True, must_exist=False, @@ -583,7 +582,18 @@ def initialize_rootdir(root: Path, yes_to_all: bool = False): path = dest / 'core' path.mkdir(parents=True, exist_ok=True) - with open(root / 'configs' / 'models.yaml','w') as yaml_file: + maybe_create_models_yaml(root) + +def maybe_create_models_yaml(root: Path): + models_yaml = root / 'configs' / 'models.yaml' + if models_yaml.exists(): + if OmegaConf.load(models_yaml).get('__metadata__'): # up to date + return + else: + logger.info('Creating new models.yaml, original saved as models.yaml.orig') + models_yaml.rename(models_yaml.parent / 'models.yaml.orig') + + with open(models_yaml,'w') as yaml_file: yaml_file.write(yaml.dump({'__metadata__': {'version':'3.0.0'} }