mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into patch-1
This commit is contained in:
commit
719a5de506
2
.github/workflows/build-container.yml
vendored
2
.github/workflows/build-container.yml
vendored
@ -47,7 +47,7 @@ jobs:
|
|||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=semver,pattern={{major}}
|
type=semver,pattern={{major}}
|
||||||
type=raw,value='sha'-{{sha}}-${{ matrix.flavor}}
|
type=sha,enable=true,prefix=sha-,suffix=${{ matrix.flavor}},format=short
|
||||||
type=raw,value={{branch}}-${{ matrix.flavor }}
|
type=raw,value={{branch}}-${{ matrix.flavor }}
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=${{ matrix.flavor == 'cuda' && github.ref == 'refs/heads/main' }}
|
latest=${{ matrix.flavor == 'cuda' && github.ref == 'refs/heads/main' }}
|
||||||
|
@ -1,28 +1,20 @@
|
|||||||
# Stable Diffusion Web UI
|
# InvokeAI UI dev setup
|
||||||
|
|
||||||
## Run
|
The UI is in `invokeai/frontend`.
|
||||||
|
|
||||||
- `python scripts/dream.py --web` serves both frontend and backend at
|
## Environment set up
|
||||||
http://localhost:9090
|
|
||||||
|
|
||||||
## Evironment
|
Install [node](https://nodejs.org/en/download/) (includes npm) and
|
||||||
|
|
||||||
Install [node](https://nodejs.org/en/download/) (includes npm) and optionally
|
|
||||||
[yarn](https://yarnpkg.com/getting-started/install).
|
[yarn](https://yarnpkg.com/getting-started/install).
|
||||||
|
|
||||||
From `frontend/` run `npm install` / `yarn install` to install the frontend
|
From `invokeai/frontend/` run `yarn install` to get everything set up.
|
||||||
packages.
|
|
||||||
|
|
||||||
## Dev
|
## Dev
|
||||||
|
|
||||||
1. From `frontend/`, run `npm dev` / `yarn dev` to start the dev server.
|
1. Start the dev server: `yarn dev`
|
||||||
2. Run `python scripts/dream.py --web`.
|
2. Start the InvokeAI UI per usual: `invokeai --web`
|
||||||
3. Navigate to the dev server address e.g. `http://localhost:5173/`.
|
3. Point your browser to the dev server address e.g. `http://localhost:5173/`
|
||||||
|
|
||||||
To build for dev: `npm build-dev` / `yarn build-dev`
|
To build for dev: `yarn build-dev`
|
||||||
|
|
||||||
To build for production: `npm build` / `yarn build`
|
To build for production: `yarn build`
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- Search repo for "TODO"
|
|
@ -15,20 +15,18 @@ from pathlib import Path
|
|||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
|
|
||||||
import npyscreen
|
import npyscreen
|
||||||
from diffusers import DiffusionPipeline, logging as dlogging
|
from diffusers import DiffusionPipeline
|
||||||
|
from diffusers import logging as dlogging
|
||||||
|
from npyscreen import widget
|
||||||
from omegaconf import OmegaConf
|
from omegaconf import OmegaConf
|
||||||
|
|
||||||
from ldm.invoke.globals import (
|
from ldm.invoke.globals import (Globals, global_cache_dir, global_config_file,
|
||||||
Globals,
|
global_models_dir, global_set_root)
|
||||||
global_cache_dir,
|
|
||||||
global_config_file,
|
|
||||||
global_models_dir,
|
|
||||||
global_set_root,
|
|
||||||
)
|
|
||||||
from ldm.invoke.model_manager import ModelManager
|
from ldm.invoke.model_manager import ModelManager
|
||||||
|
|
||||||
DEST_MERGED_MODEL_DIR = "merged_models"
|
DEST_MERGED_MODEL_DIR = "merged_models"
|
||||||
|
|
||||||
|
|
||||||
def merge_diffusion_models(
|
def merge_diffusion_models(
|
||||||
model_ids_or_paths: List[Union[str, Path]],
|
model_ids_or_paths: List[Union[str, Path]],
|
||||||
alpha: float = 0.5,
|
alpha: float = 0.5,
|
||||||
@ -48,7 +46,7 @@ def merge_diffusion_models(
|
|||||||
cache_dir, resume_download, force_download, proxies, local_files_only, use_auth_token, revision, torch_dtype, device_map
|
cache_dir, resume_download, force_download, proxies, local_files_only, use_auth_token, revision, torch_dtype, device_map
|
||||||
"""
|
"""
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.simplefilter('ignore')
|
warnings.simplefilter("ignore")
|
||||||
verbosity = dlogging.get_verbosity()
|
verbosity = dlogging.get_verbosity()
|
||||||
dlogging.set_verbosity_error()
|
dlogging.set_verbosity_error()
|
||||||
|
|
||||||
@ -188,7 +186,6 @@ class FloatTitleSlider(npyscreen.TitleText):
|
|||||||
|
|
||||||
|
|
||||||
class mergeModelsForm(npyscreen.FormMultiPageAction):
|
class mergeModelsForm(npyscreen.FormMultiPageAction):
|
||||||
|
|
||||||
interpolations = ["weighted_sum", "sigmoid", "inv_sigmoid", "add_difference"]
|
interpolations = ["weighted_sum", "sigmoid", "inv_sigmoid", "add_difference"]
|
||||||
|
|
||||||
def __init__(self, parentApp, name):
|
def __init__(self, parentApp, name):
|
||||||
@ -214,20 +211,20 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
|
|
||||||
self.add_widget_intelligent(
|
self.add_widget_intelligent(
|
||||||
npyscreen.FixedText,
|
npyscreen.FixedText,
|
||||||
color='CONTROL',
|
color="CONTROL",
|
||||||
value=f"Select two models to merge and optionally a third.",
|
value=f"Select two models to merge and optionally a third.",
|
||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
self.add_widget_intelligent(
|
self.add_widget_intelligent(
|
||||||
npyscreen.FixedText,
|
npyscreen.FixedText,
|
||||||
color='CONTROL',
|
color="CONTROL",
|
||||||
value=f"Use up and down arrows to move, <space> to select an item, <tab> and <shift-tab> to move from one field to the next.",
|
value=f"Use up and down arrows to move, <space> to select an item, <tab> and <shift-tab> to move from one field to the next.",
|
||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
self.add_widget_intelligent(
|
self.add_widget_intelligent(
|
||||||
npyscreen.FixedText,
|
npyscreen.FixedText,
|
||||||
value='MODEL 1',
|
value="MODEL 1",
|
||||||
color='GOOD',
|
color="GOOD",
|
||||||
editable=False,
|
editable=False,
|
||||||
rely=4 if horizontal_layout else None,
|
rely=4 if horizontal_layout else None,
|
||||||
)
|
)
|
||||||
@ -242,15 +239,15 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
)
|
)
|
||||||
self.add_widget_intelligent(
|
self.add_widget_intelligent(
|
||||||
npyscreen.FixedText,
|
npyscreen.FixedText,
|
||||||
value='MODEL 2',
|
value="MODEL 2",
|
||||||
color='GOOD',
|
color="GOOD",
|
||||||
editable=False,
|
editable=False,
|
||||||
relx=max_width + 3 if horizontal_layout else None,
|
relx=max_width + 3 if horizontal_layout else None,
|
||||||
rely=4 if horizontal_layout else None,
|
rely=4 if horizontal_layout else None,
|
||||||
)
|
)
|
||||||
self.model2 = self.add_widget_intelligent(
|
self.model2 = self.add_widget_intelligent(
|
||||||
npyscreen.SelectOne,
|
npyscreen.SelectOne,
|
||||||
name='(2)',
|
name="(2)",
|
||||||
values=self.model_names,
|
values=self.model_names,
|
||||||
value=1,
|
value=1,
|
||||||
max_height=len(self.model_names),
|
max_height=len(self.model_names),
|
||||||
@ -261,17 +258,17 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
)
|
)
|
||||||
self.add_widget_intelligent(
|
self.add_widget_intelligent(
|
||||||
npyscreen.FixedText,
|
npyscreen.FixedText,
|
||||||
value='MODEL 3',
|
value="MODEL 3",
|
||||||
color='GOOD',
|
color="GOOD",
|
||||||
editable=False,
|
editable=False,
|
||||||
relx=max_width * 2 + 3 if horizontal_layout else None,
|
relx=max_width * 2 + 3 if horizontal_layout else None,
|
||||||
rely=4 if horizontal_layout else None,
|
rely=4 if horizontal_layout else None,
|
||||||
)
|
)
|
||||||
models_plus_none = self.model_names.copy()
|
models_plus_none = self.model_names.copy()
|
||||||
models_plus_none.insert(0,'None')
|
models_plus_none.insert(0, "None")
|
||||||
self.model3 = self.add_widget_intelligent(
|
self.model3 = self.add_widget_intelligent(
|
||||||
npyscreen.SelectOne,
|
npyscreen.SelectOne,
|
||||||
name='(3)',
|
name="(3)",
|
||||||
values=models_plus_none,
|
values=models_plus_none,
|
||||||
value=0,
|
value=0,
|
||||||
max_height=len(self.model_names) + 1,
|
max_height=len(self.model_names) + 1,
|
||||||
@ -285,14 +282,14 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
self.merged_model_name = self.add_widget_intelligent(
|
self.merged_model_name = self.add_widget_intelligent(
|
||||||
npyscreen.TitleText,
|
npyscreen.TitleText,
|
||||||
name="Name for merged model:",
|
name="Name for merged model:",
|
||||||
labelColor='CONTROL',
|
labelColor="CONTROL",
|
||||||
value="",
|
value="",
|
||||||
scroll_exit=True,
|
scroll_exit=True,
|
||||||
)
|
)
|
||||||
self.force = self.add_widget_intelligent(
|
self.force = self.add_widget_intelligent(
|
||||||
npyscreen.Checkbox,
|
npyscreen.Checkbox,
|
||||||
name="Force merge of incompatible models",
|
name="Force merge of incompatible models",
|
||||||
labelColor='CONTROL',
|
labelColor="CONTROL",
|
||||||
value=False,
|
value=False,
|
||||||
scroll_exit=True,
|
scroll_exit=True,
|
||||||
)
|
)
|
||||||
@ -301,7 +298,7 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
name="Merge Method:",
|
name="Merge Method:",
|
||||||
values=self.interpolations,
|
values=self.interpolations,
|
||||||
value=0,
|
value=0,
|
||||||
labelColor='CONTROL',
|
labelColor="CONTROL",
|
||||||
max_height=len(self.interpolations) + 1,
|
max_height=len(self.interpolations) + 1,
|
||||||
scroll_exit=True,
|
scroll_exit=True,
|
||||||
)
|
)
|
||||||
@ -312,7 +309,7 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
step=0.05,
|
step=0.05,
|
||||||
lowest=0,
|
lowest=0,
|
||||||
value=0.5,
|
value=0.5,
|
||||||
labelColor='CONTROL',
|
labelColor="CONTROL",
|
||||||
scroll_exit=True,
|
scroll_exit=True,
|
||||||
)
|
)
|
||||||
self.model1.editing = True
|
self.model1.editing = True
|
||||||
@ -322,12 +319,12 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
selected_model1 = self.model1.value[0]
|
selected_model1 = self.model1.value[0]
|
||||||
selected_model2 = self.model2.value[0]
|
selected_model2 = self.model2.value[0]
|
||||||
selected_model3 = self.model3.value[0]
|
selected_model3 = self.model3.value[0]
|
||||||
merged_model_name = f'{models[selected_model1]}+{models[selected_model2]}'
|
merged_model_name = f"{models[selected_model1]}+{models[selected_model2]}"
|
||||||
self.merged_model_name.value = merged_model_name
|
self.merged_model_name.value = merged_model_name
|
||||||
|
|
||||||
if selected_model3 > 0:
|
if selected_model3 > 0:
|
||||||
self.merge_method.values=['add_difference'],
|
self.merge_method.values = (["add_difference"],)
|
||||||
self.merged_model_name.value += f'+{models[selected_model3]}'
|
self.merged_model_name.value += f"+{models[selected_model3]}"
|
||||||
else:
|
else:
|
||||||
self.merge_method.values = self.interpolations
|
self.merge_method.values = self.interpolations
|
||||||
self.merge_method.value = 0
|
self.merge_method.value = 0
|
||||||
@ -337,7 +334,7 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
self.parentApp.setNextForm(None)
|
self.parentApp.setNextForm(None)
|
||||||
self.editing = False
|
self.editing = False
|
||||||
self.parentApp.merge_arguments = self.marshall_arguments()
|
self.parentApp.merge_arguments = self.marshall_arguments()
|
||||||
npyscreen.notify('Starting the merge...')
|
npyscreen.notify("Starting the merge...")
|
||||||
else:
|
else:
|
||||||
self.editing = True
|
self.editing = True
|
||||||
|
|
||||||
@ -374,15 +371,19 @@ class mergeModelsForm(npyscreen.FormMultiPageAction):
|
|||||||
def validate_field_values(self) -> bool:
|
def validate_field_values(self) -> bool:
|
||||||
bad_fields = []
|
bad_fields = []
|
||||||
model_names = self.model_names
|
model_names = self.model_names
|
||||||
selected_models = set((model_names[self.model1.value[0]],model_names[self.model2.value[0]]))
|
selected_models = set(
|
||||||
|
(model_names[self.model1.value[0]], model_names[self.model2.value[0]])
|
||||||
|
)
|
||||||
if self.model3.value[0] > 0:
|
if self.model3.value[0] > 0:
|
||||||
selected_models.add(model_names[self.model3.value[0] - 1])
|
selected_models.add(model_names[self.model3.value[0] - 1])
|
||||||
if len(selected_models) < 2:
|
if len(selected_models) < 2:
|
||||||
bad_fields.append(f'Please select two or three DIFFERENT models to compare. You selected {selected_models}')
|
bad_fields.append(
|
||||||
|
f"Please select two or three DIFFERENT models to compare. You selected {selected_models}"
|
||||||
|
)
|
||||||
if len(bad_fields) > 0:
|
if len(bad_fields) > 0:
|
||||||
message = 'The following problems were detected and must be corrected:'
|
message = "The following problems were detected and must be corrected:"
|
||||||
for problem in bad_fields:
|
for problem in bad_fields:
|
||||||
message += f'\n* {problem}'
|
message += f"\n* {problem}"
|
||||||
npyscreen.notify_confirm(message)
|
npyscreen.notify_confirm(message)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
@ -410,6 +411,7 @@ class Mergeapp(npyscreen.NPSAppManaged):
|
|||||||
npyscreen.setTheme(npyscreen.Themes.ElegantTheme)
|
npyscreen.setTheme(npyscreen.Themes.ElegantTheme)
|
||||||
self.main = self.addForm("MAIN", mergeModelsForm, name="Merge Models Settings")
|
self.main = self.addForm("MAIN", mergeModelsForm, name="Merge Models Settings")
|
||||||
|
|
||||||
|
|
||||||
def run_gui(args: Namespace):
|
def run_gui(args: Namespace):
|
||||||
mergeapp = Mergeapp()
|
mergeapp = Mergeapp()
|
||||||
mergeapp.run()
|
mergeapp.run()
|
||||||
@ -450,5 +452,27 @@ def main():
|
|||||||
] = cache_dir # because not clear the merge pipeline is honoring cache_dir
|
] = cache_dir # because not clear the merge pipeline is honoring cache_dir
|
||||||
args.cache_dir = cache_dir
|
args.cache_dir = cache_dir
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.front_end:
|
||||||
|
run_gui(args)
|
||||||
|
else:
|
||||||
|
run_cli(args)
|
||||||
|
print(f">> Conversion successful. New model is named {args.merged_model_name}")
|
||||||
|
except widget.NotEnoughSpaceForWidget as e:
|
||||||
|
if str(e).startswith("Height of 1 allocated"):
|
||||||
|
print(
|
||||||
|
"** You need to have at least two diffusers models defined in models.yaml in order to merge"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(f"** A layout error has occurred: {str(e)}")
|
||||||
|
sys.exit(-1)
|
||||||
|
except Exception as e:
|
||||||
|
print(">> An error occurred:")
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(-1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -17,6 +17,7 @@ from pathlib import Path
|
|||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
import npyscreen
|
import npyscreen
|
||||||
|
from npyscreen import widget
|
||||||
from omegaconf import OmegaConf
|
from omegaconf import OmegaConf
|
||||||
|
|
||||||
from ldm.invoke.globals import Globals, global_set_root
|
from ldm.invoke.globals import Globals, global_set_root
|
||||||
@ -438,11 +439,20 @@ def main():
|
|||||||
do_front_end(args)
|
do_front_end(args)
|
||||||
else:
|
else:
|
||||||
do_textual_inversion_training(**vars(args))
|
do_textual_inversion_training(**vars(args))
|
||||||
|
except widget.NotEnoughSpaceForWidget as e:
|
||||||
|
if str(e).startswith("Height of 1 allocated"):
|
||||||
|
print(
|
||||||
|
"** You need to have at least one diffusers models defined in models.yaml in order to train"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(f"** A layout error has occurred: {str(e)}")
|
||||||
|
sys.exit(-1)
|
||||||
except AssertionError as e:
|
except AssertionError as e:
|
||||||
print(str(e))
|
print(str(e))
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
import requests as request
|
import requests
|
||||||
|
|
||||||
import ldm.invoke._version as version
|
from ldm.invoke import __app_name__, __version__
|
||||||
|
|
||||||
local_version = str(version.__version__)
|
local_version = str(__version__).replace("-", "")
|
||||||
|
package_name = str(__app_name__)
|
||||||
|
|
||||||
|
|
||||||
def get_pypi_versions(package_name="InvokeAI") -> list[str]:
|
def get_pypi_versions(package_name=package_name) -> list[str]:
|
||||||
"""Get the versions of the package from PyPI"""
|
"""Get the versions of the package from PyPI"""
|
||||||
url = f"https://pypi.org/pypi/{package_name}/json"
|
url = f"https://pypi.org/pypi/{package_name}/json"
|
||||||
response = request.get(url).json()
|
response = requests.get(url).json()
|
||||||
versions: list[str] = list(response["releases"].keys())
|
versions: list[str] = list(response["releases"].keys())
|
||||||
return versions
|
return versions
|
||||||
|
|
||||||
|
|
||||||
def local_on_pypi(package_name="InvokeAI", local_version=local_version) -> bool:
|
def local_on_pypi(package_name=package_name, local_version=local_version) -> bool:
|
||||||
"""Compare the versions of the package from PyPI and the local package"""
|
"""Compare the versions of the package from PyPI and the local package"""
|
||||||
pypi_versions = get_pypi_versions(package_name)
|
pypi_versions = get_pypi_versions(package_name)
|
||||||
return local_version in pypi_versions
|
return local_version in pypi_versions
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
package_name = "InvokeAI"
|
|
||||||
if local_on_pypi():
|
if local_on_pypi():
|
||||||
print(f"Package {package_name} is up to date")
|
print(f"Package {package_name} is up to date")
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user