Rework configure/install TUI to require less space (#3989)

## What type of PR is this? (check all applicable)

- [ ] Refactor
- [ ] Feature
- [X ] Bug Fix
- [ ] Optimization
- [ ] Documentation Update
- [ ] Community Node Submission


## Have you discussed this change with the InvokeAI team?
- [ X] Yes
- [ ] No, because:

      
## Have you updated all relevant documentation?
- [X ] Yes
- [ ] No


## Description

I have reworked the console TUIs for the configure and model install
scripts to require much less vertical space. In the event that the
"NEXT" button is still missing and "page 1/2" is displayed, scrolling
beyond the last checkbox will now automatically move to page 2 where the
buttons are displayed. This is not ideal, but will no longer block user
completely.

If users continue to have problems after this, I'll get rid of the TUI
altogether and replace with a web form.

## Added/updated tests?

- [ ] Yes
- [X ] No : not needed

## [optional] Are there any post deployment tasks we need to perform?
This commit is contained in:
Lincoln Stein 2023-07-26 23:44:50 -04:00 committed by GitHub
commit fc19624bd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 54 deletions

View File

@ -45,6 +45,7 @@ from invokeai.app.services.config import (
from invokeai.backend.util.logging import InvokeAILogger from invokeai.backend.util.logging import InvokeAILogger
from invokeai.frontend.install.model_install import addModelsForm, process_and_execute from invokeai.frontend.install.model_install import addModelsForm, process_and_execute
from invokeai.frontend.install.widgets import ( from invokeai.frontend.install.widgets import (
SingleSelectColumns,
CenteredButtonPress, CenteredButtonPress,
FileBox, FileBox,
IntTitleSlider, IntTitleSlider,
@ -330,34 +331,49 @@ Use cursor arrows to make a checkbox selection, and space to toggle.
npyscreen.Checkbox, npyscreen.Checkbox,
name="Free GPU memory after each generation", name="Free GPU memory after each generation",
value=old_opts.free_gpu_mem, value=old_opts.free_gpu_mem,
max_width=45,
relx=5, relx=5,
scroll_exit=True, scroll_exit=True,
) )
self.nextrely -= 1
self.xformers_enabled = self.add_widget_intelligent( self.xformers_enabled = self.add_widget_intelligent(
npyscreen.Checkbox, npyscreen.Checkbox,
name="Enable xformers support if available", name="Enable xformers support",
value=old_opts.xformers_enabled, value=old_opts.xformers_enabled,
relx=5, max_width=30,
relx=50,
scroll_exit=True, scroll_exit=True,
) )
self.nextrely -=1
self.always_use_cpu = self.add_widget_intelligent( self.always_use_cpu = self.add_widget_intelligent(
npyscreen.Checkbox, npyscreen.Checkbox,
name="Force CPU to be used on GPU systems", name="Force CPU to be used on GPU systems",
value=old_opts.always_use_cpu, value=old_opts.always_use_cpu,
relx=5, relx=80,
scroll_exit=True, scroll_exit=True,
) )
precision = old_opts.precision or ( precision = old_opts.precision or (
"float32" if program_opts.full_precision else "auto" "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( self.precision = self.add_widget_intelligent(
npyscreen.TitleSelectOne, SingleSelectColumns,
columns = 2, columns = 3,
name="Precision", name="Precision",
values=PRECISION_CHOICES, values=PRECISION_CHOICES,
value=PRECISION_CHOICES.index(precision), value=PRECISION_CHOICES.index(precision),
begin_entry_at=3, begin_entry_at=3,
max_height=len(PRECISION_CHOICES) + 1, max_height=2,
max_width=80,
scroll_exit=True, scroll_exit=True,
) )
self.max_cache_size = self.add_widget_intelligent( self.max_cache_size = self.add_widget_intelligent(
@ -370,12 +386,6 @@ Use cursor arrows to make a checkbox selection, and space to toggle.
scroll_exit=True, scroll_exit=True,
) )
self.nextrely += 1 self.nextrely += 1
self.add_widget_intelligent(
npyscreen.FixedText,
value="Folder to recursively scan for new checkpoints, ControlNets, LoRAs and TI models (<tab> autocompletes, ctrl-N advances):",
editable=False,
color="CONTROL",
)
self.outdir = self.add_widget_intelligent( self.outdir = self.add_widget_intelligent(
FileBox, FileBox,
name="Output directory for images (<tab> autocompletes, ctrl-N advances):", name="Output directory for images (<tab> autocompletes, ctrl-N advances):",
@ -391,7 +401,7 @@ Use cursor arrows to make a checkbox selection, and space to toggle.
self.autoimport_dirs = {} self.autoimport_dirs = {}
self.autoimport_dirs['autoimport_dir'] = self.add_widget_intelligent( self.autoimport_dirs['autoimport_dir'] = self.add_widget_intelligent(
FileBox, 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), value=str(config.root_path / config.autoimport_dir),
select_dir=True, select_dir=True,
must_exist=False, must_exist=False,
@ -402,15 +412,6 @@ Use cursor arrows to make a checkbox selection, and space to toggle.
scroll_exit=True scroll_exit=True
) )
self.nextrely += 1 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 label = """BY DOWNLOADING THE STABLE DIFFUSION WEIGHT FILES, YOU AGREE TO HAVE READ
AND ACCEPTED THE CREATIVEML RESPONSIBLE AI LICENSES LOCATED AT AND ACCEPTED THE CREATIVEML RESPONSIBLE AI LICENSES LOCATED AT
https://huggingface.co/spaces/CompVis/stable-diffusion-license and https://huggingface.co/spaces/CompVis/stable-diffusion-license and
@ -440,7 +441,6 @@ https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENS
CenteredButtonPress, CenteredButtonPress,
name=label, name=label,
relx=(window_width - len(label)) // 2, relx=(window_width - len(label)) // 2,
rely=-3,
when_pressed_function=self.on_ok, when_pressed_function=self.on_ok,
) )

View File

@ -16,13 +16,13 @@ sd-2/main/stable-diffusion-2-inpainting:
description: Stable Diffusion version 2.0 inpainting model (5.21 GB) description: Stable Diffusion version 2.0 inpainting model (5.21 GB)
repo_id: stabilityai/stable-diffusion-2-inpainting repo_id: stabilityai/stable-diffusion-2-inpainting
recommended: False recommended: False
sdxl/main/stable-diffusion-xl-base-0-9: sdxl/main/stable-diffusion-xl-base-1-0:
description: Stable Diffusion XL base model (12 GB; access token required) description: Stable Diffusion XL base model (12 GB)
repo_id: stabilityai/stable-diffusion-xl-base-0.9 repo_id: stabilityai/stable-diffusion-xl-base-1.0
recommended: False recommended: False
sdxl-refiner/main/stable-diffusion-xl-refiner-0-9: sdxl-refiner/main/stable-diffusion-xl-refiner-1-0:
description: Stable Diffusion XL refiner model (12 GB; access token required) description: Stable Diffusion XL refiner model (12 GB)
repo_id: stabilityai/stable-diffusion-xl-refiner-0.9 repo_id: stabilityai/stable-diffusion-xl-refiner-1.0
recommended: False recommended: False
sd-1/main/Analog-Diffusion: sd-1/main/Analog-Diffusion:
description: An SD-1.5 model trained on diverse analog photographs (2.13 GB) description: An SD-1.5 model trained on diverse analog photographs (2.13 GB)
@ -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) description: An SD 1.5 model fine tuned on Midjourney; prompt with "mdjrny-v4 style" (2.13 GB)
repo_id: prompthero/openjourney repo_id: prompthero/openjourney
recommended: False 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: sd-1/main/seek.art_MEGA:
repo_id: coreco/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) 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) 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 repo_id: naclbit/trinart_stable_diffusion_v2
recommended: False 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: sd-1/controlnet/canny:
repo_id: lllyasviel/control_v11p_sd15_canny repo_id: lllyasviel/control_v11p_sd15_canny
recommended: True recommended: True

View File

@ -93,13 +93,7 @@ class addModelsForm(CyclingForm, npyscreen.FormMultiPage):
self.nextrely -= 1 self.nextrely -= 1
self.add_widget_intelligent( self.add_widget_intelligent(
npyscreen.FixedText, npyscreen.FixedText,
value="Use ctrl-N and ctrl-P to move to the <N>ext and <P>revious fields,", value="Use ctrl-N and ctrl-P to move to the <N>ext and <P>revious fields. Cursor keys navigate, and <space> selects.",
editable=False,
color="CAUTION",
)
self.add_widget_intelligent(
npyscreen.FixedText,
value="Use cursor arrows to make a selection, and space to toggle checkboxes.",
editable=False, editable=False,
color="CAUTION", color="CAUTION",
) )
@ -161,33 +155,40 @@ class addModelsForm(CyclingForm, npyscreen.FormMultiPage):
BufferBox, BufferBox,
name='Log Messages', name='Log Messages',
editable=False, editable=False,
max_height = 10, max_height = 8,
) )
self.nextrely += 1 self.nextrely += 1
done_label = "APPLY CHANGES" done_label = "APPLY CHANGES"
back_label = "BACK" back_label = "BACK"
cancel_label = "CANCEL"
current_position = self.nextrely
if self.multipage: if self.multipage:
self.back_button = self.add_widget_intelligent( self.back_button = self.add_widget_intelligent(
npyscreen.ButtonPress, npyscreen.ButtonPress,
name=back_label, name=back_label,
rely=-3,
when_pressed_function=self.on_back, when_pressed_function=self.on_back,
) )
else: 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( self.ok_button = self.add_widget_intelligent(
npyscreen.ButtonPress, npyscreen.ButtonPress,
name=done_label, name=done_label,
relx=(window_width - len(done_label)) // 2, 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" label = "APPLY CHANGES & EXIT"
self.nextrely = current_position
self.done = self.add_widget_intelligent( self.done = self.add_widget_intelligent(
npyscreen.ButtonPress, npyscreen.ButtonPress,
name=label, name=label,
rely=-3,
relx=window_width-len(label)-15, relx=window_width-len(label)-15,
when_pressed_function=self.on_done, when_pressed_function=self.on_done,
) )

View File

@ -17,8 +17,8 @@ from shutil import get_terminal_size
from curses import BUTTON2_CLICKED,BUTTON3_CLICKED from curses import BUTTON2_CLICKED,BUTTON3_CLICKED
# minimum size for UIs # minimum size for UIs
MIN_COLS = 136 MIN_COLS = 130
MIN_LINES = 45 MIN_LINES = 38
# ------------------------------------- # -------------------------------------
def set_terminal_size(columns: int, lines: int): def set_terminal_size(columns: int, lines: int):
@ -38,13 +38,13 @@ def set_terminal_size(columns: int, lines: int):
ts = get_terminal_size() ts = get_terminal_size()
pause = False pause = False
if ts.columns < columns: 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 pause = True
if ts.lines < lines: 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 pause = True
if pause: 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): def _set_terminal_size_powershell(width: int, height: int):
script=f''' script=f'''