mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into bugfix/convert-v2-models
This commit is contained in:
commit
159ce2ea08
9
.github/workflows/build-container.yml
vendored
9
.github/workflows/build-container.yml
vendored
@ -5,8 +5,17 @@ on:
|
|||||||
- 'main'
|
- 'main'
|
||||||
- 'update/ci/docker/*'
|
- 'update/ci/docker/*'
|
||||||
- 'update/docker/*'
|
- 'update/docker/*'
|
||||||
|
paths:
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- 'ldm/**'
|
||||||
|
- 'invokeai/backend/**'
|
||||||
|
- 'invokeai/configs/**'
|
||||||
|
- 'invokeai/frontend/dist/**'
|
||||||
|
- 'docker/Dockerfile'
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v*.*.*'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
|
67
.github/workflows/test-invoke-pip-skip.yml
vendored
Normal file
67
.github/workflows/test-invoke-pip-skip.yml
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
name: Test invoke.py pip
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- 'ldm/**'
|
||||||
|
- 'invokeai/backend/**'
|
||||||
|
- 'invokeai/configs/**'
|
||||||
|
- 'invokeai/frontend/dist/**'
|
||||||
|
merge_group:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
matrix:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version:
|
||||||
|
# - '3.9'
|
||||||
|
- '3.10'
|
||||||
|
pytorch:
|
||||||
|
# - linux-cuda-11_6
|
||||||
|
- linux-cuda-11_7
|
||||||
|
- linux-rocm-5_2
|
||||||
|
- linux-cpu
|
||||||
|
- macos-default
|
||||||
|
- windows-cpu
|
||||||
|
# - windows-cuda-11_6
|
||||||
|
# - windows-cuda-11_7
|
||||||
|
include:
|
||||||
|
# - pytorch: linux-cuda-11_6
|
||||||
|
# os: ubuntu-22.04
|
||||||
|
# extra-index-url: 'https://download.pytorch.org/whl/cu116'
|
||||||
|
# github-env: $GITHUB_ENV
|
||||||
|
- pytorch: linux-cuda-11_7
|
||||||
|
os: ubuntu-22.04
|
||||||
|
github-env: $GITHUB_ENV
|
||||||
|
- pytorch: linux-rocm-5_2
|
||||||
|
os: ubuntu-22.04
|
||||||
|
extra-index-url: 'https://download.pytorch.org/whl/rocm5.2'
|
||||||
|
github-env: $GITHUB_ENV
|
||||||
|
- pytorch: linux-cpu
|
||||||
|
os: ubuntu-22.04
|
||||||
|
extra-index-url: 'https://download.pytorch.org/whl/cpu'
|
||||||
|
github-env: $GITHUB_ENV
|
||||||
|
- pytorch: macos-default
|
||||||
|
os: macOS-12
|
||||||
|
github-env: $GITHUB_ENV
|
||||||
|
- pytorch: windows-cpu
|
||||||
|
os: windows-2022
|
||||||
|
github-env: $env:GITHUB_ENV
|
||||||
|
# - pytorch: windows-cuda-11_6
|
||||||
|
# os: windows-2022
|
||||||
|
# extra-index-url: 'https://download.pytorch.org/whl/cu116'
|
||||||
|
# github-env: $env:GITHUB_ENV
|
||||||
|
# - pytorch: windows-cuda-11_7
|
||||||
|
# os: windows-2022
|
||||||
|
# extra-index-url: 'https://download.pytorch.org/whl/cu117'
|
||||||
|
# github-env: $env:GITHUB_ENV
|
||||||
|
name: ${{ matrix.pytorch }} on ${{ matrix.python-version }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- run: 'echo "No build required"'
|
12
.github/workflows/test-invoke-pip.yml
vendored
12
.github/workflows/test-invoke-pip.yml
vendored
@ -3,7 +3,19 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'main'
|
- 'main'
|
||||||
|
paths:
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- 'ldm/**'
|
||||||
|
- 'invokeai/backend/**'
|
||||||
|
- 'invokeai/configs/**'
|
||||||
|
- 'invokeai/frontend/dist/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- 'ldm/**'
|
||||||
|
- 'invokeai/backend/**'
|
||||||
|
- 'invokeai/configs/**'
|
||||||
|
- 'invokeai/frontend/dist/**'
|
||||||
types:
|
types:
|
||||||
- 'ready_for_review'
|
- 'ready_for_review'
|
||||||
- 'opened'
|
- 'opened'
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
[![github open issues badge]][github open issues link] [![github open prs badge]][github open prs link]
|
[![github open issues badge]][github open issues link] [![github open prs badge]][github open prs link]
|
||||||
|
|
||||||
[CI checks on main badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github
|
[CI checks on main badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github
|
||||||
[CI checks on main link]: https://github.com/invoke-ai/InvokeAI/actions/workflows/test-invoke-conda.yml
|
[CI checks on main link]:https://github.com/invoke-ai/InvokeAI/actions?query=branch%3Amain
|
||||||
[discord badge]: https://flat.badgen.net/discord/members/ZmtBAhwWhy?icon=discord
|
[discord badge]: https://flat.badgen.net/discord/members/ZmtBAhwWhy?icon=discord
|
||||||
[discord link]: https://discord.gg/ZmtBAhwWhy
|
[discord link]: https://discord.gg/ZmtBAhwWhy
|
||||||
[github forks badge]: https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github
|
[github forks badge]: https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github
|
||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
InvokeAI is a leading creative engine built to empower professionals and enthusiasts alike. Generate and create stunning visual media using the latest AI-driven technologies. InvokeAI offers an industry leading Web Interface, interactive Command Line Interface, and also serves as the foundation for multiple commercial products.
|
InvokeAI is a leading creative engine built to empower professionals and enthusiasts alike. Generate and create stunning visual media using the latest AI-driven technologies. InvokeAI offers an industry leading Web Interface, interactive Command Line Interface, and also serves as the foundation for multiple commercial products.
|
||||||
|
|
||||||
**Quick links**: [[How to Install](#installation)] [<a href="https://discord.gg/ZmtBAhwWhy">Discord Server</a>] [<a href="https://invoke-ai.github.io/InvokeAI/">Documentation and Tutorials</a>] [<a href="https://github.com/invoke-ai/InvokeAI/">Code and Downloads</a>] [<a href="https://github.com/invoke-ai/InvokeAI/issues">Bug Reports</a>] [<a href="https://github.com/invoke-ai/InvokeAI/discussions">Discussion, Ideas & Q&A</a>]
|
**Quick links**: [[How to Install](https://invoke-ai.github.io/InvokeAI/#installation)] [<a href="https://discord.gg/ZmtBAhwWhy">Discord Server</a>] [<a href="https://invoke-ai.github.io/InvokeAI/">Documentation and Tutorials</a>] [<a href="https://github.com/invoke-ai/InvokeAI/">Code and Downloads</a>] [<a href="https://github.com/invoke-ai/InvokeAI/issues">Bug Reports</a>] [<a href="https://github.com/invoke-ai/InvokeAI/discussions">Discussion, Ideas & Q&A</a>]
|
||||||
|
|
||||||
_Note: InvokeAI is rapidly evolving. Please use the
|
_Note: InvokeAI is rapidly evolving. Please use the
|
||||||
[Issues](https://github.com/invoke-ai/InvokeAI/issues) tab to report bugs and make feature
|
[Issues](https://github.com/invoke-ai/InvokeAI/issues) tab to report bugs and make feature
|
||||||
|
@ -147,7 +147,7 @@ echo ***** Installed invoke launcher script ******
|
|||||||
rd /s /q binary_installer installer_files
|
rd /s /q binary_installer installer_files
|
||||||
|
|
||||||
@rem preload the models
|
@rem preload the models
|
||||||
call .venv\Scripts\python scripts\configure_invokeai.py
|
call .venv\Scripts\python ldm\invoke\config\invokeai_configure.py
|
||||||
set err_msg=----- model download clone failed -----
|
set err_msg=----- model download clone failed -----
|
||||||
if %errorlevel% neq 0 goto err_exit
|
if %errorlevel% neq 0 goto err_exit
|
||||||
deactivate
|
deactivate
|
||||||
|
@ -12,7 +12,7 @@ LABEL org.opencontainers.image.authors="mauwii@outlook.de"
|
|||||||
RUN rm -f /etc/apt/apt.conf.d/docker-clean \
|
RUN rm -f /etc/apt/apt.conf.d/docker-clean \
|
||||||
&& echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache
|
&& echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache
|
||||||
|
|
||||||
# Install necesarry packages
|
# Install necessary packages
|
||||||
RUN \
|
RUN \
|
||||||
--mount=type=cache,target=/var/cache/apt,sharing=locked \
|
--mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||||
@ -78,7 +78,7 @@ RUN python3 -c "from patchmatch import patch_match"
|
|||||||
#####################
|
#####################
|
||||||
FROM python-base AS runtime
|
FROM python-base AS runtime
|
||||||
|
|
||||||
# Create a new User
|
# Create a new user
|
||||||
ARG UNAME=appuser
|
ARG UNAME=appuser
|
||||||
RUN useradd \
|
RUN useradd \
|
||||||
--no-log-init \
|
--no-log-init \
|
||||||
|
@ -36,7 +36,7 @@ echo -e "Container Image:\t${CONTAINER_IMAGE}\n"
|
|||||||
if [[ -n "$(docker volume ls -f name="${VOLUMENAME}" -q)" ]]; then
|
if [[ -n "$(docker volume ls -f name="${VOLUMENAME}" -q)" ]]; then
|
||||||
echo -e "Volume already exists\n"
|
echo -e "Volume already exists\n"
|
||||||
else
|
else
|
||||||
echo -n "createing docker volume "
|
echo -n "creating docker volume "
|
||||||
docker volume create "${VOLUMENAME}"
|
docker volume create "${VOLUMENAME}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ from ldm.invoke.args import Args, APP_ID, APP_VERSION, calculate_init_img_hash
|
|||||||
from ldm.invoke.conditioning import get_tokens_for_prompt, get_prompt_structure
|
from ldm.invoke.conditioning import get_tokens_for_prompt, get_prompt_structure
|
||||||
from ldm.invoke.generator.diffusers_pipeline import PipelineIntermediateState
|
from ldm.invoke.generator.diffusers_pipeline import PipelineIntermediateState
|
||||||
from ldm.invoke.generator.inpaint import infill_methods
|
from ldm.invoke.generator.inpaint import infill_methods
|
||||||
from ldm.invoke.globals import Globals
|
from ldm.invoke.globals import Globals, global_converted_ckpts_dir
|
||||||
from ldm.invoke.pngwriter import PngWriter, retrieve_metadata
|
from ldm.invoke.pngwriter import PngWriter, retrieve_metadata
|
||||||
from ldm.invoke.prompt_parser import split_weighted_subprompts, Blend
|
from ldm.invoke.prompt_parser import split_weighted_subprompts, Blend
|
||||||
|
|
||||||
@ -43,7 +43,8 @@ if not os.path.isabs(args.outdir):
|
|||||||
|
|
||||||
# normalize the config directory relative to root
|
# normalize the config directory relative to root
|
||||||
if not os.path.isabs(opt.conf):
|
if not os.path.isabs(opt.conf):
|
||||||
opt.conf = os.path.normpath(os.path.join(Globals.root,opt.conf))
|
opt.conf = os.path.normpath(os.path.join(Globals.root, opt.conf))
|
||||||
|
|
||||||
|
|
||||||
class InvokeAIWebServer:
|
class InvokeAIWebServer:
|
||||||
def __init__(self, generate: Generate, gfpgan, codeformer, esrgan) -> None:
|
def __init__(self, generate: Generate, gfpgan, codeformer, esrgan) -> None:
|
||||||
@ -189,7 +190,8 @@ class InvokeAIWebServer:
|
|||||||
(width, height) = pil_image.size
|
(width, height) = pil_image.size
|
||||||
|
|
||||||
thumbnail_path = save_thumbnail(
|
thumbnail_path = save_thumbnail(
|
||||||
pil_image, os.path.basename(file_path), self.thumbnail_image_path
|
pil_image, os.path.basename(
|
||||||
|
file_path), self.thumbnail_image_path
|
||||||
)
|
)
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
@ -264,14 +266,16 @@ class InvokeAIWebServer:
|
|||||||
# location for "finished" images
|
# location for "finished" images
|
||||||
self.result_path = args.outdir
|
self.result_path = args.outdir
|
||||||
# temporary path for intermediates
|
# temporary path for intermediates
|
||||||
self.intermediate_path = os.path.join(self.result_path, "intermediates/")
|
self.intermediate_path = os.path.join(
|
||||||
|
self.result_path, "intermediates/")
|
||||||
# path for user-uploaded init images and masks
|
# path for user-uploaded init images and masks
|
||||||
self.init_image_path = os.path.join(self.result_path, "init-images/")
|
self.init_image_path = os.path.join(self.result_path, "init-images/")
|
||||||
self.mask_image_path = os.path.join(self.result_path, "mask-images/")
|
self.mask_image_path = os.path.join(self.result_path, "mask-images/")
|
||||||
# path for temp images e.g. gallery generations which are not committed
|
# path for temp images e.g. gallery generations which are not committed
|
||||||
self.temp_image_path = os.path.join(self.result_path, "temp-images/")
|
self.temp_image_path = os.path.join(self.result_path, "temp-images/")
|
||||||
# path for thumbnail images
|
# path for thumbnail images
|
||||||
self.thumbnail_image_path = os.path.join(self.result_path, "thumbnails/")
|
self.thumbnail_image_path = os.path.join(
|
||||||
|
self.result_path, "thumbnails/")
|
||||||
# txt log
|
# txt log
|
||||||
self.log_path = os.path.join(self.result_path, "invoke_log.txt")
|
self.log_path = os.path.join(self.result_path, "invoke_log.txt")
|
||||||
# make all output paths
|
# make all output paths
|
||||||
@ -290,7 +294,7 @@ class InvokeAIWebServer:
|
|||||||
def load_socketio_listeners(self, socketio):
|
def load_socketio_listeners(self, socketio):
|
||||||
@socketio.on("requestSystemConfig")
|
@socketio.on("requestSystemConfig")
|
||||||
def handle_request_capabilities():
|
def handle_request_capabilities():
|
||||||
print(f">> System config requested")
|
print(">> System config requested")
|
||||||
config = self.get_system_config()
|
config = self.get_system_config()
|
||||||
config["model_list"] = self.generate.model_manager.list_models()
|
config["model_list"] = self.generate.model_manager.list_models()
|
||||||
config["infill_methods"] = infill_methods()
|
config["infill_methods"] = infill_methods()
|
||||||
@ -301,14 +305,16 @@ class InvokeAIWebServer:
|
|||||||
try:
|
try:
|
||||||
if not search_folder:
|
if not search_folder:
|
||||||
socketio.emit(
|
socketio.emit(
|
||||||
"foundModels",
|
"foundModels",
|
||||||
{'search_folder': None, 'found_models': None},
|
{'search_folder': None, 'found_models': None},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
search_folder, found_models = self.generate.model_manager.search_models(search_folder)
|
search_folder, found_models = self.generate.model_manager.search_models(
|
||||||
|
search_folder)
|
||||||
socketio.emit(
|
socketio.emit(
|
||||||
"foundModels",
|
"foundModels",
|
||||||
{'search_folder': search_folder, 'found_models': found_models},
|
{'search_folder': search_folder,
|
||||||
|
'found_models': found_models},
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.socketio.emit("error", {"message": (str(e))})
|
self.socketio.emit("error", {"message": (str(e))})
|
||||||
@ -393,6 +399,67 @@ class InvokeAIWebServer:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
print("\n")
|
print("\n")
|
||||||
|
|
||||||
|
@socketio.on('convertToDiffusers')
|
||||||
|
def convert_to_diffusers(model_to_convert: dict):
|
||||||
|
try:
|
||||||
|
if (model_info := self.generate.model_manager.model_info(model_name=model_to_convert['model_name'])):
|
||||||
|
if 'weights' in model_info:
|
||||||
|
ckpt_path = Path(model_info['weights'])
|
||||||
|
original_config_file = Path(model_info['config'])
|
||||||
|
model_name = model_to_convert['model_name']
|
||||||
|
model_description = model_info['description']
|
||||||
|
else:
|
||||||
|
self.socketio.emit(
|
||||||
|
"error", {"message": "Model is not a valid checkpoint file"})
|
||||||
|
else:
|
||||||
|
self.socketio.emit(
|
||||||
|
"error", {"message": "Could not retrieve model info."})
|
||||||
|
|
||||||
|
if not ckpt_path.is_absolute():
|
||||||
|
ckpt_path = Path(Globals.root, ckpt_path)
|
||||||
|
|
||||||
|
if original_config_file and not original_config_file.is_absolute():
|
||||||
|
original_config_file = Path(
|
||||||
|
Globals.root, original_config_file)
|
||||||
|
|
||||||
|
diffusers_path = Path(
|
||||||
|
ckpt_path.parent.absolute(),
|
||||||
|
f'{model_name}_diffusers'
|
||||||
|
)
|
||||||
|
|
||||||
|
if model_to_convert['save_location'] == 'root':
|
||||||
|
diffusers_path = Path(global_converted_ckpts_dir(), f'{model_name}_diffusers')
|
||||||
|
|
||||||
|
if model_to_convert['save_location'] == 'custom' and model_to_convert['custom_location'] is not None:
|
||||||
|
diffusers_path = Path(model_to_convert['custom_location'], f'{model_name}_diffusers')
|
||||||
|
|
||||||
|
if diffusers_path.exists():
|
||||||
|
shutil.rmtree(diffusers_path)
|
||||||
|
|
||||||
|
self.generate.model_manager.convert_and_import(
|
||||||
|
ckpt_path,
|
||||||
|
diffusers_path,
|
||||||
|
model_name=model_name,
|
||||||
|
model_description=model_description,
|
||||||
|
vae=None,
|
||||||
|
original_config_file=original_config_file,
|
||||||
|
commit_to_conf=opt.conf,
|
||||||
|
)
|
||||||
|
|
||||||
|
new_model_list = self.generate.model_manager.list_models()
|
||||||
|
socketio.emit(
|
||||||
|
"modelConverted",
|
||||||
|
{"new_model_name": model_name,
|
||||||
|
"model_list": new_model_list, 'update': True},
|
||||||
|
)
|
||||||
|
print(f">> Model Converted: {model_name}")
|
||||||
|
except Exception as e:
|
||||||
|
self.socketio.emit("error", {"message": (str(e))})
|
||||||
|
print("\n")
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
print("\n")
|
||||||
|
|
||||||
@socketio.on("requestEmptyTempFolder")
|
@socketio.on("requestEmptyTempFolder")
|
||||||
def empty_temp_folder():
|
def empty_temp_folder():
|
||||||
try:
|
try:
|
||||||
@ -406,7 +473,8 @@ class InvokeAIWebServer:
|
|||||||
)
|
)
|
||||||
os.remove(thumbnail_path)
|
os.remove(thumbnail_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
socketio.emit("error", {"message": f"Unable to delete {f}: {str(e)}"})
|
socketio.emit(
|
||||||
|
"error", {"message": f"Unable to delete {f}: {str(e)}"})
|
||||||
pass
|
pass
|
||||||
|
|
||||||
socketio.emit("tempFolderEmptied")
|
socketio.emit("tempFolderEmptied")
|
||||||
@ -421,7 +489,8 @@ class InvokeAIWebServer:
|
|||||||
def save_temp_image_to_gallery(url):
|
def save_temp_image_to_gallery(url):
|
||||||
try:
|
try:
|
||||||
image_path = self.get_image_path_from_url(url)
|
image_path = self.get_image_path_from_url(url)
|
||||||
new_path = os.path.join(self.result_path, os.path.basename(image_path))
|
new_path = os.path.join(
|
||||||
|
self.result_path, os.path.basename(image_path))
|
||||||
shutil.copy2(image_path, new_path)
|
shutil.copy2(image_path, new_path)
|
||||||
|
|
||||||
if os.path.splitext(new_path)[1] == ".png":
|
if os.path.splitext(new_path)[1] == ".png":
|
||||||
@ -434,7 +503,8 @@ class InvokeAIWebServer:
|
|||||||
(width, height) = pil_image.size
|
(width, height) = pil_image.size
|
||||||
|
|
||||||
thumbnail_path = save_thumbnail(
|
thumbnail_path = save_thumbnail(
|
||||||
pil_image, os.path.basename(new_path), self.thumbnail_image_path
|
pil_image, os.path.basename(
|
||||||
|
new_path), self.thumbnail_image_path
|
||||||
)
|
)
|
||||||
|
|
||||||
image_array = [
|
image_array = [
|
||||||
@ -497,7 +567,8 @@ class InvokeAIWebServer:
|
|||||||
(width, height) = pil_image.size
|
(width, height) = pil_image.size
|
||||||
|
|
||||||
thumbnail_path = save_thumbnail(
|
thumbnail_path = save_thumbnail(
|
||||||
pil_image, os.path.basename(path), self.thumbnail_image_path
|
pil_image, os.path.basename(
|
||||||
|
path), self.thumbnail_image_path
|
||||||
)
|
)
|
||||||
|
|
||||||
image_array.append(
|
image_array.append(
|
||||||
@ -515,7 +586,8 @@ class InvokeAIWebServer:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
socketio.emit("error", {"message": f"Unable to load {path}: {str(e)}"})
|
socketio.emit(
|
||||||
|
"error", {"message": f"Unable to load {path}: {str(e)}"})
|
||||||
pass
|
pass
|
||||||
|
|
||||||
socketio.emit(
|
socketio.emit(
|
||||||
@ -569,7 +641,8 @@ class InvokeAIWebServer:
|
|||||||
(width, height) = pil_image.size
|
(width, height) = pil_image.size
|
||||||
|
|
||||||
thumbnail_path = save_thumbnail(
|
thumbnail_path = save_thumbnail(
|
||||||
pil_image, os.path.basename(path), self.thumbnail_image_path
|
pil_image, os.path.basename(
|
||||||
|
path), self.thumbnail_image_path
|
||||||
)
|
)
|
||||||
|
|
||||||
image_array.append(
|
image_array.append(
|
||||||
@ -588,7 +661,8 @@ class InvokeAIWebServer:
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f">> Unable to load {path}")
|
print(f">> Unable to load {path}")
|
||||||
socketio.emit("error", {"message": f"Unable to load {path}: {str(e)}"})
|
socketio.emit(
|
||||||
|
"error", {"message": f"Unable to load {path}: {str(e)}"})
|
||||||
pass
|
pass
|
||||||
|
|
||||||
socketio.emit(
|
socketio.emit(
|
||||||
@ -626,7 +700,8 @@ class InvokeAIWebServer:
|
|||||||
printable_parameters["init_mask"][:64] + "..."
|
printable_parameters["init_mask"][:64] + "..."
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f'\n>> Image Generation Parameters:\n\n{printable_parameters}\n')
|
print(
|
||||||
|
f'\n>> Image Generation Parameters:\n\n{printable_parameters}\n')
|
||||||
print(f'>> ESRGAN Parameters: {esrgan_parameters}')
|
print(f'>> ESRGAN Parameters: {esrgan_parameters}')
|
||||||
print(f'>> Facetool Parameters: {facetool_parameters}')
|
print(f'>> Facetool Parameters: {facetool_parameters}')
|
||||||
|
|
||||||
@ -662,16 +737,18 @@ class InvokeAIWebServer:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
seed = original_image["metadata"]["image"]["seed"]
|
seed = original_image["metadata"]["image"]["seed"]
|
||||||
except (KeyError) as e:
|
except KeyError:
|
||||||
seed = "unknown_seed"
|
seed = "unknown_seed"
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if postprocessing_parameters["type"] == "esrgan":
|
if postprocessing_parameters["type"] == "esrgan":
|
||||||
progress.set_current_status("common:statusUpscalingESRGAN")
|
progress.set_current_status("common:statusUpscalingESRGAN")
|
||||||
elif postprocessing_parameters["type"] == "gfpgan":
|
elif postprocessing_parameters["type"] == "gfpgan":
|
||||||
progress.set_current_status("common:statusRestoringFacesGFPGAN")
|
progress.set_current_status(
|
||||||
|
"common:statusRestoringFacesGFPGAN")
|
||||||
elif postprocessing_parameters["type"] == "codeformer":
|
elif postprocessing_parameters["type"] == "codeformer":
|
||||||
progress.set_current_status("common:statusRestoringFacesCodeFormer")
|
progress.set_current_status(
|
||||||
|
"common:statusRestoringFacesCodeFormer")
|
||||||
|
|
||||||
socketio.emit("progressUpdate", progress.to_formatted_dict())
|
socketio.emit("progressUpdate", progress.to_formatted_dict())
|
||||||
eventlet.sleep(0)
|
eventlet.sleep(0)
|
||||||
@ -760,7 +837,7 @@ class InvokeAIWebServer:
|
|||||||
|
|
||||||
@socketio.on("cancel")
|
@socketio.on("cancel")
|
||||||
def handle_cancel():
|
def handle_cancel():
|
||||||
print(f">> Cancel processing requested")
|
print(">> Cancel processing requested")
|
||||||
self.canceled.set()
|
self.canceled.set()
|
||||||
|
|
||||||
# TODO: I think this needs a safety mechanism.
|
# TODO: I think this needs a safety mechanism.
|
||||||
@ -842,12 +919,10 @@ class InvokeAIWebServer:
|
|||||||
So we need to convert each into a PIL Image.
|
So we need to convert each into a PIL Image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
truncated_outpaint_image_b64 = generation_parameters["init_img"][:64]
|
|
||||||
truncated_outpaint_mask_b64 = generation_parameters["init_mask"][:64]
|
|
||||||
|
|
||||||
init_img_url = generation_parameters["init_img"]
|
init_img_url = generation_parameters["init_img"]
|
||||||
|
|
||||||
original_bounding_box = generation_parameters["bounding_box"].copy()
|
original_bounding_box = generation_parameters["bounding_box"].copy(
|
||||||
|
)
|
||||||
|
|
||||||
initial_image = dataURL_to_image(
|
initial_image = dataURL_to_image(
|
||||||
generation_parameters["init_img"]
|
generation_parameters["init_img"]
|
||||||
@ -924,7 +999,8 @@ class InvokeAIWebServer:
|
|||||||
elif generation_parameters["generation_mode"] == "img2img":
|
elif generation_parameters["generation_mode"] == "img2img":
|
||||||
init_img_url = generation_parameters["init_img"]
|
init_img_url = generation_parameters["init_img"]
|
||||||
init_img_path = self.get_image_path_from_url(init_img_url)
|
init_img_path = self.get_image_path_from_url(init_img_url)
|
||||||
generation_parameters["init_img"] = Image.open(init_img_path).convert('RGB')
|
generation_parameters["init_img"] = Image.open(
|
||||||
|
init_img_path).convert('RGB')
|
||||||
|
|
||||||
def image_progress(sample, step):
|
def image_progress(sample, step):
|
||||||
if self.canceled.is_set():
|
if self.canceled.is_set():
|
||||||
@ -983,9 +1059,9 @@ class InvokeAIWebServer:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if generation_parameters["progress_latents"]:
|
if generation_parameters["progress_latents"]:
|
||||||
image = self.generate.sample_to_lowres_estimated_image(sample)
|
image = self.generate.sample_to_lowres_estimated_image(
|
||||||
|
sample)
|
||||||
(width, height) = image.size
|
(width, height) = image.size
|
||||||
width *= 8
|
width *= 8
|
||||||
height *= 8
|
height *= 8
|
||||||
@ -1004,7 +1080,8 @@ class InvokeAIWebServer:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
|
self.socketio.emit(
|
||||||
|
"progressUpdate", progress.to_formatted_dict())
|
||||||
eventlet.sleep(0)
|
eventlet.sleep(0)
|
||||||
|
|
||||||
def image_done(image, seed, first_seed, attention_maps_image=None):
|
def image_done(image, seed, first_seed, attention_maps_image=None):
|
||||||
@ -1016,7 +1093,6 @@ class InvokeAIWebServer:
|
|||||||
nonlocal facetool_parameters
|
nonlocal facetool_parameters
|
||||||
nonlocal progress
|
nonlocal progress
|
||||||
|
|
||||||
step_index = 1
|
|
||||||
nonlocal prior_variations
|
nonlocal prior_variations
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -1032,7 +1108,8 @@ class InvokeAIWebServer:
|
|||||||
|
|
||||||
progress.set_current_status("common:statusGenerationComplete")
|
progress.set_current_status("common:statusGenerationComplete")
|
||||||
|
|
||||||
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
|
self.socketio.emit(
|
||||||
|
"progressUpdate", progress.to_formatted_dict())
|
||||||
eventlet.sleep(0)
|
eventlet.sleep(0)
|
||||||
|
|
||||||
all_parameters = generation_parameters
|
all_parameters = generation_parameters
|
||||||
@ -1043,7 +1120,8 @@ class InvokeAIWebServer:
|
|||||||
and all_parameters["variation_amount"] > 0
|
and all_parameters["variation_amount"] > 0
|
||||||
):
|
):
|
||||||
first_seed = first_seed or seed
|
first_seed = first_seed or seed
|
||||||
this_variation = [[seed, all_parameters["variation_amount"]]]
|
this_variation = [
|
||||||
|
[seed, all_parameters["variation_amount"]]]
|
||||||
all_parameters["with_variations"] = (
|
all_parameters["with_variations"] = (
|
||||||
prior_variations + this_variation
|
prior_variations + this_variation
|
||||||
)
|
)
|
||||||
@ -1059,7 +1137,8 @@ class InvokeAIWebServer:
|
|||||||
if esrgan_parameters:
|
if esrgan_parameters:
|
||||||
progress.set_current_status("common:statusUpscaling")
|
progress.set_current_status("common:statusUpscaling")
|
||||||
progress.set_current_status_has_steps(False)
|
progress.set_current_status_has_steps(False)
|
||||||
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
|
self.socketio.emit(
|
||||||
|
"progressUpdate", progress.to_formatted_dict())
|
||||||
eventlet.sleep(0)
|
eventlet.sleep(0)
|
||||||
|
|
||||||
image = self.esrgan.process(
|
image = self.esrgan.process(
|
||||||
@ -1082,12 +1161,15 @@ class InvokeAIWebServer:
|
|||||||
|
|
||||||
if facetool_parameters:
|
if facetool_parameters:
|
||||||
if facetool_parameters["type"] == "gfpgan":
|
if facetool_parameters["type"] == "gfpgan":
|
||||||
progress.set_current_status("common:statusRestoringFacesGFPGAN")
|
progress.set_current_status(
|
||||||
|
"common:statusRestoringFacesGFPGAN")
|
||||||
elif facetool_parameters["type"] == "codeformer":
|
elif facetool_parameters["type"] == "codeformer":
|
||||||
progress.set_current_status("common:statusRestoringFacesCodeFormer")
|
progress.set_current_status(
|
||||||
|
"common:statusRestoringFacesCodeFormer")
|
||||||
|
|
||||||
progress.set_current_status_has_steps(False)
|
progress.set_current_status_has_steps(False)
|
||||||
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
|
self.socketio.emit(
|
||||||
|
"progressUpdate", progress.to_formatted_dict())
|
||||||
eventlet.sleep(0)
|
eventlet.sleep(0)
|
||||||
|
|
||||||
if facetool_parameters["type"] == "gfpgan":
|
if facetool_parameters["type"] == "gfpgan":
|
||||||
@ -1117,7 +1199,8 @@ class InvokeAIWebServer:
|
|||||||
all_parameters["facetool_type"] = facetool_parameters["type"]
|
all_parameters["facetool_type"] = facetool_parameters["type"]
|
||||||
|
|
||||||
progress.set_current_status("common:statusSavingImage")
|
progress.set_current_status("common:statusSavingImage")
|
||||||
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
|
self.socketio.emit(
|
||||||
|
"progressUpdate", progress.to_formatted_dict())
|
||||||
eventlet.sleep(0)
|
eventlet.sleep(0)
|
||||||
|
|
||||||
# restore the stashed URLS and discard the paths, we are about to send the result to client
|
# restore the stashed URLS and discard the paths, we are about to send the result to client
|
||||||
@ -1128,12 +1211,14 @@ class InvokeAIWebServer:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if "init_mask" in all_parameters:
|
if "init_mask" in all_parameters:
|
||||||
all_parameters["init_mask"] = "" # TODO: store the mask in metadata
|
# TODO: store the mask in metadata
|
||||||
|
all_parameters["init_mask"] = ""
|
||||||
|
|
||||||
if generation_parameters["generation_mode"] == "unifiedCanvas":
|
if generation_parameters["generation_mode"] == "unifiedCanvas":
|
||||||
all_parameters["bounding_box"] = original_bounding_box
|
all_parameters["bounding_box"] = original_bounding_box
|
||||||
|
|
||||||
metadata = self.parameters_to_generated_image_metadata(all_parameters)
|
metadata = self.parameters_to_generated_image_metadata(
|
||||||
|
all_parameters)
|
||||||
|
|
||||||
command = parameters_to_command(all_parameters)
|
command = parameters_to_command(all_parameters)
|
||||||
|
|
||||||
@ -1163,15 +1248,18 @@ class InvokeAIWebServer:
|
|||||||
|
|
||||||
if progress.total_iterations > progress.current_iteration:
|
if progress.total_iterations > progress.current_iteration:
|
||||||
progress.set_current_step(1)
|
progress.set_current_step(1)
|
||||||
progress.set_current_status("common:statusIterationComplete")
|
progress.set_current_status(
|
||||||
|
"common:statusIterationComplete")
|
||||||
progress.set_current_status_has_steps(False)
|
progress.set_current_status_has_steps(False)
|
||||||
else:
|
else:
|
||||||
progress.mark_complete()
|
progress.mark_complete()
|
||||||
|
|
||||||
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
|
self.socketio.emit(
|
||||||
|
"progressUpdate", progress.to_formatted_dict())
|
||||||
eventlet.sleep(0)
|
eventlet.sleep(0)
|
||||||
|
|
||||||
parsed_prompt, _ = get_prompt_structure(generation_parameters["prompt"])
|
parsed_prompt, _ = get_prompt_structure(
|
||||||
|
generation_parameters["prompt"])
|
||||||
tokens = None if type(parsed_prompt) is Blend else \
|
tokens = None if type(parsed_prompt) is Blend else \
|
||||||
get_tokens_for_prompt(self.generate.model, parsed_prompt)
|
get_tokens_for_prompt(self.generate.model, parsed_prompt)
|
||||||
attention_maps_image_base64_url = None if attention_maps_image is None \
|
attention_maps_image_base64_url = None if attention_maps_image is None \
|
||||||
@ -1345,7 +1433,8 @@ class InvokeAIWebServer:
|
|||||||
self, parameters, original_image_path
|
self, parameters, original_image_path
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
current_metadata = retrieve_metadata(original_image_path)["sd-metadata"]
|
current_metadata = retrieve_metadata(
|
||||||
|
original_image_path)["sd-metadata"]
|
||||||
postprocessing_metadata = {}
|
postprocessing_metadata = {}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -1385,7 +1474,8 @@ class InvokeAIWebServer:
|
|||||||
postprocessing_metadata
|
postprocessing_metadata
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
current_metadata["image"]["postprocessing"] = [postprocessing_metadata]
|
current_metadata["image"]["postprocessing"] = [
|
||||||
|
postprocessing_metadata]
|
||||||
|
|
||||||
return current_metadata
|
return current_metadata
|
||||||
|
|
||||||
@ -1424,7 +1514,7 @@ class InvokeAIWebServer:
|
|||||||
if step_index:
|
if step_index:
|
||||||
filename += f".{step_index}"
|
filename += f".{step_index}"
|
||||||
if postprocessing:
|
if postprocessing:
|
||||||
filename += f".postprocessed"
|
filename += ".postprocessed"
|
||||||
|
|
||||||
filename += ".png"
|
filename += ".png"
|
||||||
|
|
||||||
@ -1497,7 +1587,8 @@ class InvokeAIWebServer:
|
|||||||
)
|
)
|
||||||
elif "thumbnails" in url:
|
elif "thumbnails" in url:
|
||||||
return os.path.abspath(
|
return os.path.abspath(
|
||||||
os.path.join(self.thumbnail_image_path, os.path.basename(url))
|
os.path.join(self.thumbnail_image_path,
|
||||||
|
os.path.basename(url))
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return os.path.abspath(
|
return os.path.abspath(
|
||||||
@ -1666,10 +1757,12 @@ def dataURL_to_image(dataURL: str) -> ImageType:
|
|||||||
)
|
)
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Converts an image into a base64 image dataURL.
|
Converts an image into a base64 image dataURL.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def image_to_dataURL(image: ImageType) -> str:
|
def image_to_dataURL(image: ImageType) -> str:
|
||||||
buffered = io.BytesIO()
|
buffered = io.BytesIO()
|
||||||
image.save(buffered, format="PNG")
|
image.save(buffered, format="PNG")
|
||||||
@ -1679,7 +1772,6 @@ def image_to_dataURL(image: ImageType) -> str:
|
|||||||
return image_base64
|
return image_base64
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Converts a base64 image dataURL into bytes.
|
Converts a base64 image dataURL into bytes.
|
||||||
The dataURL is split on the first commma.
|
The dataURL is split on the first commma.
|
||||||
|
@ -3,3 +3,4 @@ dist/
|
|||||||
node_modules/
|
node_modules/
|
||||||
patches/
|
patches/
|
||||||
public/
|
public/
|
||||||
|
stats.html
|
||||||
|
@ -3,3 +3,4 @@ dist/
|
|||||||
node_modules/
|
node_modules/
|
||||||
patches/
|
patches/
|
||||||
public/
|
public/
|
||||||
|
stats.html
|
||||||
|
638
invokeai/frontend/dist/assets/index-12bd70ca.js
vendored
Normal file
638
invokeai/frontend/dist/assets/index-12bd70ca.js
vendored
Normal file
File diff suppressed because one or more lines are too long
638
invokeai/frontend/dist/assets/index-a93d4500.js
vendored
638
invokeai/frontend/dist/assets/index-a93d4500.js
vendored
File diff suppressed because one or more lines are too long
1
invokeai/frontend/dist/assets/index-c1af841f.css
vendored
Normal file
1
invokeai/frontend/dist/assets/index-c1af841f.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
invokeai/frontend/dist/index.html
vendored
4
invokeai/frontend/dist/index.html
vendored
@ -5,8 +5,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||||
<link rel="shortcut icon" type="icon" href="./assets/favicon-0d253ced.ico" />
|
<link rel="shortcut icon" type="icon" href="./assets/favicon-0d253ced.ico" />
|
||||||
<script type="module" crossorigin src="./assets/index-a93d4500.js"></script>
|
<script type="module" crossorigin src="./assets/index-12bd70ca.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index-fecb6dd4.css">
|
<link rel="stylesheet" href="./assets/index-c1af841f.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -58,5 +58,7 @@
|
|||||||
"statusUpscaling": "Upscaling",
|
"statusUpscaling": "Upscaling",
|
||||||
"statusUpscalingESRGAN": "Upscaling (ESRGAN)",
|
"statusUpscalingESRGAN": "Upscaling (ESRGAN)",
|
||||||
"statusLoadingModel": "Loading Model",
|
"statusLoadingModel": "Loading Model",
|
||||||
"statusModelChanged": "Model Changed"
|
"statusModelChanged": "Model Changed",
|
||||||
|
"statusConvertingModel": "Converting Model",
|
||||||
|
"statusModelConverted": "Model Converted"
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,23 @@
|
|||||||
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
||||||
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
||||||
"formMessageDiffusersVAELocation": "VAE Location",
|
"formMessageDiffusersVAELocation": "VAE Location",
|
||||||
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above."
|
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above.",
|
||||||
|
"convert": "Convert",
|
||||||
|
"convertToDiffusers": "Convert To Diffusers",
|
||||||
|
"convertToDiffusersHelpText1": "This model will be converted to the 🧨 Diffusers format.",
|
||||||
|
"convertToDiffusersHelpText2": "This process will replace your Model Manager entry with the Diffusers version of the same model.",
|
||||||
|
"convertToDiffusersHelpText3": "Your checkpoint file on the disk will NOT be deleted or modified in anyway. You can add your checkpoint to the Model Manager again if you want to.",
|
||||||
|
"convertToDiffusersHelpText4": "This is a one time process only. It might take around 30s-60s depending on the specifications of your computer.",
|
||||||
|
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 4GB-7GB in size.",
|
||||||
|
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
||||||
|
"v1": "v1",
|
||||||
|
"v2": "v2",
|
||||||
|
"inpainting": "v1 Inpainting",
|
||||||
|
"customConfig": "Custom Config",
|
||||||
|
"pathToCustomConfig": "Path To Custom Config",
|
||||||
|
"statusConverting": "Converting",
|
||||||
|
"sameFolder": "Same Folder",
|
||||||
|
"invokeRoot": "Invoke Models",
|
||||||
|
"custom": "Custom",
|
||||||
|
"customSaveLocation": "Custom Save Location"
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,25 @@
|
|||||||
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
||||||
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
||||||
"formMessageDiffusersVAELocation": "VAE Location",
|
"formMessageDiffusersVAELocation": "VAE Location",
|
||||||
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above."
|
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above.",
|
||||||
|
"convert": "Convert",
|
||||||
|
"convertToDiffusers": "Convert To Diffusers",
|
||||||
|
"convertToDiffusersHelpText1": "This model will be converted to the 🧨 Diffusers format.",
|
||||||
|
"convertToDiffusersHelpText2": "This process will replace your Model Manager entry with the Diffusers version of the same model.",
|
||||||
|
"convertToDiffusersHelpText3": "Your checkpoint file on the disk will NOT be deleted or modified in anyway. You can add your checkpoint to the Model Manager again if you want to.",
|
||||||
|
"convertToDiffusersHelpText4": "This is a one time process only. It might take around 30s-60s depending on the specifications of your computer.",
|
||||||
|
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 4GB-7GB in size.",
|
||||||
|
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
||||||
|
"convertToDiffusersSaveLocation": "Save Location",
|
||||||
|
"v1": "v1",
|
||||||
|
"v2": "v2",
|
||||||
|
"inpainting": "v1 Inpainting",
|
||||||
|
"customConfig": "Custom Config",
|
||||||
|
"pathToCustomConfig": "Path To Custom Config",
|
||||||
|
"statusConverting": "Converting",
|
||||||
|
"modelConverted": "Model Converted",
|
||||||
|
"sameFolder": "Same folder",
|
||||||
|
"invokeRoot": "InvokeAI folder",
|
||||||
|
"custom": "Custom",
|
||||||
|
"customSaveLocation": "Custom Save Location"
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,6 @@
|
|||||||
"useInitImg": "Use Initial Image",
|
"useInitImg": "Use Initial Image",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"deleteImage": "Delete Image",
|
"deleteImage": "Delete Image",
|
||||||
"initialImage": "Inital Image",
|
"initialImage": "Initial Image",
|
||||||
"showOptionsPanel": "Show Options Panel"
|
"showOptionsPanel": "Show Options Panel"
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,6 @@
|
|||||||
"useInitImg": "Use Initial Image",
|
"useInitImg": "Use Initial Image",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"deleteImage": "Delete Image",
|
"deleteImage": "Delete Image",
|
||||||
"initialImage": "Inital Image",
|
"initialImage": "Initial Image",
|
||||||
"showOptionsPanel": "Show Options Panel"
|
"showOptionsPanel": "Show Options Panel"
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
"useInitImg": "Use Initial Image",
|
"useInitImg": "Use Initial Image",
|
||||||
"info": "情報",
|
"info": "情報",
|
||||||
"deleteImage": "画像を削除",
|
"deleteImage": "画像を削除",
|
||||||
"initialImage": "Inital Image",
|
"initialImage": "Initial Image",
|
||||||
"showOptionsPanel": "オプションパネルを表示"
|
"showOptionsPanel": "オプションパネルを表示"
|
||||||
}
|
}
|
||||||
|
|
@ -58,5 +58,7 @@
|
|||||||
"statusUpscaling": "Upscaling",
|
"statusUpscaling": "Upscaling",
|
||||||
"statusUpscalingESRGAN": "Upscaling (ESRGAN)",
|
"statusUpscalingESRGAN": "Upscaling (ESRGAN)",
|
||||||
"statusLoadingModel": "Loading Model",
|
"statusLoadingModel": "Loading Model",
|
||||||
"statusModelChanged": "Model Changed"
|
"statusModelChanged": "Model Changed",
|
||||||
|
"statusConvertingModel": "Converting Model",
|
||||||
|
"statusModelConverted": "Model Converted"
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,23 @@
|
|||||||
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
||||||
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
||||||
"formMessageDiffusersVAELocation": "VAE Location",
|
"formMessageDiffusersVAELocation": "VAE Location",
|
||||||
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above."
|
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above.",
|
||||||
|
"convert": "Convert",
|
||||||
|
"convertToDiffusers": "Convert To Diffusers",
|
||||||
|
"convertToDiffusersHelpText1": "This model will be converted to the 🧨 Diffusers format.",
|
||||||
|
"convertToDiffusersHelpText2": "This process will replace your Model Manager entry with the Diffusers version of the same model.",
|
||||||
|
"convertToDiffusersHelpText3": "Your checkpoint file on the disk will NOT be deleted or modified in anyway. You can add your checkpoint to the Model Manager again if you want to.",
|
||||||
|
"convertToDiffusersHelpText4": "This is a one time process only. It might take around 30s-60s depending on the specifications of your computer.",
|
||||||
|
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 4GB-7GB in size.",
|
||||||
|
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
||||||
|
"v1": "v1",
|
||||||
|
"v2": "v2",
|
||||||
|
"inpainting": "v1 Inpainting",
|
||||||
|
"customConfig": "Custom Config",
|
||||||
|
"pathToCustomConfig": "Path To Custom Config",
|
||||||
|
"statusConverting": "Converting",
|
||||||
|
"sameFolder": "Same Folder",
|
||||||
|
"invokeRoot": "Invoke Models",
|
||||||
|
"custom": "Custom",
|
||||||
|
"customSaveLocation": "Custom Save Location"
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,25 @@
|
|||||||
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
||||||
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
||||||
"formMessageDiffusersVAELocation": "VAE Location",
|
"formMessageDiffusersVAELocation": "VAE Location",
|
||||||
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above."
|
"formMessageDiffusersVAELocationDesc": "If not provided, InvokeAI will look for the VAE file inside the model location given above.",
|
||||||
|
"convert": "Convert",
|
||||||
|
"convertToDiffusers": "Convert To Diffusers",
|
||||||
|
"convertToDiffusersHelpText1": "This model will be converted to the 🧨 Diffusers format.",
|
||||||
|
"convertToDiffusersHelpText2": "This process will replace your Model Manager entry with the Diffusers version of the same model.",
|
||||||
|
"convertToDiffusersHelpText3": "Your checkpoint file on the disk will NOT be deleted or modified in anyway. You can add your checkpoint to the Model Manager again if you want to.",
|
||||||
|
"convertToDiffusersHelpText4": "This is a one time process only. It might take around 30s-60s depending on the specifications of your computer.",
|
||||||
|
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 4GB-7GB in size.",
|
||||||
|
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
||||||
|
"convertToDiffusersSaveLocation": "Save Location",
|
||||||
|
"v1": "v1",
|
||||||
|
"v2": "v2",
|
||||||
|
"inpainting": "v1 Inpainting",
|
||||||
|
"customConfig": "Custom Config",
|
||||||
|
"pathToCustomConfig": "Path To Custom Config",
|
||||||
|
"statusConverting": "Converting",
|
||||||
|
"modelConverted": "Model Converted",
|
||||||
|
"sameFolder": "Same folder",
|
||||||
|
"invokeRoot": "InvokeAI folder",
|
||||||
|
"custom": "Custom",
|
||||||
|
"customSaveLocation": "Custom Save Location"
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,6 @@
|
|||||||
"useInitImg": "Use Initial Image",
|
"useInitImg": "Use Initial Image",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"deleteImage": "Delete Image",
|
"deleteImage": "Delete Image",
|
||||||
"initialImage": "Inital Image",
|
"initialImage": "Initial Image",
|
||||||
"showOptionsPanel": "Show Options Panel"
|
"showOptionsPanel": "Show Options Panel"
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,6 @@
|
|||||||
"useInitImg": "Use Initial Image",
|
"useInitImg": "Use Initial Image",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"deleteImage": "Delete Image",
|
"deleteImage": "Delete Image",
|
||||||
"initialImage": "Inital Image",
|
"initialImage": "Initial Image",
|
||||||
"showOptionsPanel": "Show Options Panel"
|
"showOptionsPanel": "Show Options Panel"
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
"useInitImg": "Use Initial Image",
|
"useInitImg": "Use Initial Image",
|
||||||
"info": "情報",
|
"info": "情報",
|
||||||
"deleteImage": "画像を削除",
|
"deleteImage": "画像を削除",
|
||||||
"initialImage": "Inital Image",
|
"initialImage": "Initial Image",
|
||||||
"showOptionsPanel": "オプションパネルを表示"
|
"showOptionsPanel": "オプションパネルを表示"
|
||||||
}
|
}
|
||||||
|
|
@ -3,8 +3,8 @@ import { Flex, Spinner } from '@chakra-ui/react';
|
|||||||
const Loading = () => {
|
const Loading = () => {
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
width={'100vw'}
|
width="100vw"
|
||||||
height={'100vh'}
|
height="100vh"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
>
|
>
|
||||||
|
11
invokeai/frontend/src/app/invokeai.d.ts
vendored
11
invokeai/frontend/src/app/invokeai.d.ts
vendored
@ -219,6 +219,12 @@ export declare type InvokeDiffusersModelConfigProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export declare type InvokeModelConversionProps = {
|
||||||
|
model_name: string;
|
||||||
|
save_location: string;
|
||||||
|
custom_location: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These types type data received from the server via socketio.
|
* These types type data received from the server via socketio.
|
||||||
*/
|
*/
|
||||||
@ -228,6 +234,11 @@ export declare type ModelChangeResponse = {
|
|||||||
model_list: ModelList;
|
model_list: ModelList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export declare type ModelConvertedResponse = {
|
||||||
|
converted_model_name: string;
|
||||||
|
model_list: ModelList;
|
||||||
|
};
|
||||||
|
|
||||||
export declare type ModelAddedResponse = {
|
export declare type ModelAddedResponse = {
|
||||||
new_model_name: string;
|
new_model_name: string;
|
||||||
model_list: ModelList;
|
model_list: ModelList;
|
||||||
|
@ -38,6 +38,11 @@ export const addNewModel = createAction<
|
|||||||
|
|
||||||
export const deleteModel = createAction<string>('socketio/deleteModel');
|
export const deleteModel = createAction<string>('socketio/deleteModel');
|
||||||
|
|
||||||
|
export const convertToDiffusers =
|
||||||
|
createAction<InvokeAI.InvokeModelConversionProps>(
|
||||||
|
'socketio/convertToDiffusers'
|
||||||
|
);
|
||||||
|
|
||||||
export const requestModelChange = createAction<string>(
|
export const requestModelChange = createAction<string>(
|
||||||
'socketio/requestModelChange'
|
'socketio/requestModelChange'
|
||||||
);
|
);
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
addLogEntry,
|
addLogEntry,
|
||||||
generationRequested,
|
generationRequested,
|
||||||
modelChangeRequested,
|
modelChangeRequested,
|
||||||
|
modelConvertRequested,
|
||||||
setIsProcessing,
|
setIsProcessing,
|
||||||
} from 'features/system/store/systemSlice';
|
} from 'features/system/store/systemSlice';
|
||||||
import { InvokeTabName } from 'features/ui/store/tabMap';
|
import { InvokeTabName } from 'features/ui/store/tabMap';
|
||||||
@ -178,6 +179,12 @@ const makeSocketIOEmitters = (
|
|||||||
emitDeleteModel: (modelName: string) => {
|
emitDeleteModel: (modelName: string) => {
|
||||||
socketio.emit('deleteModel', modelName);
|
socketio.emit('deleteModel', modelName);
|
||||||
},
|
},
|
||||||
|
emitConvertToDiffusers: (
|
||||||
|
modelToConvert: InvokeAI.InvokeModelConversionProps
|
||||||
|
) => {
|
||||||
|
dispatch(modelConvertRequested());
|
||||||
|
socketio.emit('convertToDiffusers', modelToConvert);
|
||||||
|
},
|
||||||
emitRequestModelChange: (modelName: string) => {
|
emitRequestModelChange: (modelName: string) => {
|
||||||
dispatch(modelChangeRequested());
|
dispatch(modelChangeRequested());
|
||||||
socketio.emit('requestModelChange', modelName);
|
socketio.emit('requestModelChange', modelName);
|
||||||
|
@ -365,6 +365,7 @@ const makeSocketIOListeners = (
|
|||||||
const { new_model_name, model_list, update } = data;
|
const { new_model_name, model_list, update } = data;
|
||||||
dispatch(setModelList(model_list));
|
dispatch(setModelList(model_list));
|
||||||
dispatch(setIsProcessing(false));
|
dispatch(setIsProcessing(false));
|
||||||
|
dispatch(setCurrentStatus(i18n.t('modelmanager:modelAdded')));
|
||||||
dispatch(
|
dispatch(
|
||||||
addLogEntry({
|
addLogEntry({
|
||||||
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
||||||
@ -407,6 +408,30 @@ const makeSocketIOListeners = (
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
onModelConverted: (data: InvokeAI.ModelConvertedResponse) => {
|
||||||
|
const { converted_model_name, model_list } = data;
|
||||||
|
dispatch(setModelList(model_list));
|
||||||
|
dispatch(setCurrentStatus(i18n.t('common:statusModelConverted')));
|
||||||
|
dispatch(setIsProcessing(false));
|
||||||
|
dispatch(setIsCancelable(true));
|
||||||
|
dispatch(
|
||||||
|
addLogEntry({
|
||||||
|
timestamp: dateFormat(new Date(), 'isoDateTime'),
|
||||||
|
message: `Model converted: ${converted_model_name}`,
|
||||||
|
level: 'info',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
dispatch(
|
||||||
|
addToast({
|
||||||
|
title: `${i18n.t(
|
||||||
|
'modelmanager:modelConverted'
|
||||||
|
)}: ${converted_model_name}`,
|
||||||
|
status: 'success',
|
||||||
|
duration: 2500,
|
||||||
|
isClosable: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
onModelChanged: (data: InvokeAI.ModelChangeResponse) => {
|
onModelChanged: (data: InvokeAI.ModelChangeResponse) => {
|
||||||
const { model_name, model_list } = data;
|
const { model_name, model_list } = data;
|
||||||
dispatch(setModelList(model_list));
|
dispatch(setModelList(model_list));
|
||||||
|
@ -48,6 +48,7 @@ export const socketioMiddleware = () => {
|
|||||||
onFoundModels,
|
onFoundModels,
|
||||||
onNewModelAdded,
|
onNewModelAdded,
|
||||||
onModelDeleted,
|
onModelDeleted,
|
||||||
|
onModelConverted,
|
||||||
onModelChangeFailed,
|
onModelChangeFailed,
|
||||||
onTempFolderEmptied,
|
onTempFolderEmptied,
|
||||||
} = makeSocketIOListeners(store);
|
} = makeSocketIOListeners(store);
|
||||||
@ -64,6 +65,7 @@ export const socketioMiddleware = () => {
|
|||||||
emitSearchForModels,
|
emitSearchForModels,
|
||||||
emitAddNewModel,
|
emitAddNewModel,
|
||||||
emitDeleteModel,
|
emitDeleteModel,
|
||||||
|
emitConvertToDiffusers,
|
||||||
emitRequestModelChange,
|
emitRequestModelChange,
|
||||||
emitSaveStagingAreaImageToGallery,
|
emitSaveStagingAreaImageToGallery,
|
||||||
emitRequestEmptyTempFolder,
|
emitRequestEmptyTempFolder,
|
||||||
@ -125,6 +127,10 @@ export const socketioMiddleware = () => {
|
|||||||
onModelDeleted(data);
|
onModelDeleted(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socketio.on('modelConverted', (data: InvokeAI.ModelConvertedResponse) => {
|
||||||
|
onModelConverted(data);
|
||||||
|
});
|
||||||
|
|
||||||
socketio.on('modelChanged', (data: InvokeAI.ModelChangeResponse) => {
|
socketio.on('modelChanged', (data: InvokeAI.ModelChangeResponse) => {
|
||||||
onModelChanged(data);
|
onModelChanged(data);
|
||||||
});
|
});
|
||||||
@ -199,6 +205,11 @@ export const socketioMiddleware = () => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'socketio/convertToDiffusers': {
|
||||||
|
emitConvertToDiffusers(action.payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'socketio/requestModelChange': {
|
case 'socketio/requestModelChange': {
|
||||||
emitRequestModelChange(action.payload);
|
emitRequestModelChange(action.payload);
|
||||||
break;
|
break;
|
||||||
|
@ -13,7 +13,7 @@ const GuideIcon = forwardRef(
|
|||||||
({ feature, icon = MdHelp }: GuideIconProps, ref) => (
|
({ feature, icon = MdHelp }: GuideIconProps, ref) => (
|
||||||
<GuidePopover feature={feature}>
|
<GuidePopover feature={feature}>
|
||||||
<Box ref={ref}>
|
<Box ref={ref}>
|
||||||
<Icon marginBottom={'-.15rem'} as={icon} />
|
<Icon marginBottom="-.15rem" as={icon} />
|
||||||
</Box>
|
</Box>
|
||||||
</GuidePopover>
|
</GuidePopover>
|
||||||
)
|
)
|
||||||
|
@ -29,15 +29,15 @@ const GuidePopover = ({ children, feature }: GuideProps) => {
|
|||||||
if (!shouldDisplayGuides) return null;
|
if (!shouldDisplayGuides) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover trigger={'hover'}>
|
<Popover trigger="hover">
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
<Box>{children}</Box>
|
<Box>{children}</Box>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
className={`guide-popover-content`}
|
className="guide-popover-content"
|
||||||
maxWidth="400px"
|
maxWidth="400px"
|
||||||
onClick={(e) => e.preventDefault()}
|
onClick={(e) => e.preventDefault()}
|
||||||
cursor={'initial'}
|
cursor="initial"
|
||||||
>
|
>
|
||||||
<PopoverArrow className="guide-popover-arrow" />
|
<PopoverArrow className="guide-popover-arrow" />
|
||||||
<div className="guide-popover-guide-content">{text}</div>
|
<div className="guide-popover-guide-content">{text}</div>
|
||||||
|
@ -169,7 +169,7 @@ export default function IAISlider(props: IAIFullSliderProps) {
|
|||||||
{label}
|
{label}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<HStack w={'100%'} gap={2} alignItems="center">
|
<HStack w="100%" gap={2} alignItems="center">
|
||||||
<Slider
|
<Slider
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
value={value}
|
value={value}
|
||||||
@ -259,9 +259,9 @@ export default function IAISlider(props: IAIFullSliderProps) {
|
|||||||
|
|
||||||
{withReset && (
|
{withReset && (
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
aria-label={'Reset'}
|
aria-label="Reset"
|
||||||
tooltip={'Reset'}
|
tooltip="Reset"
|
||||||
icon={<BiReset />}
|
icon={<BiReset />}
|
||||||
onClick={handleResetDisable}
|
onClick={handleResetDisable}
|
||||||
isDisabled={isResetDisabled}
|
isDisabled={isResetDisabled}
|
||||||
|
@ -24,13 +24,13 @@ const ImageUploadOverlay = (props: ImageUploadOverlayProps) => {
|
|||||||
<div className="dropzone-container">
|
<div className="dropzone-container">
|
||||||
{isDragAccept && (
|
{isDragAccept && (
|
||||||
<div className="dropzone-overlay is-drag-accept">
|
<div className="dropzone-overlay is-drag-accept">
|
||||||
<Heading size={'lg'}>Upload Image{overlaySecondaryText}</Heading>
|
<Heading size="lg">Upload Image{overlaySecondaryText}</Heading>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isDragReject && (
|
{isDragReject && (
|
||||||
<div className="dropzone-overlay is-drag-reject">
|
<div className="dropzone-overlay is-drag-reject">
|
||||||
<Heading size={'lg'}>Invalid Upload</Heading>
|
<Heading size="lg">Invalid Upload</Heading>
|
||||||
<Heading size={'md'}>Must be single JPEG or PNG image</Heading>
|
<Heading size="md">Must be single JPEG or PNG image</Heading>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,7 @@ const ImageUploaderButton = (props: ImageUploaderButtonProps) => {
|
|||||||
>
|
>
|
||||||
<div className="image-upload-button">
|
<div className="image-upload-button">
|
||||||
<FaUpload />
|
<FaUpload />
|
||||||
<Heading size={'lg'}>Click or Drag and Drop</Heading>
|
<Heading size="lg">Click or Drag and Drop</Heading>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -178,12 +178,16 @@ export const frontendToBackendParameters = (
|
|||||||
? randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX)
|
? randomInt(NUMPY_RAND_MIN, NUMPY_RAND_MAX)
|
||||||
: seed;
|
: seed;
|
||||||
|
|
||||||
// parameters common to txt2img and img2img
|
// txt2img exclusive parameters
|
||||||
if (['txt2img', 'img2img'].includes(generationMode)) {
|
if (generationMode === 'txt2img') {
|
||||||
generationParameters.seamless = seamless;
|
|
||||||
generationParameters.hires_fix = hiresFix;
|
generationParameters.hires_fix = hiresFix;
|
||||||
|
|
||||||
if (hiresFix) generationParameters.strength = hiresStrength;
|
if (hiresFix) generationParameters.strength = hiresStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parameters common to txt2img and img2img
|
||||||
|
if (['txt2img', 'img2img'].includes(generationMode)) {
|
||||||
|
generationParameters.seamless = seamless;
|
||||||
|
|
||||||
if (shouldRunESRGAN) {
|
if (shouldRunESRGAN) {
|
||||||
esrganParameters = {
|
esrganParameters = {
|
||||||
|
@ -17,7 +17,7 @@ const ClearCanvasHistoryButtonModal = () => {
|
|||||||
acceptCallback={() => dispatch(clearCanvasHistory())}
|
acceptCallback={() => dispatch(clearCanvasHistory())}
|
||||||
acceptButtonText={t('unifiedcanvas:clearHistory')}
|
acceptButtonText={t('unifiedcanvas:clearHistory')}
|
||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIButton size={'sm'} leftIcon={<FaTrash />} isDisabled={isStaging}>
|
<IAIButton size="sm" leftIcon={<FaTrash />} isDisabled={isStaging}>
|
||||||
{t('unifiedcanvas:clearCanvasHistory')}
|
{t('unifiedcanvas:clearCanvasHistory')}
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ const IAICanvas = () => {
|
|||||||
<Stage
|
<Stage
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
ref={canvasStageRefCallback}
|
ref={canvasStageRefCallback}
|
||||||
className={'inpainting-canvas-stage'}
|
className="inpainting-canvas-stage"
|
||||||
style={{
|
style={{
|
||||||
...(stageCursor ? { cursor: stageCursor } : {}),
|
...(stageCursor ? { cursor: stageCursor } : {}),
|
||||||
}}
|
}}
|
||||||
@ -165,19 +165,19 @@ const IAICanvas = () => {
|
|||||||
onWheel={handleWheel}
|
onWheel={handleWheel}
|
||||||
draggable={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
|
draggable={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
|
||||||
>
|
>
|
||||||
<Layer id={'grid'} visible={shouldShowGrid}>
|
<Layer id="grid" visible={shouldShowGrid}>
|
||||||
<IAICanvasGrid />
|
<IAICanvasGrid />
|
||||||
</Layer>
|
</Layer>
|
||||||
|
|
||||||
<Layer
|
<Layer
|
||||||
id={'base'}
|
id="base"
|
||||||
ref={canvasBaseLayerRefCallback}
|
ref={canvasBaseLayerRefCallback}
|
||||||
listening={false}
|
listening={false}
|
||||||
imageSmoothingEnabled={false}
|
imageSmoothingEnabled={false}
|
||||||
>
|
>
|
||||||
<IAICanvasObjectRenderer />
|
<IAICanvasObjectRenderer />
|
||||||
</Layer>
|
</Layer>
|
||||||
<Layer id={'mask'} visible={isMaskEnabled} listening={false}>
|
<Layer id="mask" visible={isMaskEnabled} listening={false}>
|
||||||
<IAICanvasMaskLines visible={true} listening={false} />
|
<IAICanvasMaskLines visible={true} listening={false} />
|
||||||
<IAICanvasMaskCompositer listening={false} />
|
<IAICanvasMaskCompositer listening={false} />
|
||||||
</Layer>
|
</Layer>
|
||||||
|
@ -49,7 +49,7 @@ const IAICanvasBoundingBoxOverlay = () => {
|
|||||||
offsetY={stageCoordinates.y / stageScale}
|
offsetY={stageCoordinates.y / stageScale}
|
||||||
height={stageDimensions.height / stageScale}
|
height={stageDimensions.height / stageScale}
|
||||||
width={stageDimensions.width / stageScale}
|
width={stageDimensions.width / stageScale}
|
||||||
fill={'rgba(0,0,0,0.4)'}
|
fill="rgba(0,0,0,0.4)"
|
||||||
listening={false}
|
listening={false}
|
||||||
visible={shouldDarkenOutsideBoundingBox}
|
visible={shouldDarkenOutsideBoundingBox}
|
||||||
/>
|
/>
|
||||||
@ -58,10 +58,10 @@ const IAICanvasBoundingBoxOverlay = () => {
|
|||||||
y={boundingBoxCoordinates.y}
|
y={boundingBoxCoordinates.y}
|
||||||
width={boundingBoxDimensions.width}
|
width={boundingBoxDimensions.width}
|
||||||
height={boundingBoxDimensions.height}
|
height={boundingBoxDimensions.height}
|
||||||
fill={'rgb(255,255,255)'}
|
fill="rgb(255,255,255)"
|
||||||
listening={false}
|
listening={false}
|
||||||
visible={shouldDarkenOutsideBoundingBox}
|
visible={shouldDarkenOutsideBoundingBox}
|
||||||
globalCompositeOperation={'destination-out'}
|
globalCompositeOperation="destination-out"
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
|
@ -163,10 +163,10 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
|||||||
width={stageDimensions.width / stageScale}
|
width={stageDimensions.width / stageScale}
|
||||||
fillPatternImage={fillPatternImage}
|
fillPatternImage={fillPatternImage}
|
||||||
fillPatternOffsetY={!isNumber(offset) ? 0 : offset}
|
fillPatternOffsetY={!isNumber(offset) ? 0 : offset}
|
||||||
fillPatternRepeat={'repeat'}
|
fillPatternRepeat="repeat"
|
||||||
fillPatternScale={{ x: 1 / stageScale, y: 1 / stageScale }}
|
fillPatternScale={{ x: 1 / stageScale, y: 1 / stageScale }}
|
||||||
listening={true}
|
listening={true}
|
||||||
globalCompositeOperation={'source-in'}
|
globalCompositeOperation="source-in"
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -36,7 +36,7 @@ const IAICanvasLines = (props: InpaintingCanvasLinesProps) => {
|
|||||||
<Line
|
<Line
|
||||||
key={i}
|
key={i}
|
||||||
points={line.points}
|
points={line.points}
|
||||||
stroke={'rgb(0,0,0)'} // The lines can be any color, just need alpha > 0
|
stroke="rgb(0,0,0)" // The lines can be any color, just need alpha > 0
|
||||||
strokeWidth={line.strokeWidth * 2}
|
strokeWidth={line.strokeWidth * 2}
|
||||||
tension={0}
|
tension={0}
|
||||||
lineCap="round"
|
lineCap="round"
|
||||||
|
@ -93,8 +93,8 @@ const IAICanvasObjectRenderer = () => {
|
|||||||
y={obj.y}
|
y={obj.y}
|
||||||
width={obj.width}
|
width={obj.width}
|
||||||
height={obj.height}
|
height={obj.height}
|
||||||
fill={'rgb(255, 255, 255)'}
|
fill="rgb(255, 255, 255)"
|
||||||
globalCompositeOperation={'destination-out'}
|
globalCompositeOperation="destination-out"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ const IAICanvasStagingArea = (props: Props) => {
|
|||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
strokeWidth={1}
|
strokeWidth={1}
|
||||||
stroke={'white'}
|
stroke="white"
|
||||||
strokeScaleEnabled={false}
|
strokeScaleEnabled={false}
|
||||||
/>
|
/>
|
||||||
<Rect
|
<Rect
|
||||||
@ -77,7 +77,7 @@ const IAICanvasStagingArea = (props: Props) => {
|
|||||||
height={height}
|
height={height}
|
||||||
dash={[4, 4]}
|
dash={[4, 4]}
|
||||||
strokeWidth={1}
|
strokeWidth={1}
|
||||||
stroke={'black'}
|
stroke="black"
|
||||||
strokeScaleEnabled={false}
|
strokeScaleEnabled={false}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
@ -114,11 +114,11 @@ const IAICanvasStagingAreaToolbar = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
pos={'absolute'}
|
pos="absolute"
|
||||||
bottom={'1rem'}
|
bottom="1rem"
|
||||||
w={'100%'}
|
w="100%"
|
||||||
align={'center'}
|
align="center"
|
||||||
justify={'center'}
|
justify="center"
|
||||||
filter="drop-shadow(0 0.5rem 1rem rgba(0,0,0))"
|
filter="drop-shadow(0 0.5rem 1rem rgba(0,0,0))"
|
||||||
onMouseOver={handleMouseOver}
|
onMouseOver={handleMouseOver}
|
||||||
onMouseOut={handleMouseOut}
|
onMouseOut={handleMouseOut}
|
||||||
|
@ -172,7 +172,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
|
|||||||
x={brushX}
|
x={brushX}
|
||||||
y={brushY}
|
y={brushY}
|
||||||
radius={radius}
|
radius={radius}
|
||||||
stroke={'rgba(255,255,255,0.4)'}
|
stroke="rgba(255,255,255,0.4)"
|
||||||
strokeWidth={strokeWidth * 2}
|
strokeWidth={strokeWidth * 2}
|
||||||
strokeEnabled={true}
|
strokeEnabled={true}
|
||||||
listening={false}
|
listening={false}
|
||||||
@ -181,7 +181,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
|
|||||||
x={brushX}
|
x={brushX}
|
||||||
y={brushY}
|
y={brushY}
|
||||||
radius={radius}
|
radius={radius}
|
||||||
stroke={'rgba(0,0,0,1)'}
|
stroke="rgba(0,0,0,1)"
|
||||||
strokeWidth={strokeWidth}
|
strokeWidth={strokeWidth}
|
||||||
strokeEnabled={true}
|
strokeEnabled={true}
|
||||||
listening={false}
|
listening={false}
|
||||||
@ -192,14 +192,14 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
|
|||||||
x={brushX}
|
x={brushX}
|
||||||
y={brushY}
|
y={brushY}
|
||||||
radius={dotRadius * 2}
|
radius={dotRadius * 2}
|
||||||
fill={'rgba(255,255,255,0.4)'}
|
fill="rgba(255,255,255,0.4)"
|
||||||
listening={false}
|
listening={false}
|
||||||
/>
|
/>
|
||||||
<Circle
|
<Circle
|
||||||
x={brushX}
|
x={brushX}
|
||||||
y={brushY}
|
y={brushY}
|
||||||
radius={dotRadius}
|
radius={dotRadius}
|
||||||
fill={'rgba(0,0,0,1)'}
|
fill="rgba(0,0,0,1)"
|
||||||
listening={false}
|
listening={false}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
@ -269,12 +269,12 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
|||||||
<Transformer
|
<Transformer
|
||||||
anchorCornerRadius={3}
|
anchorCornerRadius={3}
|
||||||
anchorDragBoundFunc={anchorDragBoundFunc}
|
anchorDragBoundFunc={anchorDragBoundFunc}
|
||||||
anchorFill={'rgba(212,216,234,1)'}
|
anchorFill="rgba(212,216,234,1)"
|
||||||
anchorSize={15}
|
anchorSize={15}
|
||||||
anchorStroke={'rgb(42,42,42)'}
|
anchorStroke="rgb(42,42,42)"
|
||||||
borderDash={[4, 4]}
|
borderDash={[4, 4]}
|
||||||
borderEnabled={true}
|
borderEnabled={true}
|
||||||
borderStroke={'black'}
|
borderStroke="black"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
enabledAnchors={tool === 'move' ? undefined : []}
|
enabledAnchors={tool === 'move' ? undefined : []}
|
||||||
flipEnabled={false}
|
flipEnabled={false}
|
||||||
|
@ -121,7 +121,7 @@ const IAICanvasMaskOptions = () => {
|
|||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Flex direction={'column'} gap={'0.5rem'}>
|
<Flex direction="column" gap="0.5rem">
|
||||||
<IAICheckbox
|
<IAICheckbox
|
||||||
label={`${t('unifiedcanvas:enableMask')} (H)`}
|
label={`${t('unifiedcanvas:enableMask')} (H)`}
|
||||||
isChecked={isMaskEnabled}
|
isChecked={isMaskEnabled}
|
||||||
@ -139,7 +139,7 @@ const IAICanvasMaskOptions = () => {
|
|||||||
color={maskColor}
|
color={maskColor}
|
||||||
onChange={(newColor) => dispatch(setMaskColor(newColor))}
|
onChange={(newColor) => dispatch(setMaskColor(newColor))}
|
||||||
/>
|
/>
|
||||||
<IAIButton size={'sm'} leftIcon={<FaTrash />} onClick={handleClearMask}>
|
<IAIButton size="sm" leftIcon={<FaTrash />} onClick={handleClearMask}>
|
||||||
{t('unifiedcanvas:clearMask')} (Shift+C)
|
{t('unifiedcanvas:clearMask')} (Shift+C)
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -97,7 +97,7 @@ const IAICanvasSettingsButtonPopover = () => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Flex direction={'column'} gap={'0.5rem'}>
|
<Flex direction="column" gap="0.5rem">
|
||||||
<IAICheckbox
|
<IAICheckbox
|
||||||
label={t('unifiedcanvas:showIntermediates')}
|
label={t('unifiedcanvas:showIntermediates')}
|
||||||
isChecked={shouldShowIntermediates}
|
isChecked={shouldShowIntermediates}
|
||||||
|
@ -228,13 +228,8 @@ const IAICanvasToolChooserOptions = () => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex minWidth="15rem" direction="column" gap="1rem" width="100%">
|
||||||
minWidth={'15rem'}
|
<Flex gap="1rem" justifyContent="space-between">
|
||||||
direction={'column'}
|
|
||||||
gap={'1rem'}
|
|
||||||
width={'100%'}
|
|
||||||
>
|
|
||||||
<Flex gap={'1rem'} justifyContent="space-between">
|
|
||||||
<IAISlider
|
<IAISlider
|
||||||
label={t('unifiedcanvas:brushSize')}
|
label={t('unifiedcanvas:brushSize')}
|
||||||
value={brushSize}
|
value={brushSize}
|
||||||
|
@ -415,14 +415,14 @@ const CurrentImageButtons = () => {
|
|||||||
>
|
>
|
||||||
<div className="current-image-send-to-popover">
|
<div className="current-image-send-to-popover">
|
||||||
<IAIButton
|
<IAIButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
onClick={handleClickUseAsInitialImage}
|
onClick={handleClickUseAsInitialImage}
|
||||||
leftIcon={<FaShare />}
|
leftIcon={<FaShare />}
|
||||||
>
|
>
|
||||||
{t('parameters:sendToImg2Img')}
|
{t('parameters:sendToImg2Img')}
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
<IAIButton
|
<IAIButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
onClick={handleSendToCanvas}
|
onClick={handleSendToCanvas}
|
||||||
leftIcon={<FaShare />}
|
leftIcon={<FaShare />}
|
||||||
>
|
>
|
||||||
@ -430,14 +430,14 @@ const CurrentImageButtons = () => {
|
|||||||
</IAIButton>
|
</IAIButton>
|
||||||
|
|
||||||
<IAIButton
|
<IAIButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
onClick={handleCopyImage}
|
onClick={handleCopyImage}
|
||||||
leftIcon={<FaCopy />}
|
leftIcon={<FaCopy />}
|
||||||
>
|
>
|
||||||
{t('parameters:copyImage')}
|
{t('parameters:copyImage')}
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
<IAIButton
|
<IAIButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
onClick={handleCopyImageLink}
|
onClick={handleCopyImageLink}
|
||||||
leftIcon={<FaCopy />}
|
leftIcon={<FaCopy />}
|
||||||
>
|
>
|
||||||
@ -445,7 +445,7 @@ const CurrentImageButtons = () => {
|
|||||||
</IAIButton>
|
</IAIButton>
|
||||||
|
|
||||||
<Link download={true} href={currentImage?.url}>
|
<Link download={true} href={currentImage?.url}>
|
||||||
<IAIButton leftIcon={<FaDownload />} size={'sm'} w="100%">
|
<IAIButton leftIcon={<FaDownload />} size="sm" w="100%">
|
||||||
{t('parameters:downloadImage')}
|
{t('parameters:downloadImage')}
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -82,7 +82,7 @@ export default function CurrentImagePreview() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'current-image-preview'}>
|
<div className="current-image-preview">
|
||||||
{imageToDisplay && (
|
{imageToDisplay && (
|
||||||
<Image
|
<Image
|
||||||
src={imageToDisplay.url}
|
src={imageToDisplay.url}
|
||||||
|
@ -116,13 +116,13 @@ const DeleteImageModal = forwardRef(
|
|||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
|
|
||||||
<AlertDialogBody>
|
<AlertDialogBody>
|
||||||
<Flex direction={'column'} gap={5}>
|
<Flex direction="column" gap={5}>
|
||||||
<Text>
|
<Text>
|
||||||
Are you sure? Deleted images will be sent to the Bin. You
|
Are you sure? Deleted images will be sent to the Bin. You
|
||||||
can restore from there if you wish to.
|
can restore from there if you wish to.
|
||||||
</Text>
|
</Text>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems="center">
|
||||||
<FormLabel mb={0}>Don't ask me again</FormLabel>
|
<FormLabel mb={0}>Don't ask me again</FormLabel>
|
||||||
<Switch
|
<Switch
|
||||||
checked={!shouldConfirmOnDelete}
|
checked={!shouldConfirmOnDelete}
|
||||||
|
@ -175,12 +175,12 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
>
|
>
|
||||||
<ContextMenu.Trigger>
|
<ContextMenu.Trigger>
|
||||||
<Box
|
<Box
|
||||||
position={'relative'}
|
position="relative"
|
||||||
key={uuid}
|
key={uuid}
|
||||||
className="hoverable-image"
|
className="hoverable-image"
|
||||||
onMouseOver={handleMouseOver}
|
onMouseOver={handleMouseOver}
|
||||||
onMouseOut={handleMouseOut}
|
onMouseOut={handleMouseOut}
|
||||||
userSelect={'none'}
|
userSelect="none"
|
||||||
draggable={true}
|
draggable={true}
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
>
|
>
|
||||||
@ -189,15 +189,15 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
objectFit={
|
objectFit={
|
||||||
shouldUseSingleGalleryColumn ? 'contain' : galleryImageObjectFit
|
shouldUseSingleGalleryColumn ? 'contain' : galleryImageObjectFit
|
||||||
}
|
}
|
||||||
rounded={'md'}
|
rounded="md"
|
||||||
src={thumbnail || url}
|
src={thumbnail || url}
|
||||||
loading={'lazy'}
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
<div className="hoverable-image-content" onClick={handleSelectImage}>
|
<div className="hoverable-image-content" onClick={handleSelectImage}>
|
||||||
{isSelected && (
|
{isSelected && (
|
||||||
<Icon
|
<Icon
|
||||||
width={'50%'}
|
width="50%"
|
||||||
height={'50%'}
|
height="50%"
|
||||||
as={FaCheck}
|
as={FaCheck}
|
||||||
className="hoverable-image-check"
|
className="hoverable-image-check"
|
||||||
/>
|
/>
|
||||||
@ -210,7 +210,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
aria-label={t('parameters:deleteImage')}
|
aria-label={t('parameters:deleteImage')}
|
||||||
icon={<FaTrashAlt />}
|
icon={<FaTrashAlt />}
|
||||||
size="xs"
|
size="xs"
|
||||||
variant={'imageHoverIconButton'}
|
variant="imageHoverIconButton"
|
||||||
fontSize={14}
|
fontSize={14}
|
||||||
isDisabled={!mayDeleteImage}
|
isDisabled={!mayDeleteImage}
|
||||||
/>
|
/>
|
||||||
@ -221,7 +221,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
</ContextMenu.Trigger>
|
</ContextMenu.Trigger>
|
||||||
<ContextMenu.Content
|
<ContextMenu.Content
|
||||||
className="hoverable-image-context-menu"
|
className="hoverable-image-context-menu"
|
||||||
sticky={'always'}
|
sticky="always"
|
||||||
onInteractOutside={(e) => {
|
onInteractOutside={(e) => {
|
||||||
e.detail.originalEvent.preventDefault();
|
e.detail.originalEvent.preventDefault();
|
||||||
}}
|
}}
|
||||||
|
@ -281,7 +281,7 @@ export default function ImageGallery() {
|
|||||||
<Resizable
|
<Resizable
|
||||||
minWidth={galleryMinWidth}
|
minWidth={galleryMinWidth}
|
||||||
maxWidth={shouldPinGallery ? galleryMaxWidth : window.innerWidth}
|
maxWidth={shouldPinGallery ? galleryMaxWidth : window.innerWidth}
|
||||||
className={'image-gallery-popup'}
|
className="image-gallery-popup"
|
||||||
handleStyles={{
|
handleStyles={{
|
||||||
left: {
|
left: {
|
||||||
width: '15px',
|
width: '15px',
|
||||||
@ -395,14 +395,14 @@ export default function ImageGallery() {
|
|||||||
{shouldShowButtons ? (
|
{shouldShowButtons ? (
|
||||||
<>
|
<>
|
||||||
<IAIButton
|
<IAIButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
data-selected={currentCategory === 'result'}
|
data-selected={currentCategory === 'result'}
|
||||||
onClick={() => dispatch(setCurrentCategory('result'))}
|
onClick={() => dispatch(setCurrentCategory('result'))}
|
||||||
>
|
>
|
||||||
{t('gallery:generations')}
|
{t('gallery:generations')}
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
<IAIButton
|
<IAIButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
data-selected={currentCategory === 'user'}
|
data-selected={currentCategory === 'user'}
|
||||||
onClick={() => dispatch(setCurrentCategory('user'))}
|
onClick={() => dispatch(setCurrentCategory('user'))}
|
||||||
>
|
>
|
||||||
@ -433,14 +433,14 @@ export default function ImageGallery() {
|
|||||||
<IAIPopover
|
<IAIPopover
|
||||||
isLazy
|
isLazy
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
placement={'left'}
|
placement="left"
|
||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
aria-label={t('gallery:gallerySettings')}
|
aria-label={t('gallery:gallerySettings')}
|
||||||
icon={<FaWrench />}
|
icon={<FaWrench />}
|
||||||
className="image-gallery-icon-btn"
|
className="image-gallery-icon-btn"
|
||||||
cursor={'pointer'}
|
cursor="pointer"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -455,7 +455,7 @@ export default function ImageGallery() {
|
|||||||
label={t('gallery:galleryImageSize')}
|
label={t('gallery:galleryImageSize')}
|
||||||
/>
|
/>
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
aria-label={t('gallery:galleryImageResetSize')}
|
aria-label={t('gallery:galleryImageResetSize')}
|
||||||
tooltip={t('gallery:galleryImageResetSize')}
|
tooltip={t('gallery:galleryImageResetSize')}
|
||||||
onClick={() => dispatch(setGalleryImageMinimumWidth(64))}
|
onClick={() => dispatch(setGalleryImageMinimumWidth(64))}
|
||||||
@ -505,8 +505,8 @@ export default function ImageGallery() {
|
|||||||
</IAIPopover>
|
</IAIPopover>
|
||||||
|
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
className={'image-gallery-icon-btn'}
|
className="image-gallery-icon-btn"
|
||||||
aria-label={t('gallery:pinGallery')}
|
aria-label={t('gallery:pinGallery')}
|
||||||
tooltip={`${t('gallery:pinGallery')} (Shift+G)`}
|
tooltip={`${t('gallery:pinGallery')} (Shift+G)`}
|
||||||
onClick={handleSetShouldPinGallery}
|
onClick={handleSetShouldPinGallery}
|
||||||
|
@ -71,8 +71,8 @@ const MetadataItem = ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
aria-label="Use this parameter"
|
aria-label="Use this parameter"
|
||||||
icon={<IoArrowUndoCircleOutline />}
|
icon={<IoArrowUndoCircleOutline />}
|
||||||
size={'xs'}
|
size="xs"
|
||||||
variant={'ghost'}
|
variant="ghost"
|
||||||
fontSize={20}
|
fontSize={20}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
@ -83,23 +83,23 @@ const MetadataItem = ({
|
|||||||
<IconButton
|
<IconButton
|
||||||
aria-label={`Copy ${label}`}
|
aria-label={`Copy ${label}`}
|
||||||
icon={<FaCopy />}
|
icon={<FaCopy />}
|
||||||
size={'xs'}
|
size="xs"
|
||||||
variant={'ghost'}
|
variant="ghost"
|
||||||
fontSize={14}
|
fontSize={14}
|
||||||
onClick={() => navigator.clipboard.writeText(value.toString())}
|
onClick={() => navigator.clipboard.writeText(value.toString())}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<Flex direction={labelPosition ? 'column' : 'row'}>
|
<Flex direction={labelPosition ? 'column' : 'row'}>
|
||||||
<Text fontWeight={'semibold'} whiteSpace={'pre-wrap'} pr={2}>
|
<Text fontWeight="semibold" whiteSpace="pre-wrap" pr={2}>
|
||||||
{label}:
|
{label}:
|
||||||
</Text>
|
</Text>
|
||||||
{isLink ? (
|
{isLink ? (
|
||||||
<Link href={value.toString()} isExternal wordBreak={'break-all'}>
|
<Link href={value.toString()} isExternal wordBreak="break-all">
|
||||||
{value.toString()} <ExternalLinkIcon mx="2px" />
|
{value.toString()} <ExternalLinkIcon mx="2px" />
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<Text overflowY={'scroll'} wordBreak={'break-all'}>
|
<Text overflowY="scroll" wordBreak="break-all">
|
||||||
{value.toString()}
|
{value.toString()}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
@ -163,10 +163,10 @@ const ImageMetadataViewer = memo(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`image-metadata-viewer ${styleClass}`}>
|
<div className={`image-metadata-viewer ${styleClass}`}>
|
||||||
<Flex gap={1} direction={'column'} width={'100%'}>
|
<Flex gap={1} direction="column" width="100%">
|
||||||
<Flex gap={2}>
|
<Flex gap={2}>
|
||||||
<Text fontWeight={'semibold'}>File:</Text>
|
<Text fontWeight="semibold">File:</Text>
|
||||||
<Link href={image.url} isExternal maxW={'calc(100% - 3rem)'}>
|
<Link href={image.url} isExternal maxW="calc(100% - 3rem)">
|
||||||
{image.url.length > 64
|
{image.url.length > 64
|
||||||
? image.url.substring(0, 64).concat('...')
|
? image.url.substring(0, 64).concat('...')
|
||||||
: image.url}
|
: image.url}
|
||||||
@ -304,7 +304,7 @@ const ImageMetadataViewer = memo(
|
|||||||
)}
|
)}
|
||||||
{postprocessing && postprocessing.length > 0 && (
|
{postprocessing && postprocessing.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Heading size={'sm'}>Postprocessing</Heading>
|
<Heading size="sm">Postprocessing</Heading>
|
||||||
{postprocessing.map(
|
{postprocessing.map(
|
||||||
(
|
(
|
||||||
postprocess: InvokeAI.PostProcessedImageMetadata,
|
postprocess: InvokeAI.PostProcessedImageMetadata,
|
||||||
@ -313,13 +313,8 @@ const ImageMetadataViewer = memo(
|
|||||||
if (postprocess.type === 'esrgan') {
|
if (postprocess.type === 'esrgan') {
|
||||||
const { scale, strength, denoise_str } = postprocess;
|
const { scale, strength, denoise_str } = postprocess;
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex key={i} pl="2rem" gap={1} direction="column">
|
||||||
key={i}
|
<Text size="md">{`${
|
||||||
pl={'2rem'}
|
|
||||||
gap={1}
|
|
||||||
direction={'column'}
|
|
||||||
>
|
|
||||||
<Text size={'md'}>{`${
|
|
||||||
i + 1
|
i + 1
|
||||||
}: Upscale (ESRGAN)`}</Text>
|
}: Upscale (ESRGAN)`}</Text>
|
||||||
<MetadataItem
|
<MetadataItem
|
||||||
@ -348,13 +343,8 @@ const ImageMetadataViewer = memo(
|
|||||||
} else if (postprocess.type === 'gfpgan') {
|
} else if (postprocess.type === 'gfpgan') {
|
||||||
const { strength } = postprocess;
|
const { strength } = postprocess;
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex key={i} pl="2rem" gap={1} direction="column">
|
||||||
key={i}
|
<Text size="md">{`${
|
||||||
pl={'2rem'}
|
|
||||||
gap={1}
|
|
||||||
direction={'column'}
|
|
||||||
>
|
|
||||||
<Text size={'md'}>{`${
|
|
||||||
i + 1
|
i + 1
|
||||||
}: Face restoration (GFPGAN)`}</Text>
|
}: Face restoration (GFPGAN)`}</Text>
|
||||||
|
|
||||||
@ -371,13 +361,8 @@ const ImageMetadataViewer = memo(
|
|||||||
} else if (postprocess.type === 'codeformer') {
|
} else if (postprocess.type === 'codeformer') {
|
||||||
const { strength, fidelity } = postprocess;
|
const { strength, fidelity } = postprocess;
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex key={i} pl="2rem" gap={1} direction="column">
|
||||||
key={i}
|
<Text size="md">{`${
|
||||||
pl={'2rem'}
|
|
||||||
gap={1}
|
|
||||||
direction={'column'}
|
|
||||||
>
|
|
||||||
<Text size={'md'}>{`${
|
|
||||||
i + 1
|
i + 1
|
||||||
}: Face restoration (Codeformer)`}</Text>
|
}: Face restoration (Codeformer)`}</Text>
|
||||||
|
|
||||||
@ -413,30 +398,30 @@ const ImageMetadataViewer = memo(
|
|||||||
value={dreamPrompt}
|
value={dreamPrompt}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Flex gap={2} direction={'column'}>
|
<Flex gap={2} direction="column">
|
||||||
<Flex gap={2}>
|
<Flex gap={2}>
|
||||||
<Tooltip label={`Copy metadata JSON`}>
|
<Tooltip label="Copy metadata JSON">
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="Copy metadata JSON"
|
aria-label="Copy metadata JSON"
|
||||||
icon={<FaCopy />}
|
icon={<FaCopy />}
|
||||||
size={'xs'}
|
size="xs"
|
||||||
variant={'ghost'}
|
variant="ghost"
|
||||||
fontSize={14}
|
fontSize={14}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigator.clipboard.writeText(metadataJSON)
|
navigator.clipboard.writeText(metadataJSON)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Text fontWeight={'semibold'}>Metadata JSON:</Text>
|
<Text fontWeight="semibold">Metadata JSON:</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<div className={'image-json-viewer'}>
|
<div className="image-json-viewer">
|
||||||
<pre>{metadataJSON}</pre>
|
<pre>{metadataJSON}</pre>
|
||||||
</div>
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Center width={'100%'} pt={10}>
|
<Center width="100%" pt={10}>
|
||||||
<Text fontSize={'lg'} fontWeight="semibold">
|
<Text fontSize="lg" fontWeight="semibold">
|
||||||
No metadata available
|
No metadata available
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
|
@ -23,8 +23,8 @@ export default function InvokeAccordionItem(props: InvokeAccordionItemProps) {
|
|||||||
return (
|
return (
|
||||||
<AccordionItem className="advanced-parameters-item">
|
<AccordionItem className="advanced-parameters-item">
|
||||||
<AccordionButton className="advanced-parameters-header">
|
<AccordionButton className="advanced-parameters-header">
|
||||||
<Flex width={'100%'} gap={'0.5rem'} align={'center'}>
|
<Flex width="100%" gap="0.5rem" align="center">
|
||||||
<Box flexGrow={1} textAlign={'left'}>
|
<Box flexGrow={1} textAlign="left">
|
||||||
{header}
|
{header}
|
||||||
</Box>
|
</Box>
|
||||||
{additionalHeaderComponents}
|
{additionalHeaderComponents}
|
||||||
|
@ -63,7 +63,7 @@ const FaceRestoreSettings = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction={'column'} gap={2}>
|
<Flex direction="column" gap={2}>
|
||||||
<IAISelect
|
<IAISelect
|
||||||
label={t('parameters:type')}
|
label={t('parameters:type')}
|
||||||
validValues={FACETOOL_TYPES.concat()}
|
validValues={FACETOOL_TYPES.concat()}
|
||||||
|
@ -36,7 +36,7 @@ export default function ImageToImageStrength(props: ImageToImageStrengthProps) {
|
|||||||
styleClass={styleClass}
|
styleClass={styleClass}
|
||||||
withInput
|
withInput
|
||||||
withSliderMarks
|
withSliderMarks
|
||||||
inputWidth={'5.5rem'}
|
inputWidth="5.5rem"
|
||||||
withReset
|
withReset
|
||||||
handleReset={handleImg2ImgStrengthReset}
|
handleReset={handleImg2ImgStrengthReset}
|
||||||
/>
|
/>
|
||||||
|
@ -49,7 +49,7 @@ const HiresStrength = () => {
|
|||||||
isInteger={false}
|
isInteger={false}
|
||||||
withInput
|
withInput
|
||||||
withSliderMarks
|
withSliderMarks
|
||||||
inputWidth={'5.5rem'}
|
inputWidth="5.5rem"
|
||||||
withReset
|
withReset
|
||||||
handleReset={handleHiResStrengthReset}
|
handleReset={handleHiResStrengthReset}
|
||||||
isSliderDisabled={!hiresFix}
|
isSliderDisabled={!hiresFix}
|
||||||
@ -75,10 +75,10 @@ const HiresSettings = () => {
|
|||||||
dispatch(setHiresFix(e.target.checked));
|
dispatch(setHiresFix(e.target.checked));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap={2} direction={'column'}>
|
<Flex gap={2} direction="column">
|
||||||
<IAISwitch
|
<IAISwitch
|
||||||
label={t('parameters:hiresOptim')}
|
label={t('parameters:hiresOptim')}
|
||||||
fontSize={'md'}
|
fontSize="md"
|
||||||
isChecked={hiresFix}
|
isChecked={hiresFix}
|
||||||
onChange={handleChangeHiresFix}
|
onChange={handleChangeHiresFix}
|
||||||
/>
|
/>
|
||||||
|
@ -3,7 +3,7 @@ import SeamlessSettings from './SeamlessSettings';
|
|||||||
|
|
||||||
const ImageToImageOutputSettings = () => {
|
const ImageToImageOutputSettings = () => {
|
||||||
return (
|
return (
|
||||||
<Flex gap={2} direction={'column'}>
|
<Flex gap={2} direction="column">
|
||||||
<SeamlessSettings />
|
<SeamlessSettings />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@ import SeamlessSettings from './SeamlessSettings';
|
|||||||
|
|
||||||
const OutputSettings = () => {
|
const OutputSettings = () => {
|
||||||
return (
|
return (
|
||||||
<Flex gap={2} direction={'column'}>
|
<Flex gap={2} direction="column">
|
||||||
<SeamlessSettings />
|
<SeamlessSettings />
|
||||||
<HiresSettings />
|
<HiresSettings />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -22,10 +22,10 @@ const SeamlessSettings = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap={2} direction={'column'}>
|
<Flex gap={2} direction="column">
|
||||||
<IAISwitch
|
<IAISwitch
|
||||||
label={t('parameters:seamlessTiling')}
|
label={t('parameters:seamlessTiling')}
|
||||||
fontSize={'md'}
|
fontSize="md"
|
||||||
isChecked={seamless}
|
isChecked={seamless}
|
||||||
onChange={handleChangeSeamless}
|
onChange={handleChangeSeamless}
|
||||||
/>
|
/>
|
||||||
|
@ -10,7 +10,7 @@ import Threshold from './Threshold';
|
|||||||
*/
|
*/
|
||||||
const SeedSettings = () => {
|
const SeedSettings = () => {
|
||||||
return (
|
return (
|
||||||
<Flex gap={2} direction={'column'}>
|
<Flex gap={2} direction="column">
|
||||||
<RandomizeSeed />
|
<RandomizeSeed />
|
||||||
<Flex gap={2}>
|
<Flex gap={2}>
|
||||||
<Seed />
|
<Seed />
|
||||||
|
@ -18,7 +18,7 @@ export default function ShuffleSeed() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
size={'sm'}
|
size="sm"
|
||||||
isDisabled={shouldRandomizeSeed}
|
isDisabled={shouldRandomizeSeed}
|
||||||
onClick={handleClickRandomizeSeed}
|
onClick={handleClickRandomizeSeed}
|
||||||
padding="0 1.5rem"
|
padding="0 1.5rem"
|
||||||
|
@ -18,7 +18,7 @@ export default function GenerateVariationsToggle() {
|
|||||||
return (
|
return (
|
||||||
<IAISwitch
|
<IAISwitch
|
||||||
isChecked={shouldGenerateVariations}
|
isChecked={shouldGenerateVariations}
|
||||||
width={'auto'}
|
width="auto"
|
||||||
onChange={handleChangeShouldGenerateVariations}
|
onChange={handleChangeShouldGenerateVariations}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -7,7 +7,7 @@ import VariationAmount from './VariationAmount';
|
|||||||
*/
|
*/
|
||||||
const VariationsSettings = () => {
|
const VariationsSettings = () => {
|
||||||
return (
|
return (
|
||||||
<Flex gap={2} direction={'column'}>
|
<Flex gap={2} direction="column">
|
||||||
<VariationAmount />
|
<VariationAmount />
|
||||||
<SeedWeights />
|
<SeedWeights />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -71,7 +71,7 @@ const PromptInput = () => {
|
|||||||
id="prompt"
|
id="prompt"
|
||||||
name="prompt"
|
name="prompt"
|
||||||
placeholder={t('parameters:promptPlaceholder')}
|
placeholder={t('parameters:promptPlaceholder')}
|
||||||
size={'lg'}
|
size="lg"
|
||||||
value={prompt}
|
value={prompt}
|
||||||
onChange={handleChangePrompt}
|
onChange={handleChangePrompt}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
@ -27,7 +27,7 @@ const EmptyTempFolderButtonModal = () => {
|
|||||||
acceptCallback={acceptCallback}
|
acceptCallback={acceptCallback}
|
||||||
acceptButtonText={t('unifiedcanvas:emptyFolder')}
|
acceptButtonText={t('unifiedcanvas:emptyFolder')}
|
||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIButton leftIcon={<FaTrash />} size={'sm'} isDisabled={isStaging}>
|
<IAIButton leftIcon={<FaTrash />} size="sm" isDisabled={isStaging}>
|
||||||
{t('unifiedcanvas:emptyTempImageFolder')}
|
{t('unifiedcanvas:emptyTempImageFolder')}
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ const Console = () => {
|
|||||||
bottom: 0,
|
bottom: 0,
|
||||||
zIndex: 9999,
|
zIndex: 9999,
|
||||||
}}
|
}}
|
||||||
maxHeight={'90vh'}
|
maxHeight="90vh"
|
||||||
>
|
>
|
||||||
<div className="console" ref={viewerRef} onScroll={handleOnScroll}>
|
<div className="console" ref={viewerRef} onScroll={handleOnScroll}>
|
||||||
{log.map((entry, i) => {
|
{log.map((entry, i) => {
|
||||||
@ -130,11 +130,11 @@ const Console = () => {
|
|||||||
label={shouldAutoscroll ? 'Autoscroll On' : 'Autoscroll Off'}
|
label={shouldAutoscroll ? 'Autoscroll On' : 'Autoscroll Off'}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={'console-autoscroll-icon-button'}
|
className="console-autoscroll-icon-button"
|
||||||
data-autoscroll-enabled={shouldAutoscroll}
|
data-autoscroll-enabled={shouldAutoscroll}
|
||||||
size="sm"
|
size="sm"
|
||||||
aria-label="Toggle autoscroll"
|
aria-label="Toggle autoscroll"
|
||||||
variant={'solid'}
|
variant="solid"
|
||||||
icon={<FaAngleDoubleDown />}
|
icon={<FaAngleDoubleDown />}
|
||||||
onClick={() => setShouldAutoscroll(!shouldAutoscroll)}
|
onClick={() => setShouldAutoscroll(!shouldAutoscroll)}
|
||||||
/>
|
/>
|
||||||
@ -145,11 +145,11 @@ const Console = () => {
|
|||||||
label={shouldShowLogViewer ? 'Hide Console' : 'Show Console'}
|
label={shouldShowLogViewer ? 'Hide Console' : 'Show Console'}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={'console-toggle-icon-button'}
|
className="console-toggle-icon-button"
|
||||||
data-error-seen={hasError || !wasErrorSeen}
|
data-error-seen={hasError || !wasErrorSeen}
|
||||||
size="sm"
|
size="sm"
|
||||||
position={'fixed'}
|
position="fixed"
|
||||||
variant={'solid'}
|
variant="solid"
|
||||||
aria-label="Toggle Log Viewer"
|
aria-label="Toggle Log Viewer"
|
||||||
icon={shouldShowLogViewer ? <FaMinus /> : <FaCode />}
|
icon={shouldShowLogViewer ? <FaMinus /> : <FaCode />}
|
||||||
onClick={handleClickLogViewerToggle}
|
onClick={handleClickLogViewerToggle}
|
||||||
|
@ -54,7 +54,7 @@ export default function LanguagePicker() {
|
|||||||
aria-label={t('common:languagePickerLabel')}
|
aria-label={t('common:languagePickerLabel')}
|
||||||
tooltip={t('common:languagePickerLabel')}
|
tooltip={t('common:languagePickerLabel')}
|
||||||
icon={<FaLanguage />}
|
icon={<FaLanguage />}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={26}
|
fontSize={26}
|
||||||
|
@ -99,8 +99,8 @@ export default function AddCheckpointModel() {
|
|||||||
>
|
>
|
||||||
{({ handleSubmit, errors, touched }) => (
|
{({ handleSubmit, errors, touched }) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<VStack rowGap={'0.5rem'}>
|
<VStack rowGap="0.5rem">
|
||||||
<Text fontSize={20} fontWeight="bold" alignSelf={'start'}>
|
<Text fontSize={20} fontWeight="bold" alignSelf="start">
|
||||||
{t('modelmanager:manual')}
|
{t('modelmanager:manual')}
|
||||||
</Text>
|
</Text>
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
@ -111,7 +111,7 @@ export default function AddCheckpointModel() {
|
|||||||
<FormLabel htmlFor="name" fontSize="sm">
|
<FormLabel htmlFor="name" fontSize="sm">
|
||||||
{t('modelmanager:name')}
|
{t('modelmanager:name')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="name"
|
id="name"
|
||||||
@ -138,7 +138,7 @@ export default function AddCheckpointModel() {
|
|||||||
<FormLabel htmlFor="description" fontSize="sm">
|
<FormLabel htmlFor="description" fontSize="sm">
|
||||||
{t('modelmanager:description')}
|
{t('modelmanager:description')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="description"
|
id="description"
|
||||||
@ -164,7 +164,7 @@ export default function AddCheckpointModel() {
|
|||||||
<FormLabel htmlFor="config" fontSize="sm">
|
<FormLabel htmlFor="config" fontSize="sm">
|
||||||
{t('modelmanager:config')}
|
{t('modelmanager:config')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="config"
|
id="config"
|
||||||
@ -190,7 +190,7 @@ export default function AddCheckpointModel() {
|
|||||||
<FormLabel htmlFor="config" fontSize="sm">
|
<FormLabel htmlFor="config" fontSize="sm">
|
||||||
{t('modelmanager:modelLocation')}
|
{t('modelmanager:modelLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="weights"
|
id="weights"
|
||||||
@ -213,7 +213,7 @@ export default function AddCheckpointModel() {
|
|||||||
<FormLabel htmlFor="vae" fontSize="sm">
|
<FormLabel htmlFor="vae" fontSize="sm">
|
||||||
{t('modelmanager:vaeLocation')}
|
{t('modelmanager:vaeLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="vae"
|
id="vae"
|
||||||
@ -231,13 +231,13 @@ export default function AddCheckpointModel() {
|
|||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<HStack width={'100%'}>
|
<HStack width="100%">
|
||||||
{/* Width */}
|
{/* Width */}
|
||||||
<FormControl isInvalid={!!errors.width && touched.width}>
|
<FormControl isInvalid={!!errors.width && touched.width}>
|
||||||
<FormLabel htmlFor="width" fontSize="sm">
|
<FormLabel htmlFor="width" fontSize="sm">
|
||||||
{t('modelmanager:width')}
|
{t('modelmanager:width')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field id="width" name="width">
|
<Field id="width" name="width">
|
||||||
{({
|
{({
|
||||||
field,
|
field,
|
||||||
@ -276,7 +276,7 @@ export default function AddCheckpointModel() {
|
|||||||
<FormLabel htmlFor="height" fontSize="sm">
|
<FormLabel htmlFor="height" fontSize="sm">
|
||||||
{t('modelmanager:height')}
|
{t('modelmanager:height')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field id="height" name="height">
|
<Field id="height" name="height">
|
||||||
{({
|
{({
|
||||||
field,
|
field,
|
||||||
|
@ -105,7 +105,7 @@ export default function AddDiffusersModel() {
|
|||||||
>
|
>
|
||||||
{({ handleSubmit, errors, touched }) => (
|
{({ handleSubmit, errors, touched }) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<VStack rowGap={'0.5rem'}>
|
<VStack rowGap="0.5rem">
|
||||||
<FormItemWrapper>
|
<FormItemWrapper>
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
<FormControl
|
<FormControl
|
||||||
@ -115,7 +115,7 @@ export default function AddDiffusersModel() {
|
|||||||
<FormLabel htmlFor="name" fontSize="sm">
|
<FormLabel htmlFor="name" fontSize="sm">
|
||||||
{t('modelmanager:name')}
|
{t('modelmanager:name')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="name"
|
id="name"
|
||||||
@ -145,7 +145,7 @@ export default function AddDiffusersModel() {
|
|||||||
<FormLabel htmlFor="description" fontSize="sm">
|
<FormLabel htmlFor="description" fontSize="sm">
|
||||||
{t('modelmanager:description')}
|
{t('modelmanager:description')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="description"
|
id="description"
|
||||||
@ -182,7 +182,7 @@ export default function AddDiffusersModel() {
|
|||||||
<FormLabel htmlFor="path" fontSize="sm">
|
<FormLabel htmlFor="path" fontSize="sm">
|
||||||
{t('modelmanager:modelLocation')}
|
{t('modelmanager:modelLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="path"
|
id="path"
|
||||||
@ -205,7 +205,7 @@ export default function AddDiffusersModel() {
|
|||||||
<FormLabel htmlFor="repo_id" fontSize="sm">
|
<FormLabel htmlFor="repo_id" fontSize="sm">
|
||||||
{t('modelmanager:repo_id')}
|
{t('modelmanager:repo_id')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="repo_id"
|
id="repo_id"
|
||||||
@ -242,7 +242,7 @@ export default function AddDiffusersModel() {
|
|||||||
<FormLabel htmlFor="vae.path" fontSize="sm">
|
<FormLabel htmlFor="vae.path" fontSize="sm">
|
||||||
{t('modelmanager:vaeLocation')}
|
{t('modelmanager:vaeLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="vae.path"
|
id="vae.path"
|
||||||
@ -267,7 +267,7 @@ export default function AddDiffusersModel() {
|
|||||||
<FormLabel htmlFor="vae.repo_id" fontSize="sm">
|
<FormLabel htmlFor="vae.repo_id" fontSize="sm">
|
||||||
{t('modelmanager:vaeRepoID')}
|
{t('modelmanager:vaeRepoID')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="vae.repo_id"
|
id="vae.repo_id"
|
||||||
|
@ -72,9 +72,9 @@ export default function AddModel() {
|
|||||||
tooltip={t('modelmanager:addNewModel')}
|
tooltip={t('modelmanager:addNewModel')}
|
||||||
onClick={onOpen}
|
onClick={onOpen}
|
||||||
className="modal-close-btn"
|
className="modal-close-btn"
|
||||||
size={'sm'}
|
size="sm"
|
||||||
>
|
>
|
||||||
<Flex columnGap={'0.5rem'} alignItems="center">
|
<Flex columnGap="0.5rem" alignItems="center">
|
||||||
<FaPlus />
|
<FaPlus />
|
||||||
{t('modelmanager:addNew')}
|
{t('modelmanager:addNew')}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -27,6 +27,7 @@ import type { InvokeModelConfigProps } from 'app/invokeai';
|
|||||||
import type { RootState } from 'app/store';
|
import type { RootState } from 'app/store';
|
||||||
import type { FieldInputProps, FormikProps } from 'formik';
|
import type { FieldInputProps, FormikProps } from 'formik';
|
||||||
import { isEqual, pickBy } from 'lodash';
|
import { isEqual, pickBy } from 'lodash';
|
||||||
|
import ModelConvert from './ModelConvert';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[systemSelector],
|
[systemSelector],
|
||||||
@ -101,10 +102,11 @@ export default function CheckpointModelEdit() {
|
|||||||
|
|
||||||
return openModel ? (
|
return openModel ? (
|
||||||
<Flex flexDirection="column" rowGap="1rem" width="100%">
|
<Flex flexDirection="column" rowGap="1rem" width="100%">
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center" gap={4} justifyContent="space-between">
|
||||||
<Text fontSize="lg" fontWeight="bold">
|
<Text fontSize="lg" fontWeight="bold">
|
||||||
{openModel}
|
{openModel}
|
||||||
</Text>
|
</Text>
|
||||||
|
<ModelConvert model={openModel} />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex
|
<Flex
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
@ -119,7 +121,7 @@ export default function CheckpointModelEdit() {
|
|||||||
>
|
>
|
||||||
{({ handleSubmit, errors, touched }) => (
|
{({ handleSubmit, errors, touched }) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<VStack rowGap={'0.5rem'} alignItems="start">
|
<VStack rowGap="0.5rem" alignItems="start">
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<FormControl
|
<FormControl
|
||||||
isInvalid={!!errors.description && touched.description}
|
isInvalid={!!errors.description && touched.description}
|
||||||
@ -128,7 +130,7 @@ export default function CheckpointModelEdit() {
|
|||||||
<FormLabel htmlFor="description" fontSize="sm">
|
<FormLabel htmlFor="description" fontSize="sm">
|
||||||
{t('modelmanager:description')}
|
{t('modelmanager:description')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="description"
|
id="description"
|
||||||
@ -154,7 +156,7 @@ export default function CheckpointModelEdit() {
|
|||||||
<FormLabel htmlFor="config" fontSize="sm">
|
<FormLabel htmlFor="config" fontSize="sm">
|
||||||
{t('modelmanager:config')}
|
{t('modelmanager:config')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="config"
|
id="config"
|
||||||
@ -180,7 +182,7 @@ export default function CheckpointModelEdit() {
|
|||||||
<FormLabel htmlFor="config" fontSize="sm">
|
<FormLabel htmlFor="config" fontSize="sm">
|
||||||
{t('modelmanager:modelLocation')}
|
{t('modelmanager:modelLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="weights"
|
id="weights"
|
||||||
@ -203,7 +205,7 @@ export default function CheckpointModelEdit() {
|
|||||||
<FormLabel htmlFor="vae" fontSize="sm">
|
<FormLabel htmlFor="vae" fontSize="sm">
|
||||||
{t('modelmanager:vaeLocation')}
|
{t('modelmanager:vaeLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="vae"
|
id="vae"
|
||||||
@ -221,13 +223,13 @@ export default function CheckpointModelEdit() {
|
|||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<HStack width={'100%'}>
|
<HStack width="100%">
|
||||||
{/* Width */}
|
{/* Width */}
|
||||||
<FormControl isInvalid={!!errors.width && touched.width}>
|
<FormControl isInvalid={!!errors.width && touched.width}>
|
||||||
<FormLabel htmlFor="width" fontSize="sm">
|
<FormLabel htmlFor="width" fontSize="sm">
|
||||||
{t('modelmanager:width')}
|
{t('modelmanager:width')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field id="width" name="width">
|
<Field id="width" name="width">
|
||||||
{({
|
{({
|
||||||
field,
|
field,
|
||||||
@ -265,7 +267,7 @@ export default function CheckpointModelEdit() {
|
|||||||
<FormLabel htmlFor="height" fontSize="sm">
|
<FormLabel htmlFor="height" fontSize="sm">
|
||||||
{t('modelmanager:height')}
|
{t('modelmanager:height')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field id="height" name="height">
|
<Field id="height" name="height">
|
||||||
{({
|
{({
|
||||||
field,
|
field,
|
||||||
|
@ -128,7 +128,7 @@ export default function DiffusersModelEdit() {
|
|||||||
>
|
>
|
||||||
{({ handleSubmit, errors, touched }) => (
|
{({ handleSubmit, errors, touched }) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<VStack rowGap={'0.5rem'} alignItems="start">
|
<VStack rowGap="0.5rem" alignItems="start">
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<FormControl
|
<FormControl
|
||||||
isInvalid={!!errors.description && touched.description}
|
isInvalid={!!errors.description && touched.description}
|
||||||
@ -137,7 +137,7 @@ export default function DiffusersModelEdit() {
|
|||||||
<FormLabel htmlFor="description" fontSize="sm">
|
<FormLabel htmlFor="description" fontSize="sm">
|
||||||
{t('modelmanager:description')}
|
{t('modelmanager:description')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="description"
|
id="description"
|
||||||
@ -163,7 +163,7 @@ export default function DiffusersModelEdit() {
|
|||||||
<FormLabel htmlFor="path" fontSize="sm">
|
<FormLabel htmlFor="path" fontSize="sm">
|
||||||
{t('modelmanager:modelLocation')}
|
{t('modelmanager:modelLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="path"
|
id="path"
|
||||||
@ -186,7 +186,7 @@ export default function DiffusersModelEdit() {
|
|||||||
<FormLabel htmlFor="repo_id" fontSize="sm">
|
<FormLabel htmlFor="repo_id" fontSize="sm">
|
||||||
{t('modelmanager:repo_id')}
|
{t('modelmanager:repo_id')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="repo_id"
|
id="repo_id"
|
||||||
@ -211,7 +211,7 @@ export default function DiffusersModelEdit() {
|
|||||||
<FormLabel htmlFor="vae.path" fontSize="sm">
|
<FormLabel htmlFor="vae.path" fontSize="sm">
|
||||||
{t('modelmanager:vaeLocation')}
|
{t('modelmanager:vaeLocation')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="vae.path"
|
id="vae.path"
|
||||||
@ -236,7 +236,7 @@ export default function DiffusersModelEdit() {
|
|||||||
<FormLabel htmlFor="vae.repo_id" fontSize="sm">
|
<FormLabel htmlFor="vae.repo_id" fontSize="sm">
|
||||||
{t('modelmanager:vaeRepoID')}
|
{t('modelmanager:vaeRepoID')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<Field
|
<Field
|
||||||
as={IAIInput}
|
as={IAIInput}
|
||||||
id="vae.repo_id"
|
id="vae.repo_id"
|
||||||
|
@ -0,0 +1,148 @@
|
|||||||
|
import {
|
||||||
|
Flex,
|
||||||
|
ListItem,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
|
Text,
|
||||||
|
UnorderedList,
|
||||||
|
Tooltip,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { convertToDiffusers } from 'app/socketio/actions';
|
||||||
|
import { RootState } from 'app/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||||
|
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import IAIInput from 'common/components/IAIInput';
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
interface ModelConvertProps {
|
||||||
|
model: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ModelConvert(props: ModelConvertProps) {
|
||||||
|
const { model } = props;
|
||||||
|
|
||||||
|
const model_list = useAppSelector(
|
||||||
|
(state: RootState) => state.system.model_list
|
||||||
|
);
|
||||||
|
|
||||||
|
const retrievedModel = model_list[model];
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const isProcessing = useAppSelector(
|
||||||
|
(state: RootState) => state.system.isProcessing
|
||||||
|
);
|
||||||
|
|
||||||
|
const isConnected = useAppSelector(
|
||||||
|
(state: RootState) => state.system.isConnected
|
||||||
|
);
|
||||||
|
|
||||||
|
const [saveLocation, setSaveLocation] = useState<string>('same');
|
||||||
|
const [customSaveLocation, setCustomSaveLocation] = useState<string>('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSaveLocation('same');
|
||||||
|
}, [model]);
|
||||||
|
|
||||||
|
const modelConvertCancelHandler = () => {
|
||||||
|
setSaveLocation('same');
|
||||||
|
};
|
||||||
|
|
||||||
|
const modelConvertHandler = () => {
|
||||||
|
const modelToConvert = {
|
||||||
|
model_name: model,
|
||||||
|
save_location: saveLocation,
|
||||||
|
custom_location:
|
||||||
|
saveLocation === 'custom' && customSaveLocation !== ''
|
||||||
|
? customSaveLocation
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
dispatch(convertToDiffusers(modelToConvert));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAIAlertDialog
|
||||||
|
title={`${t('modelmanager:convert')} ${model}`}
|
||||||
|
acceptCallback={modelConvertHandler}
|
||||||
|
cancelCallback={modelConvertCancelHandler}
|
||||||
|
acceptButtonText={`${t('modelmanager:convert')}`}
|
||||||
|
triggerComponent={
|
||||||
|
<IAIButton
|
||||||
|
size={'sm'}
|
||||||
|
aria-label={t('modelmanager:convertToDiffusers')}
|
||||||
|
isDisabled={
|
||||||
|
retrievedModel.status === 'active' || isProcessing || !isConnected
|
||||||
|
}
|
||||||
|
className=" modal-close-btn"
|
||||||
|
marginRight="2rem"
|
||||||
|
>
|
||||||
|
🧨 {t('modelmanager:convertToDiffusers')}
|
||||||
|
</IAIButton>
|
||||||
|
}
|
||||||
|
motionPreset="slideInBottom"
|
||||||
|
>
|
||||||
|
<Flex flexDirection="column" rowGap={4}>
|
||||||
|
<Text>{t('modelmanager:convertToDiffusersHelpText1')}</Text>
|
||||||
|
<UnorderedList>
|
||||||
|
<ListItem>{t('modelmanager:convertToDiffusersHelpText2')}</ListItem>
|
||||||
|
<ListItem>{t('modelmanager:convertToDiffusersHelpText3')}</ListItem>
|
||||||
|
<ListItem>{t('modelmanager:convertToDiffusersHelpText4')}</ListItem>
|
||||||
|
<ListItem>{t('modelmanager:convertToDiffusersHelpText5')}</ListItem>
|
||||||
|
</UnorderedList>
|
||||||
|
<Text>{t('modelmanager:convertToDiffusersHelpText6')}</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex flexDir="column" gap={4}>
|
||||||
|
<Flex marginTop="1rem" flexDir="column" gap={2}>
|
||||||
|
<Text fontWeight="bold">
|
||||||
|
{t('modelmanager:convertToDiffusersSaveLocation')}
|
||||||
|
</Text>
|
||||||
|
<RadioGroup value={saveLocation} onChange={(v) => setSaveLocation(v)}>
|
||||||
|
<Flex gap={4}>
|
||||||
|
<Radio value="same">
|
||||||
|
<Tooltip label="Save converted model in the same folder">
|
||||||
|
{t('modelmanager:sameFolder')}
|
||||||
|
</Tooltip>
|
||||||
|
</Radio>
|
||||||
|
|
||||||
|
<Radio value="root">
|
||||||
|
<Tooltip label="Save converted model in the InvokeAI root folder">
|
||||||
|
{t('modelmanager:invokeRoot')}
|
||||||
|
</Tooltip>
|
||||||
|
</Radio>
|
||||||
|
|
||||||
|
<Radio value="custom">
|
||||||
|
<Tooltip label="Save converted model in a custom folder">
|
||||||
|
{t('modelmanager:custom')}
|
||||||
|
</Tooltip>
|
||||||
|
</Radio>
|
||||||
|
</Flex>
|
||||||
|
</RadioGroup>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{saveLocation === 'custom' && (
|
||||||
|
<Flex flexDirection="column" rowGap={2}>
|
||||||
|
<Text
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="sm"
|
||||||
|
color="var(--text-color-secondary)"
|
||||||
|
>
|
||||||
|
{t('modelmanager:customSaveLocation')}
|
||||||
|
</Text>
|
||||||
|
<IAIInput
|
||||||
|
value={customSaveLocation}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value !== '')
|
||||||
|
setCustomSaveLocation(e.target.value);
|
||||||
|
}}
|
||||||
|
width="25rem"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</IAIAlertDialog>
|
||||||
|
);
|
||||||
|
}
|
@ -176,9 +176,9 @@ const ModelList = () => {
|
|||||||
}, [models, searchText, t, isSelectedFilter]);
|
}, [models, searchText, t, isSelectedFilter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDirection={'column'} rowGap="2rem" width="50%" minWidth="50%">
|
<Flex flexDirection="column" rowGap="2rem" width="50%" minWidth="50%">
|
||||||
<Flex justifyContent={'space-between'}>
|
<Flex justifyContent="space-between">
|
||||||
<Text fontSize={'1.4rem'} fontWeight="bold">
|
<Text fontSize="1.4rem" fontWeight="bold">
|
||||||
{t('modelmanager:availableModels')}
|
{t('modelmanager:availableModels')}
|
||||||
</Text>
|
</Text>
|
||||||
<AddModel />
|
<AddModel />
|
||||||
@ -190,10 +190,10 @@ const ModelList = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
flexDirection={'column'}
|
flexDirection="column"
|
||||||
gap={1}
|
gap={1}
|
||||||
maxHeight={window.innerHeight - 360}
|
maxHeight={window.innerHeight - 360}
|
||||||
overflow={'scroll'}
|
overflow="scroll"
|
||||||
paddingRight="1rem"
|
paddingRight="1rem"
|
||||||
>
|
>
|
||||||
<Flex columnGap="0.5rem">
|
<Flex columnGap="0.5rem">
|
||||||
|
@ -56,7 +56,7 @@ export default function ModelListItem(props: ModelListItemProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
alignItems={'center'}
|
alignItems="center"
|
||||||
padding="0.5rem 0.5rem"
|
padding="0.5rem 0.5rem"
|
||||||
borderRadius="0.2rem"
|
borderRadius="0.2rem"
|
||||||
backgroundColor={name === openModel ? 'var(--accent-color)' : ''}
|
backgroundColor={name === openModel ? 'var(--accent-color)' : ''}
|
||||||
@ -69,23 +69,24 @@ export default function ModelListItem(props: ModelListItemProps) {
|
|||||||
>
|
>
|
||||||
<Box onClick={openModelHandler} cursor="pointer">
|
<Box onClick={openModelHandler} cursor="pointer">
|
||||||
<Tooltip label={description} hasArrow placement="bottom">
|
<Tooltip label={description} hasArrow placement="bottom">
|
||||||
<Text fontWeight={'bold'}>{name}</Text>
|
<Text fontWeight="bold">{name}</Text>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer onClick={openModelHandler} cursor="pointer" />
|
<Spacer onClick={openModelHandler} cursor="pointer" />
|
||||||
<Flex gap={2} alignItems="center">
|
<Flex gap={2} alignItems="center">
|
||||||
<Text color={statusTextColor()}>{status}</Text>
|
<Text color={statusTextColor()}>{status}</Text>
|
||||||
<Button
|
<Button
|
||||||
size={'sm'}
|
size="sm"
|
||||||
onClick={handleChangeModel}
|
onClick={handleChangeModel}
|
||||||
isDisabled={status === 'active' || isProcessing || !isConnected}
|
isDisabled={status === 'active' || isProcessing || !isConnected}
|
||||||
className="modal-close-btn"
|
className="modal-close-btn"
|
||||||
>
|
>
|
||||||
{t('modelmanager:load')}
|
{t('modelmanager:load')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
icon={<EditIcon />}
|
icon={<EditIcon />}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
onClick={openModelHandler}
|
onClick={openModelHandler}
|
||||||
aria-label="Modify Config"
|
aria-label="Modify Config"
|
||||||
isDisabled={status === 'active' || isProcessing || !isConnected}
|
isDisabled={status === 'active' || isProcessing || !isConnected}
|
||||||
@ -98,7 +99,7 @@ export default function ModelListItem(props: ModelListItemProps) {
|
|||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
icon={<DeleteIcon />}
|
icon={<DeleteIcon />}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
aria-label={t('modelmanager:deleteConfig')}
|
aria-label={t('modelmanager:deleteConfig')}
|
||||||
isDisabled={status === 'active' || isProcessing || !isConnected}
|
isDisabled={status === 'active' || isProcessing || !isConnected}
|
||||||
className=" modal-close-btn"
|
className=" modal-close-btn"
|
||||||
@ -106,7 +107,7 @@ export default function ModelListItem(props: ModelListItemProps) {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Flex rowGap={'1rem'} flexDirection="column">
|
<Flex rowGap="1rem" flexDirection="column">
|
||||||
<p style={{ fontWeight: 'bold' }}>{t('modelmanager:deleteMsg1')}</p>
|
<p style={{ fontWeight: 'bold' }}>{t('modelmanager:deleteMsg1')}</p>
|
||||||
<p style={{ color: 'var(--text-color-secondary' }}>
|
<p style={{ color: 'var(--text-color-secondary' }}>
|
||||||
{t('modelmanager:deleteMsg2')}
|
{t('modelmanager:deleteMsg2')}
|
||||||
|
@ -58,11 +58,7 @@ export default function ModelManagerModal({
|
|||||||
<ModalHeader fontWeight="bold">
|
<ModalHeader fontWeight="bold">
|
||||||
{t('modelmanager:modelManager')}
|
{t('modelmanager:modelManager')}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<Flex
|
<Flex padding="0 1.5rem 1.5rem 1.5rem" width="100%" columnGap="2rem">
|
||||||
padding={'0 1.5rem 1.5rem 1.5rem'}
|
|
||||||
width="100%"
|
|
||||||
columnGap={'2rem'}
|
|
||||||
>
|
|
||||||
<ModelList />
|
<ModelList />
|
||||||
{openModel && model_list[openModel]['format'] === 'diffusers' ? (
|
{openModel && model_list[openModel]['format'] === 'diffusers' ? (
|
||||||
<DiffusersModelEdit />
|
<DiffusersModelEdit />
|
||||||
|
@ -3,7 +3,16 @@ import IAICheckbox from 'common/components/IAICheckbox';
|
|||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Box, Flex, FormControl, HStack, Text, VStack } from '@chakra-ui/react';
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
FormControl,
|
||||||
|
HStack,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
|
Text,
|
||||||
|
VStack,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||||
@ -43,16 +52,16 @@ function ModelExistsTag() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
position={'absolute'}
|
position="absolute"
|
||||||
zIndex={2}
|
zIndex={2}
|
||||||
right={4}
|
right={4}
|
||||||
top={4}
|
top={4}
|
||||||
fontSize="0.7rem"
|
fontSize="0.7rem"
|
||||||
fontWeight={'bold'}
|
fontWeight="bold"
|
||||||
backgroundColor={'var(--accent-color)'}
|
backgroundColor="var(--accent-color)"
|
||||||
padding={'0.2rem 0.5rem'}
|
padding="0.2rem 0.5rem"
|
||||||
borderRadius="0.2rem"
|
borderRadius="0.2rem"
|
||||||
alignItems={'center'}
|
alignItems="center"
|
||||||
>
|
>
|
||||||
{t('modelmanager:modelExists')}
|
{t('modelmanager:modelExists')}
|
||||||
</Box>
|
</Box>
|
||||||
@ -87,7 +96,7 @@ function SearchModelEntry({
|
|||||||
value={model.name}
|
value={model.name}
|
||||||
label={
|
label={
|
||||||
<>
|
<>
|
||||||
<VStack alignItems={'start'}>
|
<VStack alignItems="start">
|
||||||
<p style={{ fontWeight: 'bold' }}>{model.name}</p>
|
<p style={{ fontWeight: 'bold' }}>{model.name}</p>
|
||||||
<p style={{ fontStyle: 'italic' }}>{model.location}</p>
|
<p style={{ fontStyle: 'italic' }}>{model.location}</p>
|
||||||
</VStack>
|
</VStack>
|
||||||
@ -96,9 +105,9 @@ function SearchModelEntry({
|
|||||||
isChecked={modelsToAdd.includes(model.name)}
|
isChecked={modelsToAdd.includes(model.name)}
|
||||||
isDisabled={existingModels.includes(model.location)}
|
isDisabled={existingModels.includes(model.location)}
|
||||||
onChange={foundModelsChangeHandler}
|
onChange={foundModelsChangeHandler}
|
||||||
padding={'1rem'}
|
padding="1rem"
|
||||||
backgroundColor={'var(--background-color)'}
|
backgroundColor="var(--background-color)"
|
||||||
borderRadius={'0.5rem'}
|
borderRadius="0.5rem"
|
||||||
_checked={{
|
_checked={{
|
||||||
backgroundColor: 'var(--accent-color)',
|
backgroundColor: 'var(--accent-color)',
|
||||||
color: 'var(--text-color)',
|
color: 'var(--text-color)',
|
||||||
@ -135,6 +144,8 @@ export default function SearchModels() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [modelsToAdd, setModelsToAdd] = React.useState<string[]>([]);
|
const [modelsToAdd, setModelsToAdd] = React.useState<string[]>([]);
|
||||||
|
const [modelType, setModelType] = React.useState<string>('v1');
|
||||||
|
const [pathToConfig, setPathToConfig] = React.useState<string>('');
|
||||||
|
|
||||||
const resetSearchModelHandler = () => {
|
const resetSearchModelHandler = () => {
|
||||||
dispatch(setSearchFolder(null));
|
dispatch(setSearchFolder(null));
|
||||||
@ -167,11 +178,19 @@ export default function SearchModels() {
|
|||||||
const modelsToBeAdded = foundModels?.filter((foundModel) =>
|
const modelsToBeAdded = foundModels?.filter((foundModel) =>
|
||||||
modelsToAdd.includes(foundModel.name)
|
modelsToAdd.includes(foundModel.name)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const configFiles = {
|
||||||
|
v1: 'configs/stable-diffusion/v1-inference.yaml',
|
||||||
|
v2: 'configs/stable-diffusion/v2-inference-v.yaml',
|
||||||
|
inpainting: 'configs/stable-diffusion/v1-inpainting-inference.yaml',
|
||||||
|
custom: pathToConfig,
|
||||||
|
};
|
||||||
|
|
||||||
modelsToBeAdded?.forEach((model) => {
|
modelsToBeAdded?.forEach((model) => {
|
||||||
const modelFormat = {
|
const modelFormat = {
|
||||||
name: model.name,
|
name: model.name,
|
||||||
description: '',
|
description: '',
|
||||||
config: 'configs/stable-diffusion/v1-inference.yaml',
|
config: configFiles[modelType as keyof typeof configFiles],
|
||||||
weights: model.location,
|
weights: model.location,
|
||||||
vae: '',
|
vae: '',
|
||||||
width: 512,
|
width: 512,
|
||||||
@ -224,12 +243,12 @@ export default function SearchModels() {
|
|||||||
<>
|
<>
|
||||||
{searchFolder ? (
|
{searchFolder ? (
|
||||||
<Flex
|
<Flex
|
||||||
flexDirection={'column'}
|
flexDirection="column"
|
||||||
padding={'1rem'}
|
padding="1rem"
|
||||||
backgroundColor={'var(--background-color)'}
|
backgroundColor="var(--background-color)"
|
||||||
borderRadius="0.5rem"
|
borderRadius="0.5rem"
|
||||||
rowGap={'0.5rem'}
|
rowGap="0.5rem"
|
||||||
position={'relative'}
|
position="relative"
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
style={{
|
style={{
|
||||||
@ -252,7 +271,7 @@ export default function SearchModels() {
|
|||||||
aria-label={t('modelmanager:scanAgain')}
|
aria-label={t('modelmanager:scanAgain')}
|
||||||
tooltip={t('modelmanager:scanAgain')}
|
tooltip={t('modelmanager:scanAgain')}
|
||||||
icon={<BiReset />}
|
icon={<BiReset />}
|
||||||
position={'absolute'}
|
position="absolute"
|
||||||
right={16}
|
right={16}
|
||||||
fontSize={18}
|
fontSize={18}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
@ -261,7 +280,7 @@ export default function SearchModels() {
|
|||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label={t('modelmanager:clearCheckpointFolder')}
|
aria-label={t('modelmanager:clearCheckpointFolder')}
|
||||||
icon={<FaPlus style={{ transform: 'rotate(45deg)' }} />}
|
icon={<FaPlus style={{ transform: 'rotate(45deg)' }} />}
|
||||||
position={'absolute'}
|
position="absolute"
|
||||||
right={5}
|
right={5}
|
||||||
onClick={resetSearchModelHandler}
|
onClick={resetSearchModelHandler}
|
||||||
/>
|
/>
|
||||||
@ -300,8 +319,8 @@ export default function SearchModels() {
|
|||||||
</Formik>
|
</Formik>
|
||||||
)}
|
)}
|
||||||
{foundModels && (
|
{foundModels && (
|
||||||
<Flex flexDirection={'column'} rowGap={'1rem'}>
|
<Flex flexDirection="column" rowGap="1rem">
|
||||||
<Flex justifyContent={'space-between'} alignItems="center">
|
<Flex justifyContent="space-between" alignItems="center">
|
||||||
<p>
|
<p>
|
||||||
{t('modelmanager:modelsFound')}: {foundModels.length}
|
{t('modelmanager:modelsFound')}: {foundModels.length}
|
||||||
</p>
|
</p>
|
||||||
@ -309,8 +328,8 @@ export default function SearchModels() {
|
|||||||
{t('modelmanager:selected')}: {modelsToAdd.length}
|
{t('modelmanager:selected')}: {modelsToAdd.length}
|
||||||
</p>
|
</p>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex columnGap={'0.5rem'} justifyContent={'space-between'}>
|
<Flex columnGap="0.5rem" justifyContent="space-between">
|
||||||
<Flex columnGap={'0.5rem'}>
|
<Flex columnGap="0.5rem">
|
||||||
<IAIButton
|
<IAIButton
|
||||||
isDisabled={modelsToAdd.length === foundModels.length}
|
isDisabled={modelsToAdd.length === foundModels.length}
|
||||||
onClick={addAllToSelected}
|
onClick={addAllToSelected}
|
||||||
@ -346,6 +365,55 @@ export default function SearchModels() {
|
|||||||
{t('modelmanager:addSelected')}
|
{t('modelmanager:addSelected')}
|
||||||
</IAIButton>
|
</IAIButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
gap={4}
|
||||||
|
backgroundColor="var(--background-color)"
|
||||||
|
padding="1rem 1rem"
|
||||||
|
borderRadius="0.2rem"
|
||||||
|
flexDirection="column"
|
||||||
|
>
|
||||||
|
<Flex gap={4}>
|
||||||
|
<Text fontWeight="bold" color="var(--text-color-secondary)">
|
||||||
|
Pick Model Type:
|
||||||
|
</Text>
|
||||||
|
<RadioGroup
|
||||||
|
value={modelType}
|
||||||
|
onChange={(v) => setModelType(v)}
|
||||||
|
defaultValue="v1"
|
||||||
|
name="model_type"
|
||||||
|
>
|
||||||
|
<Flex gap={4}>
|
||||||
|
<Radio value="v1">{t('modelmanager:v1')}</Radio>
|
||||||
|
<Radio value="v2">{t('modelmanager:v2')}</Radio>
|
||||||
|
<Radio value="inpainting">
|
||||||
|
{t('modelmanager:inpainting')}
|
||||||
|
</Radio>
|
||||||
|
<Radio value="custom">{t('modelmanager:customConfig')}</Radio>
|
||||||
|
</Flex>
|
||||||
|
</RadioGroup>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{modelType === 'custom' && (
|
||||||
|
<Flex flexDirection="column" rowGap={2}>
|
||||||
|
<Text
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="sm"
|
||||||
|
color="var(--text-color-secondary)"
|
||||||
|
>
|
||||||
|
{t('modelmanager:pathToCustomConfig')}
|
||||||
|
</Text>
|
||||||
|
<IAIInput
|
||||||
|
value={pathToConfig}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.value !== '') setPathToConfig(e.target.value);
|
||||||
|
}}
|
||||||
|
width="42.5rem"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
rowGap="1rem"
|
rowGap="1rem"
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
div {
|
div {
|
||||||
background-color: var(--progress-bar-color);
|
background-color: var(--progress-bar-color);
|
||||||
|
transition: width 0.2s ease-in-out;
|
||||||
|
|
||||||
&[data-indeterminate] {
|
&[data-indeterminate] {
|
||||||
background-color: unset;
|
background-color: unset;
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
|
@ -206,7 +206,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="settings-modal-reset">
|
<div className="settings-modal-reset">
|
||||||
<Heading size={'md'}>{t('settings:resetWebUI')}</Heading>
|
<Heading size="md">{t('settings:resetWebUI')}</Heading>
|
||||||
<Button colorScheme="red" onClick={handleClickResetWebUI}>
|
<Button colorScheme="red" onClick={handleClickResetWebUI}>
|
||||||
{t('settings:resetWebUI')}
|
{t('settings:resetWebUI')}
|
||||||
</Button>
|
</Button>
|
||||||
@ -232,8 +232,8 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
|||||||
<ModalOverlay bg="blackAlpha.300" backdropFilter="blur(40px)" />
|
<ModalOverlay bg="blackAlpha.300" backdropFilter="blur(40px)" />
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<ModalBody pb={6} pt={6}>
|
<ModalBody pb={6} pt={6}>
|
||||||
<Flex justifyContent={'center'}>
|
<Flex justifyContent="center">
|
||||||
<Text fontSize={'lg'}>
|
<Text fontSize="lg">
|
||||||
<Text>{t('settings:resetComplete')}</Text>
|
<Text>{t('settings:resetComplete')}</Text>
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -56,7 +56,7 @@ const SiteHeader = () => {
|
|||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label={t('modelmanager:modelManager')}
|
aria-label={t('modelmanager:modelManager')}
|
||||||
tooltip={t('modelmanager:modelManager')}
|
tooltip={t('modelmanager:modelManager')}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={20}
|
fontSize={20}
|
||||||
@ -68,7 +68,7 @@ const SiteHeader = () => {
|
|||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label={t('common:hotkeysLabel')}
|
aria-label={t('common:hotkeysLabel')}
|
||||||
tooltip={t('common:hotkeysLabel')}
|
tooltip={t('common:hotkeysLabel')}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={20}
|
fontSize={20}
|
||||||
@ -86,7 +86,7 @@ const SiteHeader = () => {
|
|||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={20}
|
fontSize={20}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
icon={
|
icon={
|
||||||
<Link isExternal href="http://github.com/invoke-ai/InvokeAI/issues">
|
<Link isExternal href="http://github.com/invoke-ai/InvokeAI/issues">
|
||||||
<FaBug />
|
<FaBug />
|
||||||
@ -100,7 +100,7 @@ const SiteHeader = () => {
|
|||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={20}
|
fontSize={20}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
icon={
|
icon={
|
||||||
<Link isExternal href="http://github.com/invoke-ai/InvokeAI">
|
<Link isExternal href="http://github.com/invoke-ai/InvokeAI">
|
||||||
<FaGithub />
|
<FaGithub />
|
||||||
@ -114,7 +114,7 @@ const SiteHeader = () => {
|
|||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={20}
|
fontSize={20}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
icon={
|
icon={
|
||||||
<Link isExternal href="https://discord.gg/ZmtBAhwWhy">
|
<Link isExternal href="https://discord.gg/ZmtBAhwWhy">
|
||||||
<FaDiscord />
|
<FaDiscord />
|
||||||
@ -129,7 +129,7 @@ const SiteHeader = () => {
|
|||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={22}
|
fontSize={22}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
icon={<MdSettings />}
|
icon={<MdSettings />}
|
||||||
/>
|
/>
|
||||||
</SettingsModal>
|
</SettingsModal>
|
||||||
|
@ -46,7 +46,7 @@ export default function ThemeChanger() {
|
|||||||
width: '6rem',
|
width: '6rem',
|
||||||
}}
|
}}
|
||||||
leftIcon={currentTheme === theme ? <FaCheck /> : undefined}
|
leftIcon={currentTheme === theme ? <FaCheck /> : undefined}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
onClick={() => handleChangeTheme(theme)}
|
onClick={() => handleChangeTheme(theme)}
|
||||||
key={theme}
|
key={theme}
|
||||||
>
|
>
|
||||||
@ -64,7 +64,7 @@ export default function ThemeChanger() {
|
|||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label={t('common:themeLabel')}
|
aria-label={t('common:themeLabel')}
|
||||||
size={'sm'}
|
size="sm"
|
||||||
variant="link"
|
variant="link"
|
||||||
data-variant="link"
|
data-variant="link"
|
||||||
fontSize={20}
|
fontSize={20}
|
||||||
@ -72,7 +72,7 @@ export default function ThemeChanger() {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<VStack align={'stretch'}>{renderThemeOptions()}</VStack>
|
<VStack align="stretch">{renderThemeOptions()}</VStack>
|
||||||
</IAIPopover>
|
</IAIPopover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,12 @@ export const systemSlice = createSlice({
|
|||||||
state.isProcessing = true;
|
state.isProcessing = true;
|
||||||
state.currentStatusHasSteps = false;
|
state.currentStatusHasSteps = false;
|
||||||
},
|
},
|
||||||
|
modelConvertRequested: (state) => {
|
||||||
|
state.currentStatus = i18n.t('common:statusConvertingModel');
|
||||||
|
state.isCancelable = false;
|
||||||
|
state.isProcessing = true;
|
||||||
|
state.currentStatusHasSteps = false;
|
||||||
|
},
|
||||||
setSaveIntermediatesInterval: (state, action: PayloadAction<number>) => {
|
setSaveIntermediatesInterval: (state, action: PayloadAction<number>) => {
|
||||||
state.saveIntermediatesInterval = action.payload;
|
state.saveIntermediatesInterval = action.payload;
|
||||||
},
|
},
|
||||||
@ -265,6 +271,7 @@ export const {
|
|||||||
setModelList,
|
setModelList,
|
||||||
setIsCancelable,
|
setIsCancelable,
|
||||||
modelChangeRequested,
|
modelChangeRequested,
|
||||||
|
modelConvertRequested,
|
||||||
setSaveIntermediatesInterval,
|
setSaveIntermediatesInterval,
|
||||||
setEnableImageDebugging,
|
setEnableImageDebugging,
|
||||||
generationRequested,
|
generationRequested,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { Feature } from 'app/features';
|
import { Feature } from 'app/features';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
|
||||||
import FaceRestoreSettings from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings';
|
import FaceRestoreSettings from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings';
|
||||||
import FaceRestoreToggle from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle';
|
import FaceRestoreToggle from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle';
|
||||||
import ImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageFit';
|
import ImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageFit';
|
||||||
@ -16,10 +15,7 @@ import ParametersAccordion from 'features/parameters/components/ParametersAccord
|
|||||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||||
import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput';
|
import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput';
|
||||||
import PromptInput from 'features/parameters/components/PromptInput/PromptInput';
|
import PromptInput from 'features/parameters/components/PromptInput/PromptInput';
|
||||||
import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
|
|
||||||
import InvokeOptionsPanel from 'features/ui/components/InvokeParametersPanel';
|
import InvokeOptionsPanel from 'features/ui/components/InvokeParametersPanel';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export default function ImageToImagePanel() {
|
export default function ImageToImagePanel() {
|
||||||
@ -56,17 +52,6 @@ export default function ImageToImagePanel() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
|
|
||||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (activeTabName === 'img2img') {
|
|
||||||
const handleChangeHiresFix = () => dispatch(setHiresFix(false));
|
|
||||||
handleChangeHiresFix();
|
|
||||||
}
|
|
||||||
}, [activeTabName, dispatch]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvokeOptionsPanel>
|
<InvokeOptionsPanel>
|
||||||
<Flex flexDir="column" rowGap="0.5rem">
|
<Flex flexDir="column" rowGap="0.5rem">
|
||||||
|
@ -35,9 +35,9 @@ export default function InitImagePreview() {
|
|||||||
{initialImage && (
|
{initialImage && (
|
||||||
<div className="init-image-preview">
|
<div className="init-image-preview">
|
||||||
<Image
|
<Image
|
||||||
fit={'contain'}
|
fit="contain"
|
||||||
maxWidth={'100%'}
|
maxWidth="100%"
|
||||||
maxHeight={'100%'}
|
maxHeight="100%"
|
||||||
src={
|
src={
|
||||||
typeof initialImage === 'string' ? initialImage : initialImage.url
|
typeof initialImage === 'string' ? initialImage : initialImage.url
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,10 @@ export default function InitialImageOverlay() {
|
|||||||
|
|
||||||
return initialImage ? (
|
return initialImage ? (
|
||||||
<Image
|
<Image
|
||||||
fit={'contain'}
|
fit="contain"
|
||||||
src={typeof initialImage === 'string' ? initialImage : initialImage.url}
|
src={typeof initialImage === 'string' ? initialImage : initialImage.url}
|
||||||
rounded={'md'}
|
rounded="md"
|
||||||
className={'checkerboard'}
|
className="checkerboard"
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
|
@ -31,32 +31,32 @@ export interface InvokeTabInfo {
|
|||||||
|
|
||||||
export const tabDict: Record<InvokeTabName, InvokeTabInfo> = {
|
export const tabDict: Record<InvokeTabName, InvokeTabInfo> = {
|
||||||
txt2img: {
|
txt2img: {
|
||||||
title: <TextToImageIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <TextToImageIcon fill="black" boxSize="2.5rem" />,
|
||||||
workarea: <TextToImageWorkarea />,
|
workarea: <TextToImageWorkarea />,
|
||||||
tooltip: 'Text To Image',
|
tooltip: 'Text To Image',
|
||||||
},
|
},
|
||||||
img2img: {
|
img2img: {
|
||||||
title: <ImageToImageIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <ImageToImageIcon fill="black" boxSize="2.5rem" />,
|
||||||
workarea: <ImageToImageWorkarea />,
|
workarea: <ImageToImageWorkarea />,
|
||||||
tooltip: 'Image To Image',
|
tooltip: 'Image To Image',
|
||||||
},
|
},
|
||||||
unifiedCanvas: {
|
unifiedCanvas: {
|
||||||
title: <UnifiedCanvasIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <UnifiedCanvasIcon fill="black" boxSize="2.5rem" />,
|
||||||
workarea: <UnifiedCanvasWorkarea />,
|
workarea: <UnifiedCanvasWorkarea />,
|
||||||
tooltip: 'Unified Canvas',
|
tooltip: 'Unified Canvas',
|
||||||
},
|
},
|
||||||
nodes: {
|
nodes: {
|
||||||
title: <NodesIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <NodesIcon fill="black" boxSize="2.5rem" />,
|
||||||
workarea: <NodesWIP />,
|
workarea: <NodesWIP />,
|
||||||
tooltip: 'Nodes',
|
tooltip: 'Nodes',
|
||||||
},
|
},
|
||||||
postprocess: {
|
postprocess: {
|
||||||
title: <PostprocessingIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <PostprocessingIcon fill="black" boxSize="2.5rem" />,
|
||||||
workarea: <PostProcessingWIP />,
|
workarea: <PostProcessingWIP />,
|
||||||
tooltip: 'Post Processing',
|
tooltip: 'Post Processing',
|
||||||
},
|
},
|
||||||
training: {
|
training: {
|
||||||
title: <TrainingIcon fill={'black'} boxSize={'2.5rem'} />,
|
title: <TrainingIcon fill="black" boxSize="2.5rem" />,
|
||||||
workarea: <TrainingWIP />,
|
workarea: <TrainingWIP />,
|
||||||
tooltip: 'Training',
|
tooltip: 'Training',
|
||||||
},
|
},
|
||||||
@ -122,7 +122,7 @@ export default function InvokeTabs() {
|
|||||||
key={key}
|
key={key}
|
||||||
hasArrow
|
hasArrow
|
||||||
label={tabDict[key as keyof typeof tabDict].tooltip}
|
label={tabDict[key as keyof typeof tabDict].tooltip}
|
||||||
placement={'right'}
|
placement="right"
|
||||||
>
|
>
|
||||||
<Tab>{tabDict[key as keyof typeof tabDict].title}</Tab>
|
<Tab>{tabDict[key as keyof typeof tabDict].title}</Tab>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -147,7 +147,7 @@ export default function InvokeTabs() {
|
|||||||
<Tabs
|
<Tabs
|
||||||
isLazy
|
isLazy
|
||||||
className="app-tabs"
|
className="app-tabs"
|
||||||
variant={'unstyled'}
|
variant="unstyled"
|
||||||
defaultIndex={activeTab}
|
defaultIndex={activeTab}
|
||||||
index={activeTab}
|
index={activeTab}
|
||||||
onChange={(index: number) => {
|
onChange={(index: number) => {
|
||||||
|
@ -45,21 +45,16 @@ const UnifiedCanvasDisplayBeta = () => {
|
|||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'workarea-single-view'}>
|
<div className="workarea-single-view">
|
||||||
<Flex
|
<Flex
|
||||||
flexDirection={'row'}
|
flexDirection="row"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
columnGap={'1rem'}
|
columnGap="1rem"
|
||||||
padding="1rem"
|
padding="1rem"
|
||||||
>
|
>
|
||||||
<UnifiedCanvasToolbarBeta />
|
<UnifiedCanvasToolbarBeta />
|
||||||
<Flex
|
<Flex width="100%" height="100%" flexDirection="column" rowGap="1rem">
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
flexDirection={'column'}
|
|
||||||
rowGap={'1rem'}
|
|
||||||
>
|
|
||||||
<UnifiedCanvasToolSettingsBeta />
|
<UnifiedCanvasToolSettingsBeta />
|
||||||
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
|
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -4,7 +4,7 @@ import UnifiedCanvasLimitStrokesToBox from './UnifiedCanvasLimitStrokesToBox';
|
|||||||
|
|
||||||
export default function UnifiedCanvasBaseBrushSettings() {
|
export default function UnifiedCanvasBaseBrushSettings() {
|
||||||
return (
|
return (
|
||||||
<Flex gap={'1rem'} alignItems="center">
|
<Flex gap="1rem" alignItems="center">
|
||||||
<UnifiedCanvasBrushSettings />
|
<UnifiedCanvasBrushSettings />
|
||||||
<UnifiedCanvasLimitStrokesToBox />
|
<UnifiedCanvasLimitStrokesToBox />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -4,7 +4,7 @@ import UnifiedCanvasColorPicker from './UnifiedCanvasColorPicker';
|
|||||||
|
|
||||||
export default function UnifiedCanvasBrushSettings() {
|
export default function UnifiedCanvasBrushSettings() {
|
||||||
return (
|
return (
|
||||||
<Flex columnGap={'1rem'} alignItems="center">
|
<Flex columnGap="1rem" alignItems="center">
|
||||||
<UnifiedCanvasBrushSize />
|
<UnifiedCanvasBrushSize />
|
||||||
<UnifiedCanvasColorPicker />
|
<UnifiedCanvasColorPicker />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -49,7 +49,7 @@ export default function UnifiedCanvasBrushSize() {
|
|||||||
onChange={(newSize) => dispatch(setBrushSize(newSize))}
|
onChange={(newSize) => dispatch(setBrushSize(newSize))}
|
||||||
sliderNumberInputProps={{ max: 500 }}
|
sliderNumberInputProps={{ max: 500 }}
|
||||||
inputReadOnly={false}
|
inputReadOnly={false}
|
||||||
width={'100px'}
|
width="100px"
|
||||||
isCompact
|
isCompact
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -14,7 +14,7 @@ export default function UnifiedCanvasClearMask() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<IAIButton
|
<IAIButton
|
||||||
size={'sm'}
|
size="sm"
|
||||||
leftIcon={<FaTrash />}
|
leftIcon={<FaTrash />}
|
||||||
onClick={handleClearMask}
|
onClick={handleClearMask}
|
||||||
tooltip={`${t('unifiedcanvas:clearMask')} (Shift+C)`}
|
tooltip={`${t('unifiedcanvas:clearMask')} (Shift+C)`}
|
||||||
|
@ -92,7 +92,7 @@ export default function UnifiedCanvasColorPicker() {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Flex minWidth={'15rem'} direction={'column'} gap={'1rem'} width={'100%'}>
|
<Flex minWidth="15rem" direction="column" gap="1rem" width="100%">
|
||||||
{layer === 'base' && (
|
{layer === 'base' && (
|
||||||
<IAIColorPicker
|
<IAIColorPicker
|
||||||
style={{
|
style={{
|
||||||
|
@ -6,7 +6,7 @@ import UnifiedCanvasPreserveMask from './UnifiedCanvasPreserveMask';
|
|||||||
|
|
||||||
export default function UnifiedCanvasMaskBrushSettings() {
|
export default function UnifiedCanvasMaskBrushSettings() {
|
||||||
return (
|
return (
|
||||||
<Flex gap={'1rem'} alignItems="center">
|
<Flex gap="1rem" alignItems="center">
|
||||||
<UnifiedCanvasBrushSettings />
|
<UnifiedCanvasBrushSettings />
|
||||||
<UnifiedCanvasEnableMask />
|
<UnifiedCanvasEnableMask />
|
||||||
<UnifiedCanvasPreserveMask />
|
<UnifiedCanvasPreserveMask />
|
||||||
|
@ -5,7 +5,7 @@ import UnifiedCanvasSnapToGrid from './UnifiedCanvasSnapToGrid';
|
|||||||
|
|
||||||
export default function UnifiedCanvasMoveSettings() {
|
export default function UnifiedCanvasMoveSettings() {
|
||||||
return (
|
return (
|
||||||
<Flex alignItems={'center'} gap="1rem">
|
<Flex alignItems="center" gap="1rem">
|
||||||
<UnifiedCanvasShowGrid />
|
<UnifiedCanvasShowGrid />
|
||||||
<UnifiedCanvasSnapToGrid />
|
<UnifiedCanvasSnapToGrid />
|
||||||
<UnifiedCanvasDarkenOutsideSelection />
|
<UnifiedCanvasDarkenOutsideSelection />
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user