diff --git a/docker/Dockerfile b/docker/Dockerfile
index 864bc5eb609..7ea078af0d9 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -55,6 +55,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \
FROM node:20-slim AS web-builder
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
+RUN corepack use pnpm@8.x
RUN corepack enable
WORKDIR /build
diff --git a/invokeai/app/api/routers/model_manager.py b/invokeai/app/api/routers/model_manager.py
index f73b7a86b1e..d19b028cb65 100644
--- a/invokeai/app/api/routers/model_manager.py
+++ b/invokeai/app/api/routers/model_manager.py
@@ -6,7 +6,7 @@
import traceback
from copy import deepcopy
from tempfile import TemporaryDirectory
-from typing import Any, Dict, List, Optional, Type
+from typing import List, Optional, Type
from fastapi import Body, Path, Query, Response, UploadFile
from fastapi.responses import FileResponse, HTMLResponse
@@ -430,13 +430,11 @@ async def delete_model_image(
async def install_model(
source: str = Query(description="Model source to install, can be a local path, repo_id, or remote URL"),
inplace: Optional[bool] = Query(description="Whether or not to install a local model in place", default=False),
- # TODO(MM2): Can we type this?
- config: Optional[Dict[str, Any]] = Body(
- description="Dict of fields that override auto-probed values in the model config record, such as name, description and prediction_type ",
- default=None,
+ access_token: Optional[str] = Query(description="access token for the remote resource", default=None),
+ config: ModelRecordChanges = Body(
+ description="Object containing fields that override auto-probed values in the model config record, such as name, description and prediction_type ",
example={"name": "string", "description": "string"},
),
- access_token: Optional[str] = None,
) -> ModelInstallJob:
"""Install a model using a string identifier.
@@ -451,8 +449,9 @@ async def install_model(
- model/name:fp16:path/to/model.safetensors
- model/name::path/to/model.safetensors
- `config` is an optional dict containing model configuration values that will override
- the ones that are probed automatically.
+ `config` is a ModelRecordChanges object. Fields in this object will override
+ the ones that are probed automatically. Pass an empty object to accept
+ all the defaults.
`access_token` is an optional access token for use with Urls that require
authentication.
@@ -737,7 +736,7 @@ async def convert_model(
# write the converted file to the convert path
raw_model = converted_model.model
assert hasattr(raw_model, "save_pretrained")
- raw_model.save_pretrained(convert_path)
+ raw_model.save_pretrained(convert_path) # type: ignore
assert convert_path.exists()
# temporarily rename the original safetensors file so that there is no naming conflict
@@ -750,12 +749,12 @@ async def convert_model(
try:
new_key = installer.install_path(
convert_path,
- config={
- "name": original_name,
- "description": model_config.description,
- "hash": model_config.hash,
- "source": model_config.source,
- },
+ config=ModelRecordChanges(
+ name=original_name,
+ description=model_config.description,
+ hash=model_config.hash,
+ source=model_config.source,
+ ),
)
except Exception as e:
logger.error(str(e))
diff --git a/invokeai/app/invocations/spandrel_image_to_image.py b/invokeai/app/invocations/spandrel_image_to_image.py
index 3282106a427..ae4f48ef77c 100644
--- a/invokeai/app/invocations/spandrel_image_to_image.py
+++ b/invokeai/app/invocations/spandrel_image_to_image.py
@@ -23,7 +23,7 @@
from invokeai.backend.tiles.utils import TBLR, Tile
-@invocation("spandrel_image_to_image", title="Image-to-Image", tags=["upscale"], category="upscale", version="1.2.0")
+@invocation("spandrel_image_to_image", title="Image-to-Image", tags=["upscale"], category="upscale", version="1.3.0")
class SpandrelImageToImageInvocation(BaseInvocation, WithMetadata, WithBoard):
"""Run any spandrel image-to-image model (https://github.com/chaiNNer-org/spandrel)."""
@@ -36,16 +36,6 @@ class SpandrelImageToImageInvocation(BaseInvocation, WithMetadata, WithBoard):
tile_size: int = InputField(
default=512, description="The tile size for tiled image-to-image. Set to 0 to disable tiling."
)
- scale: float = InputField(
- default=4.0,
- gt=0.0,
- le=16.0,
- description="The final scale of the output image. If the model does not upscale the image, this will be ignored.",
- )
- fit_to_multiple_of_8: bool = InputField(
- default=False,
- description="If true, the output image will be resized to the nearest multiple of 8 in both dimensions.",
- )
@classmethod
def scale_tile(cls, tile: Tile, scale: int) -> Tile:
@@ -152,6 +142,47 @@ def upscale_image(
return pil_image
+ @torch.inference_mode()
+ def invoke(self, context: InvocationContext) -> ImageOutput:
+ # Images are converted to RGB, because most models don't support an alpha channel. In the future, we may want to
+ # revisit this.
+ image = context.images.get_pil(self.image.image_name, mode="RGB")
+
+ # Load the model.
+ spandrel_model_info = context.models.load(self.image_to_image_model)
+
+ # Do the upscaling.
+ with spandrel_model_info as spandrel_model:
+ assert isinstance(spandrel_model, SpandrelImageToImageModel)
+
+ # Upscale the image
+ pil_image = self.upscale_image(image, self.tile_size, spandrel_model, context.util.is_canceled)
+
+ image_dto = context.images.save(image=pil_image)
+ return ImageOutput.build(image_dto)
+
+
+@invocation(
+ "spandrel_image_to_image_autoscale",
+ title="Image-to-Image (Autoscale)",
+ tags=["upscale"],
+ category="upscale",
+ version="1.0.0",
+)
+class SpandrelImageToImageAutoscaleInvocation(SpandrelImageToImageInvocation):
+ """Run any spandrel image-to-image model (https://github.com/chaiNNer-org/spandrel) until the target scale is reached."""
+
+ scale: float = InputField(
+ default=4.0,
+ gt=0.0,
+ le=16.0,
+ description="The final scale of the output image. If the model does not upscale the image, this will be ignored.",
+ )
+ fit_to_multiple_of_8: bool = InputField(
+ default=False,
+ description="If true, the output image will be resized to the nearest multiple of 8 in both dimensions.",
+ )
+
@torch.inference_mode()
def invoke(self, context: InvocationContext) -> ImageOutput:
# Images are converted to RGB, because most models don't support an alpha channel. In the future, we may want to
diff --git a/invokeai/app/services/model_install/model_install_base.py b/invokeai/app/services/model_install/model_install_base.py
index 20afaeaa505..27578dd5d6b 100644
--- a/invokeai/app/services/model_install/model_install_base.py
+++ b/invokeai/app/services/model_install/model_install_base.py
@@ -3,7 +3,7 @@
from abc import ABC, abstractmethod
from pathlib import Path
-from typing import Any, Dict, List, Optional, Union
+from typing import List, Optional, Union
from pydantic.networks import AnyHttpUrl
@@ -12,7 +12,7 @@
from invokeai.app.services.events.events_base import EventServiceBase
from invokeai.app.services.invoker import Invoker
from invokeai.app.services.model_install.model_install_common import ModelInstallJob, ModelSource
-from invokeai.app.services.model_records import ModelRecordServiceBase
+from invokeai.app.services.model_records import ModelRecordChanges, ModelRecordServiceBase
from invokeai.backend.model_manager import AnyModelConfig
@@ -64,7 +64,7 @@ def event_bus(self) -> Optional["EventServiceBase"]:
def register_path(
self,
model_path: Union[Path, str],
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
) -> str:
"""
Probe and register the model at model_path.
@@ -72,7 +72,7 @@ def register_path(
This keeps the model in its current location.
:param model_path: Filesystem Path to the model.
- :param config: Dict of attributes that will override autoassigned values.
+ :param config: ModelRecordChanges object that will override autoassigned model record values.
:returns id: The string ID of the registered model.
"""
@@ -92,7 +92,7 @@ def unconditionally_delete(self, key: str) -> None:
def install_path(
self,
model_path: Union[Path, str],
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
) -> str:
"""
Probe, register and install the model in the models directory.
@@ -101,7 +101,7 @@ def install_path(
the models directory handled by InvokeAI.
:param model_path: Filesystem Path to the model.
- :param config: Dict of attributes that will override autoassigned values.
+ :param config: ModelRecordChanges object that will override autoassigned model record values.
:returns id: The string ID of the registered model.
"""
@@ -109,14 +109,14 @@ def install_path(
def heuristic_import(
self,
source: str,
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
access_token: Optional[str] = None,
inplace: Optional[bool] = False,
) -> ModelInstallJob:
r"""Install the indicated model using heuristics to interpret user intentions.
:param source: String source
- :param config: Optional dict. Any fields in this dict
+ :param config: Optional ModelRecordChanges object. Any fields in this object
will override corresponding autoassigned probe fields in the
model's config record as described in `import_model()`.
:param access_token: Optional access token for remote sources.
@@ -147,7 +147,7 @@ def heuristic_import(
def import_model(
self,
source: ModelSource,
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
) -> ModelInstallJob:
"""Install the indicated model.
diff --git a/invokeai/app/services/model_install/model_install_common.py b/invokeai/app/services/model_install/model_install_common.py
index c1538f543dc..8cbe31597f4 100644
--- a/invokeai/app/services/model_install/model_install_common.py
+++ b/invokeai/app/services/model_install/model_install_common.py
@@ -2,13 +2,14 @@
import traceback
from enum import Enum
from pathlib import Path
-from typing import Any, Dict, Literal, Optional, Set, Union
+from typing import Literal, Optional, Set, Union
from pydantic import BaseModel, Field, PrivateAttr, field_validator
from pydantic.networks import AnyHttpUrl
from typing_extensions import Annotated
from invokeai.app.services.download import DownloadJob, MultiFileDownloadJob
+from invokeai.app.services.model_records import ModelRecordChanges
from invokeai.backend.model_manager import AnyModelConfig, ModelRepoVariant
from invokeai.backend.model_manager.config import ModelSourceType
from invokeai.backend.model_manager.metadata import AnyModelRepoMetadata
@@ -133,8 +134,9 @@ class ModelInstallJob(BaseModel):
id: int = Field(description="Unique ID for this job")
status: InstallStatus = Field(default=InstallStatus.WAITING, description="Current status of install process")
error_reason: Optional[str] = Field(default=None, description="Information about why the job failed")
- config_in: Dict[str, Any] = Field(
- default_factory=dict, description="Configuration information (e.g. 'description') to apply to model."
+ config_in: ModelRecordChanges = Field(
+ default_factory=ModelRecordChanges,
+ description="Configuration information (e.g. 'description') to apply to model.",
)
config_out: Optional[AnyModelConfig] = Field(
default=None, description="After successful installation, this will hold the configuration object."
diff --git a/invokeai/app/services/model_install/model_install_default.py b/invokeai/app/services/model_install/model_install_default.py
index 5e19a349adc..e1d784f5bf4 100644
--- a/invokeai/app/services/model_install/model_install_default.py
+++ b/invokeai/app/services/model_install/model_install_default.py
@@ -163,26 +163,27 @@ def _put_in_queue(self, job: ModelInstallJob) -> None:
def register_path(
self,
model_path: Union[Path, str],
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
) -> str: # noqa D102
model_path = Path(model_path)
- config = config or {}
- if not config.get("source"):
- config["source"] = model_path.resolve().as_posix()
- config["source_type"] = ModelSourceType.Path
+ config = config or ModelRecordChanges()
+ if not config.source:
+ config.source = model_path.resolve().as_posix()
+ config.source_type = ModelSourceType.Path
return self._register(model_path, config)
def install_path(
self,
model_path: Union[Path, str],
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
) -> str: # noqa D102
model_path = Path(model_path)
- config = config or {}
+ config = config or ModelRecordChanges()
+ info: AnyModelConfig = ModelProbe.probe(
+ Path(model_path), config.model_dump(), hash_algo=self._app_config.hashing_algorithm
+ ) # type: ignore
- info: AnyModelConfig = ModelProbe.probe(Path(model_path), config, hash_algo=self._app_config.hashing_algorithm)
-
- if preferred_name := config.get("name"):
+ if preferred_name := config.name:
preferred_name = Path(preferred_name).with_suffix(model_path.suffix)
dest_path = (
@@ -204,7 +205,7 @@ def install_path(
def heuristic_import(
self,
source: str,
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
access_token: Optional[str] = None,
inplace: Optional[bool] = False,
) -> ModelInstallJob:
@@ -216,7 +217,7 @@ def heuristic_import(
source_obj.access_token = access_token
return self.import_model(source_obj, config)
- def import_model(self, source: ModelSource, config: Optional[Dict[str, Any]] = None) -> ModelInstallJob: # noqa D102
+ def import_model(self, source: ModelSource, config: Optional[ModelRecordChanges] = None) -> ModelInstallJob: # noqa D102
similar_jobs = [x for x in self.list_jobs() if x.source == source and not x.in_terminal_state]
if similar_jobs:
self._logger.warning(f"There is already an active install job for {source}. Not enqueuing.")
@@ -318,16 +319,17 @@ def _migrate_yaml(self) -> None:
model_path = self._app_config.models_path / model_path
model_path = model_path.resolve()
- config: dict[str, Any] = {}
- config["name"] = model_name
- config["description"] = stanza.get("description")
+ config = ModelRecordChanges(
+ name=model_name,
+ description=stanza.get("description"),
+ )
legacy_config_path = stanza.get("config")
if legacy_config_path:
# In v3, these paths were relative to the root. Migrate them to be relative to the legacy_conf_dir.
legacy_config_path = self._app_config.root_path / legacy_config_path
if legacy_config_path.is_relative_to(self._app_config.legacy_conf_path):
legacy_config_path = legacy_config_path.relative_to(self._app_config.legacy_conf_path)
- config["config_path"] = str(legacy_config_path)
+ config.config_path = str(legacy_config_path)
try:
id = self.register_path(model_path=model_path, config=config)
self._logger.info(f"Migrated {model_name} with id {id}")
@@ -500,11 +502,11 @@ def _register_or_install(self, job: ModelInstallJob) -> None:
job.total_bytes = self._stat_size(job.local_path)
job.bytes = job.total_bytes
self._signal_job_running(job)
- job.config_in["source"] = str(job.source)
- job.config_in["source_type"] = MODEL_SOURCE_TO_TYPE_MAP[job.source.__class__]
+ job.config_in.source = str(job.source)
+ job.config_in.source_type = MODEL_SOURCE_TO_TYPE_MAP[job.source.__class__]
# enter the metadata, if there is any
if isinstance(job.source_metadata, (HuggingFaceMetadata)):
- job.config_in["source_api_response"] = job.source_metadata.api_response
+ job.config_in.source_api_response = job.source_metadata.api_response
if job.inplace:
key = self.register_path(job.local_path, job.config_in)
@@ -639,11 +641,11 @@ def _move_model(self, old_path: Path, new_path: Path) -> Path:
return new_path
def _register(
- self, model_path: Path, config: Optional[Dict[str, Any]] = None, info: Optional[AnyModelConfig] = None
+ self, model_path: Path, config: Optional[ModelRecordChanges] = None, info: Optional[AnyModelConfig] = None
) -> str:
- config = config or {}
+ config = config or ModelRecordChanges()
- info = info or ModelProbe.probe(model_path, config, hash_algo=self._app_config.hashing_algorithm)
+ info = info or ModelProbe.probe(model_path, config.model_dump(), hash_algo=self._app_config.hashing_algorithm) # type: ignore
model_path = model_path.resolve()
@@ -674,11 +676,13 @@ def _guess_variant(self) -> Optional[ModelRepoVariant]:
precision = TorchDevice.choose_torch_dtype()
return ModelRepoVariant.FP16 if precision == torch.float16 else None
- def _import_local_model(self, source: LocalModelSource, config: Optional[Dict[str, Any]]) -> ModelInstallJob:
+ def _import_local_model(
+ self, source: LocalModelSource, config: Optional[ModelRecordChanges] = None
+ ) -> ModelInstallJob:
return ModelInstallJob(
id=self._next_id(),
source=source,
- config_in=config or {},
+ config_in=config or ModelRecordChanges(),
local_path=Path(source.path),
inplace=source.inplace or False,
)
@@ -686,7 +690,7 @@ def _import_local_model(self, source: LocalModelSource, config: Optional[Dict[st
def _import_from_hf(
self,
source: HFModelSource,
- config: Optional[Dict[str, Any]] = None,
+ config: Optional[ModelRecordChanges] = None,
) -> ModelInstallJob:
# Add user's cached access token to HuggingFace requests
if source.access_token is None:
@@ -702,7 +706,7 @@ def _import_from_hf(
def _import_from_url(
self,
source: URLModelSource,
- config: Optional[Dict[str, Any]],
+ config: Optional[ModelRecordChanges] = None,
) -> ModelInstallJob:
remote_files, metadata = self._remote_files_from_source(source)
return self._import_remote_model(
@@ -717,7 +721,7 @@ def _import_remote_model(
source: HFModelSource | URLModelSource,
remote_files: List[RemoteModelFile],
metadata: Optional[AnyModelRepoMetadata],
- config: Optional[Dict[str, Any]],
+ config: Optional[ModelRecordChanges],
) -> ModelInstallJob:
if len(remote_files) == 0:
raise ValueError(f"{source}: No downloadable files found")
@@ -730,7 +734,7 @@ def _import_remote_model(
install_job = ModelInstallJob(
id=self._next_id(),
source=source,
- config_in=config or {},
+ config_in=config or ModelRecordChanges(),
source_metadata=metadata,
local_path=destdir, # local path may change once the download has started due to content-disposition handling
bytes=0,
diff --git a/invokeai/app/services/model_records/model_records_base.py b/invokeai/app/services/model_records/model_records_base.py
index 57531cf3c19..46d11d4ddf2 100644
--- a/invokeai/app/services/model_records/model_records_base.py
+++ b/invokeai/app/services/model_records/model_records_base.py
@@ -18,6 +18,7 @@
ControlAdapterDefaultSettings,
MainModelDefaultSettings,
ModelFormat,
+ ModelSourceType,
ModelType,
ModelVariantType,
SchedulerPredictionType,
@@ -66,10 +67,16 @@ class ModelRecordChanges(BaseModelExcludeNull):
"""A set of changes to apply to a model."""
# Changes applicable to all models
+ source: Optional[str] = Field(description="original source of the model", default=None)
+ source_type: Optional[ModelSourceType] = Field(description="type of model source", default=None)
+ source_api_response: Optional[str] = Field(description="metadata from remote source", default=None)
name: Optional[str] = Field(description="Name of the model.", default=None)
path: Optional[str] = Field(description="Path to the model.", default=None)
description: Optional[str] = Field(description="Model description", default=None)
base: Optional[BaseModelType] = Field(description="The base model.", default=None)
+ type: Optional[ModelType] = Field(description="Type of model", default=None)
+ key: Optional[str] = Field(description="Database ID for this model", default=None)
+ hash: Optional[str] = Field(description="hash of model file", default=None)
trigger_phrases: Optional[set[str]] = Field(description="Set of trigger phrases for this model", default=None)
default_settings: Optional[MainModelDefaultSettings | ControlAdapterDefaultSettings] = Field(
description="Default settings for this model", default=None
diff --git a/invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SD1.5.json b/invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SD1.5.json
new file mode 100644
index 00000000000..7bc2810c75b
--- /dev/null
+++ b/invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SD1.5.json
@@ -0,0 +1,1430 @@
+{
+ "name": "MultiDiffusion SD1.5",
+ "author": "Invoke",
+ "description": "A workflow to upscale an input image with tiled upscaling, using SD1.5 based models.",
+ "version": "1.0.0",
+ "contact": "invoke@invoke.ai",
+ "tags": "tiled, upscaling, sdxl",
+ "notes": "",
+ "exposedFields": [
+ {
+ "nodeId": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "fieldName": "image"
+ },
+ {
+ "nodeId": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "fieldName": "scale"
+ },
+ {
+ "nodeId": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
+ "fieldName": "board"
+ },
+ {
+ "nodeId": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "fieldName": "a"
+ },
+ {
+ "nodeId": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
+ "fieldName": "a"
+ },
+ {
+ "nodeId": "14469dfe-9f49-4a13-89a7-eb4d45794b2b",
+ "fieldName": "prompt"
+ },
+ {
+ "nodeId": "33fe76a0-5efd-4482-a7f0-e2abf1223dc2",
+ "fieldName": "prompt"
+ },
+ {
+ "nodeId": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "fieldName": "model"
+ },
+ {
+ "nodeId": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "fieldName": "image_to_image_model"
+ },
+ {
+ "nodeId": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "fieldName": "model"
+ }
+ ],
+ "meta": {
+ "version": "3.0.0",
+ "category": "default"
+ },
+ "id": "e5b5fb01-8906-463a-963a-402dbc42f79b",
+ "nodes": [
+ {
+ "id": "33fe76a0-5efd-4482-a7f0-e2abf1223dc2",
+ "type": "invocation",
+ "data": {
+ "id": "33fe76a0-5efd-4482-a7f0-e2abf1223dc2",
+ "type": "compel",
+ "version": "1.2.0",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "prompt": {
+ "name": "prompt",
+ "label": "Negative Prompt (Optional)",
+ "value": "blurry painting, art, sketch"
+ },
+ "clip": {
+ "name": "clip",
+ "label": ""
+ },
+ "mask": {
+ "name": "mask",
+ "label": ""
+ }
+ }
+ },
+ "position": {
+ "x": -3550,
+ "y": -2725
+ }
+ },
+ {
+ "id": "14469dfe-9f49-4a13-89a7-eb4d45794b2b",
+ "type": "invocation",
+ "data": {
+ "id": "14469dfe-9f49-4a13-89a7-eb4d45794b2b",
+ "type": "compel",
+ "version": "1.2.0",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "prompt": {
+ "name": "prompt",
+ "label": "Positive Prompt (Optional)",
+ "value": "high quality studio lighting, photo"
+ },
+ "clip": {
+ "name": "clip",
+ "label": ""
+ },
+ "mask": {
+ "name": "mask",
+ "label": ""
+ }
+ }
+ },
+ "position": {
+ "x": -3550,
+ "y": -3025
+ }
+ },
+ {
+ "id": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "type": "invocation",
+ "data": {
+ "id": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "type": "main_model_loader",
+ "version": "1.0.3",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "model": {
+ "name": "model",
+ "label": "",
+ "value": {
+ "key": "e7b402e5-62e5-4acb-8c39-bee6bdb758ab",
+ "hash": "c8659e796168d076368256b57edbc1b48d6dafc1712f1bb37cc57c7c06889a6b",
+ "name": "526mix",
+ "base": "sd-1",
+ "type": "main"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": -4025,
+ "y": -3050
+ }
+ },
+ {
+ "id": "71a116e1-c631-48b3-923d-acea4753b887",
+ "type": "invocation",
+ "data": {
+ "id": "71a116e1-c631-48b3-923d-acea4753b887",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "ADD"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 0.3
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -1550
+ }
+ },
+ {
+ "id": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "type": "invocation",
+ "data": {
+ "id": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "MUL"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 0.025
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -1575
+ }
+ },
+ {
+ "id": "96e1bcd0-326b-4b67-8b14-239da2440aec",
+ "type": "invocation",
+ "data": {
+ "id": "96e1bcd0-326b-4b67-8b14-239da2440aec",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "MUL"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 0.45
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -1200
+ }
+ },
+ {
+ "id": "75a89685-0f82-40ed-9b88-e583673be9fc",
+ "type": "invocation",
+ "data": {
+ "id": "75a89685-0f82-40ed-9b88-e583673be9fc",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "ADD"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 0.15
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -1225
+ }
+ },
+ {
+ "id": "1ed88043-3519-41d5-a895-07944f03de70",
+ "type": "invocation",
+ "data": {
+ "id": "1ed88043-3519-41d5-a895-07944f03de70",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "ADD"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 0.3
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -1650
+ }
+ },
+ {
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "type": "invocation",
+ "data": {
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "MUL"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 0.032
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -1850
+ }
+ },
+ {
+ "id": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "type": "invocation",
+ "data": {
+ "id": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "type": "spandrel_image_to_image_autoscale",
+ "version": "1.0.0",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "board": {
+ "name": "board",
+ "label": ""
+ },
+ "metadata": {
+ "name": "metadata",
+ "label": ""
+ },
+ "image": {
+ "name": "image",
+ "label": "Image to Upscale",
+ "value": {
+ "image_name": "ee7009f7-a35d-488b-a2a6-21237ef5ae05.png"
+ }
+ },
+ "image_to_image_model": {
+ "name": "image_to_image_model",
+ "label": "",
+ "value": {
+ "key": "38bb1a29-8ede-42ba-b77f-64b3478896eb",
+ "hash": "blake3:e52fdbee46a484ebe9b3b20ea0aac0a35a453ab6d0d353da00acfd35ce7a91ed",
+ "name": "4xNomosWebPhoto_esrgan",
+ "base": "sdxl",
+ "type": "spandrel_image_to_image"
+ }
+ },
+ "tile_size": {
+ "name": "tile_size",
+ "label": "",
+ "value": 512
+ },
+ "scale": {
+ "name": "scale",
+ "label": "Scale (2x, 4x, 8x, 16x)",
+ "value": 2
+ },
+ "fit_to_multiple_of_8": {
+ "name": "fit_to_multiple_of_8",
+ "label": "",
+ "value": true
+ }
+ }
+ },
+ "position": {
+ "x": -4750,
+ "y": -2125
+ }
+ },
+ {
+ "id": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "type": "invocation",
+ "data": {
+ "id": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "type": "model_identifier",
+ "version": "1.0.0",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "model": {
+ "name": "model",
+ "label": "ControlNet Model - Choose a Tile ControlNet",
+ "value": {
+ "key": "20645e4d-ef97-4c5a-9243-b834a3483925",
+ "hash": "f0812e13758f91baf4e54b7dbb707b70642937d3b2098cd2b94cc36d3eba308e",
+ "name": "tile",
+ "base": "sd-1",
+ "type": "controlnet"
+ }
+ }
+ }
+ },
+ "position": {
+ "x": -3450,
+ "y": -1450
+ }
+ },
+ {
+ "id": "00239057-20d4-4cd2-a010-28727b256ea2",
+ "type": "invocation",
+ "data": {
+ "id": "00239057-20d4-4cd2-a010-28727b256ea2",
+ "type": "rand_int",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": false,
+ "inputs": {
+ "low": {
+ "name": "low",
+ "label": "",
+ "value": 0
+ },
+ "high": {
+ "name": "high",
+ "label": "",
+ "value": 2147483647
+ }
+ }
+ },
+ "position": {
+ "x": -4025,
+ "y": -2075
+ }
+ },
+ {
+ "id": "094bc4ed-5c68-4342-84f4-51056c755796",
+ "type": "invocation",
+ "data": {
+ "id": "094bc4ed-5c68-4342-84f4-51056c755796",
+ "type": "boolean",
+ "version": "1.0.1",
+ "label": "Tiled Option",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "value": {
+ "name": "value",
+ "label": "Tiled VAE (Saves VRAM, Color Inconsistency)",
+ "value": true
+ }
+ }
+ },
+ "position": {
+ "x": -2675,
+ "y": -2475
+ }
+ },
+ {
+ "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "type": "invocation",
+ "data": {
+ "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "Creativity Input",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "MUL"
+ },
+ "a": {
+ "name": "a",
+ "label": "Creativity Control (-10 to 10)",
+ "value": 0
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": -1
+ }
+ }
+ },
+ "position": {
+ "x": -3500,
+ "y": -2350
+ }
+ },
+ {
+ "id": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "type": "invocation",
+ "data": {
+ "id": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "DIV"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 100
+ }
+ }
+ },
+ "position": {
+ "x": -3500,
+ "y": -1975
+ }
+ },
+ {
+ "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "type": "invocation",
+ "data": {
+ "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "ADD"
+ },
+ "a": {
+ "name": "a",
+ "label": "A",
+ "value": 0
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 10
+ }
+ }
+ },
+ "position": {
+ "x": -3500,
+ "y": -2075
+ }
+ },
+ {
+ "id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "type": "invocation",
+ "data": {
+ "id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "MUL"
+ },
+ "a": {
+ "name": "a",
+ "label": "",
+ "value": 1
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 4.99
+ }
+ }
+ },
+ "position": {
+ "x": -3500,
+ "y": -2025
+ }
+ },
+ {
+ "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
+ "type": "invocation",
+ "data": {
+ "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "Structural Input",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "operation": {
+ "name": "operation",
+ "label": "",
+ "value": "ADD"
+ },
+ "a": {
+ "name": "a",
+ "label": "Structural Control (-10 to 10)",
+ "value": 0
+ },
+ "b": {
+ "name": "b",
+ "label": "",
+ "value": 10
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -2100
+ }
+ },
+ {
+ "id": "6636a27a-f130-4a13-b3e5-50b44e4a566f",
+ "type": "invocation",
+ "data": {
+ "id": "6636a27a-f130-4a13-b3e5-50b44e4a566f",
+ "type": "collect",
+ "version": "1.0.0",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "item": {
+ "name": "item",
+ "label": ""
+ }
+ }
+ },
+ "position": {
+ "x": -2275,
+ "y": -2075
+ }
+ },
+ {
+ "id": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "type": "invocation",
+ "data": {
+ "id": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "type": "controlnet",
+ "version": "1.1.2",
+ "label": "Initial Control (Use Tile)",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "image": {
+ "name": "image",
+ "label": ""
+ },
+ "control_model": {
+ "name": "control_model",
+ "label": ""
+ },
+ "control_weight": {
+ "name": "control_weight",
+ "label": "",
+ "value": 0.6
+ },
+ "begin_step_percent": {
+ "name": "begin_step_percent",
+ "label": "",
+ "value": 0
+ },
+ "end_step_percent": {
+ "name": "end_step_percent",
+ "label": "",
+ "value": 0.5
+ },
+ "control_mode": {
+ "name": "control_mode",
+ "label": "",
+ "value": "balanced"
+ },
+ "resize_mode": {
+ "name": "resize_mode",
+ "label": "",
+ "value": "just_resize"
+ }
+ }
+ },
+ "position": {
+ "x": -2675,
+ "y": -1775
+ }
+ },
+ {
+ "id": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "type": "invocation",
+ "data": {
+ "id": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "type": "unsharp_mask",
+ "version": "1.2.2",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "board": {
+ "name": "board",
+ "label": ""
+ },
+ "metadata": {
+ "name": "metadata",
+ "label": ""
+ },
+ "image": {
+ "name": "image",
+ "label": ""
+ },
+ "radius": {
+ "name": "radius",
+ "label": "",
+ "value": 2
+ },
+ "strength": {
+ "name": "strength",
+ "label": "",
+ "value": 50
+ }
+ }
+ },
+ "position": {
+ "x": -4400,
+ "y": -2125
+ }
+ },
+ {
+ "id": "117f982a-03da-49b1-bf9f-29711160ac02",
+ "type": "invocation",
+ "data": {
+ "id": "117f982a-03da-49b1-bf9f-29711160ac02",
+ "type": "i2l",
+ "version": "1.1.0",
+ "label": "",
+ "notes": "",
+ "isOpen": false,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "image": {
+ "name": "image",
+ "label": ""
+ },
+ "vae": {
+ "name": "vae",
+ "label": ""
+ },
+ "tiled": {
+ "name": "tiled",
+ "label": "",
+ "value": false
+ },
+ "tile_size": {
+ "name": "tile_size",
+ "label": "",
+ "value": 0
+ },
+ "fp32": {
+ "name": "fp32",
+ "label": "",
+ "value": false
+ }
+ }
+ },
+ "position": {
+ "x": -4025,
+ "y": -2125
+ }
+ },
+ {
+ "id": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
+ "type": "invocation",
+ "data": {
+ "id": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
+ "type": "l2i",
+ "version": "1.3.0",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": false,
+ "useCache": true,
+ "inputs": {
+ "board": {
+ "name": "board",
+ "label": "Output Board"
+ },
+ "metadata": {
+ "name": "metadata",
+ "label": ""
+ },
+ "latents": {
+ "name": "latents",
+ "label": ""
+ },
+ "vae": {
+ "name": "vae",
+ "label": ""
+ },
+ "tiled": {
+ "name": "tiled",
+ "label": "",
+ "value": false
+ },
+ "tile_size": {
+ "name": "tile_size",
+ "label": "",
+ "value": 0
+ },
+ "fp32": {
+ "name": "fp32",
+ "label": "",
+ "value": false
+ }
+ }
+ },
+ "position": {
+ "x": -2675,
+ "y": -2825
+ }
+ },
+ {
+ "id": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "type": "invocation",
+ "data": {
+ "id": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "type": "tiled_multi_diffusion_denoise_latents",
+ "version": "1.0.0",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "positive_conditioning": {
+ "name": "positive_conditioning",
+ "label": ""
+ },
+ "negative_conditioning": {
+ "name": "negative_conditioning",
+ "label": ""
+ },
+ "noise": {
+ "name": "noise",
+ "label": ""
+ },
+ "latents": {
+ "name": "latents",
+ "label": ""
+ },
+ "tile_height": {
+ "name": "tile_height",
+ "label": "",
+ "value": 768
+ },
+ "tile_width": {
+ "name": "tile_width",
+ "label": "",
+ "value": 768
+ },
+ "tile_overlap": {
+ "name": "tile_overlap",
+ "label": "",
+ "value": 128
+ },
+ "steps": {
+ "name": "steps",
+ "label": "",
+ "value": 25
+ },
+ "cfg_scale": {
+ "name": "cfg_scale",
+ "label": "",
+ "value": 5
+ },
+ "denoising_start": {
+ "name": "denoising_start",
+ "label": "",
+ "value": 0.6
+ },
+ "denoising_end": {
+ "name": "denoising_end",
+ "label": "",
+ "value": 1
+ },
+ "scheduler": {
+ "name": "scheduler",
+ "label": "",
+ "value": "kdpm_2"
+ },
+ "unet": {
+ "name": "unet",
+ "label": ""
+ },
+ "cfg_rescale_multiplier": {
+ "name": "cfg_rescale_multiplier",
+ "label": "",
+ "value": 0
+ },
+ "control": {
+ "name": "control",
+ "label": ""
+ }
+ }
+ },
+ "position": {
+ "x": -3050,
+ "y": -2825
+ }
+ },
+ {
+ "id": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "type": "invocation",
+ "data": {
+ "id": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "type": "controlnet",
+ "version": "1.1.2",
+ "label": "Second Phase Control (Use Tile)",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "image": {
+ "name": "image",
+ "label": ""
+ },
+ "control_model": {
+ "name": "control_model",
+ "label": ""
+ },
+ "control_weight": {
+ "name": "control_weight",
+ "label": "",
+ "value": 0.25
+ },
+ "begin_step_percent": {
+ "name": "begin_step_percent",
+ "label": "",
+ "value": 0.5
+ },
+ "end_step_percent": {
+ "name": "end_step_percent",
+ "label": "",
+ "value": 0.85
+ },
+ "control_mode": {
+ "name": "control_mode",
+ "label": "Control Mode",
+ "value": "balanced"
+ },
+ "resize_mode": {
+ "name": "resize_mode",
+ "label": "",
+ "value": "just_resize"
+ }
+ }
+ },
+ "position": {
+ "x": -2675,
+ "y": -1325
+ }
+ },
+ {
+ "id": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "type": "invocation",
+ "data": {
+ "id": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "type": "noise",
+ "version": "1.0.2",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "seed": {
+ "name": "seed",
+ "label": "",
+ "value": 3
+ },
+ "width": {
+ "name": "width",
+ "label": "",
+ "value": 512
+ },
+ "height": {
+ "name": "height",
+ "label": "",
+ "value": 512
+ },
+ "use_cpu": {
+ "name": "use_cpu",
+ "label": "",
+ "value": true
+ }
+ }
+ },
+ "position": {
+ "x": -4025,
+ "y": -2025
+ }
+ }
+ ],
+ "edges": [
+ {
+ "id": "reactflow__edge-009b38e3-4e17-4ac5-958c-14891991ae28vae-117f982a-03da-49b1-bf9f-29711160ac02vae",
+ "type": "default",
+ "source": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "target": "117f982a-03da-49b1-bf9f-29711160ac02",
+ "sourceHandle": "vae",
+ "targetHandle": "vae"
+ },
+ {
+ "id": "reactflow__edge-009b38e3-4e17-4ac5-958c-14891991ae28vae-c3b60a50-8039-4924-90e3-8c608e1fecb5vae",
+ "type": "default",
+ "source": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "target": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
+ "sourceHandle": "vae",
+ "targetHandle": "vae"
+ },
+ {
+ "id": "reactflow__edge-33fe76a0-5efd-4482-a7f0-e2abf1223dc2conditioning-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7anegative_conditioning",
+ "type": "default",
+ "source": "33fe76a0-5efd-4482-a7f0-e2abf1223dc2",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "sourceHandle": "conditioning",
+ "targetHandle": "negative_conditioning"
+ },
+ {
+ "id": "reactflow__edge-009b38e3-4e17-4ac5-958c-14891991ae28clip-33fe76a0-5efd-4482-a7f0-e2abf1223dc2clip",
+ "type": "default",
+ "source": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "target": "33fe76a0-5efd-4482-a7f0-e2abf1223dc2",
+ "sourceHandle": "clip",
+ "targetHandle": "clip"
+ },
+ {
+ "id": "reactflow__edge-14469dfe-9f49-4a13-89a7-eb4d45794b2bconditioning-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7apositive_conditioning",
+ "type": "default",
+ "source": "14469dfe-9f49-4a13-89a7-eb4d45794b2b",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "sourceHandle": "conditioning",
+ "targetHandle": "positive_conditioning"
+ },
+ {
+ "id": "reactflow__edge-009b38e3-4e17-4ac5-958c-14891991ae28clip-14469dfe-9f49-4a13-89a7-eb4d45794b2bclip",
+ "type": "default",
+ "source": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "target": "14469dfe-9f49-4a13-89a7-eb4d45794b2b",
+ "sourceHandle": "clip",
+ "targetHandle": "clip"
+ },
+ {
+ "id": "reactflow__edge-009b38e3-4e17-4ac5-958c-14891991ae28unet-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7aunet",
+ "type": "default",
+ "source": "009b38e3-4e17-4ac5-958c-14891991ae28",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "sourceHandle": "unet",
+ "targetHandle": "unet"
+ },
+ {
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21-75a89685-0f82-40ed-9b88-e583673be9fc-collapsed",
+ "type": "collapsed",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "75a89685-0f82-40ed-9b88-e583673be9fc"
+ },
+ {
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21-1ed88043-3519-41d5-a895-07944f03de70-collapsed",
+ "type": "collapsed",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "1ed88043-3519-41d5-a895-07944f03de70"
+ },
+ {
+ "id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384-c8f5c671-8c87-4d96-a75e-a9937ac6bc03-collapsed",
+ "type": "collapsed",
+ "source": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "target": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03"
+ },
+ {
+ "id": "reactflow__edge-c8f5c671-8c87-4d96-a75e-a9937ac6bc03value-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7adenoising_start",
+ "type": "default",
+ "source": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "sourceHandle": "value",
+ "targetHandle": "denoising_start"
+ },
+ {
+ "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c-49a8cc12-aa19-48c5-b6b3-04e0b603b384-collapsed",
+ "type": "collapsed",
+ "source": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "target": "49a8cc12-aa19-48c5-b6b3-04e0b603b384"
+ },
+ {
+ "id": "75a89685-0f82-40ed-9b88-e583673be9fc-96e1bcd0-326b-4b67-8b14-239da2440aec-collapsed",
+ "type": "collapsed",
+ "source": "75a89685-0f82-40ed-9b88-e583673be9fc",
+ "target": "96e1bcd0-326b-4b67-8b14-239da2440aec"
+ },
+ {
+ "id": "00e2c587-f047-4413-ad15-bd31ea53ce22-71a116e1-c631-48b3-923d-acea4753b887-collapsed",
+ "type": "collapsed",
+ "source": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "target": "71a116e1-c631-48b3-923d-acea4753b887"
+ },
+ {
+ "id": "reactflow__edge-71a116e1-c631-48b3-923d-acea4753b887value-be4082d6-e238-40ea-a9df-fc0d725e8895begin_step_percent",
+ "type": "default",
+ "source": "71a116e1-c631-48b3-923d-acea4753b887",
+ "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "sourceHandle": "value",
+ "targetHandle": "begin_step_percent"
+ },
+ {
+ "id": "reactflow__edge-71a116e1-c631-48b3-923d-acea4753b887value-b78f53b6-2eae-4956-97b4-7e73768d1491end_step_percent",
+ "type": "default",
+ "source": "71a116e1-c631-48b3-923d-acea4753b887",
+ "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "sourceHandle": "value",
+ "targetHandle": "end_step_percent"
+ },
+ {
+ "id": "reactflow__edge-00e2c587-f047-4413-ad15-bd31ea53ce22value-71a116e1-c631-48b3-923d-acea4753b887a",
+ "type": "default",
+ "source": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "target": "71a116e1-c631-48b3-923d-acea4753b887",
+ "sourceHandle": "value",
+ "targetHandle": "a",
+ "hidden": true
+ },
+ {
+ "id": "reactflow__edge-bd094e2f-41e5-4b61-9f7b-56cf337d53favalue-00e2c587-f047-4413-ad15-bd31ea53ce22a",
+ "type": "default",
+ "source": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
+ "target": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "sourceHandle": "value",
+ "targetHandle": "a"
+ },
+ {
+ "id": "reactflow__edge-96e1bcd0-326b-4b67-8b14-239da2440aecvalue-be4082d6-e238-40ea-a9df-fc0d725e8895control_weight",
+ "type": "default",
+ "source": "96e1bcd0-326b-4b67-8b14-239da2440aec",
+ "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "sourceHandle": "value",
+ "targetHandle": "control_weight"
+ },
+ {
+ "id": "reactflow__edge-75a89685-0f82-40ed-9b88-e583673be9fcvalue-96e1bcd0-326b-4b67-8b14-239da2440aeca",
+ "type": "default",
+ "source": "75a89685-0f82-40ed-9b88-e583673be9fc",
+ "target": "96e1bcd0-326b-4b67-8b14-239da2440aec",
+ "sourceHandle": "value",
+ "targetHandle": "a",
+ "hidden": true
+ },
+ {
+ "id": "reactflow__edge-9b281506-4079-4a3d-ab40-b386156fcd21value-75a89685-0f82-40ed-9b88-e583673be9fca",
+ "type": "default",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "75a89685-0f82-40ed-9b88-e583673be9fc",
+ "sourceHandle": "value",
+ "targetHandle": "a",
+ "hidden": true
+ },
+ {
+ "id": "reactflow__edge-1ed88043-3519-41d5-a895-07944f03de70value-b78f53b6-2eae-4956-97b4-7e73768d1491control_weight",
+ "type": "default",
+ "source": "1ed88043-3519-41d5-a895-07944f03de70",
+ "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "sourceHandle": "value",
+ "targetHandle": "control_weight"
+ },
+ {
+ "id": "reactflow__edge-9b281506-4079-4a3d-ab40-b386156fcd21value-1ed88043-3519-41d5-a895-07944f03de70a",
+ "type": "default",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "1ed88043-3519-41d5-a895-07944f03de70",
+ "sourceHandle": "value",
+ "targetHandle": "a",
+ "hidden": true
+ },
+ {
+ "id": "reactflow__edge-bd094e2f-41e5-4b61-9f7b-56cf337d53favalue-9b281506-4079-4a3d-ab40-b386156fcd21a",
+ "type": "default",
+ "source": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
+ "target": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "sourceHandle": "value",
+ "targetHandle": "a"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeheight-8923451b-5a27-4395-b7f2-dce875fca6f5height",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "sourceHandle": "height",
+ "targetHandle": "height"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebewidth-8923451b-5a27-4395-b7f2-dce875fca6f5width",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "sourceHandle": "width",
+ "targetHandle": "width"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage-b78f53b6-2eae-4956-97b4-7e73768d1491image",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage-be4082d6-e238-40ea-a9df-fc0d725e8895image",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage-117f982a-03da-49b1-bf9f-29711160ac02image",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "117f982a-03da-49b1-bf9f-29711160ac02",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-011039f6-04cf-4607-8eb1-3304eb819c8cimage-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage",
+ "type": "default",
+ "source": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "target": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-f936ebb3-6902-4df9-a775-6a68bac2da70model-be4082d6-e238-40ea-a9df-fc0d725e8895control_model",
+ "type": "default",
+ "source": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "sourceHandle": "model",
+ "targetHandle": "control_model"
+ },
+ {
+ "id": "reactflow__edge-f936ebb3-6902-4df9-a775-6a68bac2da70model-b78f53b6-2eae-4956-97b4-7e73768d1491control_model",
+ "type": "default",
+ "source": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "sourceHandle": "model",
+ "targetHandle": "control_model"
+ },
+ {
+ "id": "reactflow__edge-00239057-20d4-4cd2-a010-28727b256ea2value-8923451b-5a27-4395-b7f2-dce875fca6f5seed",
+ "type": "default",
+ "source": "00239057-20d4-4cd2-a010-28727b256ea2",
+ "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "sourceHandle": "value",
+ "targetHandle": "seed"
+ },
+ {
+ "id": "reactflow__edge-094bc4ed-5c68-4342-84f4-51056c755796value-c3b60a50-8039-4924-90e3-8c608e1fecb5tiled",
+ "type": "default",
+ "source": "094bc4ed-5c68-4342-84f4-51056c755796",
+ "target": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
+ "sourceHandle": "value",
+ "targetHandle": "tiled"
+ },
+ {
+ "id": "reactflow__edge-094bc4ed-5c68-4342-84f4-51056c755796value-117f982a-03da-49b1-bf9f-29711160ac02tiled",
+ "type": "default",
+ "source": "094bc4ed-5c68-4342-84f4-51056c755796",
+ "target": "117f982a-03da-49b1-bf9f-29711160ac02",
+ "sourceHandle": "value",
+ "targetHandle": "tiled"
+ },
+ {
+ "id": "reactflow__edge-1dd915a3-6756-48ed-b68b-ee3b4bd06c1dvalue-14e65dbe-4249-4b25-9a63-3a10cfaeb61ca",
+ "type": "default",
+ "source": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "target": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "sourceHandle": "value",
+ "targetHandle": "a"
+ },
+ {
+ "id": "reactflow__edge-49a8cc12-aa19-48c5-b6b3-04e0b603b384value-c8f5c671-8c87-4d96-a75e-a9937ac6bc03a",
+ "type": "default",
+ "source": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "target": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "sourceHandle": "value",
+ "targetHandle": "a",
+ "hidden": true
+ },
+ {
+ "id": "reactflow__edge-14e65dbe-4249-4b25-9a63-3a10cfaeb61cvalue-49a8cc12-aa19-48c5-b6b3-04e0b603b384a",
+ "type": "default",
+ "source": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "target": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "sourceHandle": "value",
+ "targetHandle": "a",
+ "hidden": true
+ },
+ {
+ "id": "reactflow__edge-6636a27a-f130-4a13-b3e5-50b44e4a566fcollection-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7acontrol",
+ "type": "default",
+ "source": "6636a27a-f130-4a13-b3e5-50b44e4a566f",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "sourceHandle": "collection",
+ "targetHandle": "control"
+ },
+ {
+ "id": "reactflow__edge-b78f53b6-2eae-4956-97b4-7e73768d1491control-6636a27a-f130-4a13-b3e5-50b44e4a566fitem",
+ "type": "default",
+ "source": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "target": "6636a27a-f130-4a13-b3e5-50b44e4a566f",
+ "sourceHandle": "control",
+ "targetHandle": "item"
+ },
+ {
+ "id": "reactflow__edge-be4082d6-e238-40ea-a9df-fc0d725e8895control-6636a27a-f130-4a13-b3e5-50b44e4a566fitem",
+ "type": "default",
+ "source": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "target": "6636a27a-f130-4a13-b3e5-50b44e4a566f",
+ "sourceHandle": "control",
+ "targetHandle": "item"
+ },
+ {
+ "id": "reactflow__edge-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7alatents-c3b60a50-8039-4924-90e3-8c608e1fecb5latents",
+ "type": "default",
+ "source": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "target": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
+ "sourceHandle": "latents",
+ "targetHandle": "latents"
+ },
+ {
+ "id": "reactflow__edge-117f982a-03da-49b1-bf9f-29711160ac02latents-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7alatents",
+ "type": "default",
+ "source": "117f982a-03da-49b1-bf9f-29711160ac02",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "sourceHandle": "latents",
+ "targetHandle": "latents"
+ },
+ {
+ "id": "reactflow__edge-8923451b-5a27-4395-b7f2-dce875fca6f5noise-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7anoise",
+ "type": "default",
+ "source": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "sourceHandle": "noise",
+ "targetHandle": "noise"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SDXL (Beta).json b/invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SDXL.json
similarity index 63%
rename from invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SDXL (Beta).json
rename to invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SDXL.json
index b2842315c46..876ca6f8e6f 100644
--- a/invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SDXL (Beta).json
+++ b/invokeai/app/services/workflow_records/default_workflows/MultiDiffusion SDXL.json
@@ -1,44 +1,32 @@
{
- "name": "MultiDiffusion SDXL (Beta)",
+ "name": "MultiDiffusion SDXL",
"author": "Invoke",
"description": "A workflow to upscale an input image with tiled upscaling, using SDXL based models.",
- "version": "1.0.0",
+ "version": "1.1.0",
"contact": "invoke@invoke.ai",
"tags": "tiled, upscaling, sdxl",
"notes": "",
"exposedFields": [
{
- "nodeId": "1ba845a6-eb88-49a1-a490-5fe6754f3ec9",
- "fieldName": "value"
+ "nodeId": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "fieldName": "image"
},
{
- "nodeId": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
- "fieldName": "board"
+ "nodeId": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "fieldName": "scale"
},
{
- "nodeId": "5ca87ace-edf9-49c7-a424-cd42416b86a7",
- "fieldName": "image"
+ "nodeId": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
+ "fieldName": "board"
},
{
"nodeId": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
"fieldName": "a"
},
- {
- "nodeId": "696de0e1-cdd2-42e8-abeb-57a926bc6df6",
- "fieldName": "a"
- },
{
"nodeId": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
"fieldName": "a"
},
- {
- "nodeId": "e277e4b7-01cd-4daa-86ab-7bfa3cdcd9fd",
- "fieldName": "model"
- },
- {
- "nodeId": "f0cd0d2f-9614-43f7-9944-a75b8d5ccd65",
- "fieldName": "model_name"
- },
{
"nodeId": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
"fieldName": "value"
@@ -48,13 +36,17 @@
"fieldName": "value"
},
{
- "nodeId": "094bc4ed-5c68-4342-84f4-51056c755796",
- "fieldName": "value"
+ "nodeId": "e277e4b7-01cd-4daa-86ab-7bfa3cdcd9fd",
+ "fieldName": "model"
},
{
"nodeId": "100b3143-b3fb-4ff3-bb3c-8d4d3f89ae3a",
"fieldName": "vae_model"
},
+ {
+ "nodeId": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "fieldName": "image_to_image_model"
+ },
{
"nodeId": "f936ebb3-6902-4df9-a775-6a68bac2da70",
"fieldName": "model"
@@ -64,148 +56,13 @@
"version": "3.0.0",
"category": "default"
},
+ "id": "dd607062-9e1b-48b9-89ad-9762cdfbb8f4",
"nodes": [
{
- "id": "f936ebb3-6902-4df9-a775-6a68bac2da70",
- "type": "invocation",
- "data": {
- "id": "f936ebb3-6902-4df9-a775-6a68bac2da70",
- "type": "model_identifier",
- "version": "1.0.0",
- "label": "",
- "notes": "",
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "model": {
- "name": "model",
- "label": "ControlNet Model - choose xinsir's tile ControlNet",
- "value": {
- "key": "845b6959-1657-4164-be33-fe0f63ad1752",
- "hash": "random:3b602344599a53b4e4c80a2259362e122543e6f9e8e428be76ab910f9368704b",
- "name": "controlnet-tile-sdxl-1.0",
- "base": "sdxl",
- "type": "controlnet"
- }
- }
- }
- },
- "position": {
- "x": -3983.6167650620723,
- "y": -1329.1431151846386
- }
- },
- {
- "id": "00239057-20d4-4cd2-a010-28727b256ea2",
- "type": "invocation",
- "data": {
- "id": "00239057-20d4-4cd2-a010-28727b256ea2",
- "type": "rand_int",
- "version": "1.0.1",
- "label": "",
- "notes": "",
- "isOpen": false,
- "isIntermediate": true,
- "useCache": false,
- "inputs": {
- "low": {
- "name": "low",
- "label": "",
- "value": 0
- },
- "high": {
- "name": "high",
- "label": "",
- "value": 2147483647
- }
- }
- },
- "position": {
- "x": -4000,
- "y": -1800
- }
- },
- {
- "id": "094bc4ed-5c68-4342-84f4-51056c755796",
- "type": "invocation",
- "data": {
- "id": "094bc4ed-5c68-4342-84f4-51056c755796",
- "type": "boolean",
- "version": "1.0.1",
- "label": "Tiled Option",
- "notes": "",
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "value": {
- "name": "value",
- "label": "Tiled VAE (Saves VRAM, Color Inconsistency)",
- "value": false
- }
- }
- },
- "position": {
- "x": -2746.0467136971292,
- "y": -2219.070070545694
- }
- },
- {
- "id": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
- "type": "invocation",
- "data": {
- "id": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
- "type": "string",
- "version": "1.0.1",
- "label": "",
- "notes": "",
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "value": {
- "name": "value",
- "label": "Negative Prompt (Optional)",
- "value": ""
- }
- }
- },
- "position": {
- "x": -3525,
- "y": -2525
- }
- },
- {
- "id": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
- "type": "invocation",
- "data": {
- "id": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
- "type": "string",
- "version": "1.0.1",
- "label": "",
- "notes": "",
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "value": {
- "name": "value",
- "label": "Positive Prompt (Optional)",
- "value": ""
- }
- }
- },
- "position": {
- "x": -3525,
- "y": -2825
- }
- },
- {
- "id": "6daa9526-382b-491d-964f-f53fc308664f",
+ "id": "71a116e1-c631-48b3-923d-acea4753b887",
"type": "invocation",
"data": {
- "id": "6daa9526-382b-491d-964f-f53fc308664f",
+ "id": "71a116e1-c631-48b3-923d-acea4753b887",
"type": "float_math",
"version": "1.0.1",
"label": "",
@@ -222,25 +79,25 @@
"a": {
"name": "a",
"label": "",
- "value": 0.35
+ "value": 1
},
"b": {
"name": "b",
"label": "",
- "value": 100
+ "value": 0.3
}
}
},
"position": {
- "x": -3500,
- "y": -1450
+ "x": -3050,
+ "y": -1550
}
},
{
- "id": "f1afd295-860f-48b6-a76a-90609bf2cc11",
+ "id": "00e2c587-f047-4413-ad15-bd31ea53ce22",
"type": "invocation",
"data": {
- "id": "f1afd295-860f-48b6-a76a-90609bf2cc11",
+ "id": "00e2c587-f047-4413-ad15-bd31ea53ce22",
"type": "float_math",
"version": "1.0.1",
"label": "",
@@ -262,20 +119,20 @@
"b": {
"name": "b",
"label": "",
- "value": 0.013
+ "value": 0.025
}
}
},
"position": {
- "x": -3500,
- "y": -1550
+ "x": -3050,
+ "y": -1575
}
},
{
- "id": "88ae723e-4933-4371-b52d-3ada52a59d36",
+ "id": "96e1bcd0-326b-4b67-8b14-239da2440aec",
"type": "invocation",
"data": {
- "id": "88ae723e-4933-4371-b52d-3ada52a59d36",
+ "id": "96e1bcd0-326b-4b67-8b14-239da2440aec",
"type": "float_math",
"version": "1.0.1",
"label": "",
@@ -287,33 +144,33 @@
"operation": {
"name": "operation",
"label": "",
- "value": "ADD"
+ "value": "MUL"
},
"a": {
"name": "a",
"label": "",
- "value": 0
+ "value": 1
},
"b": {
"name": "b",
"label": "",
- "value": 100
+ "value": 0.45
}
}
},
"position": {
- "x": -3500,
- "y": -1500
+ "x": -3050,
+ "y": -1200
}
},
{
- "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "id": "75a89685-0f82-40ed-9b88-e583673be9fc",
"type": "invocation",
"data": {
- "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "id": "75a89685-0f82-40ed-9b88-e583673be9fc",
"type": "float_math",
"version": "1.0.1",
- "label": "Creativity Input",
+ "label": "",
"notes": "",
"isOpen": false,
"isIntermediate": true,
@@ -322,30 +179,30 @@
"operation": {
"name": "operation",
"label": "",
- "value": "MUL"
+ "value": "ADD"
},
"a": {
"name": "a",
- "label": "Creativity Control (-10 to 10)",
- "value": 5
+ "label": "",
+ "value": 1
},
"b": {
"name": "b",
"label": "",
- "value": -1
+ "value": 0.15
}
}
},
"position": {
- "x": -3500,
- "y": -2125
+ "x": -3050,
+ "y": -1225
}
},
{
- "id": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "id": "1ed88043-3519-41d5-a895-07944f03de70",
"type": "invocation",
"data": {
- "id": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "id": "1ed88043-3519-41d5-a895-07944f03de70",
"type": "float_math",
"version": "1.0.1",
"label": "",
@@ -357,7 +214,7 @@
"operation": {
"name": "operation",
"label": "",
- "value": "DIV"
+ "value": "ADD"
},
"a": {
"name": "a",
@@ -367,20 +224,20 @@
"b": {
"name": "b",
"label": "",
- "value": 100
+ "value": 0.3
}
}
},
"position": {
- "x": -3500,
- "y": -1975
+ "x": -3050,
+ "y": -1650
}
},
{
- "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21",
"type": "invocation",
"data": {
- "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21",
"type": "float_math",
"version": "1.0.1",
"label": "",
@@ -392,139 +249,228 @@
"operation": {
"name": "operation",
"label": "",
- "value": "ADD"
+ "value": "MUL"
},
"a": {
"name": "a",
- "label": "A",
- "value": 0
+ "label": "",
+ "value": 1
},
"b": {
"name": "b",
"label": "",
- "value": 10
+ "value": 0.032
}
}
},
"position": {
- "x": -3500,
- "y": -2075
+ "x": -3050,
+ "y": -1850
}
},
{
- "id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "id": "011039f6-04cf-4607-8eb1-3304eb819c8c",
"type": "invocation",
"data": {
- "id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
- "type": "float_math",
- "version": "1.0.1",
+ "id": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "type": "spandrel_image_to_image_autoscale",
+ "version": "1.0.0",
"label": "",
"notes": "",
- "isOpen": false,
+ "isOpen": true,
"isIntermediate": true,
"useCache": true,
"inputs": {
- "operation": {
- "name": "operation",
+ "board": {
+ "name": "board",
+ "label": ""
+ },
+ "metadata": {
+ "name": "metadata",
+ "label": ""
+ },
+ "image": {
+ "name": "image",
+ "label": "Image to Upscale"
+ },
+ "image_to_image_model": {
+ "name": "image_to_image_model",
"label": "",
- "value": "MUL"
+ "value": {
+ "key": "38bb1a29-8ede-42ba-b77f-64b3478896eb",
+ "hash": "blake3:e52fdbee46a484ebe9b3b20ea0aac0a35a453ab6d0d353da00acfd35ce7a91ed",
+ "name": "4xNomosWebPhoto_esrgan",
+ "base": "sdxl",
+ "type": "spandrel_image_to_image"
+ }
},
- "a": {
- "name": "a",
+ "tile_size": {
+ "name": "tile_size",
"label": "",
- "value": 1
+ "value": 512
},
- "b": {
- "name": "b",
+ "scale": {
+ "name": "scale",
+ "label": "Scale (2x, 4x, 8x, 16x)",
+ "value": 2
+ },
+ "fit_to_multiple_of_8": {
+ "name": "fit_to_multiple_of_8",
"label": "",
- "value": 4.99
+ "value": true
}
}
},
"position": {
- "x": -3500,
- "y": -2025
+ "x": -4750,
+ "y": -2125
}
},
{
- "id": "e4d5ca7c-8fcf-4c59-9c58-67194c80dc73",
+ "id": "f936ebb3-6902-4df9-a775-6a68bac2da70",
"type": "invocation",
"data": {
- "id": "e4d5ca7c-8fcf-4c59-9c58-67194c80dc73",
- "type": "float_math",
- "version": "1.0.1",
+ "id": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "type": "model_identifier",
+ "version": "1.0.0",
"label": "",
"notes": "",
- "isOpen": false,
+ "isOpen": true,
"isIntermediate": true,
"useCache": true,
"inputs": {
- "operation": {
- "name": "operation",
- "label": "",
- "value": "ADD"
- },
- "a": {
- "name": "a",
- "label": "",
- "value": 0
- },
- "b": {
- "name": "b",
- "label": "",
- "value": 1
+ "model": {
+ "name": "model",
+ "label": "ControlNet Model - Choose a Tile ControlNet",
+ "value": {
+ "key": "74f4651f-0ace-4b7b-b616-e98360257797",
+ "hash": "blake3:167a5b84583aaed3e5c8d660b45830e82e1c602743c689d3c27773c6c8b85b4a",
+ "name": "controlnet-tile-sdxl-1.0",
+ "base": "sdxl",
+ "type": "controlnet"
+ }
}
}
},
"position": {
- "x": -3500,
- "y": -1925
+ "x": -3450,
+ "y": -1450
}
},
{
- "id": "696de0e1-cdd2-42e8-abeb-57a926bc6df6",
+ "id": "00239057-20d4-4cd2-a010-28727b256ea2",
"type": "invocation",
"data": {
- "id": "696de0e1-cdd2-42e8-abeb-57a926bc6df6",
- "type": "float_math",
+ "id": "00239057-20d4-4cd2-a010-28727b256ea2",
+ "type": "rand_int",
"version": "1.0.1",
- "label": "Sharpness Input",
+ "label": "",
"notes": "",
- "isOpen": true,
+ "isOpen": false,
"isIntermediate": true,
- "useCache": true,
+ "useCache": false,
"inputs": {
- "operation": {
- "name": "operation",
+ "low": {
+ "name": "low",
"label": "",
- "value": "ADD"
- },
- "a": {
- "name": "a",
- "label": "Sharpness Control (-10 to 10)",
"value": 0
},
- "b": {
- "name": "b",
+ "high": {
+ "name": "high",
"label": "",
- "value": 10
+ "value": 2147483647
}
}
},
"position": {
- "x": -4750,
- "y": -2275
+ "x": -4025,
+ "y": -2075
}
},
{
- "id": "79390b60-4077-4f94-ad0a-4229cc73ddb2",
+ "id": "094bc4ed-5c68-4342-84f4-51056c755796",
"type": "invocation",
"data": {
- "id": "79390b60-4077-4f94-ad0a-4229cc73ddb2",
- "type": "float_math",
+ "id": "094bc4ed-5c68-4342-84f4-51056c755796",
+ "type": "boolean",
+ "version": "1.0.1",
+ "label": "Tiled Option",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "value": {
+ "name": "value",
+ "label": "Tiled VAE (Saves VRAM, Color Inconsistency)",
+ "value": true
+ }
+ }
+ },
+ "position": {
+ "x": -2675,
+ "y": -2475
+ }
+ },
+ {
+ "id": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
+ "type": "invocation",
+ "data": {
+ "id": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
+ "type": "string",
+ "version": "1.0.1",
+ "label": "",
+ "notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "value": {
+ "name": "value",
+ "label": "Negative Prompt (Optional)",
+ "value": ""
+ }
+ }
+ },
+ "position": {
+ "x": -3500,
+ "y": -2525
+ }
+ },
+ {
+ "id": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
+ "type": "invocation",
+ "data": {
+ "id": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
+ "type": "string",
"version": "1.0.1",
"label": "",
"notes": "",
+ "isOpen": true,
+ "isIntermediate": true,
+ "useCache": true,
+ "inputs": {
+ "value": {
+ "name": "value",
+ "label": "Positive Prompt (Optional)",
+ "value": ""
+ }
+ }
+ },
+ "position": {
+ "x": -3500,
+ "y": -2825
+ }
+ },
+ {
+ "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "type": "invocation",
+ "data": {
+ "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "type": "float_math",
+ "version": "1.0.1",
+ "label": "Creativity Input",
+ "notes": "",
"isOpen": false,
"isIntermediate": true,
"useCache": true,
@@ -536,26 +482,26 @@
},
"a": {
"name": "a",
- "label": "",
- "value": 1
+ "label": "Creativity Control (-10 to 10)",
+ "value": 0
},
"b": {
"name": "b",
"label": "",
- "value": 3.75
+ "value": -1
}
}
},
"position": {
- "x": -4750,
- "y": -2000
+ "x": -3500,
+ "y": -2125
}
},
{
- "id": "4950132a-2d06-4571-b2c0-55cb37a31e9b",
+ "id": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
"type": "invocation",
"data": {
- "id": "4950132a-2d06-4571-b2c0-55cb37a31e9b",
+ "id": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
"type": "float_math",
"version": "1.0.1",
"label": "",
@@ -567,33 +513,33 @@
"operation": {
"name": "operation",
"label": "",
- "value": "ADD"
+ "value": "DIV"
},
"a": {
"name": "a",
"label": "",
- "value": 25
+ "value": 1
},
"b": {
"name": "b",
"label": "",
- "value": 1
+ "value": 100
}
}
},
"position": {
- "x": -4750,
- "y": -1950
+ "x": -3500,
+ "y": -1975
}
},
{
- "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
+ "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
"type": "invocation",
"data": {
- "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
+ "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
"type": "float_math",
"version": "1.0.1",
- "label": "Structural Input",
+ "label": "",
"notes": "",
"isOpen": false,
"isIntermediate": true,
@@ -606,7 +552,7 @@
},
"a": {
"name": "a",
- "label": "Structural Control (-10 to 10)",
+ "label": "A",
"value": 0
},
"b": {
@@ -618,14 +564,14 @@
},
"position": {
"x": -3500,
- "y": -1700
+ "y": -2075
}
},
{
- "id": "bc53651f-208b-440c-be30-f93f72ae700e",
+ "id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
"type": "invocation",
"data": {
- "id": "bc53651f-208b-440c-be30-f93f72ae700e",
+ "id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
"type": "float_math",
"version": "1.0.1",
"label": "",
@@ -647,25 +593,25 @@
"b": {
"name": "b",
"label": "",
- "value": 0.025
+ "value": 4.99
}
}
},
"position": {
"x": -3500,
- "y": -1650
+ "y": -2025
}
},
{
- "id": "67346654-cac0-446a-8cde-9af4b5a029a6",
+ "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
"type": "invocation",
"data": {
- "id": "67346654-cac0-446a-8cde-9af4b5a029a6",
+ "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
"type": "float_math",
"version": "1.0.1",
- "label": "",
+ "label": "Structural Input",
"notes": "",
- "isOpen": false,
+ "isOpen": true,
"isIntermediate": true,
"useCache": true,
"inputs": {
@@ -676,19 +622,19 @@
},
"a": {
"name": "a",
- "label": "",
- "value": 0.3
+ "label": "Structural Control (-10 to 10)",
+ "value": 0
},
"b": {
"name": "b",
"label": "",
- "value": 1
+ "value": 10
}
}
},
"position": {
- "x": -3500,
- "y": -1600
+ "x": -3050,
+ "y": -2100
}
},
{
@@ -711,8 +657,8 @@
}
},
"position": {
- "x": -3125,
- "y": -1500
+ "x": -2275,
+ "y": -2075
}
},
{
@@ -722,7 +668,7 @@
"id": "b78f53b6-2eae-4956-97b4-7e73768d1491",
"type": "controlnet",
"version": "1.1.2",
- "label": "ControlNet (use xinsir's tile ControlNet)",
+ "label": "Initial Control (Use Tile)",
"notes": "",
"isOpen": true,
"isIntermediate": true,
@@ -764,8 +710,8 @@
}
},
"position": {
- "x": -3493.4229674963885,
- "y": -1359.2223984776113
+ "x": -2675,
+ "y": -1775
}
},
{
@@ -836,7 +782,7 @@
}
},
"position": {
- "x": -3525,
+ "x": -3500,
"y": -2300
}
},
@@ -857,9 +803,9 @@
"name": "vae_model",
"label": "",
"value": {
- "key": "4bc2bddf-94d9-4efe-a8e2-5eda28710f4c",
- "hash": "random:67e47a77a1fcef9c0f5cd5d889d71c191f07383a0bf587f1849b2bc3f359440a",
- "name": "sdxl-vae-fp16-fix",
+ "key": "ff926845-090e-4d46-b81e-30289ee47474",
+ "hash": "9705ab1c31fa96b308734214fb7571a958621c7a9247eed82b7d277145f8d9fa",
+ "name": "VAEFix",
"base": "sdxl",
"type": "vae"
}
@@ -867,7 +813,7 @@
}
},
"position": {
- "x": -4000,
+ "x": -4025,
"y": -2575
}
},
@@ -886,12 +832,19 @@
"inputs": {
"model": {
"name": "model",
- "label": "SDXL Model"
+ "label": "SDXL Model",
+ "value": {
+ "key": "ab191f73-68d2-492c-8aec-b438a8cf0f45",
+ "hash": "blake3:2d50e940627e3bf555f015280ec0976d5c1fa100f7bc94e95ffbfc770e98b6fe",
+ "name": "CustomXLv7",
+ "base": "sdxl",
+ "type": "main"
+ }
}
}
},
"position": {
- "x": -4000,
+ "x": -4025,
"y": -2825
}
},
@@ -963,7 +916,7 @@
}
},
"position": {
- "x": -3525,
+ "x": -3500,
"y": -2600
}
},
@@ -976,7 +929,7 @@
"version": "1.2.2",
"label": "",
"notes": "",
- "isOpen": false,
+ "isOpen": true,
"isIntermediate": true,
"useCache": true,
"inputs": {
@@ -1006,49 +959,7 @@
},
"position": {
"x": -4400,
- "y": -1875
- }
- },
- {
- "id": "53c2d5fd-863d-4950-93e0-628f3d61b493",
- "type": "invocation",
- "data": {
- "id": "53c2d5fd-863d-4950-93e0-628f3d61b493",
- "type": "unsharp_mask",
- "version": "1.2.2",
- "label": "",
- "notes": "",
- "isOpen": false,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "board": {
- "name": "board",
- "label": ""
- },
- "metadata": {
- "name": "metadata",
- "label": ""
- },
- "image": {
- "name": "image",
- "label": ""
- },
- "radius": {
- "name": "radius",
- "label": "",
- "value": 2
- },
- "strength": {
- "name": "strength",
- "label": "",
- "value": 50
- }
- }
- },
- "position": {
- "x": -4750,
- "y": -1875
+ "y": -2125
}
},
{
@@ -1090,8 +1001,8 @@
}
},
"position": {
- "x": -4000,
- "y": -1875
+ "x": -4025,
+ "y": -2125
}
},
{
@@ -1141,8 +1052,8 @@
}
},
"position": {
- "x": -2750,
- "y": -2575
+ "x": -2675,
+ "y": -2825
}
},
{
@@ -1230,207 +1141,65 @@
}
},
"position": {
- "x": -3125,
- "y": -2575
+ "x": -3050,
+ "y": -2825
}
},
{
- "id": "1ba845a6-eb88-49a1-a490-5fe6754f3ec9",
+ "id": "be4082d6-e238-40ea-a9df-fc0d725e8895",
"type": "invocation",
"data": {
- "id": "1ba845a6-eb88-49a1-a490-5fe6754f3ec9",
- "type": "integer",
- "version": "1.0.1",
- "label": "",
+ "id": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "type": "controlnet",
+ "version": "1.1.2",
+ "label": "Second Phase Control (Use Tile)",
"notes": "",
"isOpen": true,
"isIntermediate": true,
"useCache": true,
"inputs": {
- "value": {
- "name": "value",
- "label": "Scale (2x, 4x)",
- "value": 2
+ "image": {
+ "name": "image",
+ "label": ""
+ },
+ "control_model": {
+ "name": "control_model",
+ "label": ""
+ },
+ "control_weight": {
+ "name": "control_weight",
+ "label": "",
+ "value": 0.25
+ },
+ "begin_step_percent": {
+ "name": "begin_step_percent",
+ "label": "",
+ "value": 0.5
+ },
+ "end_step_percent": {
+ "name": "end_step_percent",
+ "label": "",
+ "value": 0.85
+ },
+ "control_mode": {
+ "name": "control_mode",
+ "label": "Control Mode",
+ "value": "balanced"
+ },
+ "resize_mode": {
+ "name": "resize_mode",
+ "label": "",
+ "value": "just_resize"
}
}
},
"position": {
- "x": -4400,
- "y": -2175
+ "x": -2675,
+ "y": -1325
}
},
{
- "id": "d350feac-9686-4e0d-bd46-a96bd2630818",
- "type": "invocation",
- "data": {
- "id": "d350feac-9686-4e0d-bd46-a96bd2630818",
- "type": "integer_math",
- "version": "1.0.1",
- "label": "",
- "notes": "",
- "isOpen": false,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "operation": {
- "name": "operation",
- "label": "",
- "value": "MUL"
- },
- "a": {
- "name": "a",
- "label": "",
- "value": 1
- },
- "b": {
- "name": "b",
- "label": "",
- "value": 1
- }
- }
- },
- "position": {
- "x": -4400,
- "y": -1950
- }
- },
- {
- "id": "5b256f14-caab-40ff-b8f0-9679cd542163",
- "type": "invocation",
- "data": {
- "id": "5b256f14-caab-40ff-b8f0-9679cd542163",
- "type": "integer_math",
- "version": "1.0.1",
- "label": "",
- "notes": "",
- "isOpen": false,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "operation": {
- "name": "operation",
- "label": "",
- "value": "MUL"
- },
- "a": {
- "name": "a",
- "label": "",
- "value": 1
- },
- "b": {
- "name": "b",
- "label": "",
- "value": 1
- }
- }
- },
- "position": {
- "x": -4400,
- "y": -2000
- }
- },
- {
- "id": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "type": "invocation",
- "data": {
- "id": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "type": "img_resize",
- "version": "1.2.2",
- "label": "",
- "notes": "",
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "board": {
- "name": "board",
- "label": ""
- },
- "metadata": {
- "name": "metadata",
- "label": ""
- },
- "image": {
- "name": "image",
- "label": ""
- },
- "width": {
- "name": "width",
- "label": "",
- "value": 512
- },
- "height": {
- "name": "height",
- "label": "",
- "value": 512
- },
- "resample_mode": {
- "name": "resample_mode",
- "label": "",
- "value": "lanczos"
- }
- }
- },
- "position": {
- "x": -4375,
- "y": -1825
- }
- },
- {
- "id": "be4082d6-e238-40ea-a9df-fc0d725e8895",
- "type": "invocation",
- "data": {
- "id": "be4082d6-e238-40ea-a9df-fc0d725e8895",
- "type": "controlnet",
- "version": "1.1.2",
- "label": "ControlNet (use xinsir's tile ControlNet)",
- "notes": "",
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "image": {
- "name": "image",
- "label": ""
- },
- "control_model": {
- "name": "control_model",
- "label": ""
- },
- "control_weight": {
- "name": "control_weight",
- "label": "",
- "value": 0.25
- },
- "begin_step_percent": {
- "name": "begin_step_percent",
- "label": "",
- "value": 0.5
- },
- "end_step_percent": {
- "name": "end_step_percent",
- "label": "",
- "value": 0.8
- },
- "control_mode": {
- "name": "control_mode",
- "label": "Control Mode",
- "value": "balanced"
- },
- "resize_mode": {
- "name": "resize_mode",
- "label": "",
- "value": "just_resize"
- }
- }
- },
- "position": {
- "x": -3131.577032503611,
- "y": -1392.1075609956667
- }
- },
- {
- "id": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "id": "8923451b-5a27-4395-b7f2-dce875fca6f5",
"type": "invocation",
"data": {
"id": "8923451b-5a27-4395-b7f2-dce875fca6f5",
@@ -1465,163 +1234,23 @@
}
},
"position": {
- "x": -4000,
- "y": -1750
- }
- },
- {
- "id": "f0cd0d2f-9614-43f7-9944-a75b8d5ccd65",
- "type": "invocation",
- "data": {
- "id": "f0cd0d2f-9614-43f7-9944-a75b8d5ccd65",
- "type": "esrgan",
- "version": "1.3.2",
- "label": "",
- "notes": "",
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true,
- "inputs": {
- "board": {
- "name": "board",
- "label": ""
- },
- "metadata": {
- "name": "metadata",
- "label": ""
- },
- "image": {
- "name": "image",
- "label": ""
- },
- "model_name": {
- "name": "model_name",
- "label": "Upscaling Model",
- "value": "RealESRGAN_x4plus.pth"
- },
- "tile_size": {
- "name": "tile_size",
- "label": "",
- "value": 500
- }
- }
- },
- "position": {
- "x": -4750,
- "y": -1825
- }
- },
- {
- "id": "7dbb756b-7d79-431c-a46d-d8f7b082c127",
- "type": "invocation",
- "data": {
- "id": "7dbb756b-7d79-431c-a46d-d8f7b082c127",
- "version": "1.0.1",
- "label": "",
- "notes": "",
- "type": "float_to_int",
- "inputs": {
- "value": {
- "name": "value",
- "label": "",
- "value": 0
- },
- "multiple": {
- "name": "multiple",
- "label": "",
- "value": 8
- },
- "method": {
- "name": "method",
- "label": "",
- "value": "Floor"
- }
- },
- "isOpen": false,
- "isIntermediate": true,
- "useCache": true
- },
- "position": {
- "x": -4000,
- "y": -1950
- }
- },
- {
- "id": "5ca87ace-edf9-49c7-a424-cd42416b86a7",
- "type": "invocation",
- "data": {
- "id": "5ca87ace-edf9-49c7-a424-cd42416b86a7",
- "version": "1.0.2",
- "label": "",
- "notes": "",
- "type": "image",
- "inputs": {
- "image": {
- "name": "image",
- "label": "Image to Upscale"
- }
- },
- "isOpen": true,
- "isIntermediate": true,
- "useCache": true
- },
- "position": {
- "x": -4750,
- "y": -2850
- }
- },
- {
- "id": "f5d9bf3b-2646-4b17-9894-20fd2b4218ea",
- "type": "invocation",
- "data": {
- "id": "f5d9bf3b-2646-4b17-9894-20fd2b4218ea",
- "version": "1.0.1",
- "label": "",
- "notes": "",
- "type": "float_to_int",
- "inputs": {
- "value": {
- "name": "value",
- "label": "",
- "value": 8
- },
- "multiple": {
- "name": "multiple",
- "label": "",
- "value": 8
- },
- "method": {
- "name": "method",
- "label": "",
- "value": "Floor"
- }
- },
- "isOpen": false,
- "isIntermediate": true,
- "useCache": true
- },
- "position": {
- "x": -4000,
- "y": -2000
+ "x": -4025,
+ "y": -2025
}
}
],
"edges": [
{
- "id": "reactflow__edge-f936ebb3-6902-4df9-a775-6a68bac2da70model-be4082d6-e238-40ea-a9df-fc0d725e8895control_model",
- "type": "default",
- "source": "f936ebb3-6902-4df9-a775-6a68bac2da70",
- "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
- "sourceHandle": "model",
- "targetHandle": "control_model"
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21-75a89685-0f82-40ed-9b88-e583673be9fc-collapsed",
+ "type": "collapsed",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "75a89685-0f82-40ed-9b88-e583673be9fc"
},
{
- "id": "reactflow__edge-f936ebb3-6902-4df9-a775-6a68bac2da70model-b78f53b6-2eae-4956-97b4-7e73768d1491control_model",
- "type": "default",
- "source": "f936ebb3-6902-4df9-a775-6a68bac2da70",
- "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
- "sourceHandle": "model",
- "targetHandle": "control_model"
+ "id": "9b281506-4079-4a3d-ab40-b386156fcd21-1ed88043-3519-41d5-a895-07944f03de70-collapsed",
+ "type": "collapsed",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "1ed88043-3519-41d5-a895-07944f03de70"
},
{
"id": "49a8cc12-aa19-48c5-b6b3-04e0b603b384-c8f5c671-8c87-4d96-a75e-a9937ac6bc03-collapsed",
@@ -1630,291 +1259,264 @@
"target": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03"
},
{
- "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c-49a8cc12-aa19-48c5-b6b3-04e0b603b384-collapsed",
- "type": "collapsed",
- "source": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
- "target": "49a8cc12-aa19-48c5-b6b3-04e0b603b384"
- },
- {
- "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d-14e65dbe-4249-4b25-9a63-3a10cfaeb61c-collapsed",
- "type": "collapsed",
- "source": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
- "target": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c"
- },
- {
- "id": "reactflow__edge-00239057-20d4-4cd2-a010-28727b256ea2value-8923451b-5a27-4395-b7f2-dce875fca6f5seed",
- "type": "default",
- "source": "00239057-20d4-4cd2-a010-28727b256ea2",
- "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
- "sourceHandle": "value",
- "targetHandle": "seed"
- },
- {
- "id": "reactflow__edge-094bc4ed-5c68-4342-84f4-51056c755796value-c3b60a50-8039-4924-90e3-8c608e1fecb5tiled",
- "type": "default",
- "source": "094bc4ed-5c68-4342-84f4-51056c755796",
- "target": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
- "sourceHandle": "value",
- "targetHandle": "tiled"
- },
- {
- "id": "reactflow__edge-094bc4ed-5c68-4342-84f4-51056c755796value-117f982a-03da-49b1-bf9f-29711160ac02tiled",
- "type": "default",
- "source": "094bc4ed-5c68-4342-84f4-51056c755796",
- "target": "117f982a-03da-49b1-bf9f-29711160ac02",
- "sourceHandle": "value",
- "targetHandle": "tiled"
- },
- {
- "id": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03-e4d5ca7c-8fcf-4c59-9c58-67194c80dc73-collapsed",
- "type": "collapsed",
- "source": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
- "target": "e4d5ca7c-8fcf-4c59-9c58-67194c80dc73"
- },
- {
- "id": "d350feac-9686-4e0d-bd46-a96bd2630818-7dbb756b-7d79-431c-a46d-d8f7b082c127-collapsed",
- "type": "collapsed",
- "source": "d350feac-9686-4e0d-bd46-a96bd2630818",
- "target": "7dbb756b-7d79-431c-a46d-d8f7b082c127"
- },
- {
- "id": "5b256f14-caab-40ff-b8f0-9679cd542163-f5d9bf3b-2646-4b17-9894-20fd2b4218ea-collapsed",
- "type": "collapsed",
- "source": "5b256f14-caab-40ff-b8f0-9679cd542163",
- "target": "f5d9bf3b-2646-4b17-9894-20fd2b4218ea"
- },
- {
- "id": "4950132a-2d06-4571-b2c0-55cb37a31e9b-041c59cc-f9e4-4dc9-8b31-84648c5f3ebe-collapsed",
- "type": "collapsed",
- "source": "4950132a-2d06-4571-b2c0-55cb37a31e9b",
- "target": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe"
- },
- {
- "id": "4950132a-2d06-4571-b2c0-55cb37a31e9b-53c2d5fd-863d-4950-93e0-628f3d61b493-collapsed",
- "type": "collapsed",
- "source": "4950132a-2d06-4571-b2c0-55cb37a31e9b",
- "target": "53c2d5fd-863d-4950-93e0-628f3d61b493"
- },
- {
- "id": "reactflow__edge-f5ca24ee-21c5-4c8c-8d3c-371b5079b086value-27215391-b20e-412a-b854-7fa5927f5437style",
- "type": "default",
- "source": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
- "target": "27215391-b20e-412a-b854-7fa5927f5437",
- "sourceHandle": "value",
- "targetHandle": "style"
- },
- {
- "id": "reactflow__edge-f5ca24ee-21c5-4c8c-8d3c-371b5079b086value-27215391-b20e-412a-b854-7fa5927f5437prompt",
- "type": "default",
- "source": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
- "target": "27215391-b20e-412a-b854-7fa5927f5437",
- "sourceHandle": "value",
- "targetHandle": "prompt"
- },
- {
- "id": "reactflow__edge-c26bff37-4f12-482f-ba45-3a5d729b4c4fvalue-6142b69a-323f-4ecd-a7e5-67dc61349c51style",
+ "id": "reactflow__edge-c8f5c671-8c87-4d96-a75e-a9937ac6bc03value-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7adenoising_start",
"type": "default",
- "source": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
- "target": "6142b69a-323f-4ecd-a7e5-67dc61349c51",
+ "source": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
"sourceHandle": "value",
- "targetHandle": "style"
+ "targetHandle": "denoising_start"
},
{
- "id": "reactflow__edge-c26bff37-4f12-482f-ba45-3a5d729b4c4fvalue-6142b69a-323f-4ecd-a7e5-67dc61349c51prompt",
- "type": "default",
- "source": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
- "target": "6142b69a-323f-4ecd-a7e5-67dc61349c51",
- "sourceHandle": "value",
- "targetHandle": "prompt"
+ "id": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c-49a8cc12-aa19-48c5-b6b3-04e0b603b384-collapsed",
+ "type": "collapsed",
+ "source": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "target": "49a8cc12-aa19-48c5-b6b3-04e0b603b384"
},
{
- "id": "88ae723e-4933-4371-b52d-3ada52a59d36-6daa9526-382b-491d-964f-f53fc308664f-collapsed",
+ "id": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d-14e65dbe-4249-4b25-9a63-3a10cfaeb61c-collapsed",
"type": "collapsed",
- "source": "88ae723e-4933-4371-b52d-3ada52a59d36",
- "target": "6daa9526-382b-491d-964f-f53fc308664f"
+ "source": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "target": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c"
},
{
- "id": "f1afd295-860f-48b6-a76a-90609bf2cc11-88ae723e-4933-4371-b52d-3ada52a59d36-collapsed",
+ "id": "75a89685-0f82-40ed-9b88-e583673be9fc-96e1bcd0-326b-4b67-8b14-239da2440aec-collapsed",
"type": "collapsed",
- "source": "f1afd295-860f-48b6-a76a-90609bf2cc11",
- "target": "88ae723e-4933-4371-b52d-3ada52a59d36"
+ "source": "75a89685-0f82-40ed-9b88-e583673be9fc",
+ "target": "96e1bcd0-326b-4b67-8b14-239da2440aec"
},
{
- "id": "bc53651f-208b-440c-be30-f93f72ae700e-67346654-cac0-446a-8cde-9af4b5a029a6-collapsed",
+ "id": "00e2c587-f047-4413-ad15-bd31ea53ce22-71a116e1-c631-48b3-923d-acea4753b887-collapsed",
"type": "collapsed",
- "source": "bc53651f-208b-440c-be30-f93f72ae700e",
- "target": "67346654-cac0-446a-8cde-9af4b5a029a6"
+ "source": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "target": "71a116e1-c631-48b3-923d-acea4753b887"
},
{
- "id": "reactflow__edge-67346654-cac0-446a-8cde-9af4b5a029a6value-be4082d6-e238-40ea-a9df-fc0d725e8895begin_step_percent",
+ "id": "reactflow__edge-71a116e1-c631-48b3-923d-acea4753b887value-be4082d6-e238-40ea-a9df-fc0d725e8895begin_step_percent",
"type": "default",
- "source": "67346654-cac0-446a-8cde-9af4b5a029a6",
+ "source": "71a116e1-c631-48b3-923d-acea4753b887",
"target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
"sourceHandle": "value",
"targetHandle": "begin_step_percent"
},
{
- "id": "reactflow__edge-67346654-cac0-446a-8cde-9af4b5a029a6value-b78f53b6-2eae-4956-97b4-7e73768d1491end_step_percent",
+ "id": "reactflow__edge-71a116e1-c631-48b3-923d-acea4753b887value-b78f53b6-2eae-4956-97b4-7e73768d1491end_step_percent",
"type": "default",
- "source": "67346654-cac0-446a-8cde-9af4b5a029a6",
+ "source": "71a116e1-c631-48b3-923d-acea4753b887",
"target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
"sourceHandle": "value",
"targetHandle": "end_step_percent"
},
{
- "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa-f1afd295-860f-48b6-a76a-90609bf2cc11-collapsed",
- "type": "collapsed",
- "source": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
- "target": "f1afd295-860f-48b6-a76a-90609bf2cc11"
+ "id": "reactflow__edge-00e2c587-f047-4413-ad15-bd31ea53ce22value-71a116e1-c631-48b3-923d-acea4753b887a",
+ "type": "default",
+ "source": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "target": "71a116e1-c631-48b3-923d-acea4753b887",
+ "sourceHandle": "value",
+ "targetHandle": "a",
+ "hidden": true
},
{
- "id": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa-bc53651f-208b-440c-be30-f93f72ae700e-collapsed",
- "type": "collapsed",
+ "id": "reactflow__edge-bd094e2f-41e5-4b61-9f7b-56cf337d53favalue-00e2c587-f047-4413-ad15-bd31ea53ce22a",
+ "type": "default",
"source": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
- "target": "bc53651f-208b-440c-be30-f93f72ae700e"
+ "target": "00e2c587-f047-4413-ad15-bd31ea53ce22",
+ "sourceHandle": "value",
+ "targetHandle": "a"
},
{
- "id": "reactflow__edge-bc53651f-208b-440c-be30-f93f72ae700evalue-67346654-cac0-446a-8cde-9af4b5a029a6b",
+ "id": "reactflow__edge-96e1bcd0-326b-4b67-8b14-239da2440aecvalue-be4082d6-e238-40ea-a9df-fc0d725e8895control_weight",
"type": "default",
- "source": "bc53651f-208b-440c-be30-f93f72ae700e",
- "target": "67346654-cac0-446a-8cde-9af4b5a029a6",
+ "source": "96e1bcd0-326b-4b67-8b14-239da2440aec",
+ "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
"sourceHandle": "value",
- "targetHandle": "b",
- "hidden": true
+ "targetHandle": "control_weight"
},
{
- "id": "reactflow__edge-6daa9526-382b-491d-964f-f53fc308664fvalue-b78f53b6-2eae-4956-97b4-7e73768d1491control_weight",
+ "id": "reactflow__edge-75a89685-0f82-40ed-9b88-e583673be9fcvalue-96e1bcd0-326b-4b67-8b14-239da2440aeca",
"type": "default",
- "source": "6daa9526-382b-491d-964f-f53fc308664f",
- "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "source": "75a89685-0f82-40ed-9b88-e583673be9fc",
+ "target": "96e1bcd0-326b-4b67-8b14-239da2440aec",
"sourceHandle": "value",
- "targetHandle": "control_weight"
+ "targetHandle": "a",
+ "hidden": true
},
{
- "id": "reactflow__edge-88ae723e-4933-4371-b52d-3ada52a59d36value-6daa9526-382b-491d-964f-f53fc308664fb",
+ "id": "reactflow__edge-9b281506-4079-4a3d-ab40-b386156fcd21value-75a89685-0f82-40ed-9b88-e583673be9fca",
"type": "default",
- "source": "88ae723e-4933-4371-b52d-3ada52a59d36",
- "target": "6daa9526-382b-491d-964f-f53fc308664f",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "75a89685-0f82-40ed-9b88-e583673be9fc",
"sourceHandle": "value",
- "targetHandle": "b",
+ "targetHandle": "a",
"hidden": true
},
{
- "id": "reactflow__edge-88ae723e-4933-4371-b52d-3ada52a59d36value-be4082d6-e238-40ea-a9df-fc0d725e8895control_weight",
+ "id": "reactflow__edge-1ed88043-3519-41d5-a895-07944f03de70value-b78f53b6-2eae-4956-97b4-7e73768d1491control_weight",
"type": "default",
- "source": "88ae723e-4933-4371-b52d-3ada52a59d36",
- "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "source": "1ed88043-3519-41d5-a895-07944f03de70",
+ "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
"sourceHandle": "value",
"targetHandle": "control_weight"
},
{
- "id": "reactflow__edge-f1afd295-860f-48b6-a76a-90609bf2cc11value-88ae723e-4933-4371-b52d-3ada52a59d36b",
+ "id": "reactflow__edge-9b281506-4079-4a3d-ab40-b386156fcd21value-1ed88043-3519-41d5-a895-07944f03de70a",
"type": "default",
- "source": "f1afd295-860f-48b6-a76a-90609bf2cc11",
- "target": "88ae723e-4933-4371-b52d-3ada52a59d36",
+ "source": "9b281506-4079-4a3d-ab40-b386156fcd21",
+ "target": "1ed88043-3519-41d5-a895-07944f03de70",
"sourceHandle": "value",
- "targetHandle": "b",
+ "targetHandle": "a",
"hidden": true
},
{
- "id": "reactflow__edge-bd094e2f-41e5-4b61-9f7b-56cf337d53favalue-f1afd295-860f-48b6-a76a-90609bf2cc11a",
+ "id": "reactflow__edge-bd094e2f-41e5-4b61-9f7b-56cf337d53favalue-9b281506-4079-4a3d-ab40-b386156fcd21a",
"type": "default",
"source": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
- "target": "f1afd295-860f-48b6-a76a-90609bf2cc11",
+ "target": "9b281506-4079-4a3d-ab40-b386156fcd21",
"sourceHandle": "value",
- "targetHandle": "a",
- "hidden": true
+ "targetHandle": "a"
},
{
- "id": "reactflow__edge-1dd915a3-6756-48ed-b68b-ee3b4bd06c1dvalue-14e65dbe-4249-4b25-9a63-3a10cfaeb61ca",
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeheight-8923451b-5a27-4395-b7f2-dce875fca6f5height",
"type": "default",
- "source": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
- "target": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
- "sourceHandle": "value",
- "targetHandle": "a",
- "hidden": true
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "sourceHandle": "height",
+ "targetHandle": "height"
},
{
- "id": "reactflow__edge-e4d5ca7c-8fcf-4c59-9c58-67194c80dc73value-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7adenoising_start",
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebewidth-8923451b-5a27-4395-b7f2-dce875fca6f5width",
"type": "default",
- "source": "e4d5ca7c-8fcf-4c59-9c58-67194c80dc73",
- "target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
+ "sourceHandle": "width",
+ "targetHandle": "width"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage-b78f53b6-2eae-4956-97b4-7e73768d1491image",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage-be4082d6-e238-40ea-a9df-fc0d725e8895image",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage-117f982a-03da-49b1-bf9f-29711160ac02image",
+ "type": "default",
+ "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "target": "117f982a-03da-49b1-bf9f-29711160ac02",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-011039f6-04cf-4607-8eb1-3304eb819c8cimage-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage",
+ "type": "default",
+ "source": "011039f6-04cf-4607-8eb1-3304eb819c8c",
+ "target": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "sourceHandle": "image",
+ "targetHandle": "image"
+ },
+ {
+ "id": "reactflow__edge-f936ebb3-6902-4df9-a775-6a68bac2da70model-be4082d6-e238-40ea-a9df-fc0d725e8895control_model",
+ "type": "default",
+ "source": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
+ "sourceHandle": "model",
+ "targetHandle": "control_model"
+ },
+ {
+ "id": "reactflow__edge-f936ebb3-6902-4df9-a775-6a68bac2da70model-b78f53b6-2eae-4956-97b4-7e73768d1491control_model",
+ "type": "default",
+ "source": "f936ebb3-6902-4df9-a775-6a68bac2da70",
+ "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
+ "sourceHandle": "model",
+ "targetHandle": "control_model"
+ },
+ {
+ "id": "reactflow__edge-00239057-20d4-4cd2-a010-28727b256ea2value-8923451b-5a27-4395-b7f2-dce875fca6f5seed",
+ "type": "default",
+ "source": "00239057-20d4-4cd2-a010-28727b256ea2",
+ "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
"sourceHandle": "value",
- "targetHandle": "denoising_start"
+ "targetHandle": "seed"
},
{
- "id": "reactflow__edge-c8f5c671-8c87-4d96-a75e-a9937ac6bc03value-e4d5ca7c-8fcf-4c59-9c58-67194c80dc73b",
+ "id": "reactflow__edge-094bc4ed-5c68-4342-84f4-51056c755796value-c3b60a50-8039-4924-90e3-8c608e1fecb5tiled",
"type": "default",
- "source": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
- "target": "e4d5ca7c-8fcf-4c59-9c58-67194c80dc73",
+ "source": "094bc4ed-5c68-4342-84f4-51056c755796",
+ "target": "c3b60a50-8039-4924-90e3-8c608e1fecb5",
"sourceHandle": "value",
- "targetHandle": "b",
- "hidden": true
+ "targetHandle": "tiled"
},
{
- "id": "reactflow__edge-49a8cc12-aa19-48c5-b6b3-04e0b603b384value-c8f5c671-8c87-4d96-a75e-a9937ac6bc03a",
+ "id": "reactflow__edge-094bc4ed-5c68-4342-84f4-51056c755796value-117f982a-03da-49b1-bf9f-29711160ac02tiled",
"type": "default",
- "source": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
- "target": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
+ "source": "094bc4ed-5c68-4342-84f4-51056c755796",
+ "target": "117f982a-03da-49b1-bf9f-29711160ac02",
"sourceHandle": "value",
- "targetHandle": "a",
- "hidden": true
+ "targetHandle": "tiled"
},
{
- "id": "reactflow__edge-14e65dbe-4249-4b25-9a63-3a10cfaeb61cvalue-49a8cc12-aa19-48c5-b6b3-04e0b603b384a",
+ "id": "reactflow__edge-f5ca24ee-21c5-4c8c-8d3c-371b5079b086value-27215391-b20e-412a-b854-7fa5927f5437style",
"type": "default",
- "source": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
- "target": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "source": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
+ "target": "27215391-b20e-412a-b854-7fa5927f5437",
"sourceHandle": "value",
- "targetHandle": "a",
- "hidden": true
+ "targetHandle": "style"
},
{
- "id": "79390b60-4077-4f94-ad0a-4229cc73ddb2-4950132a-2d06-4571-b2c0-55cb37a31e9b-collapsed",
- "type": "collapsed",
- "source": "79390b60-4077-4f94-ad0a-4229cc73ddb2",
- "target": "4950132a-2d06-4571-b2c0-55cb37a31e9b"
+ "id": "reactflow__edge-f5ca24ee-21c5-4c8c-8d3c-371b5079b086value-27215391-b20e-412a-b854-7fa5927f5437prompt",
+ "type": "default",
+ "source": "f5ca24ee-21c5-4c8c-8d3c-371b5079b086",
+ "target": "27215391-b20e-412a-b854-7fa5927f5437",
+ "sourceHandle": "value",
+ "targetHandle": "prompt"
},
{
- "id": "reactflow__edge-4950132a-2d06-4571-b2c0-55cb37a31e9bvalue-041c59cc-f9e4-4dc9-8b31-84648c5f3ebestrength",
+ "id": "reactflow__edge-c26bff37-4f12-482f-ba45-3a5d729b4c4fvalue-6142b69a-323f-4ecd-a7e5-67dc61349c51style",
"type": "default",
- "source": "4950132a-2d06-4571-b2c0-55cb37a31e9b",
- "target": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
+ "source": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
+ "target": "6142b69a-323f-4ecd-a7e5-67dc61349c51",
"sourceHandle": "value",
- "targetHandle": "strength",
- "hidden": true
+ "targetHandle": "style"
},
{
- "id": "reactflow__edge-4950132a-2d06-4571-b2c0-55cb37a31e9bvalue-53c2d5fd-863d-4950-93e0-628f3d61b493strength",
+ "id": "reactflow__edge-c26bff37-4f12-482f-ba45-3a5d729b4c4fvalue-6142b69a-323f-4ecd-a7e5-67dc61349c51prompt",
"type": "default",
- "source": "4950132a-2d06-4571-b2c0-55cb37a31e9b",
- "target": "53c2d5fd-863d-4950-93e0-628f3d61b493",
+ "source": "c26bff37-4f12-482f-ba45-3a5d729b4c4f",
+ "target": "6142b69a-323f-4ecd-a7e5-67dc61349c51",
"sourceHandle": "value",
- "targetHandle": "strength",
- "hidden": true
+ "targetHandle": "prompt"
},
{
- "id": "reactflow__edge-79390b60-4077-4f94-ad0a-4229cc73ddb2value-4950132a-2d06-4571-b2c0-55cb37a31e9bb",
+ "id": "reactflow__edge-1dd915a3-6756-48ed-b68b-ee3b4bd06c1dvalue-14e65dbe-4249-4b25-9a63-3a10cfaeb61ca",
"type": "default",
- "source": "79390b60-4077-4f94-ad0a-4229cc73ddb2",
- "target": "4950132a-2d06-4571-b2c0-55cb37a31e9b",
+ "source": "1dd915a3-6756-48ed-b68b-ee3b4bd06c1d",
+ "target": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
"sourceHandle": "value",
- "targetHandle": "b",
+ "targetHandle": "a",
"hidden": true
},
{
- "id": "reactflow__edge-696de0e1-cdd2-42e8-abeb-57a926bc6df6value-79390b60-4077-4f94-ad0a-4229cc73ddb2a",
+ "id": "reactflow__edge-49a8cc12-aa19-48c5-b6b3-04e0b603b384value-c8f5c671-8c87-4d96-a75e-a9937ac6bc03a",
"type": "default",
- "source": "696de0e1-cdd2-42e8-abeb-57a926bc6df6",
- "target": "79390b60-4077-4f94-ad0a-4229cc73ddb2",
+ "source": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
+ "target": "c8f5c671-8c87-4d96-a75e-a9937ac6bc03",
"sourceHandle": "value",
- "targetHandle": "a"
+ "targetHandle": "a",
+ "hidden": true
},
{
- "id": "reactflow__edge-bd094e2f-41e5-4b61-9f7b-56cf337d53favalue-bc53651f-208b-440c-be30-f93f72ae700ea",
+ "id": "reactflow__edge-14e65dbe-4249-4b25-9a63-3a10cfaeb61cvalue-49a8cc12-aa19-48c5-b6b3-04e0b603b384a",
"type": "default",
- "source": "bd094e2f-41e5-4b61-9f7b-56cf337d53fa",
- "target": "bc53651f-208b-440c-be30-f93f72ae700e",
+ "source": "14e65dbe-4249-4b25-9a63-3a10cfaeb61c",
+ "target": "49a8cc12-aa19-48c5-b6b3-04e0b603b384",
"sourceHandle": "value",
"targetHandle": "a",
"hidden": true
@@ -1943,14 +1545,6 @@
"sourceHandle": "control",
"targetHandle": "item"
},
- {
- "id": "reactflow__edge-7671553a-cd4b-4e25-8332-9d5667e64493image-b78f53b6-2eae-4956-97b4-7e73768d1491image",
- "type": "default",
- "source": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "target": "b78f53b6-2eae-4956-97b4-7e73768d1491",
- "sourceHandle": "image",
- "targetHandle": "image"
- },
{
"id": "reactflow__edge-e277e4b7-01cd-4daa-86ab-7bfa3cdcd9fdclip2-27215391-b20e-412a-b854-7fa5927f5437clip2",
"type": "default",
@@ -2023,38 +1617,6 @@
"sourceHandle": "clip",
"targetHandle": "clip"
},
- {
- "id": "reactflow__edge-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage-7671553a-cd4b-4e25-8332-9d5667e64493image",
- "type": "default",
- "source": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
- "target": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "sourceHandle": "image",
- "targetHandle": "image"
- },
- {
- "id": "reactflow__edge-f0cd0d2f-9614-43f7-9944-a75b8d5ccd65image-041c59cc-f9e4-4dc9-8b31-84648c5f3ebeimage",
- "type": "default",
- "source": "f0cd0d2f-9614-43f7-9944-a75b8d5ccd65",
- "target": "041c59cc-f9e4-4dc9-8b31-84648c5f3ebe",
- "sourceHandle": "image",
- "targetHandle": "image"
- },
- {
- "id": "reactflow__edge-53c2d5fd-863d-4950-93e0-628f3d61b493image-f0cd0d2f-9614-43f7-9944-a75b8d5ccd65image",
- "type": "default",
- "source": "53c2d5fd-863d-4950-93e0-628f3d61b493",
- "target": "f0cd0d2f-9614-43f7-9944-a75b8d5ccd65",
- "sourceHandle": "image",
- "targetHandle": "image"
- },
- {
- "id": "reactflow__edge-5ca87ace-edf9-49c7-a424-cd42416b86a7image-53c2d5fd-863d-4950-93e0-628f3d61b493image",
- "type": "default",
- "source": "5ca87ace-edf9-49c7-a424-cd42416b86a7",
- "target": "53c2d5fd-863d-4950-93e0-628f3d61b493",
- "sourceHandle": "image",
- "targetHandle": "image"
- },
{
"id": "reactflow__edge-8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7alatents-c3b60a50-8039-4924-90e3-8c608e1fecb5latents",
"type": "default",
@@ -2078,104 +1640,6 @@
"target": "8dba0d37-cd2e-4fe5-ae9f-5464b85a8a7a",
"sourceHandle": "noise",
"targetHandle": "noise"
- },
- {
- "id": "reactflow__edge-d350feac-9686-4e0d-bd46-a96bd2630818value-7dbb756b-7d79-431c-a46d-d8f7b082c127value",
- "type": "default",
- "source": "d350feac-9686-4e0d-bd46-a96bd2630818",
- "target": "7dbb756b-7d79-431c-a46d-d8f7b082c127",
- "sourceHandle": "value",
- "targetHandle": "value",
- "hidden": true
- },
- {
- "id": "reactflow__edge-5b256f14-caab-40ff-b8f0-9679cd542163value-f5d9bf3b-2646-4b17-9894-20fd2b4218eavalue",
- "type": "default",
- "source": "5b256f14-caab-40ff-b8f0-9679cd542163",
- "target": "f5d9bf3b-2646-4b17-9894-20fd2b4218ea",
- "sourceHandle": "value",
- "targetHandle": "value",
- "hidden": true
- },
- {
- "id": "reactflow__edge-7671553a-cd4b-4e25-8332-9d5667e64493height-8923451b-5a27-4395-b7f2-dce875fca6f5height",
- "type": "default",
- "source": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
- "sourceHandle": "height",
- "targetHandle": "height"
- },
- {
- "id": "reactflow__edge-7671553a-cd4b-4e25-8332-9d5667e64493width-8923451b-5a27-4395-b7f2-dce875fca6f5width",
- "type": "default",
- "source": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "target": "8923451b-5a27-4395-b7f2-dce875fca6f5",
- "sourceHandle": "width",
- "targetHandle": "width"
- },
- {
- "id": "reactflow__edge-7671553a-cd4b-4e25-8332-9d5667e64493image-117f982a-03da-49b1-bf9f-29711160ac02image",
- "type": "default",
- "source": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "target": "117f982a-03da-49b1-bf9f-29711160ac02",
- "sourceHandle": "image",
- "targetHandle": "image"
- },
- {
- "id": "reactflow__edge-7671553a-cd4b-4e25-8332-9d5667e64493image-be4082d6-e238-40ea-a9df-fc0d725e8895image",
- "type": "default",
- "source": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "target": "be4082d6-e238-40ea-a9df-fc0d725e8895",
- "sourceHandle": "image",
- "targetHandle": "image"
- },
- {
- "id": "reactflow__edge-7dbb756b-7d79-431c-a46d-d8f7b082c127value-7671553a-cd4b-4e25-8332-9d5667e64493height",
- "type": "default",
- "source": "7dbb756b-7d79-431c-a46d-d8f7b082c127",
- "target": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "sourceHandle": "value",
- "targetHandle": "height"
- },
- {
- "id": "reactflow__edge-f5d9bf3b-2646-4b17-9894-20fd2b4218eavalue-7671553a-cd4b-4e25-8332-9d5667e64493width",
- "type": "default",
- "source": "f5d9bf3b-2646-4b17-9894-20fd2b4218ea",
- "target": "7671553a-cd4b-4e25-8332-9d5667e64493",
- "sourceHandle": "value",
- "targetHandle": "width"
- },
- {
- "id": "reactflow__edge-5ca87ace-edf9-49c7-a424-cd42416b86a7height-d350feac-9686-4e0d-bd46-a96bd2630818a",
- "type": "default",
- "source": "5ca87ace-edf9-49c7-a424-cd42416b86a7",
- "target": "d350feac-9686-4e0d-bd46-a96bd2630818",
- "sourceHandle": "height",
- "targetHandle": "a"
- },
- {
- "id": "reactflow__edge-1ba845a6-eb88-49a1-a490-5fe6754f3ec9value-d350feac-9686-4e0d-bd46-a96bd2630818b",
- "type": "default",
- "source": "1ba845a6-eb88-49a1-a490-5fe6754f3ec9",
- "target": "d350feac-9686-4e0d-bd46-a96bd2630818",
- "sourceHandle": "value",
- "targetHandle": "b"
- },
- {
- "id": "reactflow__edge-1ba845a6-eb88-49a1-a490-5fe6754f3ec9value-5b256f14-caab-40ff-b8f0-9679cd542163b",
- "type": "default",
- "source": "1ba845a6-eb88-49a1-a490-5fe6754f3ec9",
- "target": "5b256f14-caab-40ff-b8f0-9679cd542163",
- "sourceHandle": "value",
- "targetHandle": "b"
- },
- {
- "id": "reactflow__edge-5ca87ace-edf9-49c7-a424-cd42416b86a7width-5b256f14-caab-40ff-b8f0-9679cd542163a",
- "type": "default",
- "source": "5ca87ace-edf9-49c7-a424-cd42416b86a7",
- "target": "5b256f14-caab-40ff-b8f0-9679cd542163",
- "sourceHandle": "width",
- "targetHandle": "a"
}
]
-}
+}
\ No newline at end of file
diff --git a/invokeai/backend/model_manager/config.py b/invokeai/backend/model_manager/config.py
index f6cc5929c80..332ac6c8faf 100644
--- a/invokeai/backend/model_manager/config.py
+++ b/invokeai/backend/model_manager/config.py
@@ -354,7 +354,7 @@ class CLIPVisionDiffusersConfig(DiffusersConfigBase):
"""Model config for CLIPVision."""
type: Literal[ModelType.CLIPVision] = ModelType.CLIPVision
- format: Literal[ModelFormat.Diffusers]
+ format: Literal[ModelFormat.Diffusers] = ModelFormat.Diffusers
@staticmethod
def get_tag() -> Tag:
@@ -365,7 +365,7 @@ class T2IAdapterConfig(DiffusersConfigBase, ControlAdapterConfigBase):
"""Model config for T2I."""
type: Literal[ModelType.T2IAdapter] = ModelType.T2IAdapter
- format: Literal[ModelFormat.Diffusers]
+ format: Literal[ModelFormat.Diffusers] = ModelFormat.Diffusers
@staticmethod
def get_tag() -> Tag:
diff --git a/invokeai/backend/model_manager/load/model_loaders/stable_diffusion.py b/invokeai/backend/model_manager/load/model_loaders/stable_diffusion.py
index d90352f0e61..33ce4abc4d4 100644
--- a/invokeai/backend/model_manager/load/model_loaders/stable_diffusion.py
+++ b/invokeai/backend/model_manager/load/model_loaders/stable_diffusion.py
@@ -98,6 +98,9 @@ def _load_from_singlefile(
ModelVariantType.Normal: StableDiffusionXLPipeline,
ModelVariantType.Inpaint: StableDiffusionXLInpaintPipeline,
},
+ BaseModelType.StableDiffusionXLRefiner: {
+ ModelVariantType.Normal: StableDiffusionXLPipeline,
+ },
}
assert isinstance(config, MainCheckpointConfig)
try:
diff --git a/invokeai/backend/model_manager/starter_models.py b/invokeai/backend/model_manager/starter_models.py
index e1526392f67..c460a5e86e6 100644
--- a/invokeai/backend/model_manager/starter_models.py
+++ b/invokeai/backend/model_manager/starter_models.py
@@ -187,164 +187,171 @@ class StarterModel(StarterModelWithoutDependencies):
# endregion
# region ControlNet
StarterModel(
- name="QRCode Monster",
+ name="QRCode Monster v2 (SD1.5)",
base=BaseModelType.StableDiffusion1,
- source="monster-labs/control_v1p_sd15_qrcode_monster",
- description="Controlnet model that generates scannable creative QR codes",
+ source="monster-labs/control_v1p_sd15_qrcode_monster::v2",
+ description="ControlNet model that generates scannable creative QR codes",
+ type=ModelType.ControlNet,
+ ),
+ StarterModel(
+ name="QRCode Monster (SDXL)",
+ base=BaseModelType.StableDiffusionXL,
+ source="monster-labs/control_v1p_sdxl_qrcode_monster",
+ description="ControlNet model that generates scannable creative QR codes",
type=ModelType.ControlNet,
),
StarterModel(
name="canny",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_canny",
- description="Controlnet weights trained on sd-1.5 with canny conditioning.",
+ description="ControlNet weights trained on sd-1.5 with canny conditioning.",
type=ModelType.ControlNet,
),
StarterModel(
name="inpaint",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_inpaint",
- description="Controlnet weights trained on sd-1.5 with canny conditioning, inpaint version",
+ description="ControlNet weights trained on sd-1.5 with canny conditioning, inpaint version",
type=ModelType.ControlNet,
),
StarterModel(
name="mlsd",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_mlsd",
- description="Controlnet weights trained on sd-1.5 with canny conditioning, MLSD version",
+ description="ControlNet weights trained on sd-1.5 with canny conditioning, MLSD version",
type=ModelType.ControlNet,
),
StarterModel(
name="depth",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11f1p_sd15_depth",
- description="Controlnet weights trained on sd-1.5 with depth conditioning",
+ description="ControlNet weights trained on sd-1.5 with depth conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="normal_bae",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_normalbae",
- description="Controlnet weights trained on sd-1.5 with normalbae image conditioning",
+ description="ControlNet weights trained on sd-1.5 with normalbae image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="seg",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_seg",
- description="Controlnet weights trained on sd-1.5 with seg image conditioning",
+ description="ControlNet weights trained on sd-1.5 with seg image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="lineart",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_lineart",
- description="Controlnet weights trained on sd-1.5 with lineart image conditioning",
+ description="ControlNet weights trained on sd-1.5 with lineart image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="lineart_anime",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15s2_lineart_anime",
- description="Controlnet weights trained on sd-1.5 with anime image conditioning",
+ description="ControlNet weights trained on sd-1.5 with anime image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="openpose",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_openpose",
- description="Controlnet weights trained on sd-1.5 with openpose image conditioning",
+ description="ControlNet weights trained on sd-1.5 with openpose image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="scribble",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_scribble",
- description="Controlnet weights trained on sd-1.5 with scribble image conditioning",
+ description="ControlNet weights trained on sd-1.5 with scribble image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="softedge",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11p_sd15_softedge",
- description="Controlnet weights trained on sd-1.5 with soft edge conditioning",
+ description="ControlNet weights trained on sd-1.5 with soft edge conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="shuffle",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11e_sd15_shuffle",
- description="Controlnet weights trained on sd-1.5 with shuffle image conditioning",
+ description="ControlNet weights trained on sd-1.5 with shuffle image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="tile",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11f1e_sd15_tile",
- description="Controlnet weights trained on sd-1.5 with tiled image conditioning",
+ description="ControlNet weights trained on sd-1.5 with tiled image conditioning",
type=ModelType.ControlNet,
),
StarterModel(
name="ip2p",
base=BaseModelType.StableDiffusion1,
source="lllyasviel/control_v11e_sd15_ip2p",
- description="Controlnet weights trained on sd-1.5 with ip2p conditioning.",
+ description="ControlNet weights trained on sd-1.5 with ip2p conditioning.",
type=ModelType.ControlNet,
),
StarterModel(
name="canny-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="xinsir/controlnet-canny-sdxl-1.0",
- description="Controlnet weights trained on sdxl-1.0 with canny conditioning, by Xinsir.",
+ source="xinsir/controlNet-canny-sdxl-1.0",
+ description="ControlNet weights trained on sdxl-1.0 with canny conditioning, by Xinsir.",
type=ModelType.ControlNet,
),
StarterModel(
name="depth-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="diffusers/controlnet-depth-sdxl-1.0",
- description="Controlnet weights trained on sdxl-1.0 with depth conditioning.",
+ source="diffusers/controlNet-depth-sdxl-1.0",
+ description="ControlNet weights trained on sdxl-1.0 with depth conditioning.",
type=ModelType.ControlNet,
),
StarterModel(
name="softedge-dexined-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="SargeZT/controlnet-sd-xl-1.0-softedge-dexined",
- description="Controlnet weights trained on sdxl-1.0 with dexined soft edge preprocessing.",
+ source="SargeZT/controlNet-sd-xl-1.0-softedge-dexined",
+ description="ControlNet weights trained on sdxl-1.0 with dexined soft edge preprocessing.",
type=ModelType.ControlNet,
),
StarterModel(
name="depth-16bit-zoe-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="SargeZT/controlnet-sd-xl-1.0-depth-16bit-zoe",
- description="Controlnet weights trained on sdxl-1.0 with Zoe's preprocessor (16 bits).",
+ source="SargeZT/controlNet-sd-xl-1.0-depth-16bit-zoe",
+ description="ControlNet weights trained on sdxl-1.0 with Zoe's preprocessor (16 bits).",
type=ModelType.ControlNet,
),
StarterModel(
name="depth-zoe-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="diffusers/controlnet-zoe-depth-sdxl-1.0",
- description="Controlnet weights trained on sdxl-1.0 with Zoe's preprocessor (32 bits).",
+ source="diffusers/controlNet-zoe-depth-sdxl-1.0",
+ description="ControlNet weights trained on sdxl-1.0 with Zoe's preprocessor (32 bits).",
type=ModelType.ControlNet,
),
StarterModel(
name="openpose-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="xinsir/controlnet-openpose-sdxl-1.0",
- description="Controlnet weights trained on sdxl-1.0 compatible with the DWPose processor by Xinsir.",
+ source="xinsir/controlNet-openpose-sdxl-1.0",
+ description="ControlNet weights trained on sdxl-1.0 compatible with the DWPose processor by Xinsir.",
type=ModelType.ControlNet,
),
StarterModel(
name="scribble-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="xinsir/controlnet-scribble-sdxl-1.0",
- description="Controlnet weights trained on sdxl-1.0 compatible with various lineart processors and black/white sketches by Xinsir.",
+ source="xinsir/controlNet-scribble-sdxl-1.0",
+ description="ControlNet weights trained on sdxl-1.0 compatible with various lineart processors and black/white sketches by Xinsir.",
type=ModelType.ControlNet,
),
StarterModel(
name="tile-sdxl",
base=BaseModelType.StableDiffusionXL,
- source="xinsir/controlnet-tile-sdxl-1.0",
- description="Controlnet weights trained on sdxl-1.0 with tiled image conditioning",
+ source="xinsir/controlNet-tile-sdxl-1.0",
+ description="ControlNet weights trained on sdxl-1.0 with tiled image conditioning",
type=ModelType.ControlNet,
),
# endregion
diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json
index f2210e4c680..879985accd4 100644
--- a/invokeai/frontend/web/package.json
+++ b/invokeai/frontend/web/package.json
@@ -155,5 +155,8 @@
"vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.6.0"
+ },
+ "engines": {
+ "pnpm": "8"
}
}
diff --git a/invokeai/frontend/web/public/locales/ar.json b/invokeai/frontend/web/public/locales/ar.json
index ee370d1e421..bb04edfa8b3 100644
--- a/invokeai/frontend/web/public/locales/ar.json
+++ b/invokeai/frontend/web/public/locales/ar.json
@@ -77,10 +77,6 @@
"title": "استعادة الوجوه",
"desc": "استعادة الصورة الحالية"
},
- "upscale": {
- "title": "تحسين الحجم",
- "desc": "تحسين حجم الصورة الحالية"
- },
"showInfo": {
"title": "عرض المعلومات",
"desc": "عرض معلومات البيانات الخاصة بالصورة الحالية"
@@ -255,8 +251,6 @@
"type": "نوع",
"strength": "قوة",
"upscaling": "تصغير",
- "upscale": "تصغير",
- "upscaleImage": "تصغير الصورة",
"scale": "مقياس",
"imageFit": "ملائمة الصورة الأولية لحجم الخرج",
"scaleBeforeProcessing": "تحجيم قبل المعالجة",
diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json
index 352b6ffcbf2..b8a204df1d8 100644
--- a/invokeai/frontend/web/public/locales/de.json
+++ b/invokeai/frontend/web/public/locales/de.json
@@ -187,10 +187,6 @@
"title": "Gesicht restaurieren",
"desc": "Das aktuelle Bild restaurieren"
},
- "upscale": {
- "title": "Hochskalieren",
- "desc": "Das aktuelle Bild hochskalieren"
- },
"showInfo": {
"title": "Info anzeigen",
"desc": "Metadaten des aktuellen Bildes anzeigen"
@@ -433,8 +429,6 @@
"type": "Art",
"strength": "Stärke",
"upscaling": "Hochskalierung",
- "upscale": "Hochskalieren (Shift + U)",
- "upscaleImage": "Bild hochskalieren",
"scale": "Maßstab",
"imageFit": "Ausgangsbild an Ausgabegröße anpassen",
"scaleBeforeProcessing": "Skalieren vor der Verarbeitung",
diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json
index 8fc600d6c96..659df78d9b0 100644
--- a/invokeai/frontend/web/public/locales/en.json
+++ b/invokeai/frontend/web/public/locales/en.json
@@ -32,12 +32,14 @@
"deleteBoardAndImages": "Delete Board and Images",
"deleteBoardOnly": "Delete Board Only",
"deletedBoardsCannotbeRestored": "Deleted boards cannot be restored",
+ "hideBoards": "Hide Boards",
"loading": "Loading...",
"menuItemAutoAdd": "Auto-add to this Board",
"move": "Move",
"movingImagesToBoard_one": "Moving {{count}} image to board:",
"movingImagesToBoard_other": "Moving {{count}} images to board:",
"myBoard": "My Board",
+ "noBoards": "No {{boardType}} Boards",
"noMatching": "No matching Boards",
"private": "Private Boards",
"searchBoard": "Search Boards...",
@@ -46,6 +48,7 @@
"topMessage": "This board contains images used in the following features:",
"unarchiveBoard": "Unarchive Board",
"uncategorized": "Uncategorized",
+ "viewBoards": "View Boards",
"downloadBoard": "Download Board",
"imagesWithCount_one": "{{count}} image",
"imagesWithCount_other": "{{count}} images",
@@ -102,6 +105,7 @@
"negativePrompt": "Negative Prompt",
"discordLabel": "Discord",
"dontAskMeAgain": "Don't ask me again",
+ "dontShowMeThese": "Don't show me these",
"editor": "Editor",
"error": "Error",
"file": "File",
@@ -373,10 +377,14 @@
"displayBoardSearch": "Display Board Search",
"displaySearch": "Display Search",
"download": "Download",
+ "exitBoardSearch": "Exit Board Search",
+ "exitSearch": "Exit Search",
"featuresWillReset": "If you delete this image, those features will immediately be reset.",
"galleryImageSize": "Image Size",
"gallerySettings": "Gallery Settings",
+ "go": "Go",
"image": "image",
+ "jump": "Jump",
"loading": "Loading",
"loadMore": "Load More",
"newestFirst": "Newest First",
@@ -636,9 +644,9 @@
"title": "Undo Stroke"
},
"unifiedCanvasHotkeys": "Unified Canvas",
- "upscale": {
- "desc": "Upscale the current image",
- "title": "Upscale"
+ "postProcess": {
+ "desc": "Process the current image using the selected post-processing model",
+ "title": "Process Image"
},
"toggleViewer": {
"desc": "Switches between the Image Viewer and workspace for the current tab.",
@@ -1035,8 +1043,8 @@
"symmetry": "Symmetry",
"tileSize": "Tile Size",
"type": "Type",
- "upscale": "Upscale (Shift + U)",
- "upscaleImage": "Upscale Image",
+ "postProcessing": "Post-Processing (Shift + U)",
+ "processImage": "Process Image",
"upscaling": "Upscaling",
"useAll": "Use All",
"useSize": "Use Size",
@@ -1092,6 +1100,8 @@
"displayInProgress": "Display Progress Images",
"enableImageDebugging": "Enable Image Debugging",
"enableInformationalPopovers": "Enable Informational Popovers",
+ "informationalPopoversDisabled": "Informational Popovers Disabled",
+ "informationalPopoversDisabledDesc": "Informational popovers have been disabled. Enable them in Settings.",
"enableInvisibleWatermark": "Enable Invisible Watermark",
"enableNSFWChecker": "Enable NSFW Checker",
"general": "General",
@@ -1499,6 +1509,30 @@
"seamlessTilingYAxis": {
"heading": "Seamless Tiling Y Axis",
"paragraphs": ["Seamlessly tile an image along the vertical axis."]
+ },
+ "upscaleModel": {
+ "heading": "Upscale Model",
+ "paragraphs": [
+ "The upscale model scales the image to the output size before details are added. Any supported upscale model may be used, but some are specialized for different kinds of images, like photos or line drawings."
+ ]
+ },
+ "scale": {
+ "heading": "Scale",
+ "paragraphs": [
+ "Scale controls the output image size, and is based on a multiple of the input image resolution. For example a 2x upscale on a 1024x1024 image would produce a 2048 x 2048 output."
+ ]
+ },
+ "creativity": {
+ "heading": "Creativity",
+ "paragraphs": [
+ "Creativity controls the amount of freedom granted to the model when adding details. Low creativity stays close to the original image, while high creativity allows for more change. When using a prompt, high creativity increases the influence of the prompt."
+ ]
+ },
+ "structure": {
+ "heading": "Structure",
+ "paragraphs": [
+ "Structure controls how closely the output image will keep to the layout of the original. Low structure allows major changes, while high structure strictly maintains the original composition and layout."
+ ]
}
},
"unifiedCanvas": {
@@ -1645,7 +1679,9 @@
"creativity": "Creativity",
"structure": "Structure",
"upscaleModel": "Upscale Model",
+ "postProcessingModel": "Post-Processing Model",
"scale": "Scale",
+ "postProcessingMissingModelWarning": "Visit the Model Manager to install a post-processing (image to image) model.",
"missingModelsWarning": "Visit the Model Manager to install the required models:",
"mainModelDesc": "Main model (SD1.5 or SDXL architecture)",
"tileControlNetModelDesc": "Tile ControlNet model for the chosen main model architecture",
@@ -1654,6 +1690,12 @@
"missingUpscaleModel": "Missing upscale model",
"missingTileControlNetModel": "No valid tile ControlNet models installed"
},
+ "upsell": {
+ "inviteTeammates": "Invite Teammates",
+ "professional": "Professional",
+ "professionalUpsell": "Available in Invoke’s Professional Edition. Click here or visit invoke.com/pricing for more details.",
+ "shareAccess": "Share Access"
+ },
"ui": {
"tabs": {
"generation": "Generation",
diff --git a/invokeai/frontend/web/public/locales/es.json b/invokeai/frontend/web/public/locales/es.json
index 52ee3b5fe3f..fa87dd0c76d 100644
--- a/invokeai/frontend/web/public/locales/es.json
+++ b/invokeai/frontend/web/public/locales/es.json
@@ -151,10 +151,6 @@
"title": "Restaurar rostros",
"desc": "Restaurar rostros en la imagen actual"
},
- "upscale": {
- "title": "Aumentar resolución",
- "desc": "Aumentar la resolución de la imagen actual"
- },
"showInfo": {
"title": "Mostrar información",
"desc": "Mostar metadatos de la imagen actual"
@@ -360,8 +356,6 @@
"type": "Tipo",
"strength": "Fuerza",
"upscaling": "Aumento de resolución",
- "upscale": "Aumentar resolución",
- "upscaleImage": "Aumentar la resolución de la imagen",
"scale": "Escala",
"imageFit": "Ajuste tamaño de imagen inicial al tamaño objetivo",
"scaleBeforeProcessing": "Redimensionar antes de procesar",
@@ -408,7 +402,12 @@
"showProgressInViewer": "Mostrar las imágenes del progreso en el visor",
"ui": "Interfaz del usuario",
"generation": "Generación",
- "beta": "Beta"
+ "beta": "Beta",
+ "reloadingIn": "Recargando en",
+ "intermediatesClearedFailed": "Error limpiando los intermediarios",
+ "intermediatesCleared_one": "Borrado {{count}} intermediario",
+ "intermediatesCleared_many": "Borrados {{count}} intermediarios",
+ "intermediatesCleared_other": "Borrados {{count}} intermediarios"
},
"toast": {
"uploadFailed": "Error al subir archivo",
@@ -426,7 +425,12 @@
"parameterSet": "Conjunto de parámetros",
"parameterNotSet": "Parámetro no configurado",
"problemCopyingImage": "No se puede copiar la imagen",
- "errorCopied": "Error al copiar"
+ "errorCopied": "Error al copiar",
+ "baseModelChanged": "Modelo base cambiado",
+ "addedToBoard": "Añadido al tablero",
+ "baseModelChangedCleared_one": "Borrado o desactivado {{count}} submodelo incompatible",
+ "baseModelChangedCleared_many": "Borrados o desactivados {{count}} submodelos incompatibles",
+ "baseModelChangedCleared_other": "Borrados o desactivados {{count}} submodelos incompatibles"
},
"tooltip": {
"feature": {
@@ -540,7 +544,13 @@
"downloadBoard": "Descargar panel",
"deleteBoardOnly": "Borrar solo el panel",
"myBoard": "Mi panel",
- "noMatching": "No hay paneles que coincidan"
+ "noMatching": "No hay paneles que coincidan",
+ "imagesWithCount_one": "{{count}} imagen",
+ "imagesWithCount_many": "{{count}} imágenes",
+ "imagesWithCount_other": "{{count}} imágenes",
+ "assetsWithCount_one": "{{count}} activo",
+ "assetsWithCount_many": "{{count}} activos",
+ "assetsWithCount_other": "{{count}} activos"
},
"accordions": {
"compositing": {
@@ -590,6 +600,27 @@
"balanced": "Equilibrado",
"beginEndStepPercent": "Inicio / Final Porcentaje de pasos",
"detectResolution": "Detectar resolución",
- "beginEndStepPercentShort": "Inicio / Final %"
+ "beginEndStepPercentShort": "Inicio / Final %",
+ "t2i_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.t2iAdapter))",
+ "controlnet": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.controlNet))",
+ "ip_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.ipAdapter))",
+ "addControlNet": "Añadir $t(common.controlNet)",
+ "addIPAdapter": "Añadir $t(common.ipAdapter)",
+ "controlAdapter_one": "Adaptador de control",
+ "controlAdapter_many": "Adaptadores de control",
+ "controlAdapter_other": "Adaptadores de control",
+ "addT2IAdapter": "Añadir $t(common.t2iAdapter)"
+ },
+ "queue": {
+ "back": "Atrás",
+ "front": "Delante",
+ "batchQueuedDesc_one": "Se agregó {{count}} sesión a {{direction}} la cola",
+ "batchQueuedDesc_many": "Se agregaron {{count}} sesiones a {{direction}} la cola",
+ "batchQueuedDesc_other": "Se agregaron {{count}} sesiones a {{direction}} la cola"
+ },
+ "upsell": {
+ "inviteTeammates": "Invitar compañeros de equipo",
+ "shareAccess": "Compartir acceso",
+ "professionalUpsell": "Disponible en la edición profesional de Invoke. Haz clic aquí o visita invoke.com/pricing para obtener más detalles."
}
}
diff --git a/invokeai/frontend/web/public/locales/fr.json b/invokeai/frontend/web/public/locales/fr.json
index 558545b2f4e..efc181c59a2 100644
--- a/invokeai/frontend/web/public/locales/fr.json
+++ b/invokeai/frontend/web/public/locales/fr.json
@@ -130,10 +130,6 @@
"title": "Restaurer les visages",
"desc": "Restaurer l'image actuelle"
},
- "upscale": {
- "title": "Agrandir",
- "desc": "Agrandir l'image actuelle"
- },
"showInfo": {
"title": "Afficher les informations",
"desc": "Afficher les informations de métadonnées de l'image actuelle"
@@ -308,8 +304,6 @@
"type": "Type",
"strength": "Force",
"upscaling": "Agrandissement",
- "upscale": "Agrandir",
- "upscaleImage": "Image en Agrandissement",
"scale": "Echelle",
"imageFit": "Ajuster Image Initiale à la Taille de Sortie",
"scaleBeforeProcessing": "Echelle Avant Traitement",
diff --git a/invokeai/frontend/web/public/locales/he.json b/invokeai/frontend/web/public/locales/he.json
index dbbb3cbec44..def170fdbc9 100644
--- a/invokeai/frontend/web/public/locales/he.json
+++ b/invokeai/frontend/web/public/locales/he.json
@@ -90,10 +90,6 @@
"desc": "שחזור התמונה הנוכחית",
"title": "שחזור פרצופים"
},
- "upscale": {
- "title": "הגדלת קנה מידה",
- "desc": "הגדל את התמונה הנוכחית"
- },
"showInfo": {
"title": "הצג מידע",
"desc": "הצגת פרטי מטא-נתונים של התמונה הנוכחית"
@@ -263,8 +259,6 @@
"seed": "זרע",
"type": "סוג",
"strength": "חוזק",
- "upscale": "הגדלת קנה מידה",
- "upscaleImage": "הגדלת קנה מידת התמונה",
"denoisingStrength": "חוזק מנטרל הרעש",
"scaleBeforeProcessing": "שנה קנה מידה לפני עיבוד",
"scaledWidth": "קנה מידה לאחר שינוי W",
diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json
index eced64a1e3b..7637a413105 100644
--- a/invokeai/frontend/web/public/locales/it.json
+++ b/invokeai/frontend/web/public/locales/it.json
@@ -150,7 +150,11 @@
"showArchivedBoards": "Mostra le bacheche archiviate",
"searchImages": "Ricerca per metadati",
"displayBoardSearch": "Mostra la ricerca nelle Bacheche",
- "displaySearch": "Mostra la ricerca"
+ "displaySearch": "Mostra la ricerca",
+ "selectAllOnPage": "Seleziona tutto nella pagina",
+ "selectAllOnBoard": "Seleziona tutto nella bacheca",
+ "exitBoardSearch": "Esci da Ricerca bacheca",
+ "exitSearch": "Esci dalla ricerca"
},
"hotkeys": {
"keyboardShortcuts": "Tasti di scelta rapida",
@@ -210,10 +214,6 @@
"title": "Restaura volti",
"desc": "Restaura l'immagine corrente"
},
- "upscale": {
- "title": "Amplia",
- "desc": "Amplia l'immagine corrente"
- },
"showInfo": {
"title": "Mostra informazioni",
"desc": "Mostra le informazioni sui metadati dell'immagine corrente"
@@ -377,6 +377,10 @@
"toggleViewer": {
"title": "Attiva/disattiva il visualizzatore di immagini",
"desc": "Passa dal visualizzatore immagini all'area di lavoro per la scheda corrente."
+ },
+ "postProcess": {
+ "desc": "Elabora l'immagine corrente utilizzando il modello di post-elaborazione selezionato",
+ "title": "Elabora immagine"
}
},
"modelManager": {
@@ -505,8 +509,6 @@
"type": "Tipo",
"strength": "Forza",
"upscaling": "Ampliamento",
- "upscale": "Amplia (Shift + U)",
- "upscaleImage": "Amplia Immagine",
"scale": "Scala",
"imageFit": "Adatta l'immagine iniziale alle dimensioni di output",
"scaleBeforeProcessing": "Scala prima dell'elaborazione",
@@ -591,7 +593,10 @@
"infillColorValue": "Colore di riempimento",
"globalSettings": "Impostazioni globali",
"globalPositivePromptPlaceholder": "Prompt positivo globale",
- "globalNegativePromptPlaceholder": "Prompt negativo globale"
+ "globalNegativePromptPlaceholder": "Prompt negativo globale",
+ "processImage": "Elabora Immagine",
+ "sendToUpscale": "Invia a Ampliare",
+ "postProcessing": "Post-elaborazione (Shift + U)"
},
"settings": {
"models": "Modelli",
@@ -964,7 +969,10 @@
"boards": "Bacheche",
"private": "Bacheche private",
"shared": "Bacheche condivise",
- "addPrivateBoard": "Aggiungi una Bacheca Privata"
+ "addPrivateBoard": "Aggiungi una Bacheca Privata",
+ "noBoards": "Nessuna bacheca {{boardType}}",
+ "hideBoards": "Nascondi bacheche",
+ "viewBoards": "Visualizza bacheche"
},
"controlnet": {
"contentShuffleDescription": "Rimescola il contenuto di un'immagine",
@@ -1684,7 +1692,30 @@
"models": "Modelli",
"modelsTab": "$t(ui.tabs.models) $t(common.tab)",
"queue": "Coda",
- "queueTab": "$t(ui.tabs.queue) $t(common.tab)"
+ "queueTab": "$t(ui.tabs.queue) $t(common.tab)",
+ "upscaling": "Ampliamento",
+ "upscalingTab": "$t(ui.tabs.upscaling) $t(common.tab)"
}
+ },
+ "upscaling": {
+ "creativity": "Creatività",
+ "structure": "Struttura",
+ "upscaleModel": "Modello di Ampliamento",
+ "scale": "Scala",
+ "missingModelsWarning": "Visita Gestione modelli per installare i modelli richiesti:",
+ "mainModelDesc": "Modello principale (architettura SD1.5 o SDXL)",
+ "tileControlNetModelDesc": "Modello Tile ControlNet per l'architettura del modello principale scelto",
+ "upscaleModelDesc": "Modello per l'ampliamento (da immagine a immagine)",
+ "missingUpscaleInitialImage": "Immagine iniziale mancante per l'ampliamento",
+ "missingUpscaleModel": "Modello per l’ampliamento mancante",
+ "missingTileControlNetModel": "Nessun modello ControlNet Tile valido installato",
+ "postProcessingModel": "Modello di post-elaborazione",
+ "postProcessingMissingModelWarning": "Visita Gestione modelli per installare un modello di post-elaborazione (da immagine a immagine)."
+ },
+ "upsell": {
+ "inviteTeammates": "Invita collaboratori",
+ "shareAccess": "Condividi l'accesso",
+ "professional": "Professionale",
+ "professionalUpsell": "Disponibile nell'edizione Professional di Invoke. Fai clic qui o visita invoke.com/pricing per ulteriori dettagli."
}
}
diff --git a/invokeai/frontend/web/public/locales/ja.json b/invokeai/frontend/web/public/locales/ja.json
index 6d5775ecd63..e7bc11d34ee 100644
--- a/invokeai/frontend/web/public/locales/ja.json
+++ b/invokeai/frontend/web/public/locales/ja.json
@@ -199,10 +199,6 @@
"title": "顔の修復",
"desc": "現在の画像を修復"
},
- "upscale": {
- "title": "アップスケール",
- "desc": "現在の画像をアップスケール"
- },
"showInfo": {
"title": "情報を見る",
"desc": "現在の画像のメタデータ情報を表示"
@@ -427,8 +423,6 @@
"shuffle": "シャッフル",
"strength": "強度",
"upscaling": "アップスケーリング",
- "upscale": "アップスケール",
- "upscaleImage": "画像をアップスケール",
"scale": "Scale",
"scaleBeforeProcessing": "処理前のスケール",
"scaledWidth": "幅のスケール",
diff --git a/invokeai/frontend/web/public/locales/ko.json b/invokeai/frontend/web/public/locales/ko.json
index db9cd0ca673..ed745da8aa2 100644
--- a/invokeai/frontend/web/public/locales/ko.json
+++ b/invokeai/frontend/web/public/locales/ko.json
@@ -258,10 +258,6 @@
"desc": "캔버스 브러시를 선택",
"title": "브러시 선택"
},
- "upscale": {
- "desc": "현재 이미지를 업스케일",
- "title": "업스케일"
- },
"previousImage": {
"title": "이전 이미지",
"desc": "갤러리에 이전 이미지 표시"
diff --git a/invokeai/frontend/web/public/locales/nl.json b/invokeai/frontend/web/public/locales/nl.json
index afcce621638..2c38353240b 100644
--- a/invokeai/frontend/web/public/locales/nl.json
+++ b/invokeai/frontend/web/public/locales/nl.json
@@ -168,10 +168,6 @@
"title": "Herstel gezichten",
"desc": "Herstelt de huidige afbeelding"
},
- "upscale": {
- "title": "Schaal op",
- "desc": "Schaalt de huidige afbeelding op"
- },
"showInfo": {
"title": "Toon info",
"desc": "Toont de metagegevens van de huidige afbeelding"
@@ -412,8 +408,6 @@
"type": "Soort",
"strength": "Sterkte",
"upscaling": "Opschalen",
- "upscale": "Vergroot (Shift + U)",
- "upscaleImage": "Schaal afbeelding op",
"scale": "Schaal",
"imageFit": "Pas initiële afbeelding in uitvoergrootte",
"scaleBeforeProcessing": "Schalen voor verwerking",
diff --git a/invokeai/frontend/web/public/locales/pl.json b/invokeai/frontend/web/public/locales/pl.json
index b7592c3faec..0fccbded4a4 100644
--- a/invokeai/frontend/web/public/locales/pl.json
+++ b/invokeai/frontend/web/public/locales/pl.json
@@ -78,10 +78,6 @@
"title": "Popraw twarze",
"desc": "Uruchamia proces poprawiania twarzy dla aktywnego obrazu"
},
- "upscale": {
- "title": "Powiększ",
- "desc": "Uruchamia proces powiększania aktywnego obrazu"
- },
"showInfo": {
"title": "Pokaż informacje",
"desc": "Pokazuje metadane zapisane w aktywnym obrazie"
@@ -232,8 +228,6 @@
"type": "Metoda",
"strength": "Siła",
"upscaling": "Powiększanie",
- "upscale": "Powiększ",
- "upscaleImage": "Powiększ obraz",
"scale": "Skala",
"imageFit": "Przeskaluj oryginalny obraz",
"scaleBeforeProcessing": "Tryb skalowania",
diff --git a/invokeai/frontend/web/public/locales/pt.json b/invokeai/frontend/web/public/locales/pt.json
index 3003a1732b9..a8a675f22fb 100644
--- a/invokeai/frontend/web/public/locales/pt.json
+++ b/invokeai/frontend/web/public/locales/pt.json
@@ -160,10 +160,6 @@
"title": "Restaurar Rostos",
"desc": "Restaurar a imagem atual"
},
- "upscale": {
- "title": "Redimensionar",
- "desc": "Redimensionar a imagem atual"
- },
"showInfo": {
"title": "Mostrar Informações",
"desc": "Mostrar metadados de informações da imagem atual"
@@ -275,8 +271,6 @@
"showOptionsPanel": "Mostrar Painel de Opções",
"strength": "Força",
"upscaling": "Redimensionando",
- "upscale": "Redimensionar",
- "upscaleImage": "Redimensionar Imagem",
"scaleBeforeProcessing": "Escala Antes do Processamento",
"images": "Imagems",
"steps": "Passos",
diff --git a/invokeai/frontend/web/public/locales/pt_BR.json b/invokeai/frontend/web/public/locales/pt_BR.json
index c966c6db50d..1572d4fe0bc 100644
--- a/invokeai/frontend/web/public/locales/pt_BR.json
+++ b/invokeai/frontend/web/public/locales/pt_BR.json
@@ -80,10 +80,6 @@
"title": "Restaurar Rostos",
"desc": "Restaurar a imagem atual"
},
- "upscale": {
- "title": "Redimensionar",
- "desc": "Redimensionar a imagem atual"
- },
"showInfo": {
"title": "Mostrar Informações",
"desc": "Mostrar metadados de informações da imagem atual"
@@ -268,8 +264,6 @@
"type": "Tipo",
"strength": "Força",
"upscaling": "Redimensionando",
- "upscale": "Redimensionar",
- "upscaleImage": "Redimensionar Imagem",
"scale": "Escala",
"imageFit": "Caber Imagem Inicial No Tamanho de Saída",
"scaleBeforeProcessing": "Escala Antes do Processamento",
diff --git a/invokeai/frontend/web/public/locales/ru.json b/invokeai/frontend/web/public/locales/ru.json
index ecceaf42aa6..644c30fd053 100644
--- a/invokeai/frontend/web/public/locales/ru.json
+++ b/invokeai/frontend/web/public/locales/ru.json
@@ -214,10 +214,6 @@
"title": "Восстановить лица",
"desc": "Восстановить лица на текущем изображении"
},
- "upscale": {
- "title": "Увеличение",
- "desc": "Увеличить текущеее изображение"
- },
"showInfo": {
"title": "Показать метаданные",
"desc": "Показать метаданные из текущего изображения"
@@ -512,8 +508,6 @@
"type": "Тип",
"strength": "Сила",
"upscaling": "Увеличение",
- "upscale": "Увеличить",
- "upscaleImage": "Увеличить изображение",
"scale": "Масштаб",
"imageFit": "Уместить изображение",
"scaleBeforeProcessing": "Масштабировать",
diff --git a/invokeai/frontend/web/public/locales/sv.json b/invokeai/frontend/web/public/locales/sv.json
index 2c51027244a..a9ebd9f4912 100644
--- a/invokeai/frontend/web/public/locales/sv.json
+++ b/invokeai/frontend/web/public/locales/sv.json
@@ -90,10 +90,6 @@
"title": "Återskapa ansikten",
"desc": "Återskapa nuvarande bild"
},
- "upscale": {
- "title": "Skala upp",
- "desc": "Skala upp nuvarande bild"
- },
"showInfo": {
"title": "Visa info",
"desc": "Visa metadata för nuvarande bild"
diff --git a/invokeai/frontend/web/public/locales/tr.json b/invokeai/frontend/web/public/locales/tr.json
index 415bd2d7443..75efaf82945 100644
--- a/invokeai/frontend/web/public/locales/tr.json
+++ b/invokeai/frontend/web/public/locales/tr.json
@@ -416,10 +416,6 @@
"desc": "Maske/Taban katmanları arasında geçiş yapar",
"title": "Katmanı Gizle-Göster"
},
- "upscale": {
- "title": "Büyüt",
- "desc": "Seçili görseli büyüt"
- },
"setSeed": {
"title": "Tohumu Kullan",
"desc": "Seçili görselin tohumunu kullan"
@@ -641,7 +637,6 @@
"copyImage": "Görseli Kopyala",
"height": "Boy",
"width": "En",
- "upscale": "Büyüt (Shift + U)",
"useSize": "Boyutu Kullan",
"symmetry": "Bakışım",
"tileSize": "Döşeme Boyutu",
@@ -657,7 +652,6 @@
"showOptionsPanel": "Yan Paneli Göster (O ya da T)",
"shuffle": "Kar",
"usePrompt": "İstemi Kullan",
- "upscaleImage": "Görseli Büyüt",
"setToOptimalSizeTooSmall": "$t(parameters.setToOptimalSize) (çok küçük olabilir)",
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (çok büyük olabilir)",
"cfgRescaleMultiplier": "CFG Rescale Çarpanı",
diff --git a/invokeai/frontend/web/public/locales/uk.json b/invokeai/frontend/web/public/locales/uk.json
index 9bb38c21b3e..0ade5c7a1f3 100644
--- a/invokeai/frontend/web/public/locales/uk.json
+++ b/invokeai/frontend/web/public/locales/uk.json
@@ -85,10 +85,6 @@
"title": "Відновити обличчя",
"desc": "Відновити обличчя на поточному зображенні"
},
- "upscale": {
- "title": "Збільшення",
- "desc": "Збільшити поточне зображення"
- },
"showInfo": {
"title": "Показати метадані",
"desc": "Показати метадані з поточного зображення"
@@ -276,8 +272,6 @@
"type": "Тип",
"strength": "Сила",
"upscaling": "Збільшення",
- "upscale": "Збільшити",
- "upscaleImage": "Збільшити зображення",
"scale": "Масштаб",
"imageFit": "Вмістити зображення",
"scaleBeforeProcessing": "Масштабувати",
diff --git a/invokeai/frontend/web/public/locales/zh_CN.json b/invokeai/frontend/web/public/locales/zh_CN.json
index c4bb52e7cc2..aa1c723814f 100644
--- a/invokeai/frontend/web/public/locales/zh_CN.json
+++ b/invokeai/frontend/web/public/locales/zh_CN.json
@@ -193,10 +193,6 @@
"title": "面部修复",
"desc": "对当前图像进行面部修复"
},
- "upscale": {
- "title": "放大",
- "desc": "对当前图像进行放大"
- },
"showInfo": {
"title": "显示信息",
"desc": "显示当前图像的元数据"
@@ -422,8 +418,6 @@
"type": "种类",
"strength": "强度",
"upscaling": "放大",
- "upscale": "放大 (Shift + U)",
- "upscaleImage": "放大图像",
"scale": "等级",
"imageFit": "使生成图像长宽适配初始图像",
"scaleBeforeProcessing": "处理前缩放",
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts
index aad9a2a289f..a1ce52b407d 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts
@@ -1,5 +1,6 @@
import type { TypedStartListening } from '@reduxjs/toolkit';
import { createListenerMiddleware } from '@reduxjs/toolkit';
+import { addAdHocPostProcessingRequestedListener } from 'app/store/middleware/listenerMiddleware/listeners/addAdHocPostProcessingRequestedListener';
import { addCommitStagingAreaImageListener } from 'app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener';
import { addAnyEnqueuedListener } from 'app/store/middleware/listenerMiddleware/listeners/anyEnqueued';
import { addAppConfigReceivedListener } from 'app/store/middleware/listenerMiddleware/listeners/appConfigReceived';
@@ -47,7 +48,6 @@ import { addModelLoadEventListener } from 'app/store/middleware/listenerMiddlewa
import { addSocketQueueItemStatusChangedEventListener } from 'app/store/middleware/listenerMiddleware/listeners/socketio/socketQueueItemStatusChanged';
import { addStagingAreaImageSavedListener } from 'app/store/middleware/listenerMiddleware/listeners/stagingAreaImageSaved';
import { addUpdateAllNodesRequestedListener } from 'app/store/middleware/listenerMiddleware/listeners/updateAllNodesRequested';
-import { addUpscaleRequestedListener } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested';
import { addWorkflowLoadRequestedListener } from 'app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested';
import type { AppDispatch, RootState } from 'app/store/store';
@@ -142,7 +142,7 @@ addModelsLoadedListener(startAppListening);
addAppConfigReceivedListener(startAppListening);
// Ad-hoc upscale workflwo
-addUpscaleRequestedListener(startAppListening);
+addAdHocPostProcessingRequestedListener(startAppListening);
// Prompts
addDynamicPromptsListener(startAppListening);
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addAdHocPostProcessingRequestedListener.ts
similarity index 58%
rename from invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts
rename to invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addAdHocPostProcessingRequestedListener.ts
index ce480a35733..65f3198b910 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/upscaleRequested.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addAdHocPostProcessingRequestedListener.ts
@@ -2,46 +2,28 @@ import { createAction } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger';
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
import { parseify } from 'common/util/serialize';
-import { buildAdHocUpscaleGraph } from 'features/nodes/util/graph/buildAdHocUpscaleGraph';
-import { createIsAllowedToUpscaleSelector } from 'features/parameters/hooks/useIsAllowedToUpscale';
+import { buildAdHocPostProcessingGraph } from 'features/nodes/util/graph/buildAdHocPostProcessingGraph';
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
import { queueApi } from 'services/api/endpoints/queue';
import type { BatchConfig, ImageDTO } from 'services/api/types';
-export const upscaleRequested = createAction<{ imageDTO: ImageDTO }>(`upscale/upscaleRequested`);
+export const adHocPostProcessingRequested = createAction<{ imageDTO: ImageDTO }>(`upscaling/postProcessingRequested`);
-export const addUpscaleRequestedListener = (startAppListening: AppStartListening) => {
+export const addAdHocPostProcessingRequestedListener = (startAppListening: AppStartListening) => {
startAppListening({
- actionCreator: upscaleRequested,
+ actionCreator: adHocPostProcessingRequested,
effect: async (action, { dispatch, getState }) => {
const log = logger('session');
const { imageDTO } = action.payload;
- const { image_name } = imageDTO;
const state = getState();
- const { isAllowedToUpscale, detailTKey } = createIsAllowedToUpscaleSelector(imageDTO)(state);
-
- // if we can't upscale, show a toast and return
- if (!isAllowedToUpscale) {
- log.error(
- { imageDTO },
- t(detailTKey ?? 'parameters.isAllowedToUpscale.tooLarge') // should never coalesce
- );
- toast({
- id: 'NOT_ALLOWED_TO_UPSCALE',
- title: t(detailTKey ?? 'parameters.isAllowedToUpscale.tooLarge'), // should never coalesce
- status: 'error',
- });
- return;
- }
-
const enqueueBatchArg: BatchConfig = {
prepend: true,
batch: {
- graph: buildAdHocUpscaleGraph({
- image_name,
+ graph: await buildAdHocPostProcessingGraph({
+ image: imageDTO,
state,
}),
runs: 1,
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts
index 2ace69c54ea..9d02fcbfa54 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts
@@ -10,7 +10,7 @@ import { heightChanged, widthChanged } from 'features/controlLayers/store/contro
import { loraRemoved } from 'features/lora/store/loraSlice';
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
import { modelChanged, vaeSelected } from 'features/parameters/store/generationSlice';
-import { upscaleModelChanged } from 'features/parameters/store/upscaleSlice';
+import { postProcessingModelChanged, upscaleModelChanged } from 'features/parameters/store/upscaleSlice';
import { zParameterModel, zParameterVAEModel } from 'features/parameters/types/parameterSchemas';
import { getIsSizeOptimal, getOptimalDimension } from 'features/parameters/util/optimalDimension';
import { refinerModelChanged } from 'features/sdxl/store/sdxlSlice';
@@ -186,21 +186,23 @@ const handleControlAdapterModels: ModelHandler = (models, state, dispatch, _log)
};
const handleSpandrelImageToImageModels: ModelHandler = (models, state, dispatch, _log) => {
- const currentUpscaleModel = state.upscale.upscaleModel;
+ const { upscaleModel: currentUpscaleModel, postProcessingModel: currentPostProcessingModel } = state.upscale;
const upscaleModels = models.filter(isSpandrelImageToImageModelConfig);
+ const firstModel = upscaleModels[0] || null;
- if (currentUpscaleModel) {
- const isCurrentUpscaleModelAvailable = upscaleModels.some((m) => m.key === currentUpscaleModel.key);
- if (isCurrentUpscaleModelAvailable) {
- return;
- }
- }
+ const isCurrentUpscaleModelAvailable = currentUpscaleModel
+ ? upscaleModels.some((m) => m.key === currentUpscaleModel.key)
+ : false;
- const firstModel = upscaleModels[0];
- if (firstModel) {
+ if (!isCurrentUpscaleModelAvailable) {
dispatch(upscaleModelChanged(firstModel));
- return;
}
- dispatch(upscaleModelChanged(null));
+ const isCurrentPostProcessingModelAvailable = currentPostProcessingModel
+ ? upscaleModels.some((m) => m.key === currentPostProcessingModel.key)
+ : false;
+
+ if (!isCurrentPostProcessingModelAvailable) {
+ dispatch(postProcessingModelChanged(firstModel));
+ }
};
diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts
index 1a4093dfc51..6ae2011355a 100644
--- a/invokeai/frontend/web/src/app/store/store.ts
+++ b/invokeai/frontend/web/src/app/store/store.ts
@@ -25,7 +25,6 @@ import { nodesPersistConfig, nodesSlice, nodesUndoableConfig } from 'features/no
import { workflowSettingsPersistConfig, workflowSettingsSlice } from 'features/nodes/store/workflowSettingsSlice';
import { workflowPersistConfig, workflowSlice } from 'features/nodes/store/workflowSlice';
import { generationPersistConfig, generationSlice } from 'features/parameters/store/generationSlice';
-import { postprocessingPersistConfig, postprocessingSlice } from 'features/parameters/store/postprocessingSlice';
import { upscalePersistConfig, upscaleSlice } from 'features/parameters/store/upscaleSlice';
import { queueSlice } from 'features/queue/store/queueSlice';
import { sdxlPersistConfig, sdxlSlice } from 'features/sdxl/store/sdxlSlice';
@@ -53,7 +52,6 @@ const allReducers = {
[gallerySlice.name]: gallerySlice.reducer,
[generationSlice.name]: generationSlice.reducer,
[nodesSlice.name]: undoable(nodesSlice.reducer, nodesUndoableConfig),
- [postprocessingSlice.name]: postprocessingSlice.reducer,
[systemSlice.name]: systemSlice.reducer,
[configSlice.name]: configSlice.reducer,
[uiSlice.name]: uiSlice.reducer,
@@ -104,7 +102,6 @@ const persistConfigs: { [key in keyof typeof allReducers]?: PersistConfig } = {
[galleryPersistConfig.name]: galleryPersistConfig,
[generationPersistConfig.name]: generationPersistConfig,
[nodesPersistConfig.name]: nodesPersistConfig,
- [postprocessingPersistConfig.name]: postprocessingPersistConfig,
[systemPersistConfig.name]: systemPersistConfig,
[workflowPersistConfig.name]: workflowPersistConfig,
[uiPersistConfig.name]: uiPersistConfig,
diff --git a/invokeai/frontend/web/src/app/types/invokeai.ts b/invokeai/frontend/web/src/app/types/invokeai.ts
index 6d7416d95d3..bb27cf58a84 100644
--- a/invokeai/frontend/web/src/app/types/invokeai.ts
+++ b/invokeai/frontend/web/src/app/types/invokeai.ts
@@ -72,7 +72,6 @@ export type AppConfig = {
canRestoreDeletedImagesFromBin: boolean;
nodesAllowlist: string[] | undefined;
nodesDenylist: string[] | undefined;
- maxUpscalePixels?: number;
metadataFetchDebounce?: number;
workflowFetchDebounce?: number;
isLocal?: boolean;
diff --git a/invokeai/frontend/web/src/common/components/InformationalPopover/InformationalPopover.tsx b/invokeai/frontend/web/src/common/components/InformationalPopover/InformationalPopover.tsx
index 935212ee58d..cb295bb0f4c 100644
--- a/invokeai/frontend/web/src/common/components/InformationalPopover/InformationalPopover.tsx
+++ b/invokeai/frontend/web/src/common/components/InformationalPopover/InformationalPopover.tsx
@@ -10,9 +10,12 @@ import {
PopoverContent,
PopoverTrigger,
Portal,
+ Spacer,
Text,
} from '@invoke-ai/ui-library';
-import { useAppSelector } from 'app/store/storeHooks';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { setShouldEnableInformationalPopovers } from 'features/system/store/systemSlice';
+import { toast } from 'features/toast/toast';
import { merge, omit } from 'lodash-es';
import type { ReactElement } from 'react';
import { memo, useCallback, useMemo } from 'react';
@@ -71,7 +74,7 @@ type ContentProps = {
const Content = ({ data, feature }: ContentProps) => {
const { t } = useTranslation();
-
+ const dispatch = useAppDispatch();
const heading = useMemo(() => t(`popovers.${feature}.heading`), [feature, t]);
const paragraphs = useMemo(
@@ -82,16 +85,25 @@ const Content = ({ data, feature }: ContentProps) => {
[feature, t]
);
- const handleClick = useCallback(() => {
+ const onClickLearnMore = useCallback(() => {
if (!data?.href) {
return;
}
window.open(data.href);
}, [data?.href]);
+ const onClickDontShowMeThese = useCallback(() => {
+ dispatch(setShouldEnableInformationalPopovers(false));
+ toast({
+ title: t('settings.informationalPopoversDisabled'),
+ description: t('settings.informationalPopoversDisabledDesc'),
+ status: 'info',
+ });
+ }, [dispatch, t]);
+
return (
-
-
+
+
{heading && (
@@ -116,20 +128,19 @@ const Content = ({ data, feature }: ContentProps) => {
{paragraphs.map((p) => (
{p}
))}
- {data?.href && (
- <>
-
- }
- alignSelf="flex-end"
- variant="link"
- >
+
+
+
+
+
+ {data?.href && (
+ } variant="link" size="sm">
{t('common.learnMore') ?? heading}
- >
- )}
+ )}
+
diff --git a/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts b/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts
index f973d98f1a5..de28f722239 100644
--- a/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts
+++ b/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts
@@ -53,7 +53,11 @@ export type Feature =
| 'refinerCfgScale'
| 'scaleBeforeProcessing'
| 'seamlessTilingXAxis'
- | 'seamlessTilingYAxis';
+ | 'seamlessTilingYAxis'
+ | 'upscaleModel'
+ | 'scale'
+ | 'creativity'
+ | 'structure';
export type PopoverData = PopoverProps & {
image?: string;
diff --git a/invokeai/frontend/web/src/common/hooks/useAssertSingleton.ts b/invokeai/frontend/web/src/common/hooks/useAssertSingleton.ts
new file mode 100644
index 00000000000..0f7cc9db6f5
--- /dev/null
+++ b/invokeai/frontend/web/src/common/hooks/useAssertSingleton.ts
@@ -0,0 +1,18 @@
+import { useEffect } from 'react';
+import { assert } from 'tsafe';
+
+const IDS = new Set();
+
+/**
+ * Asserts that there is only one instance of a singleton entity. It can be a hook or a component.
+ * @param id The ID of the singleton entity.
+ */
+export function useAssertSingleton(id: string) {
+ useEffect(() => {
+ assert(!IDS.has(id), `There should be only one instance of ${id}`);
+ IDS.add(id);
+ return () => {
+ IDS.delete(id);
+ };
+ }, [id]);
+}
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTooltip.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTooltip.tsx
new file mode 100644
index 00000000000..63ba2991cfc
--- /dev/null
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTooltip.tsx
@@ -0,0 +1,47 @@
+import { Flex, Image, Text } from '@invoke-ai/ui-library';
+import { skipToken } from '@reduxjs/toolkit/query';
+import { useTranslation } from 'react-i18next';
+import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from 'services/api/endpoints/boards';
+import { useGetImageDTOQuery } from 'services/api/endpoints/images';
+import type { BoardDTO } from 'services/api/types';
+
+type Props = {
+ board: BoardDTO | null;
+};
+
+export const BoardTooltip = ({ board }: Props) => {
+ const { t } = useTranslation();
+ const { imagesTotal } = useGetBoardImagesTotalQuery(board?.board_id || 'none', {
+ selectFromResult: ({ data }) => {
+ return { imagesTotal: data?.total ?? 0 };
+ },
+ });
+ const { assetsTotal } = useGetBoardAssetsTotalQuery(board?.board_id || 'none', {
+ selectFromResult: ({ data }) => {
+ return { assetsTotal: data?.total ?? 0 };
+ },
+ });
+ const { currentData: coverImage } = useGetImageDTOQuery(board?.cover_image_name ?? skipToken);
+
+ return (
+
+ {coverImage && (
+
+ )}
+
+
+ {t('boards.imagesWithCount', { count: imagesTotal })}, {t('boards.assetsWithCount', { count: assetsTotal })}
+
+ {board?.archived && ({t('boards.archived')})}
+
+
+ );
+};
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTotalsTooltip.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTotalsTooltip.tsx
deleted file mode 100644
index b4c89a002df..00000000000
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTotalsTooltip.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { useTranslation } from 'react-i18next';
-import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from 'services/api/endpoints/boards';
-
-type Props = {
- board_id: string;
- isArchived: boolean;
-};
-
-export const BoardTotalsTooltip = ({ board_id, isArchived }: Props) => {
- const { t } = useTranslation();
- const { imagesTotal } = useGetBoardImagesTotalQuery(board_id, {
- selectFromResult: ({ data }) => {
- return { imagesTotal: data?.total ?? 0 };
- },
- });
- const { assetsTotal } = useGetBoardAssetsTotalQuery(board_id, {
- selectFromResult: ({ data }) => {
- return { assetsTotal: data?.total ?? 0 };
- },
- });
- return `${t('boards.imagesWithCount', { count: imagesTotal })}, ${t('boards.assetsWithCount', { count: assetsTotal })}${isArchived ? ` (${t('boards.archived')})` : ''}`;
-};
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
index 4325281e0f8..d5a96e5966b 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
@@ -1,13 +1,10 @@
-import { Box, Flex, Text } from '@invoke-ai/ui-library';
+import { Button, Collapse, Flex, Icon, Text, useDisclosure } from '@invoke-ai/ui-library';
import { EMPTY_ARRAY } from 'app/store/constants';
import { useAppSelector } from 'app/store/storeHooks';
-import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
-import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal';
import { selectListBoardsQueryArgs } from 'features/gallery/store/gallerySelectors';
-import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
-import type { CSSProperties } from 'react';
-import { memo, useMemo, useState } from 'react';
+import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
+import { PiCaretDownBold } from 'react-icons/pi';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
import type { BoardDTO } from 'services/api/types';
@@ -15,101 +12,111 @@ import AddBoardButton from './AddBoardButton';
import GalleryBoard from './GalleryBoard';
import NoBoardBoard from './NoBoardBoard';
-const overlayScrollbarsStyles: CSSProperties = {
- height: '100%',
- width: '100%',
+type Props = {
+ isPrivate: boolean;
+ setBoardToDelete: (board?: BoardDTO) => void;
};
-const BoardsList = () => {
+export const BoardsList = ({ isPrivate, setBoardToDelete }: Props) => {
+ const { t } = useTranslation();
const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId);
const boardSearchText = useAppSelector((s) => s.gallery.boardSearchText);
- const allowPrivateBoards = useAppSelector((s) => s.config.allowPrivateBoards);
const queryArgs = useAppSelector(selectListBoardsQueryArgs);
const { data: boards } = useListAllBoardsQuery(queryArgs);
- const [boardToDelete, setBoardToDelete] = useState();
- const { t } = useTranslation();
+ const allowPrivateBoards = useAppSelector((s) => s.config.allowPrivateBoards);
+ const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true });
+
+ const filteredBoards = useMemo(() => {
+ if (!boards) {
+ return EMPTY_ARRAY;
+ }
+
+ return boards.filter((board) => {
+ if (boardSearchText.length) {
+ return board.is_private === isPrivate && board.board_name.toLowerCase().includes(boardSearchText.toLowerCase());
+ } else {
+ return board.is_private === isPrivate;
+ }
+ });
+ }, [boardSearchText, boards, isPrivate]);
+
+ const boardElements = useMemo(() => {
+ const elements = [];
+ if (allowPrivateBoards && isPrivate && !boardSearchText.length) {
+ elements.push();
+ }
+
+ if (!allowPrivateBoards && !boardSearchText.length) {
+ elements.push();
+ }
+
+ filteredBoards.forEach((board) => {
+ elements.push(
+
+ );
+ });
+
+ return elements;
+ }, [allowPrivateBoards, isPrivate, boardSearchText.length, filteredBoards, selectedBoardId, setBoardToDelete]);
- const { filteredPrivateBoards, filteredSharedBoards } = useMemo(() => {
- const filteredBoards = boardSearchText
- ? boards?.filter((board) => board.board_name.toLowerCase().includes(boardSearchText.toLowerCase()))
- : boards;
- const filteredPrivateBoards = filteredBoards?.filter((board) => board.is_private) ?? EMPTY_ARRAY;
- const filteredSharedBoards = filteredBoards?.filter((board) => !board.is_private) ?? EMPTY_ARRAY;
- return { filteredPrivateBoards, filteredSharedBoards };
- }, [boardSearchText, boards]);
+ const boardListTitle = useMemo(() => {
+ if (allowPrivateBoards) {
+ return isPrivate ? t('boards.private') : t('boards.shared');
+ } else {
+ return t('boards.boards');
+ }
+ }, [isPrivate, allowPrivateBoards, t]);
return (
- <>
-
-
-
- {allowPrivateBoards && (
-
-
-
- {t('boards.private')}
-
-
-
-
-
- {filteredPrivateBoards.map((board) => (
-
- ))}
-
-
- )}
-
-
-
- {allowPrivateBoards ? t('boards.shared') : t('boards.boards')}
-
-
-
-
- {!allowPrivateBoards && }
- {filteredSharedBoards.map((board) => (
-
- ))}
-
+
+
+ {allowPrivateBoards ? (
+
-
-
-
- >
+
+ ) : (
+
+ {boardListTitle}
+
+ )}
+
+
+
+
+ {boardElements.length ? (
+ boardElements
+ ) : (
+
+ {t('boards.noBoards', { boardType: boardSearchText.length ? 'Matching' : '' })}
+
+ )}
+
+
+
);
};
-export default memo(BoardsList);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsListWrapper.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsListWrapper.tsx
new file mode 100644
index 00000000000..637dbd304a3
--- /dev/null
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsListWrapper.tsx
@@ -0,0 +1,35 @@
+import { Box } from '@invoke-ai/ui-library';
+import { useAppSelector } from 'app/store/storeHooks';
+import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
+import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal';
+import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
+import type { CSSProperties } from 'react';
+import { memo, useState } from 'react';
+import type { BoardDTO } from 'services/api/types';
+
+import { BoardsList } from './BoardsList';
+
+const overlayScrollbarsStyles: CSSProperties = {
+ height: '100%',
+ width: '100%',
+};
+
+const BoardsListWrapper = () => {
+ const allowPrivateBoards = useAppSelector((s) => s.config.allowPrivateBoards);
+ const [boardToDelete, setBoardToDelete] = useState();
+
+ return (
+ <>
+
+
+
+ {allowPrivateBoards && }
+
+
+
+
+
+ >
+ );
+};
+export default memo(BoardsListWrapper);
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsSearch.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsSearch.tsx
index fb53a137957..931c1e6cbb7 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsSearch.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsSearch.tsx
@@ -40,7 +40,7 @@ const BoardsSearch = () => {
);
return (
-
+
{(ref) => (
- }
- openDelay={1000}
- placement="left"
- closeOnScroll
- >
+ } openDelay={1000} placement="left" closeOnScroll p={2}>
@@ -168,7 +165,7 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps
{board.archived && !editingDisclosure.isOpen && }
{!editingDisclosure.isOpen && {board.image_count}}
- {t('unifiedCanvas.move')}} />
+ {t('unifiedCanvas.move')}} />
)}
@@ -197,8 +194,8 @@ const CoverImage = ({ board }: { board: BoardDTO }) => {
src={coverImage.thumbnail_url}
draggable={false}
objectFit="cover"
- w={8}
- h={8}
+ w={10}
+ h={10}
borderRadius="base"
borderBottomRadius="lg"
/>
@@ -206,8 +203,8 @@ const CoverImage = ({ board }: { board: BoardDTO }) => {
}
return (
-
-
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx
index 14bf3d5742d..c8b3ceb4318 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx
@@ -4,7 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIDroppable from 'common/components/IAIDroppable';
import type { RemoveFromBoardDropData } from 'features/dnd/types';
import { AutoAddBadge } from 'features/gallery/components/Boards/AutoAddBadge';
-import { BoardTotalsTooltip } from 'features/gallery/components/Boards/BoardsList/BoardTotalsTooltip';
+import { BoardTooltip } from 'features/gallery/components/Boards/BoardsList/BoardTooltip';
import NoBoardBoardContextMenu from 'features/gallery/components/Boards/NoBoardBoardContextMenu';
import { autoAddBoardIdChanged, boardIdSelected } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo } from 'react';
@@ -46,25 +46,16 @@ const NoBoardBoard = memo(({ isSelected }: Props) => {
[]
);
- const filteredOut = useMemo(() => {
- return boardSearchText ? !boardName.toLowerCase().includes(boardSearchText.toLowerCase()) : false;
- }, [boardName, boardSearchText]);
-
const { t } = useTranslation();
- if (filteredOut) {
+ if (boardSearchText.length) {
return null;
}
return (
{(ref) => (
- }
- openDelay={1000}
- placement="left"
- closeOnScroll
- >
+ } openDelay={1000} placement="left" closeOnScroll>
{
alignItems="center"
borderRadius="base"
cursor="pointer"
- px={2}
py={1}
- gap={2}
+ ps={1}
+ pe={4}
+ gap={4}
bg={isSelected ? 'base.850' : undefined}
_hover={_hover}
+ h={12}
>
-
+
{/* iconified from public/assets/images/invoke-symbol-wht-lrg.svg */}
-
+
{
-
+
{boardName}
{autoAddBoardId === 'none' && }
{imagesTotal}
- {t('unifiedCanvas.move')}} />
+ {t('unifiedCanvas.move')}} />
)}
diff --git a/invokeai/frontend/web/src/features/gallery/components/Gallery.tsx b/invokeai/frontend/web/src/features/gallery/components/Gallery.tsx
new file mode 100644
index 00000000000..8776fa888b9
--- /dev/null
+++ b/invokeai/frontend/web/src/features/gallery/components/Gallery.tsx
@@ -0,0 +1,105 @@
+import type { ChakraProps } from '@invoke-ai/ui-library';
+import {
+ Box,
+ Collapse,
+ Flex,
+ IconButton,
+ Spacer,
+ Tab,
+ TabList,
+ Tabs,
+ Text,
+ useDisclosure,
+} from '@invoke-ai/ui-library';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { useGallerySearchTerm } from 'features/gallery/components/ImageGrid/useGallerySearchTerm';
+import { galleryViewChanged } from 'features/gallery/store/gallerySlice';
+import type { CSSProperties } from 'react';
+import { useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+import { PiMagnifyingGlassBold } from 'react-icons/pi';
+import { useBoardName } from 'services/api/hooks/useBoardName';
+
+import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
+import { GalleryPagination } from './ImageGrid/GalleryPagination';
+import { GallerySearch } from './ImageGrid/GallerySearch';
+
+const BASE_STYLES: ChakraProps['sx'] = {
+ fontWeight: 'semibold',
+ fontSize: 'sm',
+ color: 'base.300',
+};
+
+const SELECTED_STYLES: ChakraProps['sx'] = {
+ borderColor: 'base.800',
+ borderBottomColor: 'base.900',
+ color: 'invokeBlue.300',
+};
+
+const COLLAPSE_STYLES: CSSProperties = { flexShrink: 0, minHeight: 0 };
+
+export const Gallery = () => {
+ const { t } = useTranslation();
+ const dispatch = useAppDispatch();
+ const galleryView = useAppSelector((s) => s.gallery.galleryView);
+ const initialSearchTerm = useAppSelector((s) => s.gallery.searchTerm);
+ const searchDisclosure = useDisclosure({ defaultIsOpen: initialSearchTerm.length > 0 });
+ const [searchTerm, onChangeSearchTerm, onResetSearchTerm] = useGallerySearchTerm();
+
+ const handleClickImages = useCallback(() => {
+ dispatch(galleryViewChanged('images'));
+ }, [dispatch]);
+
+ const handleClickAssets = useCallback(() => {
+ dispatch(galleryViewChanged('assets'));
+ }, [dispatch]);
+
+ const handleClickSearch = useCallback(() => {
+ searchDisclosure.onToggle();
+ onResetSearchTerm();
+ }, [onResetSearchTerm, searchDisclosure]);
+
+ const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId);
+ const boardName = useBoardName(selectedBoardId);
+
+ return (
+
+
+
+
+ {boardName}
+
+
+
+ {t('parameters.images')}
+
+
+ {t('gallery.assets')}
+
+ }
+ colorScheme={searchDisclosure.isOpen ? 'invokeBlue' : 'base'}
+ variant="link"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx
deleted file mode 100644
index 8ede311f9e4..00000000000
--- a/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Flex, Text } from '@invoke-ai/ui-library';
-import { useAppSelector } from 'app/store/storeHooks';
-import { memo } from 'react';
-import { useBoardName } from 'services/api/hooks/useBoardName';
-
-type Props = {
- onClick: () => void;
-};
-
-const GalleryBoardName = (props: Props) => {
- const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId);
- const boardName = useBoardName(selectedBoardId);
-
- return (
-
-
- {boardName}
-
-
- );
-};
-
-export default memo(GalleryBoardName);
diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryHeader.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryHeader.tsx
index 69c2c8fe352..ce9436811c6 100644
--- a/invokeai/frontend/web/src/features/gallery/components/GalleryHeader.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/GalleryHeader.tsx
@@ -3,32 +3,21 @@ import { useStore } from '@nanostores/react';
import { $projectName, $projectUrl } from 'app/store/nanostores/projectId';
import { memo } from 'react';
-import GalleryBoardName from './GalleryBoardName';
-
-type Props = {
- onClickBoardName: () => void;
-};
-
-export const GalleryHeader = memo((props: Props) => {
+export const GalleryHeader = memo(() => {
const projectName = useStore($projectName);
const projectUrl = useStore($projectUrl);
if (projectName && projectUrl) {
return (
-
+
{projectName}
-
);
}
- return (
-
-
-
- );
+ return null;
});
GalleryHeader.displayName = 'GalleryHeader';
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx
index 5a096f5cefc..a42410b885e 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGalleryContent.tsx
@@ -1,57 +1,28 @@
-import type { ChakraProps } from '@invoke-ai/ui-library';
-import {
- Box,
- Collapse,
- Divider,
- Flex,
- IconButton,
- Spacer,
- Tab,
- TabList,
- Tabs,
- useDisclosure,
-} from '@invoke-ai/ui-library';
+import { Box, Button, Collapse, Divider, Flex, IconButton, useDisclosure } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { GalleryHeader } from 'features/gallery/components/GalleryHeader';
-import { galleryViewChanged } from 'features/gallery/store/gallerySlice';
+import { boardSearchTextChanged } from 'features/gallery/store/gallerySlice';
import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
import { usePanel, type UsePanelOptions } from 'features/ui/hooks/usePanel';
import type { CSSProperties } from 'react';
import { memo, useCallback, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
-import { PiMagnifyingGlassBold } from 'react-icons/pi';
+import { PiCaretDownBold, PiCaretUpBold, PiMagnifyingGlassBold } from 'react-icons/pi';
import type { ImperativePanelGroupHandle } from 'react-resizable-panels';
import { Panel, PanelGroup } from 'react-resizable-panels';
-import BoardsList from './Boards/BoardsList/BoardsList';
+import BoardsListWrapper from './Boards/BoardsList/BoardsListWrapper';
import BoardsSearch from './Boards/BoardsList/BoardsSearch';
+import { Gallery } from './Gallery';
import GallerySettingsPopover from './GallerySettingsPopover/GallerySettingsPopover';
-import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
-import { GalleryPagination } from './ImageGrid/GalleryPagination';
-import { GallerySearch } from './ImageGrid/GallerySearch';
const COLLAPSE_STYLES: CSSProperties = { flexShrink: 0, minHeight: 0 };
-const BASE_STYLES: ChakraProps['sx'] = {
- fontWeight: 'semibold',
- fontSize: 'sm',
- color: 'base.300',
-};
-
-const SELECTED_STYLES: ChakraProps['sx'] = {
- borderColor: 'base.800',
- borderBottomColor: 'base.900',
- color: 'invokeBlue.300',
-};
-
const ImageGalleryContent = () => {
const { t } = useTranslation();
- const galleryView = useAppSelector((s) => s.gallery.galleryView);
- const searchTerm = useAppSelector((s) => s.gallery.searchTerm);
const boardSearchText = useAppSelector((s) => s.gallery.boardSearchText);
const dispatch = useAppDispatch();
- const searchDisclosure = useDisclosure({ defaultIsOpen: false });
- const boardSearchDisclosure = useDisclosure({ defaultIsOpen: false });
+ const boardSearchDisclosure = useDisclosure({ defaultIsOpen: !!boardSearchText.length });
const panelGroupRef = useRef(null);
const boardsListPanelOptions = useMemo(
@@ -67,42 +38,58 @@ const ImageGalleryContent = () => {
);
const boardsListPanel = usePanel(boardsListPanelOptions);
- const handleClickImages = useCallback(() => {
- dispatch(galleryViewChanged('images'));
- }, [dispatch]);
+ const handleClickBoardSearch = useCallback(() => {
+ if (boardSearchText.length) {
+ dispatch(boardSearchTextChanged(''));
+ }
+ boardSearchDisclosure.onToggle();
+ boardsListPanel.expand();
+ }, [boardSearchText.length, boardSearchDisclosure, boardsListPanel, dispatch]);
- const handleClickAssets = useCallback(() => {
- dispatch(galleryViewChanged('assets'));
- }, [dispatch]);
+ const handleToggleBoardPanel = useCallback(() => {
+ if (boardSearchText.length) {
+ dispatch(boardSearchTextChanged(''));
+ }
+ boardSearchDisclosure.onClose();
+ boardsListPanel.toggle();
+ }, [boardSearchText.length, boardSearchDisclosure, boardsListPanel, dispatch]);
return (
-
-
-
-
- }
- variant="link"
- />
- {boardSearchText && (
-
- )}
-
+
+
+
+ : }
+ >
+ {boardsListPanel.isCollapsed ? t('boards.viewBoards') : t('boards.hideBoards')}
+
+
+
+
+ }
+ colorScheme={boardSearchDisclosure.isOpen ? 'invokeBlue' : 'base'}
+ variant="link"
+ />
+
+
+
+
{
>
-
+
+
+
-
+
{
onDoubleClick={boardsListPanel.onDoubleClickHandle}
/>
-
-
-
-
- {t('parameters.images')}
-
-
- {t('gallery.assets')}
-
-
-
- }
- variant="link"
- />
- {searchTerm && (
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx
index ddc23ebe4b4..27776ab77d8 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx
@@ -3,6 +3,8 @@ import { ELLIPSIS, useGalleryPagination } from 'features/gallery/hooks/useGaller
import { useCallback } from 'react';
import { PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi';
+import { JumpTo } from './JumpTo';
+
export const GalleryPagination = () => {
const { goPrev, goNext, isPrevEnabled, isNextEnabled, pageButtons, goToPage, currentPage, total } =
useGalleryPagination();
@@ -20,7 +22,7 @@ export const GalleryPagination = () => {
}
return (
-
+
{
variant="ghost"
/>
- {pageButtons.map((page, i) => {
- if (page === ELLIPSIS) {
- return (
-
- );
- }
- return (
-
- );
- })}
+ {pageButtons.map((page, i) => (
+
+ ))}
{
isDisabled={!isNextEnabled}
variant="ghost"
/>
+
);
};
+
+type PageButtonProps = {
+ page: number | typeof ELLIPSIS;
+ currentPage: number;
+ goToPage: (page: number) => void;
+};
+
+const PageButton = ({ page, currentPage, goToPage }: PageButtonProps) => {
+ if (page === ELLIPSIS) {
+ return (
+
+ );
+ }
+ return (
+
+ );
+};
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GallerySearch.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GallerySearch.tsx
index 9e3a1bf4877..bb2fe8ff29a 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GallerySearch.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GallerySearch.tsx
@@ -1,59 +1,60 @@
import { IconButton, Input, InputGroup, InputRightElement, Spinner } from '@invoke-ai/ui-library';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { useAppSelector } from 'app/store/storeHooks';
import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
-import { searchTermChanged } from 'features/gallery/store/gallerySlice';
-import { debounce } from 'lodash-es';
-import type { ChangeEvent } from 'react';
-import { useCallback, useMemo, useState } from 'react';
+import type { ChangeEvent, KeyboardEvent } from 'react';
+import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiXBold } from 'react-icons/pi';
import { useListImagesQuery } from 'services/api/endpoints/images';
-export const GallerySearch = () => {
- const dispatch = useAppDispatch();
- const searchTerm = useAppSelector((s) => s.gallery.searchTerm);
+type Props = {
+ searchTerm: string;
+ onChangeSearchTerm: (value: string) => void;
+ onResetSearchTerm: () => void;
+};
+
+export const GallerySearch = ({ searchTerm, onChangeSearchTerm, onResetSearchTerm }: Props) => {
const { t } = useTranslation();
- const [searchTermInput, setSearchTermInput] = useState(searchTerm);
const queryArgs = useAppSelector(selectListImagesQueryArgs);
const { isPending } = useListImagesQuery(queryArgs, {
selectFromResult: ({ isLoading, isFetching }) => ({ isPending: isLoading || isFetching }),
});
- const debouncedSetSearchTerm = useMemo(() => {
- return debounce((value: string) => {
- dispatch(searchTermChanged(value));
- }, 1000);
- }, [dispatch]);
const handleChangeInput = useCallback(
(e: ChangeEvent) => {
- setSearchTermInput(e.target.value);
- debouncedSetSearchTerm(e.target.value);
+ onChangeSearchTerm(e.target.value);
},
- [debouncedSetSearchTerm]
+ [onChangeSearchTerm]
);
- const handleClearInput = useCallback(() => {
- setSearchTermInput('');
- dispatch(searchTermChanged(''));
- }, [dispatch]);
+ const handleKeydown = useCallback(
+ (e: KeyboardEvent) => {
+ // exit search mode on escape
+ if (e.key === 'Escape') {
+ onResetSearchTerm();
+ }
+ },
+ [onResetSearchTerm]
+ );
return (
{isPending && (
)}
- {!isPending && searchTermInput.length && (
+ {!isPending && searchTerm.length && (
{
+ const { t } = useTranslation();
+ const { goToPage, currentPage, pages } = useGalleryPagination();
+ const [newPage, setNewPage] = useState(currentPage);
+ const { isOpen, onToggle, onClose } = useDisclosure();
+ const ref = useRef(null);
+
+ const onOpen = useCallback(() => {
+ setNewPage(currentPage);
+ setTimeout(() => {
+ const input = ref.current?.querySelector('input');
+ input?.focus();
+ input?.select();
+ }, 0);
+ }, [currentPage]);
+
+ const onChangeJumpTo = useCallback((v: number) => {
+ setNewPage(v - 1);
+ }, []);
+
+ const onClickGo = useCallback(() => {
+ goToPage(newPage);
+ onClose();
+ }, [newPage, goToPage, onClose]);
+
+ useHotkeys(
+ 'enter',
+ () => {
+ onClickGo();
+ },
+ { enabled: isOpen, enableOnFormTags: ['input'] },
+ [isOpen, onClickGo]
+ );
+
+ useHotkeys(
+ 'esc',
+ () => {
+ setNewPage(currentPage);
+ onClose();
+ },
+ { enabled: isOpen, enableOnFormTags: ['input'] },
+ [isOpen, onClose]
+ );
+
+ useEffect(() => {
+ setNewPage(currentPage);
+ }, [currentPage]);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/useGallerySearchTerm.ts b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/useGallerySearchTerm.ts
new file mode 100644
index 00000000000..52e6f8ec08f
--- /dev/null
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/useGallerySearchTerm.ts
@@ -0,0 +1,37 @@
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
+import { searchTermChanged } from 'features/gallery/store/gallerySlice';
+import { debounce } from 'lodash-es';
+import { useCallback, useMemo, useState } from 'react';
+
+export const useGallerySearchTerm = () => {
+ // Highlander!
+ useAssertSingleton('gallery-search-state');
+
+ const dispatch = useAppDispatch();
+ const searchTerm = useAppSelector((s) => s.gallery.searchTerm);
+
+ const [localSearchTerm, setLocalSearchTerm] = useState(searchTerm);
+
+ const debouncedSetSearchTerm = useMemo(() => {
+ return debounce((val: string) => {
+ dispatch(searchTermChanged(val));
+ }, 1000);
+ }, [dispatch]);
+
+ const onChange = useCallback(
+ (val: string) => {
+ setLocalSearchTerm(val);
+ debouncedSetSearchTerm(val);
+ },
+ [debouncedSetSearchTerm]
+ );
+
+ const onReset = useCallback(() => {
+ debouncedSetSearchTerm.cancel();
+ setLocalSearchTerm('');
+ dispatch(searchTermChanged(''));
+ }, [debouncedSetSearchTerm, dispatch]);
+
+ return [localSearchTerm, onChange, onReset] as const;
+};
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImageButtons.tsx
index d500d692fe7..d1f874271d6 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImageButtons.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImageButtons.tsx
@@ -2,7 +2,7 @@ import { ButtonGroup, IconButton, Menu, MenuButton, MenuList } from '@invoke-ai/
import { useStore } from '@nanostores/react';
import { createSelector } from '@reduxjs/toolkit';
import { skipToken } from '@reduxjs/toolkit/query';
-import { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested';
+import { adHocPostProcessingRequested } from 'app/store/middleware/listenerMiddleware/listeners/addAdHocPostProcessingRequestedListener';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { iiLayerAdded } from 'features/controlLayers/store/controlLayersSlice';
import { DeleteImageButton } from 'features/deleteImageModal/components/DeleteImageButton';
@@ -14,7 +14,7 @@ import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
import { parseAndRecallImageDimensions } from 'features/metadata/util/handlers';
import { $templates } from 'features/nodes/store/nodesSlice';
-import ParamUpscalePopover from 'features/parameters/components/Upscale/ParamUpscaleSettings';
+import { PostProcessingPopover } from 'features/parameters/components/PostProcessing/PostProcessingPopover';
import { useIsQueueMutationInProgress } from 'features/queue/hooks/useIsQueueMutationInProgress';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { selectSystemSlice } from 'features/system/store/systemSlice';
@@ -97,7 +97,7 @@ const CurrentImageButtons = () => {
if (!imageDTO) {
return;
}
- dispatch(upscaleRequested({ imageDTO }));
+ dispatch(adHocPostProcessingRequested({ imageDTO }));
}, [dispatch, imageDTO]);
const handleDelete = useCallback(() => {
@@ -193,7 +193,7 @@ const CurrentImageButtons = () => {
{isUpscalingEnabled && (
- {isUpscalingEnabled && }
+ {isUpscalingEnabled && }
)}
diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts
index 75bea2dcb1a..2350a6ccf59 100644
--- a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts
+++ b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts
@@ -1,6 +1,7 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
import { offsetChanged } from 'features/gallery/store/gallerySlice';
+import { throttle } from 'lodash-es';
import { useCallback, useEffect, useMemo } from 'react';
import { useListImagesQuery } from 'services/api/endpoints/images';
@@ -80,32 +81,41 @@ export const useGalleryPagination = () => {
return offset > 0;
}, [count, offset]);
+ const onOffsetChanged = useCallback(
+ (arg: Parameters[0]) => {
+ dispatch(offsetChanged(arg));
+ },
+ [dispatch]
+ );
+
+ const throttledOnOffsetChanged = useMemo(() => throttle(onOffsetChanged, 500), [onOffsetChanged]);
+
const goNext = useCallback(
(withHotkey?: 'arrow' | 'alt+arrow') => {
- dispatch(offsetChanged({ offset: offset + (limit || 0), withHotkey }));
+ throttledOnOffsetChanged({ offset: offset + (limit || 0), withHotkey });
},
- [dispatch, offset, limit]
+ [throttledOnOffsetChanged, offset, limit]
);
const goPrev = useCallback(
(withHotkey?: 'arrow' | 'alt+arrow') => {
- dispatch(offsetChanged({ offset: Math.max(offset - (limit || 0), 0), withHotkey }));
+ throttledOnOffsetChanged({ offset: Math.max(offset - (limit || 0), 0), withHotkey });
},
- [dispatch, offset, limit]
+ [throttledOnOffsetChanged, offset, limit]
);
const goToPage = useCallback(
(page: number) => {
- dispatch(offsetChanged({ offset: page * (limit || 0) }));
+ throttledOnOffsetChanged({ offset: page * (limit || 0) });
},
- [dispatch, limit]
+ [throttledOnOffsetChanged, limit]
);
const goToFirst = useCallback(() => {
- dispatch(offsetChanged({ offset: 0 }));
- }, [dispatch]);
+ throttledOnOffsetChanged({ offset: 0 });
+ }, [throttledOnOffsetChanged]);
const goToLast = useCallback(() => {
- dispatch(offsetChanged({ offset: (pages - 1) * (limit || 0) }));
- }, [dispatch, pages, limit]);
+ throttledOnOffsetChanged({ offset: (pages - 1) * (limit || 0) });
+ }, [throttledOnOffsetChanged, pages, limit]);
// handle when total/pages decrease and user is on high page number (ie bulk removing or deleting)
useEffect(() => {
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts
index 826bec17b17..693cf3cf52d 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts
+++ b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings.ts
@@ -1,15 +1,10 @@
-import { skipToken } from '@reduxjs/toolkit/query';
import { isNil } from 'lodash-es';
import { useMemo } from 'react';
-import { useGetModelConfigWithTypeGuard } from 'services/api/hooks/useGetModelConfigWithTypeGuard';
-import { isControlNetOrT2IAdapterModelConfig } from 'services/api/types';
-
-export const useControlNetOrT2IAdapterDefaultSettings = (modelKey?: string | null) => {
- const { modelConfig, isLoading } = useGetModelConfigWithTypeGuard(
- modelKey ?? skipToken,
- isControlNetOrT2IAdapterModelConfig
- );
+import type { ControlNetModelConfig, T2IAdapterModelConfig } from 'services/api/types';
+export const useControlNetOrT2IAdapterDefaultSettings = (
+ modelConfig: ControlNetModelConfig | T2IAdapterModelConfig
+) => {
const defaultSettingsDefaults = useMemo(() => {
return {
preprocessor: {
@@ -19,5 +14,5 @@ export const useControlNetOrT2IAdapterDefaultSettings = (modelKey?: string | nul
};
}, [modelConfig?.default_settings]);
- return { defaultSettingsDefaults, isLoading };
+ return defaultSettingsDefaults;
};
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useInstallModel.ts b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useInstallModel.ts
index 7636b9f314a..12141af2a5f 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useInstallModel.ts
+++ b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useInstallModel.ts
@@ -1,11 +1,9 @@
import { toast } from 'features/toast/toast';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useInstallModelMutation } from 'services/api/endpoints/models';
+import { type InstallModelArg, useInstallModelMutation } from 'services/api/endpoints/models';
-type InstallModelArg = {
- source: string;
- inplace?: boolean;
+type InstallModelArgWithCallbacks = InstallModelArg & {
onSuccess?: () => void;
onError?: (error: unknown) => void;
};
@@ -15,8 +13,9 @@ export const useInstallModel = () => {
const [_installModel, request] = useInstallModelMutation();
const installModel = useCallback(
- ({ source, inplace, onSuccess, onError }: InstallModelArg) => {
- _installModel({ source, inplace })
+ ({ source, inplace, config, onSuccess, onError }: InstallModelArgWithCallbacks) => {
+ config ||= {};
+ _installModel({ source, inplace, config })
.unwrap()
.then((_) => {
if (onSuccess) {
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts
index 6de99673e46..55ee40ada50 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts
+++ b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useMainModelDefaultSettings.ts
@@ -1,12 +1,9 @@
-import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppSelector } from 'app/store/storeHooks';
-import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
import { selectConfigSlice } from 'features/system/store/configSlice';
import { isNil } from 'lodash-es';
import { useMemo } from 'react';
-import { useGetModelConfigWithTypeGuard } from 'services/api/hooks/useGetModelConfigWithTypeGuard';
-import { isNonRefinerMainModelConfig } from 'services/api/types';
+import type { MainModelConfig } from 'services/api/types';
const initialStatesSelector = createMemoizedSelector(selectConfigSlice, (config) => {
const { steps, guidance, scheduler, cfgRescaleMultiplier, vaePrecision, width, height } = config.sd;
@@ -22,9 +19,7 @@ const initialStatesSelector = createMemoizedSelector(selectConfigSlice, (config)
};
});
-export const useMainModelDefaultSettings = (modelKey?: string | null) => {
- const { modelConfig, isLoading } = useGetModelConfigWithTypeGuard(modelKey ?? skipToken, isNonRefinerMainModelConfig);
-
+export const useMainModelDefaultSettings = (modelConfig: MainModelConfig) => {
const {
initialSteps,
initialCfg,
@@ -81,5 +76,5 @@ export const useMainModelDefaultSettings = (modelKey?: string | null) => {
initialHeight,
]);
- return { defaultSettingsDefaults, isLoading, optimalDimension: getOptimalDimension(modelConfig) };
+ return defaultSettingsDefaults;
};
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/store/modelManagerV2Slice.ts b/invokeai/frontend/web/src/features/modelManagerV2/store/modelManagerV2Slice.ts
index c637d30fd80..8a7e3a7aa85 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/store/modelManagerV2Slice.ts
+++ b/invokeai/frontend/web/src/features/modelManagerV2/store/modelManagerV2Slice.ts
@@ -1,6 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
-import type { PersistConfig } from 'app/store/store';
+import type { PersistConfig, RootState } from 'app/store/store';
import type { ModelType } from 'services/api/types';
export type FilterableModelType = Exclude | 'refiner';
@@ -50,6 +50,8 @@ export const modelManagerV2Slice = createSlice({
export const { setSelectedModelKey, setSearchTerm, setFilteredModelType, setSelectedModelMode, setScanPath } =
modelManagerV2Slice.actions;
+export const selectModelManagerV2Slice = (state: RootState) => state.modelmanagerV2;
+
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
const migrateModelManagerState = (state: any): any => {
if (!('_version' in state)) {
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceForm.tsx
index ee5960f7d26..7257c30007f 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceForm.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceForm.tsx
@@ -1,13 +1,13 @@
import { Button, Flex, FormControl, FormErrorMessage, FormHelperText, FormLabel, Input } from '@invoke-ai/ui-library';
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
import type { ChangeEventHandler } from 'react';
-import { useCallback, useState } from 'react';
+import { memo, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLazyGetHuggingFaceModelsQuery } from 'services/api/endpoints/models';
import { HuggingFaceResults } from './HuggingFaceResults';
-export const HuggingFaceForm = () => {
+export const HuggingFaceForm = memo(() => {
const [huggingFaceRepo, setHuggingFaceRepo] = useState('');
const [displayResults, setDisplayResults] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
@@ -66,4 +66,6 @@ export const HuggingFaceForm = () => {
{data && data.urls && displayResults && }
);
-};
+});
+
+HuggingFaceForm.displayName = 'HuggingFaceForm';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResultItem.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResultItem.tsx
index 32970a3666a..5edb67eefa8 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResultItem.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResultItem.tsx
@@ -1,13 +1,13 @@
import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiPlusBold } from 'react-icons/pi';
type Props = {
result: string;
};
-export const HuggingFaceResultItem = ({ result }: Props) => {
+export const HuggingFaceResultItem = memo(({ result }: Props) => {
const { t } = useTranslation();
const [installModel] = useInstallModel();
@@ -27,4 +27,6 @@ export const HuggingFaceResultItem = ({ result }: Props) => {
} onClick={onClick} size="sm" />
);
-};
+});
+
+HuggingFaceResultItem.displayName = 'HuggingFaceResultItem';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResults.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResults.tsx
index 826fd177eaa..25546c68229 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResults.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/HuggingFaceFolder/HuggingFaceResults.tsx
@@ -11,7 +11,7 @@ import {
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
import type { ChangeEventHandler } from 'react';
-import { useCallback, useMemo, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PiXBold } from 'react-icons/pi';
@@ -21,7 +21,7 @@ type HuggingFaceResultsProps = {
results: string[];
};
-export const HuggingFaceResults = ({ results }: HuggingFaceResultsProps) => {
+export const HuggingFaceResults = memo(({ results }: HuggingFaceResultsProps) => {
const { t } = useTranslation();
const [searchTerm, setSearchTerm] = useState('');
@@ -93,4 +93,6 @@ export const HuggingFaceResults = ({ results }: HuggingFaceResultsProps) => {
>
);
-};
+});
+
+HuggingFaceResults.displayName = 'HuggingFaceResults';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/InstallModelForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/InstallModelForm.tsx
index cc052878bff..64eb725e5ed 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/InstallModelForm.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/InstallModelForm.tsx
@@ -1,7 +1,7 @@
import { Button, Checkbox, Flex, FormControl, FormHelperText, FormLabel, Input } from '@invoke-ai/ui-library';
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
import { t } from 'i18next';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
@@ -10,7 +10,7 @@ type SimpleImportModelConfig = {
inplace: boolean;
};
-export const InstallModelForm = () => {
+export const InstallModelForm = memo(() => {
const [installModel, { isLoading }] = useInstallModel();
const { register, handleSubmit, formState, reset } = useForm({
@@ -74,4 +74,6 @@ export const InstallModelForm = () => {
);
-};
+});
+
+InstallModelForm.displayName = 'InstallModelForm';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx
index b3544af5b35..c2443dde6b0 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueue.tsx
@@ -2,12 +2,12 @@ import { Box, Button, Flex, Heading } from '@invoke-ai/ui-library';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useListModelInstallsQuery, usePruneCompletedModelInstallsMutation } from 'services/api/endpoints/models';
import { ModelInstallQueueItem } from './ModelInstallQueueItem';
-export const ModelInstallQueue = () => {
+export const ModelInstallQueue = memo(() => {
const { data } = useListModelInstallsQuery();
const [_pruneCompletedModelInstalls] = usePruneCompletedModelInstallsMutation();
@@ -61,4 +61,6 @@ export const ModelInstallQueue = () => {
);
-};
+});
+
+ModelInstallQueue.displayName = 'ModelInstallQueue';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueueItem.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueueItem.tsx
index 82a28b2d75b..b14b1fbc4ca 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueueItem.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ModelInstallQueue/ModelInstallQueueItem.tsx
@@ -2,7 +2,7 @@ import { Flex, IconButton, Progress, Text, Tooltip } from '@invoke-ai/ui-library
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
import { isNil } from 'lodash-es';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { PiXBold } from 'react-icons/pi';
import { useCancelModelInstallMutation } from 'services/api/endpoints/models';
import type { ModelInstallJob } from 'services/api/types';
@@ -25,7 +25,7 @@ const formatBytes = (bytes: number) => {
return `${bytes.toFixed(2)} ${units[i]}`;
};
-export const ModelInstallQueueItem = (props: ModelListItemProps) => {
+export const ModelInstallQueueItem = memo((props: ModelListItemProps) => {
const { installJob } = props;
const [deleteImportModel] = useCancelModelInstallMutation();
@@ -124,7 +124,9 @@ export const ModelInstallQueueItem = (props: ModelListItemProps) => {
/>
);
-};
+});
+
+ModelInstallQueueItem.displayName = 'ModelInstallQueueItem';
type TooltipLabelProps = {
installJob: ModelInstallJob;
@@ -132,7 +134,7 @@ type TooltipLabelProps = {
source: string;
};
-const TooltipLabel = ({ name, source, installJob }: TooltipLabelProps) => {
+const TooltipLabel = memo(({ name, source, installJob }: TooltipLabelProps) => {
const progressString = useMemo(() => {
if (installJob.status !== 'downloading' || installJob.bytes === undefined || installJob.total_bytes === undefined) {
return '';
@@ -156,4 +158,6 @@ const TooltipLabel = ({ name, source, installJob }: TooltipLabelProps) => {
)}
>
);
-};
+});
+
+TooltipLabel.displayName = 'TooltipLabel';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderForm.tsx
index 2a8aec3285b..1cd036bf13c 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderForm.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderForm.tsx
@@ -2,13 +2,13 @@ import { Button, Flex, FormControl, FormErrorMessage, FormHelperText, FormLabel,
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setScanPath } from 'features/modelManagerV2/store/modelManagerV2Slice';
import type { ChangeEventHandler } from 'react';
-import { useCallback, useState } from 'react';
+import { memo, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLazyScanFolderQuery } from 'services/api/endpoints/models';
import { ScanModelsResults } from './ScanFolderResults';
-export const ScanModelsForm = () => {
+export const ScanModelsForm = memo(() => {
const scanPath = useAppSelector((state) => state.modelmanagerV2.scanPath);
const dispatch = useAppDispatch();
const [errorMessage, setErrorMessage] = useState('');
@@ -56,4 +56,6 @@ export const ScanModelsForm = () => {
{data && }
);
-};
+});
+
+ScanModelsForm.displayName = 'ScanModelsForm';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResultItem.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResultItem.tsx
index 4f2f77470d9..9f8c1bdc843 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResultItem.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResultItem.tsx
@@ -1,5 +1,5 @@
import { Badge, Box, Flex, IconButton, Text } from '@invoke-ai/ui-library';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiPlusBold } from 'react-icons/pi';
import type { ScanFolderResponse } from 'services/api/endpoints/models';
@@ -8,7 +8,7 @@ type Props = {
result: ScanFolderResponse[number];
installModel: (source: string) => void;
};
-export const ScanModelResultItem = ({ result, installModel }: Props) => {
+export const ScanModelResultItem = memo(({ result, installModel }: Props) => {
const { t } = useTranslation();
const handleInstall = useCallback(() => {
@@ -30,4 +30,6 @@ export const ScanModelResultItem = ({ result, installModel }: Props) => {
);
-};
+});
+
+ScanModelResultItem.displayName = 'ScanModelResultItem';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResults.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResults.tsx
index 749ef4c8e00..ee8b834a29e 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResults.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/ScanFolder/ScanFolderResults.tsx
@@ -14,7 +14,7 @@ import {
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
import type { ChangeEvent, ChangeEventHandler } from 'react';
-import { useCallback, useMemo, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PiXBold } from 'react-icons/pi';
import type { ScanFolderResponse } from 'services/api/endpoints/models';
@@ -25,7 +25,7 @@ type ScanModelResultsProps = {
results: ScanFolderResponse;
};
-export const ScanModelsResults = ({ results }: ScanModelResultsProps) => {
+export const ScanModelsResults = memo(({ results }: ScanModelResultsProps) => {
const { t } = useTranslation();
const [searchTerm, setSearchTerm] = useState('');
const [inplace, setInplace] = useState(true);
@@ -116,4 +116,6 @@ export const ScanModelsResults = ({ results }: ScanModelResultsProps) => {
>
);
-};
+});
+
+ScanModelsResults.displayName = 'ScanModelsResults';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx
index 754cbbd25ab..a3c9c82d0eb 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StartModelsResultItem.tsx
@@ -1,7 +1,7 @@
import { Badge, Box, Flex, IconButton, Text } from '@invoke-ai/ui-library';
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
import ModelBaseBadge from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelBaseBadge';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiPlusBold } from 'react-icons/pi';
import type { GetStarterModelsResponse } from 'services/api/endpoints/models';
@@ -9,20 +9,22 @@ import type { GetStarterModelsResponse } from 'services/api/endpoints/models';
type Props = {
result: GetStarterModelsResponse[number];
};
-export const StarterModelsResultItem = ({ result }: Props) => {
+export const StarterModelsResultItem = memo(({ result }: Props) => {
const { t } = useTranslation();
const allSources = useMemo(() => {
- const _allSources = [result.source];
+ const _allSources = [{ source: result.source, config: { name: result.name, description: result.description } }];
if (result.dependencies) {
- _allSources.push(...result.dependencies.map((d) => d.source));
+ for (const d of result.dependencies) {
+ _allSources.push({ source: d.source, config: { name: d.name, description: d.description } });
+ }
}
return _allSources;
}, [result]);
const [installModel] = useInstallModel();
const onClick = useCallback(() => {
- for (const source of allSources) {
- installModel({ source });
+ for (const { config, source } of allSources) {
+ installModel({ config, source });
}
}, [allSources, installModel]);
@@ -45,4 +47,6 @@ export const StarterModelsResultItem = ({ result }: Props) => {
);
-};
+});
+
+StarterModelsResultItem.displayName = 'StarterModelsResultItem';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsForm.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsForm.tsx
index 3198f1df787..837ef5c63b8 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsForm.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsForm.tsx
@@ -1,10 +1,11 @@
import { Flex } from '@invoke-ai/ui-library';
import { FetchingModelsLoader } from 'features/modelManagerV2/subpanels/ModelManagerPanel/FetchingModelsLoader';
+import { memo } from 'react';
import { useGetStarterModelsQuery } from 'services/api/endpoints/models';
import { StarterModelsResults } from './StarterModelsResults';
-export const StarterModelsForm = () => {
+export const StarterModelsForm = memo(() => {
const { isLoading, data } = useGetStarterModelsQuery();
return (
@@ -13,4 +14,6 @@ export const StarterModelsForm = () => {
{data && }
);
-};
+});
+
+StarterModelsForm.displayName = 'StarterModelsForm';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx
index ccaa29d5e25..e593ee5fc3c 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsResults.tsx
@@ -1,7 +1,7 @@
import { Flex, IconButton, Input, InputGroup, InputRightElement } from '@invoke-ai/ui-library';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import type { ChangeEventHandler } from 'react';
-import { useCallback, useMemo, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PiXBold } from 'react-icons/pi';
import type { GetStarterModelsResponse } from 'services/api/endpoints/models';
@@ -12,16 +12,23 @@ type StarterModelsResultsProps = {
results: NonNullable;
};
-export const StarterModelsResults = ({ results }: StarterModelsResultsProps) => {
+export const StarterModelsResults = memo(({ results }: StarterModelsResultsProps) => {
const { t } = useTranslation();
const [searchTerm, setSearchTerm] = useState('');
const filteredResults = useMemo(() => {
return results.filter((result) => {
const trimmedSearchTerm = searchTerm.trim().toLowerCase();
- const matchStrings = [result.name.toLowerCase(), result.type.toLowerCase(), result.description.toLowerCase()];
+ const matchStrings = [
+ result.name.toLowerCase(),
+ result.type.toLowerCase().replaceAll('_', ' '),
+ result.description.toLowerCase(),
+ ];
if (result.type === 'spandrel_image_to_image') {
matchStrings.push('upscale');
+ matchStrings.push('post-processing');
+ matchStrings.push('postprocessing');
+ matchStrings.push('post processing');
}
return matchStrings.some((matchString) => matchString.includes(trimmedSearchTerm));
});
@@ -72,4 +79,6 @@ export const StarterModelsResults = ({ results }: StarterModelsResultsProps) =>
);
-};
+});
+
+StarterModelsResults.displayName = 'StarterModelsResults';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx
index b5110722d5c..90f3a578da7 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/InstallModels.tsx
@@ -2,7 +2,7 @@ import { Box, Flex, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from '@in
import { useStore } from '@nanostores/react';
import { StarterModelsForm } from 'features/modelManagerV2/subpanels/AddModelPanel/StarterModels/StarterModelsForm';
import { atom } from 'nanostores';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { HuggingFaceForm } from './AddModelPanel/HuggingFaceFolder/HuggingFaceForm';
@@ -12,7 +12,7 @@ import { ScanModelsForm } from './AddModelPanel/ScanFolder/ScanFolderForm';
export const $installModelsTab = atom(0);
-export const InstallModels = () => {
+export const InstallModels = memo(() => {
const { t } = useTranslation();
const index = useStore($installModelsTab);
const onChange = useCallback((index: number) => {
@@ -49,4 +49,6 @@ export const InstallModels = () => {
);
-};
+});
+
+InstallModels.displayName = 'InstallModels';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManager.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManager.tsx
index dbe02392db5..a07cb8c10b1 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManager.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManager.tsx
@@ -1,14 +1,14 @@
import { Button, Flex, Heading } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import { setSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiPlusBold } from 'react-icons/pi';
import ModelList from './ModelManagerPanel/ModelList';
import { ModelListNavigation } from './ModelManagerPanel/ModelListNavigation';
-export const ModelManager = () => {
+export const ModelManager = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const handleClickAddModel = useCallback(() => {
@@ -29,4 +29,6 @@ export const ModelManager = () => {
);
-};
+});
+
+ModelManager.displayName = 'ModelManager';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx
index b82917221ef..755a6e21fb2 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelList.tsx
@@ -21,7 +21,8 @@ import { FetchingModelsLoader } from './FetchingModelsLoader';
import { ModelListWrapper } from './ModelListWrapper';
const ModelList = () => {
- const { searchTerm, filteredModelType } = useAppSelector((s) => s.modelmanagerV2);
+ const filteredModelType = useAppSelector((s) => s.modelmanagerV2.filteredModelType);
+ const searchTerm = useAppSelector((s) => s.modelmanagerV2.searchTerm);
const { t } = useTranslation();
const [mainModels, { isLoading: isLoadingMainModels }] = useMainModels();
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListItem.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListItem.tsx
index a4a6d5c8335..8bfcbd73518 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListItem.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListItem.tsx
@@ -1,7 +1,8 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { ConfirmationAlertDialog, Flex, IconButton, Spacer, Text, useDisclosure } from '@invoke-ai/ui-library';
+import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { setSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
+import { selectModelManagerV2Slice, setSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
import ModelBaseBadge from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelBaseBadge';
import ModelFormatBadge from 'features/modelManagerV2/subpanels/ModelManagerPanel/ModelFormatBadge';
import { toast } from 'features/toast/toast';
@@ -23,15 +24,21 @@ const sx: SystemStyleObject = {
"&[aria-selected='true']": { bg: 'base.700' },
};
-const ModelListItem = (props: ModelListItemProps) => {
+const ModelListItem = ({ model }: ModelListItemProps) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
- const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
+ const selectIsSelected = useMemo(
+ () =>
+ createSelector(
+ selectModelManagerV2Slice,
+ (modelManagerV2Slice) => modelManagerV2Slice.selectedModelKey === model.key
+ ),
+ [model.key]
+ );
+ const isSelected = useAppSelector(selectIsSelected);
const [deleteModel] = useDeleteModelsMutation();
const { isOpen, onOpen, onClose } = useDisclosure();
- const { model } = props;
-
const handleSelectModel = useCallback(() => {
dispatch(setSelectedModelKey(model.key));
}, [model.key, dispatch]);
@@ -43,11 +50,6 @@ const ModelListItem = (props: ModelListItemProps) => {
},
[onOpen]
);
-
- const isSelected = useMemo(() => {
- return selectedModelKey === model.key;
- }, [selectedModelKey, model.key]);
-
const handleModelDelete = useCallback(() => {
deleteModel({ key: model.key })
.unwrap()
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListNavigation.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListNavigation.tsx
index b256e8a70fd..766b4f27b88 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListNavigation.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListNavigation.tsx
@@ -3,12 +3,12 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setSearchTerm } from 'features/modelManagerV2/store/modelManagerV2Slice';
import { t } from 'i18next';
import type { ChangeEventHandler } from 'react';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { PiXBold } from 'react-icons/pi';
import { ModelTypeFilter } from './ModelTypeFilter';
-export const ModelListNavigation = () => {
+export const ModelListNavigation = memo(() => {
const dispatch = useAppDispatch();
const searchTerm = useAppSelector((s) => s.modelmanagerV2.searchTerm);
@@ -49,4 +49,6 @@ export const ModelListNavigation = () => {
);
-};
+});
+
+ModelListNavigation.displayName = 'ModelListNavigation';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListWrapper.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListWrapper.tsx
index e52bd12f259..bde79e45540 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListWrapper.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelListWrapper.tsx
@@ -1,4 +1,5 @@
import { StickyScrollable } from 'features/system/components/StickyScrollable';
+import { memo } from 'react';
import type { AnyModelConfig } from 'services/api/types';
import ModelListItem from './ModelListItem';
@@ -8,7 +9,7 @@ type ModelListWrapperProps = {
modelList: AnyModelConfig[];
};
-export const ModelListWrapper = (props: ModelListWrapperProps) => {
+export const ModelListWrapper = memo((props: ModelListWrapperProps) => {
const { title, modelList } = props;
return (
@@ -17,4 +18,6 @@ export const ModelListWrapper = (props: ModelListWrapperProps) => {
))}
);
-};
+});
+
+ModelListWrapper.displayName = 'ModelListWrapper';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx
index 1a2444870b5..9db3334e89e 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelManagerPanel/ModelTypeFilter.tsx
@@ -2,12 +2,12 @@ import { Button, Menu, MenuButton, MenuItem, MenuList } from '@invoke-ai/ui-libr
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import type { FilterableModelType } from 'features/modelManagerV2/store/modelManagerV2Slice';
import { setFilteredModelType } from 'features/modelManagerV2/store/modelManagerV2Slice';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiFunnelBold } from 'react-icons/pi';
import { objectKeys } from 'tsafe';
-export const ModelTypeFilter = () => {
+export const ModelTypeFilter = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const MODEL_TYPE_LABELS: Record = useMemo(
@@ -57,4 +57,6 @@ export const ModelTypeFilter = () => {
);
-};
+});
+
+ModelTypeFilter.displayName = 'ModelTypeFilter';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPane.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPane.tsx
index 5f1a70e0fe9..eb85434d363 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPane.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPane.tsx
@@ -1,14 +1,17 @@
import { Box } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
+import { memo } from 'react';
import { InstallModels } from './InstallModels';
import { Model } from './ModelPanel/Model';
-export const ModelPane = () => {
+export const ModelPane = memo(() => {
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
return (
{selectedModelKey ? : }
);
-};
+});
+
+ModelPane.displayName = 'ModelPane';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx
index 9a84fbc7265..25005e76c95 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings.tsx
@@ -1,26 +1,28 @@
-import { Button, Flex, Heading, SimpleGrid, Text } from '@invoke-ai/ui-library';
-import { useAppSelector } from 'app/store/storeHooks';
+import { Button, Flex, Heading, SimpleGrid } from '@invoke-ai/ui-library';
import { useControlNetOrT2IAdapterDefaultSettings } from 'features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings';
import { DefaultPreprocessor } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor';
import type { FormField } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings';
import { toast } from 'features/toast/toast';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { PiCheckBold } from 'react-icons/pi';
import { useUpdateModelMutation } from 'services/api/endpoints/models';
+import type { ControlNetModelConfig, T2IAdapterModelConfig } from 'services/api/types';
export type ControlNetOrT2IAdapterDefaultSettingsFormData = {
preprocessor: FormField;
};
-export const ControlNetOrT2IAdapterDefaultSettings = () => {
- const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
+type Props = {
+ modelConfig: ControlNetModelConfig | T2IAdapterModelConfig;
+};
+
+export const ControlNetOrT2IAdapterDefaultSettings = memo(({ modelConfig }: Props) => {
const { t } = useTranslation();
- const { defaultSettingsDefaults, isLoading: isLoadingDefaultSettings } =
- useControlNetOrT2IAdapterDefaultSettings(selectedModelKey);
+ const defaultSettingsDefaults = useControlNetOrT2IAdapterDefaultSettings(modelConfig);
const [updateModel, { isLoading: isLoadingUpdateModel }] = useUpdateModelMutation();
@@ -30,16 +32,12 @@ export const ControlNetOrT2IAdapterDefaultSettings = () => {
const onSubmit = useCallback>(
(data) => {
- if (!selectedModelKey) {
- return;
- }
-
const body = {
preprocessor: data.preprocessor.isEnabled ? data.preprocessor.value : null,
};
updateModel({
- key: selectedModelKey,
+ key: modelConfig.key,
body: { default_settings: body },
})
.unwrap()
@@ -61,13 +59,9 @@ export const ControlNetOrT2IAdapterDefaultSettings = () => {
}
});
},
- [selectedModelKey, reset, updateModel, t]
+ [updateModel, modelConfig.key, t, reset]
);
- if (isLoadingDefaultSettings) {
- return {t('common.loading')};
- }
-
return (
<>
@@ -89,4 +83,6 @@ export const ControlNetOrT2IAdapterDefaultSettings = () => {
>
);
-};
+});
+
+ControlNetOrT2IAdapterDefaultSettings.displayName = 'ControlNetOrT2IAdapterDefaultSettings';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx
index b2284336bf4..e446992779f 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor.tsx
@@ -4,7 +4,7 @@ import { InformationalPopover } from 'common/components/InformationalPopover/Inf
import type { ControlNetOrT2IAdapterDefaultSettingsFormData } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings';
import type { FormField } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -28,7 +28,7 @@ const OPTIONS = [
type DefaultSchedulerType = ControlNetOrT2IAdapterDefaultSettingsFormData['preprocessor'];
-export function DefaultPreprocessor(props: UseControllerProps) {
+export const DefaultPreprocessor = memo((props: UseControllerProps) => {
const { t } = useTranslation();
const { field } = useController(props);
@@ -63,4 +63,6 @@ export function DefaultPreprocessor(props: UseControllerProps
);
-}
+});
+
+DefaultPreprocessor.displayName = 'DefaultPreprocessor';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx
index d16ce1460c2..cde1b8d7f33 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgRescaleMultiplier.tsx
@@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -11,7 +11,7 @@ import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSetting
type DefaultCfgRescaleMultiplierType = MainModelDefaultSettingsFormData['cfgRescaleMultiplier'];
-export function DefaultCfgRescaleMultiplier(props: UseControllerProps) {
+export const DefaultCfgRescaleMultiplier = memo((props: UseControllerProps) => {
const { field } = useController(props);
const sliderMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMin);
@@ -74,4 +74,6 @@ export function DefaultCfgRescaleMultiplier(props: UseControllerProps
);
-}
+});
+
+DefaultCfgRescaleMultiplier.displayName = 'DefaultCfgRescaleMultiplier';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx
index 293261bc352..85d11daba88 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultCfgScale.tsx
@@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -11,7 +11,7 @@ import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSetting
type DefaultCfgType = MainModelDefaultSettingsFormData['cfgScale'];
-export function DefaultCfgScale(props: UseControllerProps) {
+export const DefaultCfgScale = memo((props: UseControllerProps) => {
const { field } = useController(props);
const sliderMin = useAppSelector((s) => s.config.sd.guidance.sliderMin);
@@ -74,4 +74,6 @@ export function DefaultCfgScale(props: UseControllerProps
);
-}
+});
+
+DefaultCfgScale.displayName = 'DefaultCfgScale';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultHeight.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultHeight.tsx
index a19ae26ebe0..8dc00e6239f 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultHeight.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultHeight.tsx
@@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -16,7 +16,7 @@ type Props = {
optimalDimension: number;
};
-export function DefaultHeight({ control, optimalDimension }: Props) {
+export const DefaultHeight = memo(({ control, optimalDimension }: Props) => {
const { field } = useController({ control, name: 'height' });
const sliderMin = useAppSelector((s) => s.config.sd.height.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
@@ -78,4 +78,6 @@ export function DefaultHeight({ control, optimalDimension }: Props) {
);
-}
+});
+
+DefaultHeight.displayName = 'DefaultHeight';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx
index 4397e35a51e..1ad8177cf61 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultScheduler.tsx
@@ -4,7 +4,7 @@ import { InformationalPopover } from 'common/components/InformationalPopover/Inf
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants';
import { isParameterScheduler } from 'features/parameters/types/parameterSchemas';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -13,7 +13,7 @@ import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSetting
type DefaultSchedulerType = MainModelDefaultSettingsFormData['scheduler'];
-export function DefaultScheduler(props: UseControllerProps) {
+export const DefaultScheduler = memo((props: UseControllerProps) => {
const { t } = useTranslation();
const { field } = useController(props);
@@ -51,4 +51,6 @@ export function DefaultScheduler(props: UseControllerProps
);
-}
+});
+
+DefaultScheduler.displayName = 'DefaultScheduler';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx
index 9c1912a0f78..5bfb268d08d 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultSteps.tsx
@@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -11,7 +11,7 @@ import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSetting
type DefaultSteps = MainModelDefaultSettingsFormData['steps'];
-export function DefaultSteps(props: UseControllerProps) {
+export const DefaultSteps = memo((props: UseControllerProps) => {
const { field } = useController(props);
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
@@ -74,4 +74,6 @@ export function DefaultSteps(props: UseControllerProps
);
-}
+});
+
+DefaultSteps.displayName = 'DefaultSteps';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx
index 5517d7b3478..cf1578d9f4e 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVae.tsx
@@ -4,7 +4,7 @@ import { skipToken } from '@reduxjs/toolkit/query';
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -15,7 +15,7 @@ import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSetting
type DefaultVaeType = MainModelDefaultSettingsFormData['vae'];
-export function DefaultVae(props: UseControllerProps) {
+export const DefaultVae = memo((props: UseControllerProps) => {
const { t } = useTranslation();
const { field } = useController(props);
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
@@ -64,4 +64,6 @@ export function DefaultVae(props: UseControllerProps
);
-}
+});
+
+DefaultVae.displayName = 'DefaultVae';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx
index d33cf4e08da..b725d60968d 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultVaePrecision.tsx
@@ -3,7 +3,7 @@ import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { isParameterPrecision } from 'features/parameters/types/parameterSchemas';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -17,7 +17,7 @@ const options = [
type DefaultVaePrecisionType = MainModelDefaultSettingsFormData['vaePrecision'];
-export function DefaultVaePrecision(props: UseControllerProps) {
+export const DefaultVaePrecision = memo((props: UseControllerProps) => {
const { t } = useTranslation();
const { field } = useController(props);
@@ -52,4 +52,6 @@ export function DefaultVaePrecision(props: UseControllerProps
);
-}
+});
+
+DefaultVaePrecision.displayName = 'DefaultVaePrecision';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultWidth.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultWidth.tsx
index 851dba1edeb..8986b9820b5 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultWidth.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultWidth.tsx
@@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
-import { useCallback, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@@ -16,7 +16,7 @@ type Props = {
optimalDimension: number;
};
-export function DefaultWidth({ control, optimalDimension }: Props) {
+export const DefaultWidth = memo(({ control, optimalDimension }: Props) => {
const { field } = useController({ control, name: 'width' });
const sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);
@@ -78,4 +78,6 @@ export function DefaultWidth({ control, optimalDimension }: Props) {
);
-}
+});
+
+DefaultWidth.displayName = 'DefaultWidth';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx
index 233fc7bc6bd..095b452dfcb 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings.tsx
@@ -1,16 +1,18 @@
-import { Button, Flex, Heading, SimpleGrid, Text } from '@invoke-ai/ui-library';
+import { Button, Flex, Heading, SimpleGrid } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { useMainModelDefaultSettings } from 'features/modelManagerV2/hooks/useMainModelDefaultSettings';
import { DefaultHeight } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultHeight';
import { DefaultWidth } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultWidth';
import type { ParameterScheduler } from 'features/parameters/types/parameterSchemas';
+import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
import { toast } from 'features/toast/toast';
-import { useCallback } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { PiCheckBold } from 'react-icons/pi';
import { useUpdateModelMutation } from 'services/api/endpoints/models';
+import type { MainModelConfig } from 'services/api/types';
import { DefaultCfgRescaleMultiplier } from './DefaultCfgRescaleMultiplier';
import { DefaultCfgScale } from './DefaultCfgScale';
@@ -35,16 +37,16 @@ export type MainModelDefaultSettingsFormData = {
height: FormField;
};
-export const MainModelDefaultSettings = () => {
+type Props = {
+ modelConfig: MainModelConfig;
+};
+
+export const MainModelDefaultSettings = memo(({ modelConfig }: Props) => {
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
const { t } = useTranslation();
- const {
- defaultSettingsDefaults,
- isLoading: isLoadingDefaultSettings,
- optimalDimension,
- } = useMainModelDefaultSettings(selectedModelKey);
-
+ const defaultSettingsDefaults = useMainModelDefaultSettings(modelConfig);
+ const optimalDimension = useMemo(() => getOptimalDimension(modelConfig), [modelConfig]);
const [updateModel, { isLoading: isLoadingUpdateModel }] = useUpdateModelMutation();
const { handleSubmit, control, formState, reset } = useForm({
@@ -94,10 +96,6 @@ export const MainModelDefaultSettings = () => {
[selectedModelKey, reset, updateModel, t]
);
- if (isLoadingDefaultSettings) {
- return {t('common.loading')};
- }
-
return (
<>
@@ -126,4 +124,6 @@ export const MainModelDefaultSettings = () => {
>
);
-};
+});
+
+MainModelDefaultSettings.displayName = 'MainModelDefaultSettings';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Model.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Model.tsx
index fa7ca4c394d..2934ac916ad 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Model.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/Model.tsx
@@ -1,120 +1,47 @@
-import { Button, Flex, Heading, Spacer, Text } from '@invoke-ai/ui-library';
-import { skipToken } from '@reduxjs/toolkit/query';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
-import { ModelConvertButton } from 'features/modelManagerV2/subpanels/ModelPanel/ModelConvertButton';
-import { ModelEditButton } from 'features/modelManagerV2/subpanels/ModelPanel/ModelEditButton';
-import { toast } from 'features/toast/toast';
-import { useCallback } from 'react';
-import type { SubmitHandler } from 'react-hook-form';
-import { useForm } from 'react-hook-form';
+import { useAppSelector } from 'app/store/storeHooks';
+import { IAINoContentFallback, IAINoContentFallbackWithSpinner } from 'common/components/IAIImageFallback';
+import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
-import { PiCheckBold, PiXBold } from 'react-icons/pi';
-import type { UpdateModelArg } from 'services/api/endpoints/models';
-import { useGetModelConfigQuery, useUpdateModelMutation } from 'services/api/endpoints/models';
+import { PiExclamationMarkBold } from 'react-icons/pi';
+import { modelConfigsAdapterSelectors, useGetModelConfigsQuery } from 'services/api/endpoints/models';
-import ModelImageUpload from './Fields/ModelImageUpload';
import { ModelEdit } from './ModelEdit';
import { ModelView } from './ModelView';
-export const Model = () => {
+export const Model = memo(() => {
const { t } = useTranslation();
const selectedModelMode = useAppSelector((s) => s.modelmanagerV2.selectedModelMode);
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
- const { data, isLoading } = useGetModelConfigQuery(selectedModelKey ?? skipToken);
- const [updateModel, { isLoading: isSubmitting }] = useUpdateModelMutation();
- const dispatch = useAppDispatch();
-
- const form = useForm({
- defaultValues: data,
- mode: 'onChange',
- });
-
- const onSubmit = useCallback>(
- (values) => {
- if (!data?.key) {
- return;
- }
-
- const responseBody: UpdateModelArg = {
- key: data.key,
- body: values,
- };
-
- updateModel(responseBody)
- .unwrap()
- .then((payload) => {
- form.reset(payload, { keepDefaultValues: true });
- dispatch(setSelectedModelMode('view'));
- toast({
- id: 'MODEL_UPDATED',
- title: t('modelManager.modelUpdated'),
- status: 'success',
- });
- })
- .catch((_) => {
- form.reset();
- toast({
- id: 'MODEL_UPDATE_FAILED',
- title: t('modelManager.modelUpdateFailed'),
- status: 'error',
- });
- });
- },
- [dispatch, data?.key, form, t, updateModel]
- );
-
- const handleClickCancel = useCallback(() => {
- dispatch(setSelectedModelMode('view'));
- }, [dispatch]);
+ const { data: modelConfigs, isLoading } = useGetModelConfigsQuery();
+ const modelConfig = useMemo(() => {
+ if (!modelConfigs) {
+ return null;
+ }
+ if (selectedModelKey === null) {
+ return null;
+ }
+ const modelConfig = modelConfigsAdapterSelectors.selectById(modelConfigs, selectedModelKey);
+
+ if (!modelConfig) {
+ return null;
+ }
+
+ return modelConfig;
+ }, [modelConfigs, selectedModelKey]);
if (isLoading) {
- return {t('common.loading')};
+ return ;
+ }
+
+ if (!modelConfig) {
+ return ;
}
- if (!data) {
- return {t('common.somethingWentWrong')};
+ if (selectedModelMode === 'view') {
+ return ;
}
- return (
-
-
-
-
-
-
- {data.name}
-
-
- {selectedModelMode === 'view' && }
- {selectedModelMode === 'view' && }
- {selectedModelMode === 'edit' && (
- }>
- {t('common.cancel')}
-
- )}
- {selectedModelMode === 'edit' && (
- }
- onClick={form.handleSubmit(onSubmit)}
- isLoading={isSubmitting}
- isDisabled={Boolean(Object.keys(form.formState.errors).length)}
- >
- {t('common.save')}
-
- )}
-
- {data.source && (
-
- {t('modelManager.source')}: {data?.source}
-
- )}
- {data.description}
-
-
- {selectedModelMode === 'view' ? : }
-
- );
-};
+ return ;
+});
+
+Model.displayName = 'Model';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelAttrView.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelAttrView.tsx
index ebdedffebf5..106e0a1df0f 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelAttrView.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelAttrView.tsx
@@ -1,11 +1,12 @@
import { FormControl, FormLabel, Text } from '@invoke-ai/ui-library';
+import { memo } from 'react';
interface Props {
label: string;
value: string | null | undefined;
}
-export const ModelAttrView = ({ label, value }: Props) => {
+export const ModelAttrView = memo(({ label, value }: Props) => {
return (
{label}
@@ -14,4 +15,6 @@ export const ModelAttrView = ({ label, value }: Props) => {
);
-};
+});
+
+ModelAttrView.displayName = 'ModelAttrView';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelConvertButton.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelConvertButton.tsx
index 40ffca76b4d..70775842f80 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelConvertButton.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelConvertButton.tsx
@@ -8,52 +8,46 @@ import {
UnorderedList,
useDisclosure,
} from '@invoke-ai/ui-library';
-import { skipToken } from '@reduxjs/toolkit/query';
import { toast } from 'features/toast/toast';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useConvertModelMutation, useGetModelConfigQuery } from 'services/api/endpoints/models';
+import { useConvertModelMutation } from 'services/api/endpoints/models';
+import type { CheckpointModelConfig } from 'services/api/types';
interface ModelConvertProps {
- modelKey: string | null;
+ modelConfig: CheckpointModelConfig;
}
-export const ModelConvertButton = (props: ModelConvertProps) => {
- const { modelKey } = props;
+export const ModelConvertButton = memo(({ modelConfig }: ModelConvertProps) => {
const { t } = useTranslation();
- const { data } = useGetModelConfigQuery(modelKey ?? skipToken);
const [convertModel, { isLoading }] = useConvertModelMutation();
const { isOpen, onOpen, onClose } = useDisclosure();
const modelConvertHandler = useCallback(() => {
- if (!data || isLoading) {
+ if (!modelConfig || isLoading) {
return;
}
- const toastId = `CONVERTING_MODEL_${data.key}`;
+ const toastId = `CONVERTING_MODEL_${modelConfig.key}`;
toast({
id: toastId,
- title: `${t('modelManager.convertingModelBegin')}: ${data?.name}`,
+ title: `${t('modelManager.convertingModelBegin')}: ${modelConfig.name}`,
status: 'info',
});
- convertModel(data?.key)
+ convertModel(modelConfig.key)
.unwrap()
.then(() => {
- toast({ id: toastId, title: `${t('modelManager.modelConverted')}: ${data?.name}`, status: 'success' });
+ toast({ id: toastId, title: `${t('modelManager.modelConverted')}: ${modelConfig.name}`, status: 'success' });
})
.catch(() => {
toast({
id: toastId,
- title: `${t('modelManager.modelConversionFailed')}: ${data?.name}`,
+ title: `${t('modelManager.modelConversionFailed')}: ${modelConfig.name}`,
status: 'error',
});
});
- }, [data, isLoading, t, convertModel]);
-
- if (data?.format !== 'checkpoint') {
- return;
- }
+ }, [modelConfig, isLoading, t, convertModel]);
return (
<>
@@ -68,7 +62,7 @@ export const ModelConvertButton = (props: ModelConvertProps) => {
🧨 {t('modelManager.convert')}
{
>
);
-};
+});
+
+ModelConvertButton.displayName = 'ModelConvertButton';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEdit.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEdit.tsx
index 8bc775c8724..da57c302381 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEdit.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEdit.tsx
@@ -1,4 +1,5 @@
import {
+ Button,
Checkbox,
Flex,
FormControl,
@@ -7,96 +8,154 @@ import {
Heading,
Input,
SimpleGrid,
- Text,
Textarea,
} from '@invoke-ai/ui-library';
-import { skipToken } from '@reduxjs/toolkit/query';
-import { useAppSelector } from 'app/store/storeHooks';
-import type { SubmitHandler, UseFormReturn } from 'react-hook-form';
+import { useAppDispatch } from 'app/store/storeHooks';
+import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
+import { ModelHeader } from 'features/modelManagerV2/subpanels/ModelPanel/ModelHeader';
+import { toast } from 'features/toast/toast';
+import { memo, useCallback } from 'react';
+import { type SubmitHandler, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
-import type { UpdateModelArg } from 'services/api/endpoints/models';
-import { useGetModelConfigQuery } from 'services/api/endpoints/models';
+import { PiCheckBold, PiXBold } from 'react-icons/pi';
+import { type UpdateModelArg, useUpdateModelMutation } from 'services/api/endpoints/models';
+import type { AnyModelConfig } from 'services/api/types';
import BaseModelSelect from './Fields/BaseModelSelect';
import ModelVariantSelect from './Fields/ModelVariantSelect';
import PredictionTypeSelect from './Fields/PredictionTypeSelect';
type Props = {
- form: UseFormReturn;
- onSubmit: SubmitHandler;
+ modelConfig: AnyModelConfig;
};
const stringFieldOptions = {
validate: (value?: string | null) => (value && value.trim().length > 3) || 'Must be at least 3 characters',
};
-export const ModelEdit = ({ form }: Props) => {
- const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
- const { data, isLoading } = useGetModelConfigQuery(selectedModelKey ?? skipToken);
+export const ModelEdit = memo(({ modelConfig }: Props) => {
const { t } = useTranslation();
+ const [updateModel, { isLoading: isSubmitting }] = useUpdateModelMutation();
+ const dispatch = useAppDispatch();
- if (isLoading) {
- return {t('common.loading')};
- }
+ const form = useForm({
+ defaultValues: modelConfig,
+ mode: 'onChange',
+ });
- if (!data) {
- return {t('common.somethingWentWrong')};
- }
+ const onSubmit = useCallback>(
+ (values) => {
+ const responseBody: UpdateModelArg = {
+ key: modelConfig.key,
+ body: values,
+ };
- return (
-
-
+
);
-};
+});
+
+ModelEdit.displayName = 'ModelEdit';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEditButton.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEditButton.tsx
index 1d0f506282e..d81c4431484 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEditButton.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelEditButton.tsx
@@ -1,11 +1,11 @@
import { Button } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
-import { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { IoPencil } from 'react-icons/io5';
-export const ModelEditButton = () => {
+export const ModelEditButton = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
@@ -18,4 +18,6 @@ export const ModelEditButton = () => {
{t('modelManager.edit')}
);
-};
+});
+
+ModelEditButton.displayName = 'ModelEditButton';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelHeader.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelHeader.tsx
new file mode 100644
index 00000000000..a30f96b7fc6
--- /dev/null
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelHeader.tsx
@@ -0,0 +1,36 @@
+import { Flex, Heading, Spacer, Text } from '@invoke-ai/ui-library';
+import ModelImageUpload from 'features/modelManagerV2/subpanels/ModelPanel/Fields/ModelImageUpload';
+import type { PropsWithChildren } from 'react';
+import { memo } from 'react';
+import { useTranslation } from 'react-i18next';
+import type { AnyModelConfig } from 'services/api/types';
+
+type Props = PropsWithChildren<{
+ modelConfig: AnyModelConfig;
+}>;
+
+export const ModelHeader = memo(({ modelConfig, children }: Props) => {
+ const { t } = useTranslation();
+ return (
+
+
+
+
+
+ {modelConfig.name}
+
+
+ {children}
+
+ {modelConfig.source && (
+
+ {t('modelManager.source')}: {modelConfig.source}
+
+ )}
+ {modelConfig.description}
+
+
+ );
+});
+
+ModelHeader.displayName = 'ModelHeader';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx
index 83ae94c9bb5..f02a84efb36 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/ModelView.tsx
@@ -1,55 +1,67 @@
-import { Box, Flex, SimpleGrid, Text } from '@invoke-ai/ui-library';
-import { skipToken } from '@reduxjs/toolkit/query';
-import { useAppSelector } from 'app/store/storeHooks';
+import { Box, Flex, SimpleGrid } from '@invoke-ai/ui-library';
import { ControlNetOrT2IAdapterDefaultSettings } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings';
+import { ModelConvertButton } from 'features/modelManagerV2/subpanels/ModelPanel/ModelConvertButton';
+import { ModelEditButton } from 'features/modelManagerV2/subpanels/ModelPanel/ModelEditButton';
+import { ModelHeader } from 'features/modelManagerV2/subpanels/ModelPanel/ModelHeader';
import { TriggerPhrases } from 'features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases';
+import { memo } from 'react';
import { useTranslation } from 'react-i18next';
-import { useGetModelConfigQuery } from 'services/api/endpoints/models';
+import type { AnyModelConfig } from 'services/api/types';
import { MainModelDefaultSettings } from './MainModelDefaultSettings/MainModelDefaultSettings';
import { ModelAttrView } from './ModelAttrView';
-export const ModelView = () => {
- const { t } = useTranslation();
- const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
- const { data, isLoading } = useGetModelConfigQuery(selectedModelKey ?? skipToken);
-
- if (isLoading) {
- return {t('common.loading')};
- }
+type Props = {
+ modelConfig: AnyModelConfig;
+};
- if (!data) {
- return {t('common.somethingWentWrong')};
- }
+export const ModelView = memo(({ modelConfig }: Props) => {
+ const { t } = useTranslation();
return (
-
-
-
-
-
-
-
- {data.type === 'main' && }
- {data.type === 'main' && data.format === 'diffusers' && data.repo_variant && (
-
+
+
+ {modelConfig.format === 'checkpoint' && modelConfig.type === 'main' && (
+
+ )}
+
+
+
+
+
+
+
+
+
+ {modelConfig.type === 'main' && (
+
+ )}
+ {modelConfig.type === 'main' && modelConfig.format === 'diffusers' && modelConfig.repo_variant && (
+
+ )}
+ {modelConfig.type === 'main' && modelConfig.format === 'checkpoint' && (
+ <>
+
+
+
+ >
+ )}
+ {modelConfig.type === 'ip_adapter' && modelConfig.format === 'invokeai' && (
+
+ )}
+
+
+
+ {modelConfig.type === 'main' && modelConfig.base !== 'sdxl-refiner' && (
+
)}
- {data.type === 'main' && data.format === 'checkpoint' && (
- <>
-
-
-
- >
+ {(modelConfig.type === 'controlnet' || modelConfig.type === 't2i_adapter') && (
+
)}
- {data.type === 'ip_adapter' && data.format === 'invokeai' && (
-
- )}
-
-
-
- {data.type === 'main' && data.base !== 'sdxl-refiner' && }
- {(data.type === 'controlnet' || data.type === 't2i_adapter') && }
- {(data.type === 'main' || data.type === 'lora') && }
-
+ {(modelConfig.type === 'main' || modelConfig.type === 'lora') && }
+
+
);
-};
+});
+
+ModelView.displayName = 'ModelView';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/SettingToggle.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/SettingToggle.tsx
index 15e4693c4f0..45aeab22986 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/SettingToggle.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/SettingToggle.tsx
@@ -1,4 +1,4 @@
-import { Switch } from '@invoke-ai/ui-library';
+import { Switch, typedMemo } from '@invoke-ai/ui-library';
import type { ChangeEvent } from 'react';
import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
@@ -6,7 +6,7 @@ import { useController } from 'react-hook-form';
import type { FormField } from './MainModelDefaultSettings/MainModelDefaultSettings';
-export function SettingToggle>>(props: UseControllerProps) {
+export const SettingToggle = typedMemo(>>(props: UseControllerProps) => {
const { field } = useController(props);
const value = useMemo(() => {
@@ -25,4 +25,6 @@ export function SettingToggle>>(props:
);
return ;
-}
+});
+
+SettingToggle.displayName = 'SettingToggle';
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx
index 9352d7996c2..3f5133dedfb 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases.tsx
@@ -9,19 +9,19 @@ import {
TagCloseButton,
TagLabel,
} from '@invoke-ai/ui-library';
-import { skipToken } from '@reduxjs/toolkit/query';
-import { useAppSelector } from 'app/store/storeHooks';
import type { ChangeEvent } from 'react';
-import { useCallback, useMemo, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PiPlusBold } from 'react-icons/pi';
-import { useGetModelConfigQuery, useUpdateModelMutation } from 'services/api/endpoints/models';
-import { isLoRAModelConfig, isNonRefinerMainModelConfig } from 'services/api/types';
+import { useUpdateModelMutation } from 'services/api/endpoints/models';
+import type { LoRAModelConfig, MainModelConfig } from 'services/api/types';
-export const TriggerPhrases = () => {
+type Props = {
+ modelConfig: MainModelConfig | LoRAModelConfig;
+};
+
+export const TriggerPhrases = memo(({ modelConfig }: Props) => {
const { t } = useTranslation();
- const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
- const { currentData: modelConfig } = useGetModelConfigQuery(selectedModelKey ?? skipToken);
const [phrase, setPhrase] = useState('');
const [updateModel, { isLoading }] = useUpdateModelMutation();
@@ -31,9 +31,6 @@ export const TriggerPhrases = () => {
}, []);
const triggerPhrases = useMemo(() => {
- if (!modelConfig || (!isNonRefinerMainModelConfig(modelConfig) && !isLoRAModelConfig(modelConfig))) {
- return [];
- }
return modelConfig?.trigger_phrases || [];
}, [modelConfig]);
@@ -48,10 +45,6 @@ export const TriggerPhrases = () => {
}, [phrase, triggerPhrases]);
const addTriggerPhrase = useCallback(async () => {
- if (!selectedModelKey) {
- return;
- }
-
if (!phrase.length || triggerPhrases.includes(phrase)) {
return;
}
@@ -59,22 +52,18 @@ export const TriggerPhrases = () => {
setPhrase('');
await updateModel({
- key: selectedModelKey,
+ key: modelConfig.key,
body: { trigger_phrases: [...triggerPhrases, phrase] },
}).unwrap();
- }, [updateModel, selectedModelKey, phrase, triggerPhrases]);
+ }, [phrase, triggerPhrases, updateModel, modelConfig.key]);
const removeTriggerPhrase = useCallback(
async (phraseToRemove: string) => {
- if (!selectedModelKey) {
- return;
- }
-
const filteredPhrases = triggerPhrases.filter((p) => p !== phraseToRemove);
- await updateModel({ key: selectedModelKey, body: { trigger_phrases: filteredPhrases } }).unwrap();
+ await updateModel({ key: modelConfig.key, body: { trigger_phrases: filteredPhrases } }).unwrap();
},
- [updateModel, selectedModelKey, triggerPhrases]
+ [triggerPhrases, updateModel, modelConfig]
);
const onTriggerPhraseAddFormSubmit = useCallback(
@@ -103,7 +92,9 @@ export const TriggerPhrases = () => {
{t('common.add')}
- {!!errors.length && errors.map((error) => {error})}
+ {errors.map((error) => (
+ {error}
+ ))}
@@ -118,4 +109,6 @@ export const TriggerPhrases = () => {
);
-};
+});
+
+TriggerPhrases.displayName = 'TriggerPhrases';
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useCopyPaste.ts b/invokeai/frontend/web/src/features/nodes/hooks/useCopyPaste.ts
index 32db806cde0..2a2bfde904c 100644
--- a/invokeai/frontend/web/src/features/nodes/hooks/useCopyPaste.ts
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useCopyPaste.ts
@@ -59,17 +59,19 @@ const pasteSelection = (withEdgesToCopiedNodes?: boolean) => {
for (const edge of copiedEdges) {
if (edge.source === node.id) {
edge.source = id;
- edge.id = edge.id.replace(node.data.id, id);
- }
- if (edge.target === node.id) {
+ } else if (edge.target === node.id) {
edge.target = id;
- edge.id = edge.id.replace(node.data.id, id);
}
}
node.id = id;
node.data.id = id;
});
+ copiedEdges.forEach((edge) => {
+ // Copied edges need a fresh id too
+ edge.id = uuidv4();
+ });
+
const nodeChanges: NodeChange[] = [];
const edgeChanges: EdgeChange[] = [];
// Deselect existing nodes
diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocPostProcessingGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocPostProcessingGraph.ts
new file mode 100644
index 00000000000..7e943500cbb
--- /dev/null
+++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocPostProcessingGraph.ts
@@ -0,0 +1,40 @@
+import type { RootState } from 'app/store/store';
+import { fetchModelConfigWithTypeGuard } from 'features/metadata/util/modelFetchingHelpers';
+import type { GraphType } from 'features/nodes/util/graph/generation/Graph';
+import { Graph } from 'features/nodes/util/graph/generation/Graph';
+import { getBoardField } from 'features/nodes/util/graph/graphBuilderUtils';
+import type { ImageDTO } from 'services/api/types';
+import { isSpandrelImageToImageModelConfig } from 'services/api/types';
+import { assert } from 'tsafe';
+
+import { getModelMetadataField } from './canvas/metadata';
+import { SPANDREL } from './constants';
+
+type Arg = {
+ image: ImageDTO;
+ state: RootState;
+};
+
+export const buildAdHocPostProcessingGraph = async ({ image, state }: Arg): Promise => {
+ const { postProcessingModel } = state.upscale;
+
+ assert(postProcessingModel, 'No post-processing model found in state');
+
+ const g = new Graph('adhoc-post-processing-graph');
+ g.addNode({
+ id: SPANDREL,
+ type: 'spandrel_image_to_image',
+ image_to_image_model: postProcessingModel,
+ image,
+ board: getBoardField(state),
+ is_intermediate: false,
+ });
+
+ const modelConfig = await fetchModelConfigWithTypeGuard(postProcessingModel.key, isSpandrelImageToImageModelConfig);
+
+ g.upsertMetadata({
+ upscale_model: getModelMetadataField(modelConfig),
+ });
+
+ return g.getGraph();
+};
diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts
deleted file mode 100644
index 60343c5e893..00000000000
--- a/invokeai/frontend/web/src/features/nodes/util/graph/buildAdHocUpscaleGraph.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import type { RootState } from 'app/store/store';
-import { getBoardField } from 'features/nodes/util/graph/graphBuilderUtils';
-import type { Graph, Invocation, NonNullableGraph } from 'services/api/types';
-
-import { addCoreMetadataNode, upsertMetadata } from './canvas/metadata';
-import { ESRGAN } from './constants';
-
-type Arg = {
- image_name: string;
- state: RootState;
-};
-
-export const buildAdHocUpscaleGraph = ({ image_name, state }: Arg): Graph => {
- const { esrganModelName } = state.postprocessing;
-
- const realesrganNode: Invocation<'esrgan'> = {
- id: ESRGAN,
- type: 'esrgan',
- image: { image_name },
- model_name: esrganModelName,
- is_intermediate: false,
- board: getBoardField(state),
- };
-
- const graph: NonNullableGraph = {
- id: `adhoc-esrgan-graph`,
- nodes: {
- [ESRGAN]: realesrganNode,
- },
- edges: [],
- };
-
- addCoreMetadataNode(graph, {}, ESRGAN);
- upsertMetadata(graph, {
- esrgan_model: esrganModelName,
- });
-
- return graph;
-};
diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts
index 1516a3fae3b..551cc451132 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts
@@ -38,7 +38,7 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise
const upscaleNode = g.addNode({
id: SPANDREL,
- type: 'spandrel_image_to_image',
+ type: 'spandrel_image_to_image_autoscale',
image: upscaleInitialImage,
image_to_image_model: upscaleModel,
fit_to_multiple_of_8: true,
diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/constants.ts b/invokeai/frontend/web/src/features/nodes/util/graph/constants.ts
index 200b8305e33..5bc2192f53e 100644
--- a/invokeai/frontend/web/src/features/nodes/util/graph/constants.ts
+++ b/invokeai/frontend/web/src/features/nodes/util/graph/constants.ts
@@ -36,7 +36,6 @@ export const CONTROL_NET_COLLECT = 'control_net_collect';
export const IP_ADAPTER_COLLECT = 'ip_adapter_collect';
export const T2I_ADAPTER_COLLECT = 't2i_adapter_collect';
export const METADATA = 'core_metadata';
-export const ESRGAN = 'esrgan';
export const SPANDREL = 'spandrel';
export const SDXL_MODEL_LOADER = 'sdxl_model_loader';
export const SDXL_DENOISE_LATENTS = 'sdxl_denoise_latents';
diff --git a/invokeai/frontend/web/src/features/parameters/components/MainModel/ParamMainModelSelect.tsx b/invokeai/frontend/web/src/features/parameters/components/MainModel/ParamMainModelSelect.tsx
index 26bf80af7bb..c9410dd7a45 100644
--- a/invokeai/frontend/web/src/features/parameters/components/MainModel/ParamMainModelSelect.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/MainModel/ParamMainModelSelect.tsx
@@ -51,7 +51,7 @@ const ParamMainModelSelect = () => {
{t('modelManager.model')}
-
+
{
+ const { t } = useTranslation();
+ const [modelConfigs, { isLoading }] = useSpandrelImageToImageModels();
+
+ const model = useAppSelector((s) => s.upscale.postProcessingModel);
+ const dispatch = useAppDispatch();
+
+ const tooltipLabel = useMemo(() => {
+ if (!modelConfigs.length || !model) {
+ return;
+ }
+ return modelConfigs.find((m) => m.key === model?.key)?.description;
+ }, [modelConfigs, model]);
+
+ const _onChange = useCallback(
+ (v: SpandrelImageToImageModelConfig | null) => {
+ dispatch(postProcessingModelChanged(v));
+ },
+ [dispatch]
+ );
+
+ const { options, value, onChange, placeholder, noOptionsMessage } = useModelCombobox({
+ modelConfigs,
+ onChange: _onChange,
+ selectedModel: model,
+ isLoading,
+ });
+
+ return (
+
+ {t('upscaling.postProcessingModel')}
+
+
+
+
+
+
+ );
+};
+
+export default memo(ParamPostProcessingModel);
diff --git a/invokeai/frontend/web/src/features/parameters/components/PostProcessing/PostProcessingPopover.tsx b/invokeai/frontend/web/src/features/parameters/components/PostProcessing/PostProcessingPopover.tsx
new file mode 100644
index 00000000000..e9092fbee87
--- /dev/null
+++ b/invokeai/frontend/web/src/features/parameters/components/PostProcessing/PostProcessingPopover.tsx
@@ -0,0 +1,90 @@
+import {
+ Button,
+ Flex,
+ IconButton,
+ Popover,
+ PopoverBody,
+ PopoverContent,
+ PopoverTrigger,
+ Text,
+ useDisclosure,
+} from '@invoke-ai/ui-library';
+import { adHocPostProcessingRequested } from 'app/store/middleware/listenerMiddleware/listeners/addAdHocPostProcessingRequestedListener';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { $installModelsTab } from 'features/modelManagerV2/subpanels/InstallModels';
+import ParamPostProcessingModel from 'features/parameters/components/PostProcessing/ParamPostProcessingModel';
+import { useIsQueueMutationInProgress } from 'features/queue/hooks/useIsQueueMutationInProgress';
+import { setActiveTab } from 'features/ui/store/uiSlice';
+import { memo, useCallback } from 'react';
+import { Trans, useTranslation } from 'react-i18next';
+import { PiFrameCornersBold } from 'react-icons/pi';
+import type { ImageDTO } from 'services/api/types';
+
+type Props = { imageDTO?: ImageDTO };
+
+export const PostProcessingPopover = memo((props: Props) => {
+ const { imageDTO } = props;
+ const dispatch = useAppDispatch();
+ const { postProcessingModel } = useAppSelector((s) => s.upscale);
+ const inProgress = useIsQueueMutationInProgress();
+ const { t } = useTranslation();
+ const { isOpen, onOpen, onClose } = useDisclosure();
+
+ const handleClickUpscale = useCallback(() => {
+ onClose();
+ if (!imageDTO) {
+ return;
+ }
+ dispatch(adHocPostProcessingRequested({ imageDTO }));
+ }, [dispatch, imageDTO, onClose]);
+
+ return (
+
+
+ }
+ aria-label={t('parameters.postProcessing')}
+ />
+
+
+
+
+
+ {!postProcessingModel && }
+
+
+
+
+
+ );
+});
+
+PostProcessingPopover.displayName = 'PostProcessingPopover';
+
+const MissingModelWarning = () => {
+ const dispatch = useAppDispatch();
+
+ const handleGoToModelManager = useCallback(() => {
+ dispatch(setActiveTab('models'));
+ $installModelsTab.set(3);
+ }, [dispatch]);
+
+ return (
+
+
+
+ ),
+ }}
+ />
+
+
+ );
+};
diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamCreativity.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamCreativity.tsx
index 955c3ded5aa..0304a732cb5 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamCreativity.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamCreativity.tsx
@@ -1,5 +1,6 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { creativityChanged } from 'features/parameters/store/upscaleSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -25,7 +26,9 @@ const ParamCreativity = () => {
return (
- {t('upscaling.creativity')}
+
+ {t('upscaling.creativity')}
+
[] = [
- {
- label: 'x2 Upscalers',
- options: [
- {
- label: 'RealESRGAN x2 Plus',
- value: 'RealESRGAN_x2plus.pth',
- description: 'Attempts to retain sharpness, low smoothing',
- },
- ],
- },
- {
- label: 'x4 Upscalers',
- options: [
- {
- label: 'RealESRGAN x4 Plus',
- value: 'RealESRGAN_x4plus.pth',
- description: 'Best for photos and highly detailed images, medium smoothing',
- },
- {
- label: 'RealESRGAN x4 Plus (anime 6B)',
- value: 'RealESRGAN_x4plus_anime_6B.pth',
- description: 'Best for anime/manga, high smoothing',
- },
- {
- label: 'ESRGAN SRx4',
- value: 'ESRGAN_SRx4_DF2KOST_official-ff704c30.pth',
- description: 'Retains sharpness, low smoothing',
- },
- ],
- },
-];
-
-const ParamESRGANModel = () => {
- const { t } = useTranslation();
-
- const esrganModelName = useAppSelector((s) => s.postprocessing.esrganModelName);
-
- const dispatch = useAppDispatch();
-
- const onChange = useCallback(
- (v) => {
- if (!isParamESRGANModelName(v?.value)) {
- return;
- }
- dispatch(esrganModelNameChanged(v.value));
- },
- [dispatch]
- );
-
- const value = useMemo(
- () => options.flatMap((o) => o.options).find((m) => m.value === esrganModelName),
- [esrganModelName]
- );
-
- return (
-
- {t('models.esrganModel')}
-
-
- );
-};
-
-export default memo(ParamESRGANModel);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamSpandrelModel.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamSpandrelModel.tsx
index 11216692ecb..501245d77b7 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamSpandrelModel.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamSpandrelModel.tsx
@@ -1,5 +1,6 @@
import { Box, Combobox, FormControl, FormLabel, Tooltip } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { useModelCombobox } from 'common/hooks/useModelCombobox';
import { upscaleModelChanged } from 'features/parameters/store/upscaleSlice';
import { memo, useCallback, useMemo } from 'react';
@@ -37,7 +38,9 @@ const ParamSpandrelModel = () => {
return (
- {t('upscaling.upscaleModel')}
+
+ {t('upscaling.upscaleModel')}
+
{
options={options}
onChange={onChange}
noOptionsMessage={noOptionsMessage}
+ isDisabled={options.length === 0}
/>
diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamStructure.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamStructure.tsx
index 07c543f5968..d3cd85c8468 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamStructure.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamStructure.tsx
@@ -1,5 +1,6 @@
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { structureChanged } from 'features/parameters/store/upscaleSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -25,7 +26,9 @@ const ParamStructure = () => {
return (
- {t('upscaling.structure')}
+
+ {t('upscaling.structure')}
+
{
- const { imageDTO } = props;
- const dispatch = useAppDispatch();
- const inProgress = useIsQueueMutationInProgress();
- const { t } = useTranslation();
- const { isOpen, onOpen, onClose } = useDisclosure();
- const { isAllowedToUpscale, detail } = useIsAllowedToUpscale(imageDTO);
-
- const handleClickUpscale = useCallback(() => {
- onClose();
- if (!imageDTO || !isAllowedToUpscale) {
- return;
- }
- dispatch(upscaleRequested({ imageDTO }));
- }, [dispatch, imageDTO, isAllowedToUpscale, onClose]);
-
- return (
-
-
- }
- aria-label={t('parameters.upscale')}
- />
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default memo(ParamUpscalePopover);
diff --git a/invokeai/frontend/web/src/features/parameters/hooks/useIsAllowedToUpscale.ts b/invokeai/frontend/web/src/features/parameters/hooks/useIsAllowedToUpscale.ts
deleted file mode 100644
index 95fc52df229..00000000000
--- a/invokeai/frontend/web/src/features/parameters/hooks/useIsAllowedToUpscale.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
-import { useAppSelector } from 'app/store/storeHooks';
-import { selectPostprocessingSlice } from 'features/parameters/store/postprocessingSlice';
-import { selectConfigSlice } from 'features/system/store/configSlice';
-import { useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import type { ImageDTO } from 'services/api/types';
-
-const getUpscaledPixels = (imageDTO?: ImageDTO, maxUpscalePixels?: number) => {
- if (!imageDTO) {
- return;
- }
- if (!maxUpscalePixels) {
- return;
- }
- const { width, height } = imageDTO;
- const x4 = height * 4 * width * 4;
- const x2 = height * 2 * width * 2;
- return { x4, x2 };
-};
-
-const getIsAllowedToUpscale = (upscaledPixels?: ReturnType, maxUpscalePixels?: number) => {
- if (!upscaledPixels || !maxUpscalePixels) {
- return { x4: true, x2: true };
- }
- const isAllowedToUpscale = { x4: false, x2: false };
- if (upscaledPixels.x4 <= maxUpscalePixels) {
- isAllowedToUpscale.x4 = true;
- }
- if (upscaledPixels.x2 <= maxUpscalePixels) {
- isAllowedToUpscale.x2 = true;
- }
-
- return isAllowedToUpscale;
-};
-
-const getDetailTKey = (isAllowedToUpscale?: ReturnType, scaleFactor?: number) => {
- if (!isAllowedToUpscale || !scaleFactor) {
- return;
- }
-
- if (isAllowedToUpscale.x4 && isAllowedToUpscale.x2) {
- return;
- }
-
- if (!isAllowedToUpscale.x2 && !isAllowedToUpscale.x4) {
- return 'parameters.isAllowedToUpscale.tooLarge';
- }
-
- if (!isAllowedToUpscale.x4 && isAllowedToUpscale.x2 && scaleFactor === 4) {
- return 'parameters.isAllowedToUpscale.useX2Model';
- }
-
- return;
-};
-
-export const createIsAllowedToUpscaleSelector = (imageDTO?: ImageDTO) =>
- createMemoizedSelector(selectPostprocessingSlice, selectConfigSlice, (postprocessing, config) => {
- const { esrganModelName } = postprocessing;
- const { maxUpscalePixels } = config;
-
- const upscaledPixels = getUpscaledPixels(imageDTO, maxUpscalePixels);
- const isAllowedToUpscale = getIsAllowedToUpscale(upscaledPixels, maxUpscalePixels);
- const scaleFactor = esrganModelName.includes('x2') ? 2 : 4;
- const detailTKey = getDetailTKey(isAllowedToUpscale, scaleFactor);
- return {
- isAllowedToUpscale: scaleFactor === 2 ? isAllowedToUpscale.x2 : isAllowedToUpscale.x4,
- detailTKey,
- };
- });
-
-export const useIsAllowedToUpscale = (imageDTO?: ImageDTO) => {
- const { t } = useTranslation();
- const selectIsAllowedToUpscale = useMemo(() => createIsAllowedToUpscaleSelector(imageDTO), [imageDTO]);
- const { isAllowedToUpscale, detailTKey } = useAppSelector(selectIsAllowedToUpscale);
-
- return {
- isAllowedToUpscale,
- detail: detailTKey ? t(detailTKey) : undefined,
- };
-};
diff --git a/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts b/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts
deleted file mode 100644
index c15bf982b85..00000000000
--- a/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import type { PayloadAction } from '@reduxjs/toolkit';
-import { createSlice } from '@reduxjs/toolkit';
-import type { PersistConfig, RootState } from 'app/store/store';
-import { z } from 'zod';
-
-const zParamESRGANModelName = z.enum([
- 'RealESRGAN_x4plus.pth',
- 'RealESRGAN_x4plus_anime_6B.pth',
- 'ESRGAN_SRx4_DF2KOST_official-ff704c30.pth',
- 'RealESRGAN_x2plus.pth',
-]);
-type ParamESRGANModelName = z.infer;
-export const isParamESRGANModelName = (v: unknown): v is ParamESRGANModelName =>
- zParamESRGANModelName.safeParse(v).success;
-
-interface PostprocessingState {
- _version: 1;
- esrganModelName: ParamESRGANModelName;
-}
-
-const initialPostprocessingState: PostprocessingState = {
- _version: 1,
- esrganModelName: 'RealESRGAN_x4plus.pth',
-};
-
-export const postprocessingSlice = createSlice({
- name: 'postprocessing',
- initialState: initialPostprocessingState,
- reducers: {
- esrganModelNameChanged: (state, action: PayloadAction) => {
- state.esrganModelName = action.payload;
- },
- },
-});
-
-export const { esrganModelNameChanged } = postprocessingSlice.actions;
-
-export const selectPostprocessingSlice = (state: RootState) => state.postprocessing;
-
-/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
-const migratePostprocessingState = (state: any): any => {
- if (!('_version' in state)) {
- state._version = 1;
- }
- return state;
-};
-
-export const postprocessingPersistConfig: PersistConfig = {
- name: postprocessingSlice.name,
- initialState: initialPostprocessingState,
- migrate: migratePostprocessingState,
- persistDenylist: [],
-};
diff --git a/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts b/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts
index f0b8d81ad82..0ea4523a154 100644
--- a/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts
+++ b/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts
@@ -12,6 +12,7 @@ interface UpscaleState {
creativity: number;
tileControlnetModel: ControlNetModelConfig | null;
scale: number;
+ postProcessingModel: ParameterSpandrelImageToImageModel | null;
}
const initialUpscaleState: UpscaleState = {
@@ -22,6 +23,7 @@ const initialUpscaleState: UpscaleState = {
creativity: 0,
tileControlnetModel: null,
scale: 4,
+ postProcessingModel: null,
};
export const upscaleSlice = createSlice({
@@ -46,6 +48,9 @@ export const upscaleSlice = createSlice({
scaleChanged: (state, action: PayloadAction) => {
state.scale = action.payload;
},
+ postProcessingModelChanged: (state, action: PayloadAction) => {
+ state.postProcessingModel = action.payload;
+ },
},
});
@@ -56,6 +61,7 @@ export const {
creativityChanged,
tileControlnetModelChanged,
scaleChanged,
+ postProcessingModelChanged,
} = upscaleSlice.actions;
export const selectUpscalelice = (state: RootState) => state.upscale;
diff --git a/invokeai/frontend/web/src/features/sdxl/components/SDXLRefiner/ParamSDXLRefinerModelSelect.tsx b/invokeai/frontend/web/src/features/sdxl/components/SDXLRefiner/ParamSDXLRefinerModelSelect.tsx
index 619f55f5f8c..e18ccbfbb27 100644
--- a/invokeai/frontend/web/src/features/sdxl/components/SDXLRefiner/ParamSDXLRefinerModelSelect.tsx
+++ b/invokeai/frontend/web/src/features/sdxl/components/SDXLRefiner/ParamSDXLRefinerModelSelect.tsx
@@ -1,4 +1,4 @@
-import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
+import { Box, Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
@@ -37,18 +37,20 @@ const ParamSDXLRefinerModelSelect = () => {
optionsFilter,
});
return (
-
+
{t('sdxl.refinermodel')}
-
+
+
+
);
};
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx
index 682878187f3..7ed7eaf5ccd 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx
@@ -64,7 +64,7 @@ export const AdvancedSettingsAccordion = memo(() => {
const badges = useAppSelector(selectBadges);
const { t } = useTranslation();
const { isOpen, onToggle } = useStandaloneAccordionToggle({
- id: 'advanced-settings',
+ id: `'advanced-settings-${activeTabName}`,
defaultIsOpen: false,
});
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx
index 1d9eee7cd8a..a809a355873 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion.tsx
@@ -14,6 +14,7 @@ import ParamMainModelSelect from 'features/parameters/components/MainModel/Param
import { UseDefaultSettingsButton } from 'features/parameters/components/MainModel/UseDefaultSettingsButton';
import { useExpanderToggle } from 'features/settingsAccordions/hooks/useExpanderToggle';
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
+import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { filter } from 'lodash-es';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -26,6 +27,7 @@ const formLabelProps: FormLabelProps = {
export const GenerationSettingsAccordion = memo(() => {
const { t } = useTranslation();
const modelConfig = useSelectedModelConfig();
+ const activeTabName = useAppSelector(activeTabNameSelector);
const selectBadges = useMemo(
() =>
createMemoizedSelector(selectLoraSlice, (lora) => {
@@ -42,8 +44,8 @@ export const GenerationSettingsAccordion = memo(() => {
defaultIsOpen: false,
});
const { isOpen: isOpenAccordion, onToggle: onToggleAccordion } = useStandaloneAccordionToggle({
- id: 'generation-settings',
- defaultIsOpen: true,
+ id: `generation-settings-${activeTabName}`,
+ defaultIsOpen: activeTabName !== 'upscaling',
});
return (
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx
index bf5bdf13e4e..eb73ebe961d 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/RefinerSettingsAccordion/RefinerSettingsAccordion.tsx
@@ -62,7 +62,7 @@ const RefinerSettingsAccordionContent: React.FC = memo(() => {
return (
-
+
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider.tsx
index 385add771aa..dd4f46557f3 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider.tsx
@@ -1,5 +1,6 @@
import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { scaleChanged } from 'features/parameters/store/upscaleSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
@@ -22,7 +23,9 @@ export const UpscaleScaleSlider = memo(() => {
return (
- {t('upscaling.scale')}
+
+ {t('upscaling.scale')}
+
{
const { upscaleModel, upscaleInitialImage, scale } = upscaleSlice;
@@ -53,12 +53,12 @@ export const UpscaleSettingsAccordion = memo(() => {
-
+
-
+
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/MultidiffusionWarning.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleWarning.tsx
similarity index 90%
rename from invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/MultidiffusionWarning.tsx
rename to invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleWarning.tsx
index f3e2aa66048..0c2c16d302d 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/MultidiffusionWarning.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleWarning.tsx
@@ -7,10 +7,11 @@ import { useCallback, useEffect, useMemo } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useControlNetModels } from 'services/api/hooks/modelsByType';
-export const MultidiffusionWarning = () => {
+export const UpscaleWarning = () => {
const { t } = useTranslation();
const model = useAppSelector((s) => s.generation.model);
- const { tileControlnetModel, upscaleModel } = useAppSelector((s) => s.upscale);
+ const upscaleModel = useAppSelector((s) => s.upscale.upscaleModel);
+ const tileControlnetModel = useAppSelector((s) => s.upscale.tileControlnetModel);
const dispatch = useAppDispatch();
const [modelConfigs, { isLoading }] = useControlNetModels();
const disabledTabs = useAppSelector((s) => s.config.disabledTabs);
@@ -34,8 +35,9 @@ export const MultidiffusionWarning = () => {
if (!upscaleModel) {
_warnings.push(t('upscaling.upscaleModelDesc'));
}
+
return _warnings;
- }, [model, upscaleModel, tileControlnetModel, t]);
+ }, [model, tileControlnetModel, upscaleModel, t]);
const handleGoToModelManager = useCallback(() => {
dispatch(setActiveTab('models'));
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts b/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts
index d69d08d17d2..ac094a093fd 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts
+++ b/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts
@@ -18,5 +18,6 @@ export const useStandaloneAccordionToggle = (arg: UseStandaloneAccordionToggleAr
const onToggle = useCallback(() => {
dispatch(accordionStateChanged({ id: arg.id, isOpen: !isOpen }));
}, [arg.id, dispatch, isOpen]);
+
return { isOpen, onToggle };
};
diff --git a/invokeai/frontend/web/src/features/system/components/HotkeysModal/useHotkeyData.ts b/invokeai/frontend/web/src/features/system/components/HotkeysModal/useHotkeyData.ts
index 79d957d7d36..76590db443b 100644
--- a/invokeai/frontend/web/src/features/system/components/HotkeysModal/useHotkeyData.ts
+++ b/invokeai/frontend/web/src/features/system/components/HotkeysModal/useHotkeyData.ts
@@ -102,8 +102,8 @@ export const useHotkeyData = (): HotkeyGroup[] => {
hotkeys: [['A']],
},
{
- title: t('hotkeys.upscale.title'),
- desc: t('hotkeys.upscale.desc'),
+ title: t('hotkeys.postProcess.title'),
+ desc: t('hotkeys.postProcess.desc'),
hotkeys: [['Shift', 'U']],
},
{
diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx
index b424a129ee5..33455e50fa7 100644
--- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx
+++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx
@@ -5,6 +5,7 @@ import {
MenuGroup,
MenuItem,
MenuList,
+ Portal,
useDisclosure,
useGlobalMenuClose,
} from '@invoke-ai/ui-library';
@@ -14,10 +15,18 @@ import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { discordLink, githubLink } from 'features/system/store/constants';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
-import { PiBugBeetleBold, PiInfoBold, PiKeyboardBold, PiToggleRightFill } from 'react-icons/pi';
+import {
+ PiBugBeetleBold,
+ PiInfoBold,
+ PiKeyboardBold,
+ PiShareNetworkFill,
+ PiToggleRightFill,
+ PiUsersBold,
+} from 'react-icons/pi';
import { RiDiscordFill, RiGithubFill, RiSettings4Line } from 'react-icons/ri';
import SettingsModal from './SettingsModal';
+import { SettingsUpsellMenuItem } from './SettingsUpsellMenuItem';
const SettingsMenu = () => {
const { t } = useTranslation();
const { isOpen, onOpen, onClose } = useDisclosure();
@@ -28,7 +37,7 @@ const SettingsMenu = () => {
const isGithubLinkEnabled = useFeatureStatus('githubLink');
return (
-