both forms functional; need integration

This commit is contained in:
Lincoln Stein 2023-02-19 13:12:05 -05:00
parent 587faa3e52
commit e5646d7241
2 changed files with 416 additions and 350 deletions

View File

@ -8,8 +8,11 @@
#
print("Loading Python libraries...\n")
import argparse
import curses
import npyscreen
import io
import os
import re
import shutil
import sys
import traceback
@ -18,9 +21,10 @@ from pathlib import Path
from urllib import request
import transformers
from getpass_asterisk import getpass_asterisk
from argparse import Namespace
from huggingface_hub import HfFolder
from huggingface_hub import login as hf_hub_login
from omegaconf import OmegaConf
from tqdm import tqdm
from transformers import (
@ -31,10 +35,12 @@ from transformers import (
)
import invokeai.configs as configs
from ldm.invoke.config.model_install_backend import download_from_hf
from ldm.invoke.config.model_install import select_and_download_models
from ldm.invoke.globals import Globals, global_config_dir
from ldm.invoke.readline import generic_completer
from ..args import Args, PRECISION_CHOICES
from .model_install_backend import download_from_hf
from .model_install import select_and_download_models
from .widgets import IntTitleSlider
from ..globals import Globals, global_config_dir
from ..readline import generic_completer
warnings.filterwarnings("ignore")
@ -53,16 +59,19 @@ SD_Configs = Path(global_config_dir()) / "stable-diffusion"
Datasets = OmegaConf.load(Dataset_path)
completer = generic_completer(["yes", "no"])
Config_preamble = """# This file describes the alternative machine learning models
# available to InvokeAI script.
#
# To add a new model, follow the examples below. Each
# model requires a model config file, a weights file,
# and the width and height of the images it
# was trained on.
INIT_FILE_PREAMBLE = """# InvokeAI initialization file
# This is the InvokeAI initialization file, which contains command-line default values.
# Feel free to edit. If anything goes wrong, you can re-initialize this file by deleting
# or renaming it and then running invokeai-configure again.
# Place frequently-used startup commands here, one or more per line.
# Examples:
# --outdir=D:\data\images
# --no-nsfw_checker
# --web --host=0.0.0.0
# --steps=20
# -Ak_euler_a -C10.0
"""
# --------------------------------------------
def postscript(errors: None):
if not any(errors):
@ -111,7 +120,6 @@ def yes_or_no(prompt: str, default_yes=True):
else:
return response[0] in ("y", "Y")
# ---------------------------------------------
def HfLogin(access_token) -> str:
"""
@ -128,122 +136,23 @@ def HfLogin(access_token) -> str:
sys.stdout = sys.__stdout__
print(exc)
raise exc
# -------------------------------------
class ProgressBar:
def __init__(self, model_name="file"):
self.pbar = None
self.name = model_name
# -------------------------------Authenticate against Hugging Face
def save_hf_token(yes_to_all=False):
print("** LICENSE AGREEMENT FOR WEIGHT FILES **")
print("=" * shutil.get_terminal_size()[0])
print(
"""
By downloading the Stable Diffusion weight files from the official Hugging Face
repository, you agree to have read and accepted the CreativeML Responsible AI License.
The license terms are located here:
https://huggingface.co/spaces/CompVis/stable-diffusion-license
"""
)
print("=" * shutil.get_terminal_size()[0])
if not yes_to_all:
accepted = False
while not accepted:
accepted = yes_or_no("Accept the above License terms?")
if not accepted:
print("Please accept the License or Ctrl+C to exit.")
else:
print("Thank you!")
else:
print(
"The program was started with a '--yes' flag, which indicates user's acceptance of the above License terms."
)
# Authenticate to Huggingface using environment variables.
# If successful, authentication will persist for either interactive or non-interactive use.
# Default env var expected by HuggingFace is HUGGING_FACE_HUB_TOKEN.
print("=" * shutil.get_terminal_size()[0])
print("Authenticating to Huggingface")
hf_envvars = ["HUGGING_FACE_HUB_TOKEN", "HUGGINGFACE_TOKEN"]
token_found = False
if not (access_token := HfFolder.get_token()):
print("Huggingface token not found in cache.")
for ev in hf_envvars:
if access_token := os.getenv(ev):
print(
f"Token was found in the {ev} environment variable.... Logging in."
)
try:
HfLogin(access_token)
continue
except ValueError:
print(f"Login failed due to invalid token found in {ev}")
else:
print(f"Token was not found in the environment variable {ev}.")
else:
print("Huggingface token found in cache.")
try:
HfLogin(access_token)
token_found = True
except ValueError:
print("Login failed due to invalid token found in cache")
if not (yes_to_all or token_found):
print(
f""" You may optionally enter your Huggingface token now. InvokeAI
*will* work without it but you will not be able to automatically
download some of the Hugging Face style concepts. See
https://invoke-ai.github.io/InvokeAI/features/CONCEPTS/#using-a-hugging-face-concept
for more information.
Visit https://huggingface.co/settings/tokens to generate a token. (Sign up for an account if needed).
Paste the token below using {"Ctrl+Shift+V" if sys.platform == "linux" else "Command+V" if sys.platform == "darwin" else "Ctrl+V, right-click, or Edit>Paste"}.
Alternatively, press 'Enter' to skip this step and continue.
You may re-run the configuration script again in the future if you do not wish to set the token right now.
"""
)
again = True
while again:
try:
access_token = getpass_asterisk.getpass_asterisk(prompt="HF Token ")
if access_token is None or len(access_token) == 0:
raise EOFError
HfLogin(access_token)
access_token = HfFolder.get_token()
again = False
except ValueError:
again = yes_or_no(
"Failed to log in to Huggingface. Would you like to try again?"
)
if not again:
print(
"\nRe-run the configuration script whenever you wish to set the token."
)
print("...Continuing...")
except EOFError:
# this happens if the user pressed Enter on the prompt without any input; assume this means they don't want to input a token
# safety net needed against accidental "Enter"?
print("None provided - continuing")
again = False
elif access_token is None:
print()
print(
"HuggingFace login did not succeed. Some functionality may be limited; see https://invoke-ai.github.io/InvokeAI/features/CONCEPTS/#using-a-hugging-face-concept for more information"
)
print()
print(
f"Re-run the configuration script without '--yes' to set the HuggingFace token interactively, or use one of the environment variables: {', '.join(hf_envvars)}"
)
print("=" * shutil.get_terminal_size()[0])
return access_token
def __call__(self, block_num, block_size, total_size):
if not self.pbar:
self.pbar = tqdm(
desc=self.name,
initial=0,
unit="iB",
unit_scale=True,
unit_divisor=1000,
total=total_size,
)
self.pbar.update(block_size)
# ---------------------------------------------
def download_with_progress_bar(model_url: str, model_dest: str, label: str = "the"):
@ -381,79 +290,270 @@ def get_root(root: str = None) -> str:
return Globals.root
# -------------------------------------
def select_root(root: str, yes_to_all: bool = False):
default = root or os.path.expanduser("~/invokeai")
if yes_to_all:
return default
completer.set_default_dir(default)
completer.complete_extensions(())
completer.set_line(default)
directory = input(
f"Select a directory in which to install InvokeAI's models and configuration files [{default}]: "
).strip(" \\")
return directory or default
class editOptsForm(npyscreen.FormMultiPage):
def create(self):
old_opts = self.parentApp.old_opts
first_time = not (Globals.root / Globals.initfile).exists()
access_token = HfFolder.get_token()
window_height, window_width = curses.initscr().getmaxyx()
for i in [
'Configure startup settings. You can come back and change these later.',
'Use ctrl-N and ctrl-P to move to the <N>ext and <P>revious fields.',
'Use cursor arrows to make a checkbox selection, and space to toggle.',
]:
self.add_widget_intelligent(
npyscreen.FixedText,
value=i,
editable=False,
color='CONTROL',
)
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='(<tab> autocompletes, ctrl-N advances):',
value=old_opts.outdir or 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.safety_checker = self.add_widget_intelligent(
npyscreen.Checkbox,
name='NSFW checker',
value=old_opts.safety_checker,
relx = 5,
scroll_exit=True,
)
self.nextrely += 1
for i in [
'If you have an account at HuggingFace you may paste your access token here',
'to allow InvokeAI to download styles & subjects from the "Concept Library".',
'See https://huggingface.co/settings/tokens',
]:
self.add_widget_intelligent(
npyscreen.FixedText,
value=i,
editable=False,
color='CONTROL',
)
self.hf_token = self.add_widget_intelligent(
npyscreen.TitlePassword,
name='Access Token (use shift-ctrl-V to paste):',
value=access_token,
begin_entry_at=42,
use_two_lines=False,
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",
begin_entry_at=0,
editable=False,
color="CONTROL",
scroll_exit=True
)
self.nextrely -= 1
self.free_gpu_mem = self.add_widget_intelligent(
npyscreen.Checkbox,
name='Free GPU memory after each generation',
value=old_opts.free_gpu_mem,
relx=5,
scroll_exit=True
)
self.xformers = self.add_widget_intelligent(
npyscreen.Checkbox,
name='Enable xformers support if available',
value=old_opts.xformers,
relx=5,
scroll_exit=True
)
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,
scroll_exit=True
)
self.precision = self.add_widget_intelligent(
npyscreen.TitleSelectOne,
name='Precision',
values=PRECISION_CHOICES,
value=PRECISION_CHOICES.index(old_opts.precision),
begin_entry_at=3,
max_height=len(PRECISION_CHOICES)+1,
scroll_exit=True,
)
self.max_loaded_models = self.add_widget_intelligent(
IntTitleSlider,
name="Number of models to cache in CPU memory (each will use 2-4 GB!)",
value=old_opts.max_loaded_models,
out_of=10,
lowest=1,
begin_entry_at=4,
scroll_exit=True
)
self.nextrely += 1
self.add_widget_intelligent(
npyscreen.FixedText,
value='Directory containing embedding/textual inversion files:',
editable=False,
color='CONTROL',
)
self.embedding_path = self.add_widget_intelligent(
npyscreen.TitleFilename,
name='(<tab> autocompletes, ctrl-N advances):',
value=str(default_embedding_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.TitleFixedText,
name="== LICENSE ==",
begin_entry_at=0,
editable=False,
color="CONTROL",
scroll_exit=True
)
self.nextrely -= 1
for i in [
'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'
]:
self.add_widget_intelligent(
npyscreen.FixedText,
value=i,
editable=False,
color='CONTROL',
)
self.license_acceptance = self.add_widget_intelligent(
npyscreen.Checkbox,
name='I accept the CreativeML Responsible AI License',
value=not first_time,
relx = 2,
scroll_exit=True
)
self.nextrely += 1
self.ok_button = self.add_widget_intelligent(
npyscreen.ButtonPress,
name='DONE',
relx= (window_width-len('DONE'))//2,
rely= -3,
when_pressed_function=self.on_ok
)
def on_ok(self):
options = self.marshall_arguments()
if self.validate_field_values(options):
self.parentApp.setNextForm(None)
self.editing = False
else:
self.editing = True
def validate_field_values(self, opt: Namespace) -> bool:
bad_fields = []
if not opt.license_acceptance:
bad_fields.append(
'Please accept the license terms before proceeding to model downloads'
)
if not Path(opt.outdir).parent.exists():
bad_fields.append(
f'The output directory does not seem to be valid. Please check that {str(Path(opt.outdir).parent)} is an existing directory.'
)
if not Path(opt.embedding_path).parent.exists():
bad_fields.append(
f'The embedding directory does not seem to be valid. Please check that {str(Path(opt.embedding_path).parent)} is an existing directory.'
)
if len(bad_fields) > 0:
message = "The following problems were detected and must be corrected:\n"
for problem in bad_fields:
message += f"* {problem}\n"
npyscreen.notify_confirm(message)
return False
else:
return True
def marshall_arguments(self):
new_opts = Namespace()
for attr in ['outdir','safety_checker','free_gpu_mem','max_loaded_models',
'xformers','always_use_cpu','embedding_path']:
setattr(new_opts, attr, getattr(self, attr).value)
new_opts.hf_token = self.hf_token.value
new_opts.license_acceptance = self.license_acceptance.value
new_opts.precision = PRECISION_CHOICES[self.precision.value[0]]
return new_opts
# -------------------------------------
def select_outputs(root: str, yes_to_all: bool = False):
default = os.path.normpath(os.path.join(root, "outputs"))
if yes_to_all:
return default
completer.set_default_dir(os.path.expanduser("~"))
completer.complete_extensions(())
completer.set_line(default)
directory = input(
f"Select the default directory for image outputs [{default}]: "
).strip(" \\")
return directory or default
class EditOptApplication(npyscreen.NPSAppManaged):
def __init__(self, old_opts=argparse.Namespace):
super().__init__()
self.old_opts=old_opts
def onStart(self):
npyscreen.setTheme(npyscreen.Themes.DefaultTheme)
self.main = self.addForm(
"MAIN",
editOptsForm,
name='InvokeAI Startup Options',
)
def new_opts(self):
return self.main.marshall_arguments()
def edit_opts(old_opts: argparse.Namespace)->argparse.Namespace:
editApp = EditOptApplication(old_opts)
editApp.run()
return editApp.new_opts()
# -------------------------------------
def initialize_rootdir(root: str, yes_to_all: bool = False):
print("** INITIALIZING INVOKEAI RUNTIME DIRECTORY **")
root_selected = False
while not root_selected:
outputs = select_outputs(root, yes_to_all)
outputs = (
outputs
if os.path.isabs(outputs)
else os.path.abspath(os.path.join(Globals.root, outputs))
)
print(f'\nInvokeAI image outputs will be placed into "{outputs}".')
if not yes_to_all:
root_selected = yes_or_no("Accept this location?")
else:
root_selected = True
print(
f'\nYou may change the chosen output directory at any time by editing the --outdir options in "{Globals.initfile}",'
)
print(
"You may also change the runtime directory by setting the environment variable INVOKEAI_ROOT.\n"
)
enable_safety_checker = True
if not yes_to_all:
print(
"The NSFW (not safe for work) checker blurs out images that potentially contain sexual imagery."
)
print(
"It can be selectively enabled at run time with --nsfw_checker, and disabled with --no-nsfw_checker."
)
print(
"The following option will set whether the checker is enabled by default. Like other options, you can"
)
print(f"change this setting later by editing the file {Globals.initfile}.")
print(
"This is NOT recommended for systems with less than 6G VRAM because of the checker's memory requirements."
)
enable_safety_checker = yes_or_no(
"Enable the NSFW checker by default?", enable_safety_checker
)
safety_checker = "--nsfw_checker" if enable_safety_checker else "--no-nsfw_checker"
for name in (
"models",
@ -469,51 +569,80 @@ def initialize_rootdir(root: str, yes_to_all: bool = False):
if not os.path.samefile(configs_src, configs_dest):
shutil.copytree(configs_src, configs_dest, dirs_exist_ok=True)
init_file = os.path.join(Globals.root, Globals.initfile)
print(f'Creating the initialization file at "{init_file}".\n')
with open(init_file, "w") as f:
f.write(
f"""# InvokeAI initialization file
# This is the InvokeAI initialization file, which contains command-line default values.
# Feel free to edit. If anything goes wrong, you can re-initialize this file by deleting
# or renaming it and then running invokeai-configure again.
# the --outdir option controls the default location of image files.
--outdir="{outputs}"
# generation arguments
{safety_checker}
# You may place other frequently-used startup commands here, one or more per line.
# Examples:
# --web --host=0.0.0.0
# --steps=20
# -Ak_euler_a -C10.0
#
"""
)
# -------------------------------------
def do_edit_opt_form(old_opts: argparse.Namespace)->argparse.Namespace:
editApp = EditOptApplication(old_opts)
editApp.run()
return editApp.new_opts()
# -------------------------------------
class ProgressBar:
def __init__(self, model_name="file"):
self.pbar = None
self.name = model_name
def edit_options(init_file: Path):
# get current settings from initfile
opt = Args().parse_args()
new_opt = do_edit_opt_form(opt)
write_opts(new_opt, init_file)
def __call__(self, block_num, block_size, total_size):
if not self.pbar:
self.pbar = tqdm(
desc=self.name,
initial=0,
unit="iB",
unit_scale=True,
unit_divisor=1000,
total=total_size,
)
self.pbar.update(block_size)
# -------------------------------------
def write_opts(opts: Namespace, init_file: Path):
'''
Update the invokeai.init file with values from opts Namespace
'''
# touch file if it doesn't exist
if not init_file.exists():
with open(init_file,'w') as f:
f.write(INIT_FILE_PREAMBLE)
# We want to write in the changed arguments without clobbering
# any other initialization values the user has entered. There is
# no good way to do this because of the one-way nature of
# argparse: i.e. --outdir could be --outdir, --out, or -o
# initfile needs to be replaced with a fully structured format
# such as yaml; this is a hack that will work much of the time
args_to_skip = re.compile('^--?(o|out|no-xformer|xformer|free|no-nsfw|nsfw|prec|max_load|embed)')
new_file = f'{init_file}.new'
try:
lines = open(init_file,'r').readlines()
with open(new_file,'w') as out_file:
for line in lines:
if not args_to_skip.match(line):
out_file.write(line)
out_file.write(f'''
--outdir={opts.outdir}
--embedding_path={opts.embedding_path}
--precision={opts.precision}
--max_loaded_models={int(opts.max_loaded_models)}
--{'no-' if not opts.safety_checker else ''}nsfw_checker
--{'no-' if not opts.xformers else ''}xformers
{'--free_gpu_mem' if opts.free_gpu_mem else ''}
{'--always_use_cpu' if opts.always_use_cpu else ''}
''')
except OSError as e:
print(f'** An error occurred while writing the init file: {str(e)}')
os.replace(new_file, init_file)
if opts.hf_token:
HfLogin(opts.hf_token)
# -------------------------------------
def default_output_dir()->Path:
return Globals.root / 'outputs'
# -------------------------------------
def default_embedding_dir()->Path:
return Globals.root / 'embeddings'
# -------------------------------------
def write_default_options(initfile: Path):
opt = Namespace(
outdir=str(default_output_dir()),
embedding_path=str(default_embedding_dir()),
nsfw_checker=True,
max_loaded_models=2,
free_gpu_mem=True
)
write_opts(opt, initfile)
# -------------------------------------
def main():
parser = argparse.ArgumentParser(description="InvokeAI model downloader")
@ -568,11 +697,14 @@ def main():
try:
# We check for to see if the runtime directory is correctly initialized.
if Globals.root == "" or not os.path.exists(
os.path.join(Globals.root, "invokeai.init")
):
init_file = Path(Globals.root, Globals.initfile)
if not init_file.exists():
initialize_rootdir(Globals.root, opt.yes_to_all)
save_hf_token(opt.yes_to_all)
if opt.yes_to_all:
write_default_options(init_file)
else:
edit_options(init_file)
print("\n** DOWNLOADING SUPPORT MODELS **")
download_bert()

View File

@ -19,6 +19,7 @@ from typing import List
import npyscreen
import torch
from datetime import datetime
from pathlib import Path
from npyscreen import widget
from omegaconf import OmegaConf
@ -104,6 +105,9 @@ class addModelsForm(npyscreen.FormMultiPageAction):
color="CONTROL",
)
self.nextrely -= 1
# if user has already installed some initial models, then don't patronize them
# by showing more recommendations
show_recommended = self.installed_models is None or len(self.installed_models)==0
self.models_selected = self.add_widget_intelligent(
npyscreen.MultiSelect,
name="Install Starter Models",
@ -111,7 +115,7 @@ class addModelsForm(npyscreen.FormMultiPageAction):
value=[
self.starter_model_list.index(x)
for x in self.starter_model_list
if x in recommended_models
if show_recommended and x in recommended_models
],
max_height=len(starter_model_labels) + 1,
relx = 4,
@ -202,7 +206,7 @@ class addModelsForm(npyscreen.FormMultiPageAction):
def on_cancel(self):
self.parentApp.setNextForm(None)
self.ParentApp.user_cancelled = True
self.parentApp.user_cancelled = True
self.editing = False
def marshall_arguments(self):
@ -216,9 +220,13 @@ class addModelsForm(npyscreen.FormMultiPageAction):
.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
# due to some bug in npyscreen that is causing attributes to be lost
selections = self.parentApp.user_selections
# starter models to install/remove
starter_models = dict(map(lambda x: (self.starter_model_list[x], True), self.models_selected.value))
self.parentApp.purge_deleted_models=False
selections.purge_deleted_models=False
if hasattr(self,'previously_installed_models'):
unchecked = [
self.previously_installed_models.values[x]
@ -228,127 +236,52 @@ class addModelsForm(npyscreen.FormMultiPageAction):
starter_models.update(
map(lambda x: (x, False), unchecked)
)
self.parentApp.purge_deleted_models = self.purge_deleted.value
self.parentApp.starter_models=starter_models
selections.purge_deleted_models = self.purge_deleted.value
selections.starter_models=starter_models
# load directory and whether to scan on startup
if self.show_directory_fields.value:
self.parentApp.scan_directory = self.autoload_directory.value
self.parentApp.autoscan_on_startup = self.autoscan_on_startup.value
selections.scan_directory = self.autoload_directory.value
selections.autoscan_on_startup = self.autoscan_on_startup.value
else:
self.parentApp.scan_directory = None
self.parentApp.autoscan_on_startup = False
selections.scan_directory = None
selections.autoscan_on_startup = False
# URLs and the like
self.parentApp.import_model_paths = self.import_model_paths.value.split()
self.parentApp.convert_to_diffusers = self.convert_models.value[0] == 1
# big chunk of dead code
# was intended to be a status area in which output of installation steps (including tqdm) was logged in real time.
# Not used at the current time but retained for possible future implementation.
# class Log(object):
# def __init__(self, writable):
# self.writable = writable
# def __enter__(self):
# self._stdout = sys.stdout
# sys.stdout = self.writable
# return self
# def __exit__(self, *args):
# sys.stdout = self._stdout
# class outputForm(npyscreen.ActionForm):
# def create(self):
# self.done = False
# self.buffer = self.add_widget(
# npyscreen.BufferPager,
# editable=False,
# )
# def write(self,string):
# if string != '\n':
# self.buffer.buffer([string])
# def beforeEditing(self):
# if self.done:
# return
# installApp = self.parentApp
# with Log(self):
# models_to_remove = [x for x in installApp.starter_models if not installApp.starter_models[x]]
# models_to_install = [x for x in installApp.starter_models if installApp.starter_models[x]]
# directory_to_scan = installApp.scan_directory
# scan_at_startup = installApp.autoscan_on_startup
# potential_models_to_install = installApp.import_model_paths
# convert_to_diffusers = installApp.convert_to_diffusers
# print(f'these models will be removed: {models_to_remove}')
# print(f'these models will be installed: {models_to_install}')
# print(f'this directory will be scanned: {directory_to_scan}')
# print(f'these things will be downloaded: {potential_models_to_install}')
# print(f'scan at startup time? {scan_at_startup}')
# print(f'convert to diffusers? {convert_to_diffusers}')
# print(f'\nPress OK to proceed or Cancel.')
# def on_cancel(self):
# self.buffer.buffer(['goodbye!'])
# self.parentApp.setNextForm(None)
# self.editing = False
# def on_ok(self):
# if self.done:
# self.on_cancel()
# return
# installApp = self.parentApp
# with Log(self):
# models_to_remove = [x for x in installApp.starter_models if not installApp.starter_models[x]]
# models_to_install = [x for x in installApp.starter_models if installApp.starter_models[x]]
# directory_to_scan = installApp.scan_directory
# scan_at_startup = installApp.autoscan_on_startup
# potential_models_to_install = installApp.import_model_paths
# convert_to_diffusers = installApp.convert_to_diffusers
# install_requested_models(
# install_initial_models = models_to_install,
# remove_models = models_to_remove,
# scan_directory = Path(directory_to_scan) if directory_to_scan else None,
# external_models = potential_models_to_install,
# scan_at_startup = scan_at_startup,
# convert_to_diffusers = convert_to_diffusers,
# precision = 'float32' if installApp.opt.full_precision else choose_precision(torch.device(choose_torch_device())),
# config_file_path = Path(installApp.opt.config_file) if installApp.opt.config_file else None,
# )
# self.done = True
selections.import_model_paths = self.import_model_paths.value.split()
selections.convert_to_diffusers = self.convert_models.value[0] == 1
class AddModelApplication(npyscreen.NPSAppManaged):
def __init__(self, saved_args=None):
def __init__(self):
super().__init__()
self.user_cancelled = False
self.models_to_install = None
self.user_selections = Namespace(
starter_models = None,
purge_deleted_models = False,
scan_directory = None,
autoscan_on_startup = None,
import_model_paths = None,
convert_to_diffusers = None
)
def onStart(self):
npyscreen.setTheme(npyscreen.Themes.DefaultTheme)
self.main = self.addForm(
self.main_form = self.addForm(
"MAIN",
addModelsForm,
name="Add/Remove Models",
)
# self.output = self.addForm(
# 'MONITOR_OUTPUT',
# outputForm,
# name='Model Install Output'
# )
# --------------------------------------------------------
def process_and_execute(app: npyscreen.NPSAppManaged):
models_to_remove = [x for x in app.starter_models if not app.starter_models[x]]
models_to_install = [x for x in app.starter_models if app.starter_models[x]]
directory_to_scan = app.scan_directory
scan_at_startup = app.autoscan_on_startup
potential_models_to_install = app.import_model_paths
convert_to_diffusers = app.convert_to_diffusers
def process_and_execute(opt: Namespace, selections: Namespace):
models_to_remove = [x for x in selections.starter_models if not selections.starter_models[x]]
models_to_install = [x for x in selections.starter_models if selections.starter_models[x]]
directory_to_scan = selections.scan_directory
scan_at_startup = selections.autoscan_on_startup
potential_models_to_install = selections.import_model_paths
convert_to_diffusers = selections.convert_to_diffusers
install_requested_models(
install_initial_models = models_to_install,
remove_models = models_to_remove,
@ -356,9 +289,9 @@ def process_and_execute(app: npyscreen.NPSAppManaged):
external_models = potential_models_to_install,
scan_at_startup = scan_at_startup,
convert_to_diffusers = convert_to_diffusers,
precision = 'float32' if app.opt.full_precision else choose_precision(torch.device(choose_torch_device())),
purge_deleted = app.purge_deleted_models,
config_file_path = Path(app.opt.config_file) if app.opt.config_file else None,
precision = 'float32' if opt.full_precision else choose_precision(torch.device(choose_torch_device())),
purge_deleted = selections.purge_deleted_models,
config_file_path = Path(opt.config_file) if opt.config_file else None,
)
# --------------------------------------------------------
@ -371,9 +304,10 @@ def select_and_download_models(opt: Namespace):
)
else:
installApp = AddModelApplication()
installApp.opt = opt
installApp.run()
process_and_execute(installApp)
if not installApp.user_cancelled:
process_and_execute(opt, installApp.user_selections)
# -------------------------------------
def main():