mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
convert existing model display to column format
This commit is contained in:
parent
7545e38655
commit
f299f40763
@ -7,6 +7,7 @@
|
||||
# Coauthor: Kevin Turner http://github.com/keturn
|
||||
#
|
||||
import argparse
|
||||
import curses
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
@ -22,6 +23,7 @@ import npyscreen
|
||||
import requests
|
||||
from diffusers import AutoencoderKL
|
||||
from huggingface_hub import hf_hub_url
|
||||
from npyscreen import widget
|
||||
from omegaconf import OmegaConf
|
||||
from omegaconf.dictconfig import DictConfig
|
||||
from tqdm import tqdm
|
||||
@ -30,6 +32,7 @@ import invokeai.configs as configs
|
||||
from ldm.invoke.devices import choose_precision, choose_torch_device
|
||||
from ldm.invoke.generator.diffusers_pipeline import StableDiffusionGeneratorPipeline
|
||||
from ldm.invoke.globals import Globals, global_cache_dir, global_config_dir
|
||||
from ldm.invoke.config.widgets import MultiSelectColumns
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
import torch
|
||||
@ -84,37 +87,52 @@ class addModelsForm(npyscreen.FormMultiPageAction):
|
||||
self.starter_model_list = [
|
||||
x for x in list(self.initial_models.keys()) if x not in self.existing_models
|
||||
]
|
||||
self.installed_models=dict()
|
||||
super().__init__(parentApp, name)
|
||||
|
||||
def create(self):
|
||||
starter_model_labels = [
|
||||
"%-30s %-50s" % (x, self.initial_models[x].description)
|
||||
for x in self.starter_model_list
|
||||
]
|
||||
window_height, window_width = curses.initscr().getmaxyx()
|
||||
starter_model_labels = self._get_starter_model_labels()
|
||||
recommended_models = [
|
||||
x
|
||||
for x in self.starter_model_list
|
||||
if self.initial_models[x].get("recommended", False)
|
||||
]
|
||||
previously_installed_models = [
|
||||
x for x in list(self.initial_models.keys()) if x in self.existing_models
|
||||
]
|
||||
previously_installed_models = sorted(
|
||||
[
|
||||
x for x in list(self.initial_models.keys()) if x in self.existing_models
|
||||
]
|
||||
)
|
||||
|
||||
if len(previously_installed_models) > 0:
|
||||
title = self.add_widget_intelligent(
|
||||
npyscreen.TitleText,
|
||||
name="Currently installed starter models. Uncheck to delete:",
|
||||
editable=False,
|
||||
color="CONTROL",
|
||||
)
|
||||
self.nextrely -= 1
|
||||
columns = 3
|
||||
self.previously_installed_models = self.add_widget_intelligent(
|
||||
MultiSelectColumns,
|
||||
columns=columns,
|
||||
values=previously_installed_models,
|
||||
value=[x for x in range(0,len(previously_installed_models))],
|
||||
max_height=len(previously_installed_models)+1 // columns,
|
||||
slow_scroll=True,
|
||||
scroll_exit = True,
|
||||
)
|
||||
self.add_widget_intelligent(
|
||||
npyscreen.TitleText,
|
||||
name="This is a starter set of Stable Diffusion models from HuggingFace",
|
||||
name="Select from a starter set of Stable Diffusion models from HuggingFace:",
|
||||
editable=False,
|
||||
color="CONTROL",
|
||||
)
|
||||
self.add_widget_intelligent(
|
||||
npyscreen.FixedText,
|
||||
value="Select models to install:",
|
||||
editable=False,
|
||||
color="LABELBOLD",
|
||||
)
|
||||
self.nextrely -= 2
|
||||
self.add_widget_intelligent(npyscreen.FixedText, value="", editable=False),
|
||||
self.models_selected = self.add_widget_intelligent(
|
||||
npyscreen.MultiSelect,
|
||||
name="Install/Remove Models",
|
||||
name="Install Starter Models",
|
||||
values=starter_model_labels,
|
||||
value=[
|
||||
self.starter_model_list.index(x)
|
||||
@ -124,72 +142,80 @@ class addModelsForm(npyscreen.FormMultiPageAction):
|
||||
max_height=len(starter_model_labels) + 1,
|
||||
scroll_exit=True,
|
||||
)
|
||||
if len(previously_installed_models) > 0:
|
||||
title = self.add_widget_intelligent(
|
||||
npyscreen.TitleText,
|
||||
name=f"These starter models are already installed. Use the command-line or Web UIs to manage them:",
|
||||
editable=False,
|
||||
color="CONTROL",
|
||||
)
|
||||
y_origin = title.rely+1
|
||||
|
||||
# use three columns
|
||||
col_cnt = 3
|
||||
col_width = max([len(x) for x in previously_installed_models])+2
|
||||
rows = ceil(len(previously_installed_models)/col_cnt)
|
||||
previously_installed_models = sorted(previously_installed_models)
|
||||
|
||||
for i in range(0,len(previously_installed_models)):
|
||||
m = previously_installed_models[i]
|
||||
row = i % rows
|
||||
col = i // rows
|
||||
self.add_widget_intelligent(
|
||||
npyscreen.FixedText,
|
||||
value=m,
|
||||
editable=False,
|
||||
relx=col_cnt+col*col_width,
|
||||
rely=y_origin+row
|
||||
)
|
||||
self.nextrely += rows
|
||||
self.autoload_directory = self.add_widget_intelligent(
|
||||
npyscreen.TitleFilename,
|
||||
name='Import all .ckpt/.safetensors files from this directory (<tab> to autocomplete):',
|
||||
select_dir=True,
|
||||
must_exist=True,
|
||||
use_two_lines=False,
|
||||
begin_entry_at=81,
|
||||
value=os.path.expanduser('~'+'/'),
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.autoload_onstartup = self.add_widget_intelligent(
|
||||
npyscreen.Checkbox,
|
||||
name='Scan this directory each time InvokeAI starts for new models to import.',
|
||||
value=False,
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.nextrely += 1
|
||||
for line in [
|
||||
'Import checkpoint/safetensor models from the directory below.',
|
||||
'(Use <tab> to autocomplete)'
|
||||
]:
|
||||
self.add_widget_intelligent(
|
||||
npyscreen.TitleText,
|
||||
name='In the space below, you may cut and paste URLs, paths to .ckpt/.safetensor files, or HuggingFace diffusers repository names to import:',
|
||||
name=line,
|
||||
editable=False,
|
||||
color="CONTROL",
|
||||
)
|
||||
self.model_names = self.add_widget_intelligent(
|
||||
npyscreen.MultiLineEdit,
|
||||
max_width=75,
|
||||
max_height=16,
|
||||
scroll_exit=True,
|
||||
relx=18
|
||||
)
|
||||
self.autoload_onstartup = self.add_widget_intelligent(
|
||||
npyscreen.TitleSelectOne,
|
||||
name='Keep files in original format, or convert .ckpt/.safetensors into fast-loading diffusers models:',
|
||||
values=['Original format','Convert to diffusers format'],
|
||||
value=0,
|
||||
scroll_exit=True,
|
||||
self.nextrely -= 1
|
||||
self.autoload_directory = self.add_widget_intelligent(
|
||||
npyscreen.TitleFilename,
|
||||
name='Directory:',
|
||||
select_dir=True,
|
||||
must_exist=True,
|
||||
use_two_lines=False,
|
||||
value=os.path.expanduser('~'+'/'),
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.autoload_onstartup = self.add_widget_intelligent(
|
||||
npyscreen.Checkbox,
|
||||
name='Scan this directory each time InvokeAI starts for new models to import.',
|
||||
value=False,
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.nextrely += 1
|
||||
for line in [
|
||||
'In the space below, you may cut and paste URLs, paths to .ckpt/.safetensor files',
|
||||
'or HuggingFace diffusers repository names to import.',
|
||||
'(Use control-V or shift-control-V to paste):'
|
||||
]:
|
||||
self.add_widget_intelligent(
|
||||
npyscreen.TitleText,
|
||||
name=line,
|
||||
editable=False,
|
||||
color="CONTROL",
|
||||
)
|
||||
self.nextrely -= 1
|
||||
self.model_names = self.add_widget_intelligent(
|
||||
npyscreen.MultiLineEdit,
|
||||
max_width=75,
|
||||
max_height=8,
|
||||
scroll_exit=True,
|
||||
relx=3
|
||||
)
|
||||
self.autoload_onstartup = self.add_widget_intelligent(
|
||||
npyscreen.TitleSelectOne,
|
||||
name='Keep files in original format, or convert .ckpt/.safetensors into fast-loading diffusers models:',
|
||||
values=['Original format','Convert to diffusers format'],
|
||||
value=0,
|
||||
scroll_exit=True,
|
||||
)
|
||||
self.find_next_editable()
|
||||
# self.set_editing(self.models_selected)
|
||||
# self.display()
|
||||
# self.models_selected.editing=True
|
||||
# self.models_selected.edit()
|
||||
|
||||
self.models_selected.editing = True
|
||||
def _get_starter_model_labels(self):
|
||||
window_height, window_width = curses.initscr().getmaxyx()
|
||||
label_width = 25
|
||||
checkbox_width = 4
|
||||
spacing_width = 2
|
||||
description_width = window_width - label_width - checkbox_width - spacing_width
|
||||
im = self.initial_models
|
||||
names = list(im.keys())
|
||||
descriptions = [im[x].description [0:description_width-3]+'...'
|
||||
if len(im[x].description) > description_width
|
||||
else im[x].description
|
||||
for x in im]
|
||||
return [
|
||||
f"%-{label_width}s %s" % (names[x], descriptions[x]) for x in range(0,len(im))
|
||||
]
|
||||
|
||||
def on_ok(self):
|
||||
self.parentApp.setNextForm(None)
|
||||
@ -607,12 +633,23 @@ def main():
|
||||
|
||||
try:
|
||||
select_and_download_models(opt)
|
||||
except AssertionError as e:
|
||||
print(str(e))
|
||||
sys.exit(-1)
|
||||
except KeyboardInterrupt:
|
||||
print("\nGoodbye! Come back soon.")
|
||||
except Exception as e:
|
||||
print(f'\nA problem occurred during initialization.\nThe error was: "{str(e)}"')
|
||||
print(traceback.format_exc())
|
||||
|
||||
except (widget.NotEnoughSpaceForWidget, Exception) as e:
|
||||
if str(e).startswith("Height of 1 allocated"):
|
||||
print(
|
||||
"** Insufficient vertical space for the interface. Please make your window taller and try again"
|
||||
)
|
||||
elif str(e).startswith('addwstr'):
|
||||
print(
|
||||
'** Insufficient horizontal space for the interface. Please make your window wider and try again.'
|
||||
)
|
||||
else:
|
||||
print(f"** A layout error has occurred: {str(e)}")
|
||||
sys.exit(-1)
|
||||
|
||||
# -------------------------------------
|
||||
if __name__ == "__main__":
|
||||
|
70
ldm/invoke/config/widgets.py
Normal file
70
ldm/invoke/config/widgets.py
Normal file
@ -0,0 +1,70 @@
|
||||
'''
|
||||
Widget class definitions used by model_select.py, merge_diffusers.py and textual_inversion.py
|
||||
'''
|
||||
import math
|
||||
import npyscreen
|
||||
import curses
|
||||
|
||||
class FloatSlider(npyscreen.Slider):
|
||||
# this is supposed to adjust display precision, but doesn't
|
||||
def translate_value(self):
|
||||
stri = "%3.2f / %3.2f" % (self.value, self.out_of)
|
||||
l = (len(str(self.out_of))) * 2 + 4
|
||||
stri = stri.rjust(l)
|
||||
return stri
|
||||
|
||||
class FloatTitleSlider(npyscreen.TitleText):
|
||||
_entry_type = FloatSlider
|
||||
|
||||
class MultiSelectColumns(npyscreen.MultiSelect):
|
||||
def __init__(self, screen, columns: int=1, values: list=[], **keywords):
|
||||
self.columns = columns
|
||||
self.value_cnt = len(values)
|
||||
self.rows = math.ceil(self.value_cnt / self.columns)
|
||||
super().__init__(screen,values=values, **keywords)
|
||||
|
||||
def make_contained_widgets(self):
|
||||
self._my_widgets = []
|
||||
column_width = self.width // self.columns
|
||||
for h in range(self.value_cnt):
|
||||
self._my_widgets.append(
|
||||
self._contained_widgets(self.parent,
|
||||
rely=self.rely + (h % self.rows) * self._contained_widget_height,
|
||||
relx=self.relx + (h // self.rows) * column_width,
|
||||
max_width=column_width,
|
||||
max_height=self.__class__._contained_widget_height,
|
||||
)
|
||||
)
|
||||
|
||||
def set_up_handlers(self):
|
||||
super().set_up_handlers()
|
||||
self.handlers.update({
|
||||
curses.KEY_UP: self.h_cursor_line_left,
|
||||
curses.KEY_DOWN: self.h_cursor_line_right,
|
||||
}
|
||||
)
|
||||
def h_cursor_line_down(self, ch):
|
||||
self.cursor_line += self.rows
|
||||
if self.cursor_line >= len(self.values):
|
||||
if self.scroll_exit:
|
||||
self.cursor_line = len(self.values)-self.rows
|
||||
self.h_exit_down(ch)
|
||||
return True
|
||||
else:
|
||||
self.cursor_line -= self.rows
|
||||
return True
|
||||
|
||||
def h_cursor_line_up(self, ch):
|
||||
self.cursor_line -= self.rows
|
||||
if self.cursor_line < 0:
|
||||
if self.scroll_exit:
|
||||
self.cursor_line = 0
|
||||
self.h_exit_up(ch)
|
||||
else:
|
||||
self.cursor_line = 0
|
||||
|
||||
def h_cursor_line_left(self,ch):
|
||||
super().h_cursor_line_up(ch)
|
||||
|
||||
def h_cursor_line_right(self,ch):
|
||||
super().h_cursor_line_down(ch)
|
@ -20,6 +20,7 @@ from diffusers import logging as dlogging
|
||||
from npyscreen import widget
|
||||
from omegaconf import OmegaConf
|
||||
|
||||
from ldm.invoke.config.widgets import FloatTitleSlider
|
||||
from ldm.invoke.globals import (Globals, global_cache_dir, global_config_file,
|
||||
global_models_dir, global_set_root)
|
||||
from ldm.invoke.model_manager import ModelManager
|
||||
@ -172,17 +173,6 @@ def _parse_args() -> Namespace:
|
||||
|
||||
|
||||
# ------------------------- GUI HERE -------------------------
|
||||
class FloatSlider(npyscreen.Slider):
|
||||
# this is supposed to adjust display precision, but doesn't
|
||||
def translate_value(self):
|
||||
stri = "%3.2f / %3.2f" % (self.value, self.out_of)
|
||||
l = (len(str(self.out_of))) * 2 + 4
|
||||
stri = stri.rjust(l)
|
||||
return stri
|
||||
|
||||
class FloatTitleSlider(npyscreen.TitleText):
|
||||
_entry_type = FloatSlider
|
||||
|
||||
class mergeModelsForm(npyscreen.FormMultiPageAction):
|
||||
interpolations = ["weighted_sum", "sigmoid", "inv_sigmoid", "add_difference"]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user