mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Compare commits
46 Commits
label-test
...
v3.6.2
Author | SHA1 | Date | |
---|---|---|---|
57dafd294d | |||
e611baa4b4 | |||
fc448d5b6d | |||
e59954f956 | |||
86c857b9c2 | |||
0a13d7d2c7 | |||
68da5c6d22 | |||
f82744b95e | |||
5a67bc68a1 | |||
61cf4d4c70 | |||
9d20a2d5a3 | |||
8b0ac451e3 | |||
470dbe75a2 | |||
b7d19b8130 | |||
3dc13221d8 | |||
35184dbd86 | |||
0868fc2558 | |||
92fb09c4df | |||
b4cf5496b6 | |||
a0e68705dd | |||
7cb49e65bd | |||
39fedb090b | |||
f36a691219 | |||
6a2eb1d2e4 | |||
13123daa3f | |||
c859eb865e | |||
8f5e2cbcc7 | |||
2aed6e2dba | |||
52b51a6088 | |||
52b24e01e2 | |||
1178fd8bd3 | |||
a0187cc9df | |||
2f656cc357 | |||
71f9ac9985 | |||
8bbdfc45fa | |||
3cbb1a7671 | |||
b74e0de74a | |||
e7e7793896 | |||
504bdac14a | |||
b76d2cd716 | |||
022b32c724 | |||
653b820da1 | |||
4ba0bf4dcf | |||
5e4daf4bc6 | |||
7e0713c869 | |||
099d516ac0 |
40
.github/pr_labels.yml
vendored
40
.github/pr_labels.yml
vendored
@ -1,40 +0,0 @@
|
||||
Root:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: '*'
|
||||
|
||||
PythonDeps:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'pyproject.toml'
|
||||
|
||||
Python:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'invokeai/**'
|
||||
- '!invokeai/frontend/web/**'
|
||||
- 'tests/**'
|
||||
|
||||
Invocations:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'invokeai/app/invocations/**'
|
||||
|
||||
Backend:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'invokeai/backend/**'
|
||||
|
||||
Api:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'invokeai/app/api/**'
|
||||
|
||||
Services:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'invokeai/app/services/**'
|
||||
|
||||
FrontendDeps:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/*/package.json'
|
||||
- '**/*/pnpm-lock.yaml'
|
||||
|
||||
Frontend:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'invokeai/frontend/web/**'
|
16
.github/workflows/label-pr.yml
vendored
16
.github/workflows/label-pr.yml
vendored
@ -1,16 +0,0 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: .github/pr_labels.yml
|
@ -1,76 +0,0 @@
|
||||
# Contributing to the Frontend
|
||||
|
||||
# InvokeAI Web UI
|
||||
|
||||
- [InvokeAI Web UI](https://github.com/invoke-ai/InvokeAI/tree/main/invokeai/frontend/web/docs#invokeai-web-ui)
|
||||
- [Stack](https://github.com/invoke-ai/InvokeAI/tree/main/invokeai/frontend/web/docs#stack)
|
||||
- [Contributing](https://github.com/invoke-ai/InvokeAI/tree/main/invokeai/frontend/web/docs#contributing)
|
||||
- [Dev Environment](https://github.com/invoke-ai/InvokeAI/tree/main/invokeai/frontend/web/docs#dev-environment)
|
||||
- [Production builds](https://github.com/invoke-ai/InvokeAI/tree/main/invokeai/frontend/web/docs#production-builds)
|
||||
|
||||
The UI is a fairly straightforward Typescript React app, with the Unified Canvas being more complex.
|
||||
|
||||
Code is located in `invokeai/frontend/web/` for review.
|
||||
|
||||
## Stack
|
||||
|
||||
State management is Redux via [Redux Toolkit](https://github.com/reduxjs/redux-toolkit). We lean heavily on RTK:
|
||||
|
||||
- `createAsyncThunk` for HTTP requests
|
||||
- `createEntityAdapter` for fetching images and models
|
||||
- `createListenerMiddleware` for workflows
|
||||
|
||||
The API client and associated types are generated from the OpenAPI schema. See API_CLIENT.md.
|
||||
|
||||
Communication with server is a mix of HTTP and [socket.io](https://github.com/socketio/socket.io-client) (with a simple socket.io redux middleware to help).
|
||||
|
||||
[Chakra-UI](https://github.com/chakra-ui/chakra-ui) & [Mantine](https://github.com/mantinedev/mantine) for components and styling.
|
||||
|
||||
[Konva](https://github.com/konvajs/react-konva) for the canvas, but we are pushing the limits of what is feasible with it (and HTML canvas in general). We plan to rebuild it with [PixiJS](https://github.com/pixijs/pixijs) to take advantage of WebGL's improved raster handling.
|
||||
|
||||
[Vite](https://vitejs.dev/) for bundling.
|
||||
|
||||
Localisation is via [i18next](https://github.com/i18next/react-i18next), but translation happens on our [Weblate](https://hosted.weblate.org/engage/invokeai/) project. Only the English source strings should be changed on this repo.
|
||||
|
||||
## Contributing
|
||||
|
||||
Thanks for your interest in contributing to the InvokeAI Web UI!
|
||||
|
||||
We encourage you to ping @psychedelicious and @blessedcoolant on [Discord](https://discord.gg/ZmtBAhwWhy) if you want to contribute, just to touch base and ensure your work doesn't conflict with anything else going on. The project is very active.
|
||||
|
||||
### Dev Environment
|
||||
|
||||
**Setup**
|
||||
|
||||
1. Install [node](https://nodejs.org/en/download/). You can confirm node is installed with:
|
||||
```bash
|
||||
node --version
|
||||
```
|
||||
|
||||
2. Install [pnpm](https://pnpm.io/) and confirm it is installed by running this:
|
||||
```bash
|
||||
npm install --global pnpm
|
||||
pnpm --version
|
||||
```
|
||||
|
||||
From `invokeai/frontend/web/` run `pnpm install` to get everything set up.
|
||||
|
||||
Start everything in dev mode:
|
||||
1. Ensure your virtual environment is running
|
||||
2. Start the dev server: `pnpm dev`
|
||||
3. Start the InvokeAI Nodes backend: `python scripts/invokeai-web.py # run from the repo root`
|
||||
4. Point your browser to the dev server address e.g. [http://localhost:5173/](http://localhost:5173/)
|
||||
|
||||
### VSCode Remote Dev
|
||||
|
||||
We've noticed an intermittent issue with the VSCode Remote Dev port forwarding. If you use this feature of VSCode, you may intermittently click the Invoke button and then get nothing until the request times out. Suggest disabling the IDE's port forwarding feature and doing it manually via SSH:
|
||||
|
||||
`ssh -L 9090:localhost:9090 -L 5173:localhost:5173 user@host`
|
||||
|
||||
### Production builds
|
||||
|
||||
For a number of technical and logistical reasons, we need to commit UI build artefacts to the repo.
|
||||
|
||||
If you submit a PR, there is a good chance we will ask you to include a separate commit with a build of the app.
|
||||
|
||||
To build for production, run `pnpm build`.
|
@ -12,7 +12,7 @@ To get started, take a look at our [new contributors checklist](newContributorCh
|
||||
Once you're setup, for more information, you can review the documentation specific to your area of interest:
|
||||
|
||||
* #### [InvokeAI Architecure](../ARCHITECTURE.md)
|
||||
* #### [Frontend Documentation](./contributingToFrontend.md)
|
||||
* #### [Frontend Documentation](https://github.com/invoke-ai/InvokeAI/tree/main/invokeai/frontend/web)
|
||||
* #### [Node Documentation](../INVOCATIONS.md)
|
||||
* #### [Local Development](../LOCAL_DEVELOPMENT.md)
|
||||
|
||||
|
@ -24,7 +24,6 @@ download_queue_router = APIRouter(prefix="/v1/download_queue", tags=["download_q
|
||||
)
|
||||
async def list_downloads() -> List[DownloadJob]:
|
||||
"""Get a list of active and inactive jobs."""
|
||||
print("test")
|
||||
queue = ApiDependencies.invoker.services.download_queue
|
||||
return queue.list_jobs()
|
||||
|
||||
|
@ -30,6 +30,7 @@ from invokeai.app.invocations.primitives import ImageField, ImageOutput
|
||||
from invokeai.app.invocations.util import validate_begin_end_step, validate_weights
|
||||
from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin
|
||||
from invokeai.app.shared.fields import FieldDescriptions
|
||||
from invokeai.backend.image_util.depth_anything import DepthAnythingDetector
|
||||
|
||||
from ...backend.model_management import BaseModelType
|
||||
from .baseinvocation import (
|
||||
@ -602,3 +603,33 @@ class ColorMapImageProcessorInvocation(ImageProcessorInvocation):
|
||||
color_map = cv2.resize(color_map, (width, height), interpolation=cv2.INTER_NEAREST)
|
||||
color_map = Image.fromarray(color_map)
|
||||
return color_map
|
||||
|
||||
|
||||
DEPTH_ANYTHING_MODEL_SIZES = Literal["large", "base", "small"]
|
||||
|
||||
|
||||
@invocation(
|
||||
"depth_anything_image_processor",
|
||||
title="Depth Anything Processor",
|
||||
tags=["controlnet", "depth", "depth anything"],
|
||||
category="controlnet",
|
||||
version="1.0.0",
|
||||
)
|
||||
class DepthAnythingImageProcessorInvocation(ImageProcessorInvocation):
|
||||
"""Generates a depth map based on the Depth Anything algorithm"""
|
||||
|
||||
model_size: DEPTH_ANYTHING_MODEL_SIZES = InputField(
|
||||
default="small", description="The size of the depth model to use"
|
||||
)
|
||||
resolution: int = InputField(default=512, ge=64, multiple_of=64, description=FieldDescriptions.image_res)
|
||||
offload: bool = InputField(default=False)
|
||||
|
||||
def run_processor(self, image):
|
||||
depth_anything_detector = DepthAnythingDetector()
|
||||
depth_anything_detector.load_model(model_size=self.model_size)
|
||||
|
||||
if image.mode == "RGBA":
|
||||
image = image.convert("RGB")
|
||||
|
||||
processed_image = depth_anything_detector(image=image, resolution=self.resolution, offload=self.offload)
|
||||
return processed_image
|
||||
|
@ -75,8 +75,6 @@ from .model import ModelInfo, UNetField, VaeField
|
||||
if choose_torch_device() == torch.device("mps"):
|
||||
from torch import mps
|
||||
|
||||
print("test")
|
||||
|
||||
DEFAULT_PRECISION = choose_precision(choose_torch_device())
|
||||
|
||||
SAMPLER_NAME_VALUES = Literal[tuple(SCHEDULER_MAP.keys())]
|
||||
|
@ -23,7 +23,6 @@ class DefaultInvocationProcessor(InvocationProcessorABC):
|
||||
self.__threadLimit = BoundedSemaphore(1)
|
||||
self.__invoker = invoker
|
||||
self.__stop_event = Event()
|
||||
print("test")
|
||||
self.__invoker_thread = Thread(
|
||||
name="invoker_processor",
|
||||
target=self.__process,
|
||||
|
@ -31,6 +31,7 @@ class WorkflowRecordOrderBy(str, Enum, metaclass=MetaEnum):
|
||||
class WorkflowCategory(str, Enum, metaclass=MetaEnum):
|
||||
User = "user"
|
||||
Default = "default"
|
||||
Project = "project"
|
||||
|
||||
|
||||
class WorkflowMeta(BaseModel):
|
||||
|
109
invokeai/backend/image_util/depth_anything/__init__.py
Normal file
109
invokeai/backend/image_util/depth_anything/__init__.py
Normal file
@ -0,0 +1,109 @@
|
||||
import pathlib
|
||||
from typing import Literal, Union
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
from einops import repeat
|
||||
from PIL import Image
|
||||
from torchvision.transforms import Compose
|
||||
|
||||
from invokeai.app.services.config.config_default import InvokeAIAppConfig
|
||||
from invokeai.backend.image_util.depth_anything.model.dpt import DPT_DINOv2
|
||||
from invokeai.backend.image_util.depth_anything.utilities.util import NormalizeImage, PrepareForNet, Resize
|
||||
from invokeai.backend.util.devices import choose_torch_device
|
||||
from invokeai.backend.util.util import download_with_progress_bar
|
||||
|
||||
config = InvokeAIAppConfig.get_config()
|
||||
|
||||
DEPTH_ANYTHING_MODELS = {
|
||||
"large": {
|
||||
"url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitl14.pth?download=true",
|
||||
"local": "any/annotators/depth_anything/depth_anything_vitl14.pth",
|
||||
},
|
||||
"base": {
|
||||
"url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitb14.pth?download=true",
|
||||
"local": "any/annotators/depth_anything/depth_anything_vitb14.pth",
|
||||
},
|
||||
"small": {
|
||||
"url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vits14.pth?download=true",
|
||||
"local": "any/annotators/depth_anything/depth_anything_vits14.pth",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
transform = Compose(
|
||||
[
|
||||
Resize(
|
||||
width=518,
|
||||
height=518,
|
||||
resize_target=False,
|
||||
keep_aspect_ratio=True,
|
||||
ensure_multiple_of=14,
|
||||
resize_method="lower_bound",
|
||||
image_interpolation_method=cv2.INTER_CUBIC,
|
||||
),
|
||||
NormalizeImage(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
||||
PrepareForNet(),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class DepthAnythingDetector:
|
||||
def __init__(self) -> None:
|
||||
self.model = None
|
||||
self.model_size: Union[Literal["large", "base", "small"], None] = None
|
||||
|
||||
def load_model(self, model_size=Literal["large", "base", "small"]):
|
||||
DEPTH_ANYTHING_MODEL_PATH = pathlib.Path(config.models_path / DEPTH_ANYTHING_MODELS[model_size]["local"])
|
||||
if not DEPTH_ANYTHING_MODEL_PATH.exists():
|
||||
download_with_progress_bar(DEPTH_ANYTHING_MODELS[model_size]["url"], DEPTH_ANYTHING_MODEL_PATH)
|
||||
|
||||
if not self.model or model_size != self.model_size:
|
||||
del self.model
|
||||
self.model_size = model_size
|
||||
|
||||
match self.model_size:
|
||||
case "small":
|
||||
self.model = DPT_DINOv2(encoder="vits", features=64, out_channels=[48, 96, 192, 384])
|
||||
case "base":
|
||||
self.model = DPT_DINOv2(encoder="vitb", features=128, out_channels=[96, 192, 384, 768])
|
||||
case "large":
|
||||
self.model = DPT_DINOv2(encoder="vitl", features=256, out_channels=[256, 512, 1024, 1024])
|
||||
case _:
|
||||
raise TypeError("Not a supported model")
|
||||
|
||||
self.model.load_state_dict(torch.load(DEPTH_ANYTHING_MODEL_PATH.as_posix(), map_location="cpu"))
|
||||
self.model.eval()
|
||||
|
||||
self.model.to(choose_torch_device())
|
||||
return self.model
|
||||
|
||||
def to(self, device):
|
||||
self.model.to(device)
|
||||
return self
|
||||
|
||||
def __call__(self, image, resolution=512, offload=False):
|
||||
image = np.array(image, dtype=np.uint8)
|
||||
image = image[:, :, ::-1] / 255.0
|
||||
|
||||
image_height, image_width = image.shape[:2]
|
||||
image = transform({"image": image})["image"]
|
||||
image = torch.from_numpy(image).unsqueeze(0).to(choose_torch_device())
|
||||
|
||||
with torch.no_grad():
|
||||
depth = self.model(image)
|
||||
depth = F.interpolate(depth[None], (image_height, image_width), mode="bilinear", align_corners=False)[0, 0]
|
||||
depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255.0
|
||||
|
||||
depth_map = repeat(depth, "h w -> h w 3").cpu().numpy().astype(np.uint8)
|
||||
depth_map = Image.fromarray(depth_map)
|
||||
|
||||
new_height = int(image_height * (resolution / image_width))
|
||||
depth_map = depth_map.resize((resolution, new_height))
|
||||
|
||||
if offload:
|
||||
del self.model
|
||||
|
||||
return depth_map
|
145
invokeai/backend/image_util/depth_anything/model/blocks.py
Normal file
145
invokeai/backend/image_util/depth_anything/model/blocks.py
Normal file
@ -0,0 +1,145 @@
|
||||
import torch.nn as nn
|
||||
|
||||
|
||||
def _make_scratch(in_shape, out_shape, groups=1, expand=False):
|
||||
scratch = nn.Module()
|
||||
|
||||
out_shape1 = out_shape
|
||||
out_shape2 = out_shape
|
||||
out_shape3 = out_shape
|
||||
if len(in_shape) >= 4:
|
||||
out_shape4 = out_shape
|
||||
|
||||
if expand:
|
||||
out_shape1 = out_shape
|
||||
out_shape2 = out_shape * 2
|
||||
out_shape3 = out_shape * 4
|
||||
if len(in_shape) >= 4:
|
||||
out_shape4 = out_shape * 8
|
||||
|
||||
scratch.layer1_rn = nn.Conv2d(
|
||||
in_shape[0], out_shape1, kernel_size=3, stride=1, padding=1, bias=False, groups=groups
|
||||
)
|
||||
scratch.layer2_rn = nn.Conv2d(
|
||||
in_shape[1], out_shape2, kernel_size=3, stride=1, padding=1, bias=False, groups=groups
|
||||
)
|
||||
scratch.layer3_rn = nn.Conv2d(
|
||||
in_shape[2], out_shape3, kernel_size=3, stride=1, padding=1, bias=False, groups=groups
|
||||
)
|
||||
if len(in_shape) >= 4:
|
||||
scratch.layer4_rn = nn.Conv2d(
|
||||
in_shape[3], out_shape4, kernel_size=3, stride=1, padding=1, bias=False, groups=groups
|
||||
)
|
||||
|
||||
return scratch
|
||||
|
||||
|
||||
class ResidualConvUnit(nn.Module):
|
||||
"""Residual convolution module."""
|
||||
|
||||
def __init__(self, features, activation, bn):
|
||||
"""Init.
|
||||
|
||||
Args:
|
||||
features (int): number of features
|
||||
"""
|
||||
super().__init__()
|
||||
|
||||
self.bn = bn
|
||||
|
||||
self.groups = 1
|
||||
|
||||
self.conv1 = nn.Conv2d(features, features, kernel_size=3, stride=1, padding=1, bias=True, groups=self.groups)
|
||||
|
||||
self.conv2 = nn.Conv2d(features, features, kernel_size=3, stride=1, padding=1, bias=True, groups=self.groups)
|
||||
|
||||
if self.bn:
|
||||
self.bn1 = nn.BatchNorm2d(features)
|
||||
self.bn2 = nn.BatchNorm2d(features)
|
||||
|
||||
self.activation = activation
|
||||
|
||||
self.skip_add = nn.quantized.FloatFunctional()
|
||||
|
||||
def forward(self, x):
|
||||
"""Forward pass.
|
||||
|
||||
Args:
|
||||
x (tensor): input
|
||||
|
||||
Returns:
|
||||
tensor: output
|
||||
"""
|
||||
|
||||
out = self.activation(x)
|
||||
out = self.conv1(out)
|
||||
if self.bn:
|
||||
out = self.bn1(out)
|
||||
|
||||
out = self.activation(out)
|
||||
out = self.conv2(out)
|
||||
if self.bn:
|
||||
out = self.bn2(out)
|
||||
|
||||
if self.groups > 1:
|
||||
out = self.conv_merge(out)
|
||||
|
||||
return self.skip_add.add(out, x)
|
||||
|
||||
|
||||
class FeatureFusionBlock(nn.Module):
|
||||
"""Feature fusion block."""
|
||||
|
||||
def __init__(self, features, activation, deconv=False, bn=False, expand=False, align_corners=True, size=None):
|
||||
"""Init.
|
||||
|
||||
Args:
|
||||
features (int): number of features
|
||||
"""
|
||||
super(FeatureFusionBlock, self).__init__()
|
||||
|
||||
self.deconv = deconv
|
||||
self.align_corners = align_corners
|
||||
|
||||
self.groups = 1
|
||||
|
||||
self.expand = expand
|
||||
out_features = features
|
||||
if self.expand:
|
||||
out_features = features // 2
|
||||
|
||||
self.out_conv = nn.Conv2d(features, out_features, kernel_size=1, stride=1, padding=0, bias=True, groups=1)
|
||||
|
||||
self.resConfUnit1 = ResidualConvUnit(features, activation, bn)
|
||||
self.resConfUnit2 = ResidualConvUnit(features, activation, bn)
|
||||
|
||||
self.skip_add = nn.quantized.FloatFunctional()
|
||||
|
||||
self.size = size
|
||||
|
||||
def forward(self, *xs, size=None):
|
||||
"""Forward pass.
|
||||
|
||||
Returns:
|
||||
tensor: output
|
||||
"""
|
||||
output = xs[0]
|
||||
|
||||
if len(xs) == 2:
|
||||
res = self.resConfUnit1(xs[1])
|
||||
output = self.skip_add.add(output, res)
|
||||
|
||||
output = self.resConfUnit2(output)
|
||||
|
||||
if (size is None) and (self.size is None):
|
||||
modifier = {"scale_factor": 2}
|
||||
elif size is None:
|
||||
modifier = {"size": self.size}
|
||||
else:
|
||||
modifier = {"size": size}
|
||||
|
||||
output = nn.functional.interpolate(output, **modifier, mode="bilinear", align_corners=self.align_corners)
|
||||
|
||||
output = self.out_conv(output)
|
||||
|
||||
return output
|
183
invokeai/backend/image_util/depth_anything/model/dpt.py
Normal file
183
invokeai/backend/image_util/depth_anything/model/dpt.py
Normal file
@ -0,0 +1,183 @@
|
||||
from pathlib import Path
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
|
||||
from .blocks import FeatureFusionBlock, _make_scratch
|
||||
|
||||
torchhub_path = Path(__file__).parent.parent / "torchhub"
|
||||
|
||||
|
||||
def _make_fusion_block(features, use_bn, size=None):
|
||||
return FeatureFusionBlock(
|
||||
features,
|
||||
nn.ReLU(False),
|
||||
deconv=False,
|
||||
bn=use_bn,
|
||||
expand=False,
|
||||
align_corners=True,
|
||||
size=size,
|
||||
)
|
||||
|
||||
|
||||
class DPTHead(nn.Module):
|
||||
def __init__(self, nclass, in_channels, features, out_channels, use_bn=False, use_clstoken=False):
|
||||
super(DPTHead, self).__init__()
|
||||
|
||||
self.nclass = nclass
|
||||
self.use_clstoken = use_clstoken
|
||||
|
||||
self.projects = nn.ModuleList(
|
||||
[
|
||||
nn.Conv2d(
|
||||
in_channels=in_channels,
|
||||
out_channels=out_channel,
|
||||
kernel_size=1,
|
||||
stride=1,
|
||||
padding=0,
|
||||
)
|
||||
for out_channel in out_channels
|
||||
]
|
||||
)
|
||||
|
||||
self.resize_layers = nn.ModuleList(
|
||||
[
|
||||
nn.ConvTranspose2d(
|
||||
in_channels=out_channels[0], out_channels=out_channels[0], kernel_size=4, stride=4, padding=0
|
||||
),
|
||||
nn.ConvTranspose2d(
|
||||
in_channels=out_channels[1], out_channels=out_channels[1], kernel_size=2, stride=2, padding=0
|
||||
),
|
||||
nn.Identity(),
|
||||
nn.Conv2d(
|
||||
in_channels=out_channels[3], out_channels=out_channels[3], kernel_size=3, stride=2, padding=1
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
if use_clstoken:
|
||||
self.readout_projects = nn.ModuleList()
|
||||
for _ in range(len(self.projects)):
|
||||
self.readout_projects.append(nn.Sequential(nn.Linear(2 * in_channels, in_channels), nn.GELU()))
|
||||
|
||||
self.scratch = _make_scratch(
|
||||
out_channels,
|
||||
features,
|
||||
groups=1,
|
||||
expand=False,
|
||||
)
|
||||
|
||||
self.scratch.stem_transpose = None
|
||||
|
||||
self.scratch.refinenet1 = _make_fusion_block(features, use_bn)
|
||||
self.scratch.refinenet2 = _make_fusion_block(features, use_bn)
|
||||
self.scratch.refinenet3 = _make_fusion_block(features, use_bn)
|
||||
self.scratch.refinenet4 = _make_fusion_block(features, use_bn)
|
||||
|
||||
head_features_1 = features
|
||||
head_features_2 = 32
|
||||
|
||||
if nclass > 1:
|
||||
self.scratch.output_conv = nn.Sequential(
|
||||
nn.Conv2d(head_features_1, head_features_1, kernel_size=3, stride=1, padding=1),
|
||||
nn.ReLU(True),
|
||||
nn.Conv2d(head_features_1, nclass, kernel_size=1, stride=1, padding=0),
|
||||
)
|
||||
else:
|
||||
self.scratch.output_conv1 = nn.Conv2d(
|
||||
head_features_1, head_features_1 // 2, kernel_size=3, stride=1, padding=1
|
||||
)
|
||||
|
||||
self.scratch.output_conv2 = nn.Sequential(
|
||||
nn.Conv2d(head_features_1 // 2, head_features_2, kernel_size=3, stride=1, padding=1),
|
||||
nn.ReLU(True),
|
||||
nn.Conv2d(head_features_2, 1, kernel_size=1, stride=1, padding=0),
|
||||
nn.ReLU(True),
|
||||
nn.Identity(),
|
||||
)
|
||||
|
||||
def forward(self, out_features, patch_h, patch_w):
|
||||
out = []
|
||||
for i, x in enumerate(out_features):
|
||||
if self.use_clstoken:
|
||||
x, cls_token = x[0], x[1]
|
||||
readout = cls_token.unsqueeze(1).expand_as(x)
|
||||
x = self.readout_projects[i](torch.cat((x, readout), -1))
|
||||
else:
|
||||
x = x[0]
|
||||
|
||||
x = x.permute(0, 2, 1).reshape((x.shape[0], x.shape[-1], patch_h, patch_w))
|
||||
|
||||
x = self.projects[i](x)
|
||||
x = self.resize_layers[i](x)
|
||||
|
||||
out.append(x)
|
||||
|
||||
layer_1, layer_2, layer_3, layer_4 = out
|
||||
|
||||
layer_1_rn = self.scratch.layer1_rn(layer_1)
|
||||
layer_2_rn = self.scratch.layer2_rn(layer_2)
|
||||
layer_3_rn = self.scratch.layer3_rn(layer_3)
|
||||
layer_4_rn = self.scratch.layer4_rn(layer_4)
|
||||
|
||||
path_4 = self.scratch.refinenet4(layer_4_rn, size=layer_3_rn.shape[2:])
|
||||
path_3 = self.scratch.refinenet3(path_4, layer_3_rn, size=layer_2_rn.shape[2:])
|
||||
path_2 = self.scratch.refinenet2(path_3, layer_2_rn, size=layer_1_rn.shape[2:])
|
||||
path_1 = self.scratch.refinenet1(path_2, layer_1_rn)
|
||||
|
||||
out = self.scratch.output_conv1(path_1)
|
||||
out = F.interpolate(out, (int(patch_h * 14), int(patch_w * 14)), mode="bilinear", align_corners=True)
|
||||
out = self.scratch.output_conv2(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class DPT_DINOv2(nn.Module):
|
||||
def __init__(
|
||||
self,
|
||||
features,
|
||||
out_channels,
|
||||
encoder="vitl",
|
||||
use_bn=False,
|
||||
use_clstoken=False,
|
||||
):
|
||||
super(DPT_DINOv2, self).__init__()
|
||||
|
||||
assert encoder in ["vits", "vitb", "vitl"]
|
||||
|
||||
# # in case the Internet connection is not stable, please load the DINOv2 locally
|
||||
# if use_local:
|
||||
# self.pretrained = torch.hub.load(
|
||||
# torchhub_path / "facebookresearch_dinov2_main",
|
||||
# "dinov2_{:}14".format(encoder),
|
||||
# source="local",
|
||||
# pretrained=False,
|
||||
# )
|
||||
# else:
|
||||
# self.pretrained = torch.hub.load(
|
||||
# "facebookresearch/dinov2",
|
||||
# "dinov2_{:}14".format(encoder),
|
||||
# )
|
||||
|
||||
self.pretrained = torch.hub.load(
|
||||
"facebookresearch/dinov2",
|
||||
"dinov2_{:}14".format(encoder),
|
||||
)
|
||||
|
||||
dim = self.pretrained.blocks[0].attn.qkv.in_features
|
||||
|
||||
self.depth_head = DPTHead(1, dim, features, out_channels=out_channels, use_bn=use_bn, use_clstoken=use_clstoken)
|
||||
|
||||
def forward(self, x):
|
||||
h, w = x.shape[-2:]
|
||||
|
||||
features = self.pretrained.get_intermediate_layers(x, 4, return_class_token=True)
|
||||
|
||||
patch_h, patch_w = h // 14, w // 14
|
||||
|
||||
depth = self.depth_head(features, patch_h, patch_w)
|
||||
depth = F.interpolate(depth, size=(h, w), mode="bilinear", align_corners=True)
|
||||
depth = F.relu(depth)
|
||||
|
||||
return depth.squeeze(1)
|
227
invokeai/backend/image_util/depth_anything/utilities/util.py
Normal file
227
invokeai/backend/image_util/depth_anything/utilities/util.py
Normal file
@ -0,0 +1,227 @@
|
||||
import math
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
|
||||
def apply_min_size(sample, size, image_interpolation_method=cv2.INTER_AREA):
|
||||
"""Rezise the sample to ensure the given size. Keeps aspect ratio.
|
||||
|
||||
Args:
|
||||
sample (dict): sample
|
||||
size (tuple): image size
|
||||
|
||||
Returns:
|
||||
tuple: new size
|
||||
"""
|
||||
shape = list(sample["disparity"].shape)
|
||||
|
||||
if shape[0] >= size[0] and shape[1] >= size[1]:
|
||||
return sample
|
||||
|
||||
scale = [0, 0]
|
||||
scale[0] = size[0] / shape[0]
|
||||
scale[1] = size[1] / shape[1]
|
||||
|
||||
scale = max(scale)
|
||||
|
||||
shape[0] = math.ceil(scale * shape[0])
|
||||
shape[1] = math.ceil(scale * shape[1])
|
||||
|
||||
# resize
|
||||
sample["image"] = cv2.resize(sample["image"], tuple(shape[::-1]), interpolation=image_interpolation_method)
|
||||
|
||||
sample["disparity"] = cv2.resize(sample["disparity"], tuple(shape[::-1]), interpolation=cv2.INTER_NEAREST)
|
||||
sample["mask"] = cv2.resize(
|
||||
sample["mask"].astype(np.float32),
|
||||
tuple(shape[::-1]),
|
||||
interpolation=cv2.INTER_NEAREST,
|
||||
)
|
||||
sample["mask"] = sample["mask"].astype(bool)
|
||||
|
||||
return tuple(shape)
|
||||
|
||||
|
||||
class Resize(object):
|
||||
"""Resize sample to given size (width, height)."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
width,
|
||||
height,
|
||||
resize_target=True,
|
||||
keep_aspect_ratio=False,
|
||||
ensure_multiple_of=1,
|
||||
resize_method="lower_bound",
|
||||
image_interpolation_method=cv2.INTER_AREA,
|
||||
):
|
||||
"""Init.
|
||||
|
||||
Args:
|
||||
width (int): desired output width
|
||||
height (int): desired output height
|
||||
resize_target (bool, optional):
|
||||
True: Resize the full sample (image, mask, target).
|
||||
False: Resize image only.
|
||||
Defaults to True.
|
||||
keep_aspect_ratio (bool, optional):
|
||||
True: Keep the aspect ratio of the input sample.
|
||||
Output sample might not have the given width and height, and
|
||||
resize behaviour depends on the parameter 'resize_method'.
|
||||
Defaults to False.
|
||||
ensure_multiple_of (int, optional):
|
||||
Output width and height is constrained to be multiple of this parameter.
|
||||
Defaults to 1.
|
||||
resize_method (str, optional):
|
||||
"lower_bound": Output will be at least as large as the given size.
|
||||
"upper_bound": Output will be at max as large as the given size. (Output size might be smaller
|
||||
than given size.)
|
||||
"minimal": Scale as least as possible. (Output size might be smaller than given size.)
|
||||
Defaults to "lower_bound".
|
||||
"""
|
||||
self.__width = width
|
||||
self.__height = height
|
||||
|
||||
self.__resize_target = resize_target
|
||||
self.__keep_aspect_ratio = keep_aspect_ratio
|
||||
self.__multiple_of = ensure_multiple_of
|
||||
self.__resize_method = resize_method
|
||||
self.__image_interpolation_method = image_interpolation_method
|
||||
|
||||
def constrain_to_multiple_of(self, x, min_val=0, max_val=None):
|
||||
y = (np.round(x / self.__multiple_of) * self.__multiple_of).astype(int)
|
||||
|
||||
if max_val is not None and y > max_val:
|
||||
y = (np.floor(x / self.__multiple_of) * self.__multiple_of).astype(int)
|
||||
|
||||
if y < min_val:
|
||||
y = (np.ceil(x / self.__multiple_of) * self.__multiple_of).astype(int)
|
||||
|
||||
return y
|
||||
|
||||
def get_size(self, width, height):
|
||||
# determine new height and width
|
||||
scale_height = self.__height / height
|
||||
scale_width = self.__width / width
|
||||
|
||||
if self.__keep_aspect_ratio:
|
||||
if self.__resize_method == "lower_bound":
|
||||
# scale such that output size is lower bound
|
||||
if scale_width > scale_height:
|
||||
# fit width
|
||||
scale_height = scale_width
|
||||
else:
|
||||
# fit height
|
||||
scale_width = scale_height
|
||||
elif self.__resize_method == "upper_bound":
|
||||
# scale such that output size is upper bound
|
||||
if scale_width < scale_height:
|
||||
# fit width
|
||||
scale_height = scale_width
|
||||
else:
|
||||
# fit height
|
||||
scale_width = scale_height
|
||||
elif self.__resize_method == "minimal":
|
||||
# scale as least as possbile
|
||||
if abs(1 - scale_width) < abs(1 - scale_height):
|
||||
# fit width
|
||||
scale_height = scale_width
|
||||
else:
|
||||
# fit height
|
||||
scale_width = scale_height
|
||||
else:
|
||||
raise ValueError(f"resize_method {self.__resize_method} not implemented")
|
||||
|
||||
if self.__resize_method == "lower_bound":
|
||||
new_height = self.constrain_to_multiple_of(scale_height * height, min_val=self.__height)
|
||||
new_width = self.constrain_to_multiple_of(scale_width * width, min_val=self.__width)
|
||||
elif self.__resize_method == "upper_bound":
|
||||
new_height = self.constrain_to_multiple_of(scale_height * height, max_val=self.__height)
|
||||
new_width = self.constrain_to_multiple_of(scale_width * width, max_val=self.__width)
|
||||
elif self.__resize_method == "minimal":
|
||||
new_height = self.constrain_to_multiple_of(scale_height * height)
|
||||
new_width = self.constrain_to_multiple_of(scale_width * width)
|
||||
else:
|
||||
raise ValueError(f"resize_method {self.__resize_method} not implemented")
|
||||
|
||||
return (new_width, new_height)
|
||||
|
||||
def __call__(self, sample):
|
||||
width, height = self.get_size(sample["image"].shape[1], sample["image"].shape[0])
|
||||
|
||||
# resize sample
|
||||
sample["image"] = cv2.resize(
|
||||
sample["image"],
|
||||
(width, height),
|
||||
interpolation=self.__image_interpolation_method,
|
||||
)
|
||||
|
||||
if self.__resize_target:
|
||||
if "disparity" in sample:
|
||||
sample["disparity"] = cv2.resize(
|
||||
sample["disparity"],
|
||||
(width, height),
|
||||
interpolation=cv2.INTER_NEAREST,
|
||||
)
|
||||
|
||||
if "depth" in sample:
|
||||
sample["depth"] = cv2.resize(sample["depth"], (width, height), interpolation=cv2.INTER_NEAREST)
|
||||
|
||||
if "semseg_mask" in sample:
|
||||
# sample["semseg_mask"] = cv2.resize(
|
||||
# sample["semseg_mask"], (width, height), interpolation=cv2.INTER_NEAREST
|
||||
# )
|
||||
sample["semseg_mask"] = F.interpolate(
|
||||
torch.from_numpy(sample["semseg_mask"]).float()[None, None, ...], (height, width), mode="nearest"
|
||||
).numpy()[0, 0]
|
||||
|
||||
if "mask" in sample:
|
||||
sample["mask"] = cv2.resize(
|
||||
sample["mask"].astype(np.float32),
|
||||
(width, height),
|
||||
interpolation=cv2.INTER_NEAREST,
|
||||
)
|
||||
# sample["mask"] = sample["mask"].astype(bool)
|
||||
|
||||
# print(sample['image'].shape, sample['depth'].shape)
|
||||
return sample
|
||||
|
||||
|
||||
class NormalizeImage(object):
|
||||
"""Normlize image by given mean and std."""
|
||||
|
||||
def __init__(self, mean, std):
|
||||
self.__mean = mean
|
||||
self.__std = std
|
||||
|
||||
def __call__(self, sample):
|
||||
sample["image"] = (sample["image"] - self.__mean) / self.__std
|
||||
|
||||
return sample
|
||||
|
||||
|
||||
class PrepareForNet(object):
|
||||
"""Prepare sample for usage as network input."""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __call__(self, sample):
|
||||
image = np.transpose(sample["image"], (2, 0, 1))
|
||||
sample["image"] = np.ascontiguousarray(image).astype(np.float32)
|
||||
|
||||
if "mask" in sample:
|
||||
sample["mask"] = sample["mask"].astype(np.float32)
|
||||
sample["mask"] = np.ascontiguousarray(sample["mask"])
|
||||
|
||||
if "depth" in sample:
|
||||
depth = sample["depth"].astype(np.float32)
|
||||
sample["depth"] = np.ascontiguousarray(depth)
|
||||
|
||||
if "semseg_mask" in sample:
|
||||
sample["semseg_mask"] = sample["semseg_mask"].astype(np.float32)
|
||||
sample["semseg_mask"] = np.ascontiguousarray(sample["semseg_mask"])
|
||||
|
||||
return sample
|
@ -113,7 +113,7 @@ class ModelPatcher:
|
||||
for layer_key, layer in lora.layers.items():
|
||||
if not layer_key.startswith(prefix):
|
||||
continue
|
||||
print("test")
|
||||
|
||||
# TODO(ryand): A non-negligible amount of time is currently spent resolving LoRA keys. This
|
||||
# should be improved in the following ways:
|
||||
# 1. The key mapping could be more-efficiently pre-computed. This would save time every time a
|
||||
|
@ -6,7 +6,6 @@ import { Provider } from 'react-redux';
|
||||
import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider';
|
||||
import { $baseUrl } from '../src/app/store/nanostores/baseUrl';
|
||||
import { createStore } from '../src/app/store/store';
|
||||
import { Container } from '@chakra-ui/react';
|
||||
// TODO: Disabled for IDE performance issues with our translation JSON
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
|
@ -1,79 +1,51 @@
|
||||
# InvokeAI Web UI
|
||||
# Invoke UI
|
||||
|
||||
<!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=false} -->
|
||||
|
||||
<!-- code_chunk_output -->
|
||||
|
||||
- [InvokeAI Web UI](#invokeai-web-ui)
|
||||
- [Invoke UI](#invoke-ui)
|
||||
- [Core Libraries](#core-libraries)
|
||||
- [Redux Toolkit](#redux-toolkit)
|
||||
- [Socket\.IO](#socketio)
|
||||
- [Chakra UI](#chakra-ui)
|
||||
- [KonvaJS](#konvajs)
|
||||
- [Vite](#vite)
|
||||
- [i18next & Weblate](#i18next--weblate)
|
||||
- [openapi-typescript](#openapi-typescript)
|
||||
- [reactflow](#reactflow)
|
||||
- [zod](#zod)
|
||||
- [Client Types Generation](#client-types-generation)
|
||||
- [Package Scripts](#package-scripts)
|
||||
- [Client Types Generation](#client-types-generation)
|
||||
- [Contributing](#contributing)
|
||||
- [Localization](#localization)
|
||||
- [Dev Environment](#dev-environment)
|
||||
- [VSCode Remote Dev](#vscode-remote-dev)
|
||||
- [Production builds](#production-builds)
|
||||
- [VSCode Remote Dev](#vscode-remote-dev)
|
||||
|
||||
<!-- /code_chunk_output -->
|
||||
|
||||
The UI is a fairly straightforward Typescript React app.
|
||||
|
||||
## Core Libraries
|
||||
|
||||
InvokeAI's UI is made possible by a number of excellent open-source libraries. The most heavily-used are listed below, but there are many others.
|
||||
Invoke's UI is made possible by a number of excellent open-source libraries. The most heavily-used are listed below, but there are many others.
|
||||
|
||||
### Redux Toolkit
|
||||
- [Redux Toolkit]
|
||||
- [redux-remember]
|
||||
- [Socket.IO]
|
||||
- [Chakra UI]
|
||||
- [KonvaJS]
|
||||
- [Vite]
|
||||
- [openapi-typescript]
|
||||
- [reactflow]
|
||||
- [zod]
|
||||
|
||||
[Redux Toolkit] is used for state management and fetching/caching:
|
||||
## Package Scripts
|
||||
|
||||
- `RTK-Query` for data fetching and caching
|
||||
- `createAsyncThunk` for a couple other HTTP requests
|
||||
- `createEntityAdapter` to normalize things like images and models
|
||||
- `createListenerMiddleware` for async workflows
|
||||
See `package.json` for all scripts.
|
||||
|
||||
We use [redux-remember] for persistence.
|
||||
Run with `pnpm <script name>`.
|
||||
|
||||
### Socket\.IO
|
||||
- `dev`: run the frontend in dev mode, enabling hot reloading
|
||||
- `build`: run all checks (madge, eslint, prettier, tsc) and then build the frontend
|
||||
- `typegen`: generate types from the OpenAPI schema (see [Client Types Generation])
|
||||
- `lint:madge`: check frontend for circular dependencies
|
||||
- `lint:eslint`: check frontend for code quality
|
||||
- `lint:prettier`: check frontend for code formatting
|
||||
- `lint:tsc`: check frontend for type issues
|
||||
- `lint`: run all checks concurrently
|
||||
- `fix`: run `eslint` and `prettier`, fixing fixable issues
|
||||
|
||||
[Socket.IO] is used for server-to-client events, like generation process and queue state changes.
|
||||
|
||||
### Chakra UI
|
||||
|
||||
[Chakra UI] is our primary UI library, but we also use a few components from [Mantine v6].
|
||||
|
||||
### KonvaJS
|
||||
|
||||
[KonvaJS] powers the canvas. In the future, we'd like to explore [PixiJS] or WebGPU.
|
||||
|
||||
### Vite
|
||||
|
||||
[Vite] is our bundler.
|
||||
|
||||
### i18next & Weblate
|
||||
|
||||
We use [i18next] for localization, but translation to languages other than English happens on our [Weblate] project. **Only the English source strings should be changed on this repo.**
|
||||
|
||||
### openapi-typescript
|
||||
|
||||
[openapi-typescript] is used to generate types from the server's OpenAPI schema. See TYPES_CODEGEN.md.
|
||||
|
||||
### reactflow
|
||||
|
||||
[reactflow] powers the Workflow Editor.
|
||||
|
||||
### zod
|
||||
|
||||
[zod] schemas are used to model data structures and provide runtime validation.
|
||||
|
||||
## Client Types Generation
|
||||
### Client Types Generation
|
||||
|
||||
We use [openapi-typescript] to generate types from the app's OpenAPI schema.
|
||||
|
||||
@ -88,28 +60,18 @@ python scripts/invokeai-web.py
|
||||
pnpm typegen
|
||||
```
|
||||
|
||||
## Package Scripts
|
||||
|
||||
See `package.json` for all scripts.
|
||||
|
||||
Run with `pnpm <script name>`.
|
||||
|
||||
- `dev`: run the frontend in dev mode, enabling hot reloading
|
||||
- `build`: run all checks (madge, eslint, prettier, tsc) and then build the frontend
|
||||
- `typegen`: generate types from the OpenAPI schema (see [Client Types Generation](#client-types-generation))
|
||||
- `lint:madge`: check frontend for circular dependencies
|
||||
- `lint:eslint`: check frontend for code quality
|
||||
- `lint:prettier`: check frontend for code formatting
|
||||
- `lint:tsc`: check frontend for type issues
|
||||
- `lint`: run all checks concurrently
|
||||
- `fix`: run `eslint` and `prettier`, fixing fixable issues
|
||||
|
||||
## Contributing
|
||||
|
||||
Thanks for your interest in contributing to the InvokeAI Web UI!
|
||||
Thanks for your interest in contributing to the Invoke Web UI!
|
||||
|
||||
We encourage you to ping @psychedelicious and @blessedcoolant on [discord] if you want to contribute, just to touch base and ensure your work doesn't conflict with anything else going on. The project is very active.
|
||||
|
||||
### Localization
|
||||
|
||||
We use [i18next] for localization, but translation to languages other than English happens on our [Weblate] project.
|
||||
|
||||
**Only the English source strings should be changed on this repo.**
|
||||
|
||||
### Dev Environment
|
||||
|
||||
Install [node] and [pnpm].
|
||||
@ -118,23 +80,19 @@ From `invokeai/frontend/web/` run `pnpm i` to get everything set up.
|
||||
|
||||
Start everything in dev mode:
|
||||
|
||||
1. Start the dev server: `pnpm dev`
|
||||
2. Start the InvokeAI Nodes backend: `python scripts/invokeai-web.py # run from the repo root`
|
||||
1. From `invokeai/frontend/web/`: `pnpm dev`
|
||||
2. From repo root: `python scripts/invokeai-web.py`
|
||||
3. Point your browser to the dev server address e.g. <http://localhost:5173/>
|
||||
|
||||
#### VSCode Remote Dev
|
||||
### VSCode Remote Dev
|
||||
|
||||
We've noticed an intermittent issue with the VSCode Remote Dev port forwarding. If you use this feature of VSCode, you may intermittently click the Invoke button and then get nothing until the request times out. Suggest disabling the IDE's port forwarding feature and doing it manually via SSH:
|
||||
We've noticed an intermittent issue with the VSCode Remote Dev port forwarding. If you use this feature of VSCode, you may intermittently click the Invoke button and then get nothing until the request times out.
|
||||
|
||||
`ssh -L 9090:localhost:9090 -L 5173:localhost:5173 user@host`
|
||||
We suggest disabling the IDE's port forwarding feature and doing it manually via SSH:
|
||||
|
||||
### Production builds
|
||||
|
||||
For a number of technical and logistical reasons, we need to commit UI build artefacts to the repo.
|
||||
|
||||
If you submit a PR, there is a good chance we will ask you to include a separate commit with a build of the app.
|
||||
|
||||
To build for production, run `pnpm build`.
|
||||
```sh
|
||||
ssh -L 9090:localhost:9090 -L 5173:localhost:5173 user@host
|
||||
```
|
||||
|
||||
[node]: https://nodejs.org/en/download/
|
||||
[pnpm]: https://github.com/pnpm/pnpm
|
||||
@ -143,12 +101,11 @@ To build for production, run `pnpm build`.
|
||||
[redux-remember]: https://github.com/zewish/redux-remember
|
||||
[Socket.IO]: https://github.com/socketio/socket.io
|
||||
[Chakra UI]: https://github.com/chakra-ui/chakra-ui
|
||||
[Mantine v6]: https://v6.mantine.dev/
|
||||
[KonvaJS]: https://github.com/konvajs/react-konva
|
||||
[PixiJS]: https://github.com/pixijs/pixijs
|
||||
[Vite]: https://github.com/vitejs/vite
|
||||
[i18next]: https://github.com/i18next/react-i18next
|
||||
[Weblate]: https://hosted.weblate.org/engage/invokeai/
|
||||
[openapi-typescript]: https://github.com/drwpow/openapi-typescript
|
||||
[reactflow]: https://github.com/xyflow/xyflow
|
||||
[zod]: https://github.com/colinhacks/zod
|
||||
[Client Types Generation]: #client-types-generation
|
||||
|
@ -23,7 +23,7 @@
|
||||
- [Primitive Types](#primitive-types)
|
||||
- [Complex Types](#complex-types)
|
||||
- [Collection Types](#collection-types)
|
||||
- [Polymorphic Types](#polymorphic-types)
|
||||
- [Collection or Scalar Types](#collection-or-scalar-types)
|
||||
- [Optional Fields](#optional-fields)
|
||||
- [Building Field Input Templates](#building-field-input-templates)
|
||||
- [Building Field Output Templates](#building-field-output-templates)
|
||||
|
@ -20,7 +20,6 @@
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "concurrently \"vite dev\" \"pnpm run theme:watch\"",
|
||||
"hi": "echo test",
|
||||
"dev:host": "concurrently \"vite dev --host\" \"pnpm run theme:watch\"",
|
||||
"build": "pnpm run lint && vite build",
|
||||
"typegen": "node scripts/typegen.js",
|
||||
@ -53,21 +52,12 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@chakra-ui/anatomy": "^2.2.2",
|
||||
"@chakra-ui/icons": "^2.1.1",
|
||||
"@chakra-ui/layout": "^2.3.1",
|
||||
"@chakra-ui/portal": "^2.1.0",
|
||||
"@chakra-ui/react": "^2.8.2",
|
||||
"@chakra-ui/react-use-size": "^2.1.0",
|
||||
"@chakra-ui/styled-system": "^2.9.2",
|
||||
"@chakra-ui/theme-tools": "^2.1.2",
|
||||
"@dagrejs/graphlib": "^2.1.13",
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@emotion/react": "^11.11.3",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@fontsource-variable/inter": "^5.0.16",
|
||||
"@invoke-ai/ui": "0.0.10",
|
||||
"@invoke-ai/ui": "0.0.13",
|
||||
"@mantine/form": "6.0.21",
|
||||
"@nanostores/react": "^0.7.1",
|
||||
"@reduxjs/toolkit": "2.0.1",
|
||||
|
736
invokeai/frontend/web/pnpm-lock.yaml
generated
736
invokeai/frontend/web/pnpm-lock.yaml
generated
@ -10,30 +10,12 @@ patchedDependencies:
|
||||
path: patches/reselect@5.0.1.patch
|
||||
|
||||
dependencies:
|
||||
'@chakra-ui/anatomy':
|
||||
specifier: ^2.2.2
|
||||
version: 2.2.2
|
||||
'@chakra-ui/icons':
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0)
|
||||
'@chakra-ui/layout':
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0)
|
||||
'@chakra-ui/portal':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(react-dom@18.2.0)(react@18.2.0)
|
||||
'@chakra-ui/react':
|
||||
specifier: ^2.8.2
|
||||
version: 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@10.18.0)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@chakra-ui/react-use-size':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(react@18.2.0)
|
||||
'@chakra-ui/styled-system':
|
||||
specifier: ^2.9.2
|
||||
version: 2.9.2
|
||||
'@chakra-ui/theme-tools':
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2(@chakra-ui/styled-system@2.9.2)
|
||||
'@dagrejs/graphlib':
|
||||
specifier: ^2.1.13
|
||||
version: 2.1.13
|
||||
@ -43,18 +25,12 @@ dependencies:
|
||||
'@dnd-kit/utilities':
|
||||
specifier: ^3.2.2
|
||||
version: 3.2.2(react@18.2.0)
|
||||
'@emotion/react':
|
||||
specifier: ^11.11.3
|
||||
version: 11.11.3(@types/react@18.2.48)(react@18.2.0)
|
||||
'@emotion/styled':
|
||||
specifier: ^11.11.0
|
||||
version: 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.48)(react@18.2.0)
|
||||
'@fontsource-variable/inter':
|
||||
specifier: ^5.0.16
|
||||
version: 5.0.16
|
||||
'@invoke-ai/ui':
|
||||
specifier: 0.0.10
|
||||
version: 0.0.10(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0)
|
||||
specifier: 0.0.13
|
||||
version: 0.0.13(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mantine/form':
|
||||
specifier: 6.0.21
|
||||
version: 6.0.21(react@18.2.0)
|
||||
@ -356,6 +332,92 @@ packages:
|
||||
'@jridgewell/trace-mapping': 0.3.21
|
||||
dev: true
|
||||
|
||||
/@ark-ui/anatomy@1.3.0(@internationalized/date@3.5.1):
|
||||
resolution: {integrity: sha512-1yG2MrzUlix6KthjQMCNiHnkXrWwEdFAX6D+HqGJaNu0XvaGul2J+wDNtjsdX+gxiWu1nXXEEOAWlFVYMUf65w==}
|
||||
dependencies:
|
||||
'@zag-js/accordion': 0.32.1
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/avatar': 0.32.1
|
||||
'@zag-js/carousel': 0.32.1
|
||||
'@zag-js/checkbox': 0.32.1
|
||||
'@zag-js/color-picker': 0.32.1
|
||||
'@zag-js/color-utils': 0.32.1
|
||||
'@zag-js/combobox': 0.32.1
|
||||
'@zag-js/date-picker': 0.32.1
|
||||
'@zag-js/date-utils': 0.32.1(@internationalized/date@3.5.1)
|
||||
'@zag-js/dialog': 0.32.1
|
||||
'@zag-js/editable': 0.32.1
|
||||
'@zag-js/file-upload': 0.32.1
|
||||
'@zag-js/hover-card': 0.32.1
|
||||
'@zag-js/menu': 0.32.1
|
||||
'@zag-js/number-input': 0.32.1
|
||||
'@zag-js/pagination': 0.32.1
|
||||
'@zag-js/pin-input': 0.32.1
|
||||
'@zag-js/popover': 0.32.1
|
||||
'@zag-js/presence': 0.32.1
|
||||
'@zag-js/progress': 0.32.1
|
||||
'@zag-js/radio-group': 0.32.1
|
||||
'@zag-js/rating-group': 0.32.1
|
||||
'@zag-js/select': 0.32.1
|
||||
'@zag-js/slider': 0.32.1
|
||||
'@zag-js/splitter': 0.32.1
|
||||
'@zag-js/switch': 0.32.1
|
||||
'@zag-js/tabs': 0.32.1
|
||||
'@zag-js/tags-input': 0.32.1
|
||||
'@zag-js/toast': 0.32.1
|
||||
'@zag-js/toggle-group': 0.32.1
|
||||
'@zag-js/tooltip': 0.32.1
|
||||
transitivePeerDependencies:
|
||||
- '@internationalized/date'
|
||||
dev: false
|
||||
|
||||
/@ark-ui/react@1.3.0(@internationalized/date@3.5.1)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-JHjNoIX50+mUCTaEGMjfGQWGGi31pKsV646jZJlR/1xohpYJigzg8BvO97cTsVk8fwtur+cm11gz3Nf7f5QUnA==}
|
||||
peerDependencies:
|
||||
react: '>=18.0.0'
|
||||
react-dom: '>=18.0.0'
|
||||
dependencies:
|
||||
'@ark-ui/anatomy': 1.3.0(@internationalized/date@3.5.1)
|
||||
'@zag-js/accordion': 0.32.1
|
||||
'@zag-js/avatar': 0.32.1
|
||||
'@zag-js/carousel': 0.32.1
|
||||
'@zag-js/checkbox': 0.32.1
|
||||
'@zag-js/color-picker': 0.32.1
|
||||
'@zag-js/color-utils': 0.32.1
|
||||
'@zag-js/combobox': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/date-picker': 0.32.1
|
||||
'@zag-js/date-utils': 0.32.1(@internationalized/date@3.5.1)
|
||||
'@zag-js/dialog': 0.32.1
|
||||
'@zag-js/editable': 0.32.1
|
||||
'@zag-js/file-upload': 0.32.1
|
||||
'@zag-js/hover-card': 0.32.1
|
||||
'@zag-js/menu': 0.32.1
|
||||
'@zag-js/number-input': 0.32.1
|
||||
'@zag-js/pagination': 0.32.1
|
||||
'@zag-js/pin-input': 0.32.1
|
||||
'@zag-js/popover': 0.32.1
|
||||
'@zag-js/presence': 0.32.1
|
||||
'@zag-js/progress': 0.32.1
|
||||
'@zag-js/radio-group': 0.32.1
|
||||
'@zag-js/rating-group': 0.32.1
|
||||
'@zag-js/react': 0.32.1(react-dom@18.2.0)(react@18.2.0)
|
||||
'@zag-js/select': 0.32.1
|
||||
'@zag-js/slider': 0.32.1
|
||||
'@zag-js/splitter': 0.32.1
|
||||
'@zag-js/switch': 0.32.1
|
||||
'@zag-js/tabs': 0.32.1
|
||||
'@zag-js/tags-input': 0.32.1
|
||||
'@zag-js/toast': 0.32.1
|
||||
'@zag-js/toggle-group': 0.32.1
|
||||
'@zag-js/tooltip': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@internationalized/date'
|
||||
dev: false
|
||||
|
||||
/@arthurgeron/eslint-plugin-react-usememo@2.2.3:
|
||||
resolution: {integrity: sha512-YJG+8hULmhHAxztaANswpa9hWNqEOSvbZcbd6R/JQzyNlEZ49Xh97kqZGuJGZ74rrmULckEO1m3Jh5ctqrGA2A==}
|
||||
dependencies:
|
||||
@ -2940,7 +3002,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@babel/runtime': 7.23.8
|
||||
'@emotion/babel-plugin': 11.11.0
|
||||
'@emotion/is-prop-valid': 1.2.1
|
||||
'@emotion/react': 11.11.3(@types/react@18.2.48)(react@18.2.0)
|
||||
@ -3629,7 +3691,6 @@ packages:
|
||||
resolution: {integrity: sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==}
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.1
|
||||
dev: true
|
||||
|
||||
/@floating-ui/dom@1.5.3:
|
||||
resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==}
|
||||
@ -3643,7 +3704,6 @@ packages:
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.5.3
|
||||
'@floating-ui/utils': 0.2.1
|
||||
dev: true
|
||||
|
||||
/@floating-ui/react-dom@2.0.6(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-IB8aCRFxr8nFkdYZgH+Otd9EVQPJoynxeFRGTB8voPoZMRWo8XjYuCRgpI1btvuKY69XMiLnW+ym7zoBHM90Rw==}
|
||||
@ -3662,7 +3722,6 @@ packages:
|
||||
|
||||
/@floating-ui/utils@0.2.1:
|
||||
resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==}
|
||||
dev: true
|
||||
|
||||
/@fontsource-variable/inter@5.0.16:
|
||||
resolution: {integrity: sha512-k+BUNqksTL+AN+o+OV7ILeiE9B5M5X+/jA7LWvCwjbV9ovXTqZyKRhA/x7uYv/ml8WQ0XNLBM7cRFIx4jW0/hg==}
|
||||
@ -3688,31 +3747,26 @@ packages:
|
||||
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
||||
dev: true
|
||||
|
||||
/@invoke-ai/ui@0.0.10(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-e3cX3g1xap57mkMfjsNznN6V9YS8qUTpSiyjSSr80HEsD3NjXxCoL+Ik6y/Na/KwXgcK00jM6H+xF6ahJFobvw==}
|
||||
/@internationalized/date@3.5.1:
|
||||
resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==}
|
||||
dependencies:
|
||||
'@swc/helpers': 0.5.3
|
||||
dev: false
|
||||
|
||||
/@internationalized/number@3.5.0:
|
||||
resolution: {integrity: sha512-ZY1BW8HT9WKYvaubbuqXbbDdHhOUMfE2zHHFJeTppid0S+pc8HtdIxFxaYMsGjCb4UsF+MEJ4n2TfU7iHnUK8w==}
|
||||
dependencies:
|
||||
'@swc/helpers': 0.5.3
|
||||
dev: false
|
||||
|
||||
/@invoke-ai/ui@0.0.13(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-X4Txij2dMnzPUXTPhorBHezByJQ/ceyHxCM+zZ0gpFsSyXUieOFWjaSu+dAVpghS9y0dxFQGayHvNyX6VsX/PA==}
|
||||
peerDependencies:
|
||||
'@chakra-ui/anatomy': ^2.2.2
|
||||
'@chakra-ui/icons': ^2.1.1
|
||||
'@chakra-ui/layout': ^2.3.1
|
||||
'@chakra-ui/portal': ^2.1.0
|
||||
'@chakra-ui/react': ^2.8.2
|
||||
'@chakra-ui/styled-system': ^2.9.2
|
||||
'@chakra-ui/theme-tools': ^2.1.2
|
||||
'@emotion/react': ^11.11.3
|
||||
'@emotion/styled': ^11.11.0
|
||||
'@fontsource-variable/inter': ^5.0.16
|
||||
'@nanostores/react': ^0.7.1
|
||||
chakra-react-select: ^4.7.6
|
||||
framer-motion: ^10.18.0
|
||||
lodash-es: ^4.17.21
|
||||
nanostores: ^0.9.5
|
||||
overlayscrollbars: ^2.4.6
|
||||
overlayscrollbars-react: ^0.5.3
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
react-i18next: ^14.0.0
|
||||
react-select: ^5.8.0
|
||||
dependencies:
|
||||
'@ark-ui/react': 1.3.0(@internationalized/date@3.5.1)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@chakra-ui/anatomy': 2.2.2
|
||||
'@chakra-ui/icons': 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0)
|
||||
'@chakra-ui/layout': 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0)
|
||||
@ -3734,6 +3788,17 @@ packages:
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
react-i18next: 14.0.0(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0)
|
||||
react-select: 5.8.0(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@chakra-ui/form-control'
|
||||
- '@chakra-ui/icon'
|
||||
- '@chakra-ui/media-query'
|
||||
- '@chakra-ui/menu'
|
||||
- '@chakra-ui/spinner'
|
||||
- '@chakra-ui/system'
|
||||
- '@internationalized/date'
|
||||
- '@types/react'
|
||||
- i18next
|
||||
- react-native
|
||||
dev: false
|
||||
|
||||
/@isaacs/cliui@8.0.2:
|
||||
@ -5719,6 +5784,12 @@ packages:
|
||||
resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==}
|
||||
dev: true
|
||||
|
||||
/@swc/helpers@0.5.3:
|
||||
resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@swc/types@0.1.5:
|
||||
resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
|
||||
dev: true
|
||||
@ -6679,20 +6750,567 @@ packages:
|
||||
tslib: 1.14.1
|
||||
dev: true
|
||||
|
||||
/@zag-js/accordion@0.32.1:
|
||||
resolution: {integrity: sha512-16beDVpEhXFQsQRMZLmHFruhGphSprJ5XrRu6+OM2U7aTulo1w3ENUd9uI+mIs4oTVO66lYI4Lp+dFcT2UUIYA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/anatomy@0.32.1:
|
||||
resolution: {integrity: sha512-bR+tfFfkbxwhBzGGjEQG+RUnbeCjMx7tWJxykGnGdVLwAh0wKTQBEfHEOCOQh5qU8RhKUieqemAdvc7oP3Tp4w==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/aria-hidden@0.32.1:
|
||||
resolution: {integrity: sha512-kznwxvUUHDax8Kd7YNVVCzQcwGARTRaZNOcIkw7MTLE8g/pU+C4pYkwR9iqA7/8imGfjYrZfSsQqZRTb4bkS0g==}
|
||||
dependencies:
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/auto-resize@0.32.1:
|
||||
resolution: {integrity: sha512-MO6N5gPs2xDKbFgrakn6LDWv1GgN8uhfwpsqchLJX+EaZVvLIz8cXFD+jDv3RjK+5GRWV4mIF+26SXuHRSt9Ug==}
|
||||
dependencies:
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/avatar@0.32.1:
|
||||
resolution: {integrity: sha512-5P+95pkMX2Na4yljN1etdgYyA+3HPORjWKn0Y3JamkYIAqJwRFO+taEdSm/xcRkuT6aGA3luheUowjt8wZssyA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/mutation-observer': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/carousel@0.32.1:
|
||||
resolution: {integrity: sha512-S7dUrPtiLr42Fa+S3O18kqKVqSu2yuk67bqGDtppIZSaFOugYHK4feBkZqjKw+eF12NVRRVO2j+A40d3MvxbSA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/checkbox@0.32.1:
|
||||
resolution: {integrity: sha512-5reRreGyDZ5IlBNd5m1QrYXCehVIl/pmfKMEcAfad5DcgCaHGv5j76eahxbKln/8TEdwz4eWzBrqNtwSkKL5+w==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/collection@0.32.1:
|
||||
resolution: {integrity: sha512-dAzcVQ/n+xAYoxWB/65/CQinv66RNVuq5ig0fEYszBqP+HjFnOpeGkIrEvP+bFI38hFEViiGtfr6oGAsVByOVQ==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/color-picker@0.32.1:
|
||||
resolution: {integrity: sha512-ov3FC+c2WBYmEGRXWFVb2jih2Ecejj5JqBjDL9iMLBs2KNY9jnpvtH7WnZbijNY+RMDBj+C/DNI7K2NVaamSIA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/color-utils': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/tabbable': 0.32.1
|
||||
'@zag-js/text-selection': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/color-utils@0.32.1:
|
||||
resolution: {integrity: sha512-AzupfOD7oD0mE+H9roTzwnLqtw1wYiJGOQKLPAwdwPQdznJUQD6sMOpxR/6RBuITVTm8Bl12Mr4+7s29LVJruw==}
|
||||
dependencies:
|
||||
'@zag-js/numeric-range': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/combobox@0.32.1:
|
||||
resolution: {integrity: sha512-skz2C5UxLD5JoYNP4hcPaQJu2cW7vycKqjDNI9ZtygSkZHOHx+JxpYiACBnr1vqzXatIOuDQm/HUuWW9yOT4eA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/aria-hidden': 0.32.1
|
||||
'@zag-js/collection': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/mutation-observer': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/core@0.32.1:
|
||||
resolution: {integrity: sha512-F9F7920/CisoLWALQACIhqbMvemgbv86qBULJ+UEe+a/9XgGwPh9UGn/H/q5EWkNpgEapz2b3pl3ONgKmXsK1A==}
|
||||
dependencies:
|
||||
'@zag-js/store': 0.32.1
|
||||
klona: 2.0.6
|
||||
dev: false
|
||||
|
||||
/@zag-js/date-picker@0.32.1:
|
||||
resolution: {integrity: sha512-n/hYmF+/R4+NuyfPRzCgeuLT6LJihKSuKzK29STPWy3sC/tBBHiqhNv1/4UKbatHUJXdBW2XF+N8Rw08RffcFQ==}
|
||||
dependencies:
|
||||
'@internationalized/date': 3.5.1
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/date-utils': 0.32.1(@internationalized/date@3.5.1)
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/live-region': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/text-selection': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/date-utils@0.32.1(@internationalized/date@3.5.1):
|
||||
resolution: {integrity: sha512-dbBDRSVr5pRUw3rXndyGuSshZiWqQI5JQO4D2KIFGkXzorj6WzoOpcO910Z7AdM/9cCAMpCjUrka8d8o9BpJBg==}
|
||||
peerDependencies:
|
||||
'@internationalized/date': '>=3.0.0'
|
||||
dependencies:
|
||||
'@internationalized/date': 3.5.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/dialog@0.32.1:
|
||||
resolution: {integrity: sha512-czp+qXcdAOM70SrvDo4gBpYZx6gS6HXyrpiptW3+EHa2eiCfc/Z2w+Nu+ZadOTEQGgNWlKlCLW7Ery0i9mMDsw==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/aria-hidden': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/remove-scroll': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
focus-trap: 7.5.4
|
||||
dev: false
|
||||
|
||||
/@zag-js/dismissable@0.32.1:
|
||||
resolution: {integrity: sha512-UIkG+9Eb5wrus2F2Dy4zqk0pwCV53sdnMYBxk9dpvDzBJHzW+InhVeg3UeKmPL8ELcYlhH/Bap99XCRJvxsXow==}
|
||||
dependencies:
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/interact-outside': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/dom-event@0.32.1:
|
||||
resolution: {integrity: sha512-wN6f5Kkf7C/YFN3wbEG3gUockSebyy1fPNL2BuL4C8PIP8vOD14hnHTzZWg5yYfO+veybIAL38r8I46C+bOVBQ==}
|
||||
dependencies:
|
||||
'@zag-js/text-selection': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/dom-query@0.16.0:
|
||||
resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/dom-query@0.32.1:
|
||||
resolution: {integrity: sha512-u6hrQHQ0/dcUi6xJn8d2Mu1ClN4KZpPqOKrJFSaxadWjSy+x0qp48WY2CBQ6gZ3j8IwR/XjzU9bu9wY5jJfHgA==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/editable@0.32.1:
|
||||
resolution: {integrity: sha512-QEGnfp2P9nWVp9vGNWtszspvQcF3KtBRToZrv5/DT30Mpo/uPDKtqijLs0SnB/W60ELzcIRhK4J9taGoK8O8uw==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/interact-outside': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/element-rect@0.32.1:
|
||||
resolution: {integrity: sha512-tAmxgxU2LsByK8PIs/Cj6cBJ8xZCVXE9RoStxthhuPL7xKYUfZvFGuhHVOHTHd6sDKEqbj6K1ds/TGPuglIh4w==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/element-size@0.10.5:
|
||||
resolution: {integrity: sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/element-size@0.32.1:
|
||||
resolution: {integrity: sha512-ACklufmJQpah2UqwZUlYFaKi6uWfZBeTghtbfYHcDfzRbg2Hni612v8L1JeS4vAgjeDpcdHQpXXR4AZSpGZgNw==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/file-upload@0.32.1:
|
||||
resolution: {integrity: sha512-cD0NRIDof9Vv2DemmnYe9ZPZxOZ6b8XZl8eq4G0e8+WLYtnRXyEURl8Dw0QJpfdDPQaHnnD4CNxPTQcLgP+9Sg==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/file-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/file-utils@0.32.1:
|
||||
resolution: {integrity: sha512-0PxTrljW51Lf9OCuYNlZuaLgF0v1NoVRzXa/osZ9HGceQjfo77R5G9u+/TP3u53W2PTxajEZ4eNzTibgpzNXFg==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/focus-visible@0.16.0:
|
||||
resolution: {integrity: sha512-a7U/HSopvQbrDU4GLerpqiMcHKEkQkNPeDZJWz38cw/6Upunh41GjHetq5TB84hxyCaDzJ6q2nEdNoBQfC0FKA==}
|
||||
dependencies:
|
||||
'@zag-js/dom-query': 0.16.0
|
||||
dev: false
|
||||
|
||||
/@zag-js/form-utils@0.32.1:
|
||||
resolution: {integrity: sha512-OemLBlHCHHm7t8wNcf78FRudRA7FegSgsNEzAjrRTyx+lJztDyHRLaoyI1gCEIg+0Kzl2nMxjOl4MStGsDj8iw==}
|
||||
dependencies:
|
||||
'@zag-js/mutation-observer': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/hover-card@0.32.1:
|
||||
resolution: {integrity: sha512-k66YK0z0P4LuK78+jnRoUPxJiM9GA0sbEEz3oPlvcFVXMMwnRTPNIw1OjksfAPI+Nvgg7H6D3A+7HCdRI/oBjw==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/interact-outside@0.32.1:
|
||||
resolution: {integrity: sha512-8zHuswfTAgfMCaQnp3N4WStvnL32VyxURafb21+mE4neAF/DaKfJHWnJpeUMG1Qh/eXsrMRBxVoX+nBMhHj9bg==}
|
||||
dependencies:
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/tabbable': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/live-region@0.32.1:
|
||||
resolution: {integrity: sha512-6/9QMLVZbTRh/G6MoJc/auN8r5vjdY9vUgNT680C2LOa2vnRR5/y0DkIpVgttNh1rSenQ/eLEYxp8hQF1rIYNw==}
|
||||
dependencies:
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/menu@0.32.1:
|
||||
resolution: {integrity: sha512-IPsTljVF0N9xTwub1cpGl3GAG5ttAq3h38PdZERREzT3qRgw4v3K/I1TG2vIiDXgJz8UZzUKox6ZYdU7UIAkRA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/mutation-observer': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/rect-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/mutation-observer@0.32.1:
|
||||
resolution: {integrity: sha512-/hlObxGnhAaYYVnwRJC227md0M3kSE6mO24vkqVGwq2GglS+u4zbVcBBUuWgHdMML+ZjIQrZuVycCBMfVlHq0g==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/number-input@0.32.1:
|
||||
resolution: {integrity: sha512-atyIOvoMITb4hZtQym7yD6I7grvPW83UeMFO8hCQg3HWwd2zR4+63mouWuyMoWb4QrzVFRVQBaU8OG5xGlknEw==}
|
||||
dependencies:
|
||||
'@internationalized/number': 3.5.0
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/mutation-observer': 0.32.1
|
||||
'@zag-js/number-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/number-utils@0.32.1:
|
||||
resolution: {integrity: sha512-x/nttU31TtFVTqFBM8e3ZH/0MCc+u15WAfk0rT6ESkoZcdb80rTzZVMokCKCUdpi/JdB1vjEeCLSnj+ig8oAIQ==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/numeric-range@0.32.1:
|
||||
resolution: {integrity: sha512-1Qe2URTenlrdsWuArlnQ+v5bBH2mHZD3XsK6jYV+C2lgatVzdcoN4GCSNTiF7w+So6J+NTeLMkVHMGCW1Kzx1g==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/pagination@0.32.1:
|
||||
resolution: {integrity: sha512-lhogzKxJnx5D2Xoni/xm5rkOuy15KWSxqBHVwe8+j5aSNqMy7+aRtEN2F2VQCDVL/v1fdciQvOCA9udm37kZ4w==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/pin-input@0.32.1:
|
||||
resolution: {integrity: sha512-d18cCXKUr7INL0Xm5KyIoiTRSNsPXfIlIEMl2HrAvM3r70wtEag0PmiDNA5NS2tB4LnnX0XowchGB4HsdFS/ng==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/popover@0.32.1:
|
||||
resolution: {integrity: sha512-B01if49v3crCjkvtSvIX4CBdT/475nj3DttOObc36s0YOxCEt3UihMITBD5JvIKwEqjZ6oU5t0sLcUYOqQ4f2A==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/aria-hidden': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/remove-scroll': 0.32.1
|
||||
'@zag-js/tabbable': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
focus-trap: 7.5.4
|
||||
dev: false
|
||||
|
||||
/@zag-js/popper@0.32.1:
|
||||
resolution: {integrity: sha512-aQgogW1N4VreNACSQhXQoZeXtQQtB//FXUvt1CBnW2DtmZ6YkNnaAfn186Q2lkw2/T0chITRy3eYeviwMmMrqg==}
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.5.4
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/element-rect': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/presence@0.32.1:
|
||||
resolution: {integrity: sha512-8189QMUf/L1dztAZdurx18ZwPyWlq58Mrd+GdATSaf8JstgrI1ovzVs606inQghWptKHMsH7dUIaV9UkhbSx3Q==}
|
||||
dependencies:
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/progress@0.32.1:
|
||||
resolution: {integrity: sha512-ClkQvNYnuIpKfAPUceZXY5E2m/3NnIm21cvHe4gAoJ88YdqEHd5rIRoHP63g8ET8Ct/2KkBRkgR+LrQnGQOomA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/radio-group@0.32.1:
|
||||
resolution: {integrity: sha512-NvdSjwRF38qIh0oM68jERf71uiwV2JFTrGeQEs3EIqONzULwL6jR2p4P1wm3JJNBAkSYBKZMER5cVUUcqM3kjQ==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/element-rect': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/rating-group@0.32.1:
|
||||
resolution: {integrity: sha512-RBaFRCw7P00bgTrEjUHT3h/OGRO8XmXKkQYqqhm1tsVbeTsT47iwHoc6XnMEiGBonaJDwN/J0oFasw7GNg5sow==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/react@0.32.1(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-b1SB7hXXv1K6CmXkcy5Y7mb0YRWkyvulyhK8VW5O5hIAPuGxOTx70psmVeZbmVzhjdORCiro9jKx8Ec0LfolFg==}
|
||||
peerDependencies:
|
||||
react: '>=18.0.0'
|
||||
react-dom: '>=18.0.0'
|
||||
dependencies:
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/store': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
proxy-compare: 2.5.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@zag-js/rect-utils@0.32.1:
|
||||
resolution: {integrity: sha512-cI07kgldjUZP+SLhXeG9VSl47nrENlC96Fs7jWcTfHj62rhdY8WsBJ0tiTztvwar9m1chwxXZwJowHN+nPIgDQ==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/remove-scroll@0.32.1:
|
||||
resolution: {integrity: sha512-LyXt2rNMSKb9MKeJRyKTgpk4R7jdA+9kEQTSG5qyA94jo1og7FVgA1W/E+pNkdxDEk1VplL768VU6y7E/L3DHg==}
|
||||
dependencies:
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/select@0.32.1:
|
||||
resolution: {integrity: sha512-jSzmTKCN1Fk/ZDDWM8TVGOtwgpYUDgyceegjYT+hW1mmEetu4tQcEvAr0557NOzh8akqLvcVFbg/kMj0IriKAA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/collection': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dismissable': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/mutation-observer': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/tabbable': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/slider@0.32.1:
|
||||
resolution: {integrity: sha512-iZSB3Y8/Maakxem0Ha3rBRa8AyAplhN5K50Bgz+wsv0VEzNNUmK4QgaTWReWd6SfeTRpnC5ftKCcfM2aQrLm6g==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/element-size': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/numeric-range': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/splitter@0.32.1:
|
||||
resolution: {integrity: sha512-NdHLUXtQAlnz6QpdPwcqZCqYul7LaVqsp0hgtXR2PN4HbH+VAaDfY76pUk6LBerUcykChGZvtM9U0A5FCo1x4A==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/number-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/store@0.32.1:
|
||||
resolution: {integrity: sha512-hKwzpqAPljw06oOI+eO+Is2udpmY9GsGfmdoqvZVYoK4f5sawpZY9EC/84tbK9QKWUDTbFS+0Ujc254GUThmDA==}
|
||||
dependencies:
|
||||
proxy-compare: 2.5.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/switch@0.32.1:
|
||||
resolution: {integrity: sha512-+5w/AtINA+jpORX1cuUrnyIFXrfjhqV7667EKK/zbPi0Pf1E10+TEihpfFjY6bgms9CSNWZVEb6w2f2C0PNBDA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
'@zag-js/visually-hidden': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/tabbable@0.32.1:
|
||||
resolution: {integrity: sha512-fMXtVgBiX7z3Qmdv+McrfihiSkqsDbNX2nn3e63L7jdy9ZpgnR3jG9BwUZvv7hvzkuOAFhhdKgBYYT+fkBavGg==}
|
||||
dependencies:
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/tabs@0.32.1:
|
||||
resolution: {integrity: sha512-5l8/k2Pw9Kbfsvvx6HWcVqK7Ns7ca+nyPGLSZtZLMp/Zn2q3xSG32C1U3oDaYtQVIQSiEHdnMjw0C2v+CxGDMA==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/element-rect': 0.32.1
|
||||
'@zag-js/tabbable': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/tags-input@0.32.1:
|
||||
resolution: {integrity: sha512-oliLhiMpRNbWFixHF+Oe7hySQBp7NKtL/s8rN5dLT1G1GFRMzuuht/QnmL1h8EoGGpTwaaokMo4zl4uVzHbwyw==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/auto-resize': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/form-utils': 0.32.1
|
||||
'@zag-js/interact-outside': 0.32.1
|
||||
'@zag-js/live-region': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/text-selection@0.32.1:
|
||||
resolution: {integrity: sha512-aK1uswWYF76PFoxGL+3HW/kth9uldFWSW4lOh89NfEcc6Ym7qS5B+P0HKJVM9DuQbihvQX9dyc9PvM7/LJTSRA==}
|
||||
dependencies:
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/toast@0.32.1:
|
||||
resolution: {integrity: sha512-HrfVzFX7ANS9qOewCr8qOCbgko635bZxYKMv+ojjo4U/TtwkGb43+lVU7/qwZj0z18/OtXBH5YQjFwQZXg5x8g==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/toggle-group@0.32.1:
|
||||
resolution: {integrity: sha512-MM1XI4J45rRCZiDHcMtZWud0+bWMu6IcMnrbd9oig330YAF3RzcjTlxX93YRY35F04OUMBq5el9qe3qc2vyMuw==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/tooltip@0.32.1:
|
||||
resolution: {integrity: sha512-+rsmDYTELFBHoYKg5iKShGfRD3H9FJDaZRq915Uc9YnyePMXCnWRgnVp+lk3zI+FDgysQm67SDLRJsR24Iioqg==}
|
||||
dependencies:
|
||||
'@zag-js/anatomy': 0.32.1
|
||||
'@zag-js/core': 0.32.1
|
||||
'@zag-js/dom-event': 0.32.1
|
||||
'@zag-js/dom-query': 0.32.1
|
||||
'@zag-js/popper': 0.32.1
|
||||
'@zag-js/types': 0.32.1
|
||||
'@zag-js/utils': 0.32.1
|
||||
dev: false
|
||||
|
||||
/@zag-js/types@0.32.1:
|
||||
resolution: {integrity: sha512-BLfqb+im4vtXXJqhd2ZUg/4LquEd1qPt9XN56XVjudGDTftN8n3EDpuail7VKxdL59W4jR7wW8lvl4sSgrQKWw==}
|
||||
dependencies:
|
||||
csstype: 3.1.3
|
||||
dev: false
|
||||
|
||||
/@zag-js/utils@0.32.1:
|
||||
resolution: {integrity: sha512-jrcmWYcA3L6TO4fZbPFvpSGEy2Z/mbWt6bPQbmcVgq/BltSS0YxxfPl+eD+S/rZI9aneszwsr04Z5TpladFiVA==}
|
||||
dev: false
|
||||
|
||||
/@zag-js/visually-hidden@0.32.1:
|
||||
resolution: {integrity: sha512-Vzieo4vNulzY/0zqmVfeYW/LcFJp5xtEoyUgR1FBctH8uBPBRhTIEXxKtoMablW6/vccOVo7zcu0UrR5Vx+eYQ==}
|
||||
dev: false
|
||||
|
||||
/accepts@1.3.8:
|
||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@ -9074,6 +9692,12 @@ packages:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/focus-trap@7.5.4:
|
||||
resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==}
|
||||
dependencies:
|
||||
tabbable: 6.2.0
|
||||
dev: false
|
||||
|
||||
/for-each@0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
dependencies:
|
||||
@ -11307,6 +11931,10 @@ packages:
|
||||
ipaddr.js: 1.9.1
|
||||
dev: true
|
||||
|
||||
/proxy-compare@2.5.1:
|
||||
resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==}
|
||||
dev: false
|
||||
|
||||
/proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
dev: true
|
||||
@ -11435,7 +12063,7 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.7
|
||||
'@babel/runtime': 7.23.8
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
@ -11530,7 +12158,7 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.7
|
||||
'@babel/runtime': 7.23.8
|
||||
'@types/react': 18.2.48
|
||||
focus-lock: 1.0.0
|
||||
prop-types: 15.8.1
|
||||
@ -12777,6 +13405,10 @@ packages:
|
||||
resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==}
|
||||
dev: true
|
||||
|
||||
/tabbable@6.2.0:
|
||||
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
||||
dev: false
|
||||
|
||||
/tapable@2.2.1:
|
||||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -110,7 +110,28 @@
|
||||
"somethingWentWrong": "Etwas ist schief gelaufen",
|
||||
"copyError": "$t(gallery.copy) Fehler",
|
||||
"input": "Eingabe",
|
||||
"notInstalled": "Nicht $t(common.installed)"
|
||||
"notInstalled": "Nicht $t(common.installed)",
|
||||
"advancedOptions": "Erweiterte Einstellungen",
|
||||
"alpha": "Alpha",
|
||||
"red": "Rot",
|
||||
"green": "Grün",
|
||||
"blue": "Blau",
|
||||
"delete": "Löschen",
|
||||
"or": "oder",
|
||||
"direction": "Richtung",
|
||||
"free": "Frei",
|
||||
"save": "Speichern",
|
||||
"preferencesLabel": "Präferenzen",
|
||||
"created": "Erstellt",
|
||||
"prevPage": "Vorherige Seite",
|
||||
"nextPage": "Nächste Seite",
|
||||
"unknownError": "Unbekannter Fehler",
|
||||
"unsaved": "Nicht gespeichert",
|
||||
"aboutDesc": "Verwenden Sie Invoke für die Arbeit? Dann siehe hier:",
|
||||
"localSystem": "Lokales System",
|
||||
"orderBy": "Ordnen nach",
|
||||
"saveAs": "Speicher als",
|
||||
"updated": "Aktualisiert"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Erzeugungen",
|
||||
@ -701,7 +722,8 @@
|
||||
"invokeProgressBar": "Invoke Fortschrittsanzeige",
|
||||
"mode": "Modus",
|
||||
"resetUI": "$t(accessibility.reset) von UI",
|
||||
"createIssue": "Ticket erstellen"
|
||||
"createIssue": "Ticket erstellen",
|
||||
"about": "Über"
|
||||
},
|
||||
"boards": {
|
||||
"autoAddBoard": "Automatisches Hinzufügen zum Ordner",
|
||||
@ -809,7 +831,8 @@
|
||||
"canny": "Canny",
|
||||
"hedDescription": "Ganzheitlich verschachtelte Kantenerkennung",
|
||||
"scribble": "Scribble",
|
||||
"maxFaces": "Maximal Anzahl Gesichter"
|
||||
"maxFaces": "Maximal Anzahl Gesichter",
|
||||
"resizeSimple": "Größe ändern (einfach)"
|
||||
},
|
||||
"queue": {
|
||||
"status": "Status",
|
||||
@ -999,5 +1022,27 @@
|
||||
"selectLoRA": "Wählen ein LoRA aus",
|
||||
"esrganModel": "ESRGAN Modell",
|
||||
"addLora": "LoRA hinzufügen"
|
||||
},
|
||||
"accordions": {
|
||||
"generation": {
|
||||
"title": "Erstellung",
|
||||
"modelTab": "Modell",
|
||||
"conceptsTab": "Konzepte"
|
||||
},
|
||||
"image": {
|
||||
"title": "Bild"
|
||||
},
|
||||
"advanced": {
|
||||
"title": "Erweitert"
|
||||
},
|
||||
"control": {
|
||||
"title": "Kontrolle",
|
||||
"controlAdaptersTab": "Kontroll Adapter",
|
||||
"ipTab": "Bild Beschreibung"
|
||||
},
|
||||
"compositing": {
|
||||
"coherenceTab": "Kohärenzpass",
|
||||
"infillTab": "Füllung"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,6 +224,7 @@
|
||||
"amult": "a_mult",
|
||||
"autoConfigure": "Auto configure processor",
|
||||
"balanced": "Balanced",
|
||||
"base": "Base",
|
||||
"beginEndStepPercent": "Begin / End Step Percentage",
|
||||
"bgth": "bg_th",
|
||||
"canny": "Canny",
|
||||
@ -237,6 +238,8 @@
|
||||
"controlMode": "Control Mode",
|
||||
"crop": "Crop",
|
||||
"delete": "Delete",
|
||||
"depthAnything": "Depth Anything",
|
||||
"depthAnythingDescription": "Depth map generation using the Depth Anything technique",
|
||||
"depthMidas": "Depth (Midas)",
|
||||
"depthMidasDescription": "Depth map generation using Midas",
|
||||
"depthZoe": "Depth (Zoe)",
|
||||
@ -256,6 +259,7 @@
|
||||
"colorMapTileSize": "Tile Size",
|
||||
"importImageFromCanvas": "Import Image From Canvas",
|
||||
"importMaskFromCanvas": "Import Mask From Canvas",
|
||||
"large": "Large",
|
||||
"lineart": "Lineart",
|
||||
"lineartAnime": "Lineart Anime",
|
||||
"lineartAnimeDescription": "Anime-style lineart processing",
|
||||
@ -268,6 +272,7 @@
|
||||
"minConfidence": "Min Confidence",
|
||||
"mlsd": "M-LSD",
|
||||
"mlsdDescription": "Minimalist Line Segment Detector",
|
||||
"modelSize": "Model Size",
|
||||
"none": "None",
|
||||
"noneDescription": "No processing applied",
|
||||
"normalBae": "Normal BAE",
|
||||
@ -288,6 +293,7 @@
|
||||
"selectModel": "Select a model",
|
||||
"setControlImageDimensions": "Set Control Image Dimensions To W/H",
|
||||
"showAdvanced": "Show Advanced",
|
||||
"small": "Small",
|
||||
"toggleControlNet": "Toggle this ControlNet",
|
||||
"w": "W",
|
||||
"weight": "Weight",
|
||||
@ -600,6 +606,10 @@
|
||||
"desc": "Send current image to Image to Image",
|
||||
"title": "Send To Image To Image"
|
||||
},
|
||||
"remixImage": {
|
||||
"desc": "Use all parameters except seed from the current image",
|
||||
"title": "Remix image"
|
||||
},
|
||||
"setParameters": {
|
||||
"desc": "Use all parameters of the current image",
|
||||
"title": "Set Parameters"
|
||||
@ -1216,6 +1226,7 @@
|
||||
"useCpuNoise": "Use CPU Noise",
|
||||
"cpuNoise": "CPU Noise",
|
||||
"gpuNoise": "GPU Noise",
|
||||
"remixImage": "Remix Image",
|
||||
"useInitImg": "Use Initial Image",
|
||||
"usePrompt": "Use Prompt",
|
||||
"useSeed": "Use Seed",
|
||||
@ -1697,6 +1708,7 @@
|
||||
"workflowLibrary": "Library",
|
||||
"userWorkflows": "My Workflows",
|
||||
"defaultWorkflows": "Default Workflows",
|
||||
"projectWorkflows": "Project Workflows",
|
||||
"openWorkflow": "Open Workflow",
|
||||
"uploadWorkflow": "Load from File",
|
||||
"deleteWorkflow": "Delete Workflow",
|
||||
@ -1709,6 +1721,7 @@
|
||||
"workflowSaved": "Workflow Saved",
|
||||
"noRecentWorkflows": "No Recent Workflows",
|
||||
"noUserWorkflows": "No User Workflows",
|
||||
"noWorkflows": "No Workflows",
|
||||
"noSystemWorkflows": "No System Workflows",
|
||||
"problemLoading": "Problem Loading Workflows",
|
||||
"loading": "Loading Workflows",
|
||||
|
@ -118,7 +118,14 @@
|
||||
"advancedOptions": "Opzioni avanzate",
|
||||
"free": "Libero",
|
||||
"or": "o",
|
||||
"preferencesLabel": "Preferenze"
|
||||
"preferencesLabel": "Preferenze",
|
||||
"red": "Rosso",
|
||||
"aboutHeading": "Possiedi il tuo potere creativo",
|
||||
"aboutDesc": "Utilizzi Invoke per lavoro? Guarda qui:",
|
||||
"localSystem": "Sistema locale",
|
||||
"green": "Verde",
|
||||
"blue": "Blu",
|
||||
"alpha": "Alfa"
|
||||
},
|
||||
"gallery": {
|
||||
"generations": "Generazioni",
|
||||
@ -521,7 +528,8 @@
|
||||
"customConfigFileLocation": "Posizione del file di configurazione personalizzato",
|
||||
"vaePrecision": "Precisione VAE",
|
||||
"noModelSelected": "Nessun modello selezionato",
|
||||
"conversionNotSupported": "Conversione non supportata"
|
||||
"conversionNotSupported": "Conversione non supportata",
|
||||
"configFile": "File di configurazione"
|
||||
},
|
||||
"parameters": {
|
||||
"images": "Immagini",
|
||||
@ -660,7 +668,9 @@
|
||||
"lockAspectRatio": "Blocca proporzioni",
|
||||
"swapDimensions": "Scambia dimensioni",
|
||||
"aspect": "Aspetto",
|
||||
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (potrebbe essere troppo grande)"
|
||||
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (potrebbe essere troppo grande)",
|
||||
"boxBlur": "Box",
|
||||
"gaussianBlur": "Gaussian"
|
||||
},
|
||||
"settings": {
|
||||
"models": "Modelli",
|
||||
@ -794,7 +804,9 @@
|
||||
"invalidUpload": "Caricamento non valido",
|
||||
"problemDeletingWorkflow": "Problema durante l'eliminazione del flusso di lavoro",
|
||||
"workflowDeleted": "Flusso di lavoro eliminato",
|
||||
"problemRetrievingWorkflow": "Problema nel recupero del flusso di lavoro"
|
||||
"problemRetrievingWorkflow": "Problema nel recupero del flusso di lavoro",
|
||||
"resetInitialImage": "Reimposta l'immagine iniziale",
|
||||
"uploadInitialImage": "Carica l'immagine iniziale"
|
||||
},
|
||||
"tooltip": {
|
||||
"feature": {
|
||||
@ -899,7 +911,8 @@
|
||||
"loadMore": "Carica altro",
|
||||
"mode": "Modalità",
|
||||
"resetUI": "$t(accessibility.reset) l'Interfaccia Utente",
|
||||
"createIssue": "Segnala un problema"
|
||||
"createIssue": "Segnala un problema",
|
||||
"about": "Informazioni"
|
||||
},
|
||||
"ui": {
|
||||
"hideProgressImages": "Nascondi avanzamento immagini",
|
||||
|
@ -45,7 +45,7 @@ export const useSocketIO = () => {
|
||||
const socketOptions = useMemo(() => {
|
||||
const options: Partial<ManagerOptions & SocketOptions> = {
|
||||
timeout: 60000,
|
||||
path: '/ws/socket.io',
|
||||
path: `${window.location.pathname}ws/socket.io`,
|
||||
autoConnect: false, // achtung! removing this breaks the dynamic middleware
|
||||
forceNew: true,
|
||||
};
|
||||
|
@ -36,9 +36,9 @@ export const addModelSelectedListener = () => {
|
||||
|
||||
const newModel = result.data;
|
||||
|
||||
const { base_model } = newModel;
|
||||
const newBaseModel = newModel.base_model;
|
||||
const didBaseModelChange =
|
||||
state.generation.model?.base_model !== base_model;
|
||||
state.generation.model?.base_model !== newBaseModel;
|
||||
|
||||
if (didBaseModelChange) {
|
||||
// we may need to reset some incompatible submodels
|
||||
@ -46,7 +46,7 @@ export const addModelSelectedListener = () => {
|
||||
|
||||
// handle incompatible loras
|
||||
forEach(state.lora.loras, (lora, id) => {
|
||||
if (lora.base_model !== base_model) {
|
||||
if (lora.base_model !== newBaseModel) {
|
||||
dispatch(loraRemoved(id));
|
||||
modelsCleared += 1;
|
||||
}
|
||||
@ -54,14 +54,14 @@ export const addModelSelectedListener = () => {
|
||||
|
||||
// handle incompatible vae
|
||||
const { vae } = state.generation;
|
||||
if (vae && vae.base_model !== base_model) {
|
||||
if (vae && vae.base_model !== newBaseModel) {
|
||||
dispatch(vaeSelected(null));
|
||||
modelsCleared += 1;
|
||||
}
|
||||
|
||||
// handle incompatible controlnets
|
||||
selectControlAdapterAll(state.controlAdapters).forEach((ca) => {
|
||||
if (ca.model?.base_model !== base_model) {
|
||||
if (ca.model?.base_model !== newBaseModel) {
|
||||
dispatch(
|
||||
controlAdapterIsEnabledChanged({ id: ca.id, isEnabled: false })
|
||||
);
|
||||
|
@ -46,14 +46,14 @@ export const addDynamicPromptsListener = () => {
|
||||
|
||||
if (cachedPrompts) {
|
||||
dispatch(promptsChanged(cachedPrompts.prompts));
|
||||
dispatch(parsingErrorChanged(cachedPrompts.error));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getShouldProcessPrompt(state.generation.positivePrompt)) {
|
||||
if (state.dynamicPrompts.isLoading) {
|
||||
dispatch(isLoadingChanged(false));
|
||||
}
|
||||
dispatch(promptsChanged([state.generation.positivePrompt]));
|
||||
dispatch(parsingErrorChanged(undefined));
|
||||
dispatch(isErrorChanged(false));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,7 +78,6 @@ export const addDynamicPromptsListener = () => {
|
||||
dispatch(promptsChanged(res.prompts));
|
||||
dispatch(parsingErrorChanged(res.error));
|
||||
dispatch(isErrorChanged(false));
|
||||
dispatch(isLoadingChanged(false));
|
||||
} catch {
|
||||
dispatch(isErrorChanged(true));
|
||||
dispatch(isLoadingChanged(false));
|
||||
|
@ -1,24 +1,35 @@
|
||||
import type { ChakraProps } from '@invoke-ai/ui';
|
||||
import { Box, Flex } from '@invoke-ai/ui';
|
||||
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||
import { getOverlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import type { CSSProperties, PropsWithChildren } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
type Props = PropsWithChildren & {
|
||||
maxHeight?: ChakraProps['maxHeight'];
|
||||
overflowX?: 'hidden' | 'scroll';
|
||||
overflowY?: 'hidden' | 'scroll';
|
||||
};
|
||||
|
||||
const styles: CSSProperties = { height: '100%', width: '100%' };
|
||||
|
||||
const ScrollableContent = ({ children, maxHeight }: Props) => {
|
||||
const ScrollableContent = ({
|
||||
children,
|
||||
maxHeight,
|
||||
overflowX = 'hidden',
|
||||
overflowY = 'scroll',
|
||||
}: Props) => {
|
||||
const overlayscrollbarsOptions = useMemo(
|
||||
() => getOverlayScrollbarsParams(overflowX, overflowY).options,
|
||||
[overflowX, overflowY]
|
||||
);
|
||||
return (
|
||||
<Flex w="full" h="full" maxHeight={maxHeight} position="relative">
|
||||
<Box position="absolute" top={0} left={0} right={0} bottom={0}>
|
||||
<OverlayScrollbarsComponent
|
||||
defer
|
||||
style={styles}
|
||||
options={overlayScrollbarsParams.options}
|
||||
options={overlayscrollbarsOptions}
|
||||
>
|
||||
{children}
|
||||
</OverlayScrollbarsComponent>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { cloneDeep, merge } from 'lodash-es';
|
||||
import { ClickScrollPlugin, OverlayScrollbars } from 'overlayscrollbars';
|
||||
import type { UseOverlayScrollbarsParams } from 'overlayscrollbars-react';
|
||||
|
||||
@ -16,3 +17,12 @@ export const overlayScrollbarsParams: UseOverlayScrollbarsParams = {
|
||||
overflow: { x: 'hidden' },
|
||||
},
|
||||
};
|
||||
|
||||
export const getOverlayScrollbarsParams = (
|
||||
overflowX: 'hidden' | 'scroll' = 'hidden',
|
||||
overflowY: 'hidden' | 'scroll' = 'scroll'
|
||||
) => {
|
||||
const params = cloneDeep(overlayScrollbarsParams);
|
||||
merge(params, { options: { overflow: { y: overflowY, x: overflowX } } });
|
||||
return params;
|
||||
};
|
||||
|
@ -1,9 +1,12 @@
|
||||
import type { FormLabelProps } from '@invoke-ai/ui';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Checkbox,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormControlGroup,
|
||||
FormLabel,
|
||||
IconButton,
|
||||
Popover,
|
||||
@ -33,6 +36,10 @@ import {
|
||||
PiTrashSimpleFill,
|
||||
} from 'react-icons/pi';
|
||||
|
||||
const formLabelProps: FormLabelProps = {
|
||||
flexGrow: 1,
|
||||
};
|
||||
|
||||
const IAICanvasMaskOptions = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
@ -124,40 +131,44 @@ const IAICanvasMaskOptions = () => {
|
||||
<PopoverContent>
|
||||
<PopoverBody>
|
||||
<Flex direction="column" gap={2}>
|
||||
<FormControl>
|
||||
<FormLabel>{`${t('unifiedCanvas.enableMask')} (H)`}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={isMaskEnabled}
|
||||
onChange={handleToggleEnableMask}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.preserveMaskedArea')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldPreserveMaskedArea}
|
||||
onChange={handleChangePreserveMaskedArea}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControlGroup formLabelProps={formLabelProps}>
|
||||
<FormControl>
|
||||
<FormLabel>{`${t('unifiedCanvas.enableMask')} (H)`}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={isMaskEnabled}
|
||||
onChange={handleToggleEnableMask}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.preserveMaskedArea')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldPreserveMaskedArea}
|
||||
onChange={handleChangePreserveMaskedArea}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormControlGroup>
|
||||
<Box pt={2} pb={2}>
|
||||
<IAIColorPicker
|
||||
color={maskColor}
|
||||
onChange={handleChangeMaskColor}
|
||||
/>
|
||||
</Box>
|
||||
<Button
|
||||
size="sm"
|
||||
leftIcon={<PiFloppyDiskBackFill />}
|
||||
onClick={handleSaveMask}
|
||||
>
|
||||
{t('unifiedCanvas.saveMask')}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
leftIcon={<PiTrashSimpleFill />}
|
||||
onClick={handleClearMask}
|
||||
>
|
||||
{t('unifiedCanvas.clearMask')}
|
||||
</Button>
|
||||
<ButtonGroup isAttached={false}>
|
||||
<Button
|
||||
size="sm"
|
||||
leftIcon={<PiFloppyDiskBackFill />}
|
||||
onClick={handleSaveMask}
|
||||
>
|
||||
{t('unifiedCanvas.saveMask')}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
leftIcon={<PiTrashSimpleFill />}
|
||||
onClick={handleClearMask}
|
||||
>
|
||||
{t('unifiedCanvas.clearMask')}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
|
@ -1,7 +1,9 @@
|
||||
import type { FormLabelProps } from '@invoke-ai/ui';
|
||||
import {
|
||||
Checkbox,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormControlGroup,
|
||||
FormLabel,
|
||||
IconButton,
|
||||
Popover,
|
||||
@ -28,6 +30,10 @@ import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiGearSixBold } from 'react-icons/pi';
|
||||
|
||||
const formLabelProps: FormLabelProps = {
|
||||
flexGrow: 1,
|
||||
};
|
||||
|
||||
const IAICanvasSettingsButtonPopover = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
@ -122,69 +128,73 @@ const IAICanvasSettingsButtonPopover = () => {
|
||||
<PopoverContent>
|
||||
<PopoverBody>
|
||||
<Flex direction="column" gap={2}>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.showIntermediates')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldShowIntermediates}
|
||||
onChange={handleChangeShouldShowIntermediates}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.showGrid')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldShowGrid}
|
||||
onChange={handleChangeShouldShowGrid}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.snapToGrid')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldSnapToGrid}
|
||||
onChange={handleChangeShouldSnapToGrid}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.darkenOutsideSelection')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldDarkenOutsideBoundingBox}
|
||||
onChange={handleChangeShouldDarkenOutsideBoundingBox}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.autoSaveToGallery')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldAutoSave}
|
||||
onChange={handleChangeShouldAutoSave}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.saveBoxRegionOnly')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldCropToBoundingBoxOnSave}
|
||||
onChange={handleChangeShouldCropToBoundingBoxOnSave}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.limitStrokesToBox')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldRestrictStrokesToBox}
|
||||
onChange={handleChangeShouldRestrictStrokesToBox}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.showCanvasDebugInfo')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldShowCanvasDebugInfo}
|
||||
onChange={handleChangeShouldShowCanvasDebugInfo}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.antialiasing')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldAntialias}
|
||||
onChange={handleChangeShouldAntialias}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControlGroup formLabelProps={formLabelProps}>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.showIntermediates')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldShowIntermediates}
|
||||
onChange={handleChangeShouldShowIntermediates}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.showGrid')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldShowGrid}
|
||||
onChange={handleChangeShouldShowGrid}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.snapToGrid')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldSnapToGrid}
|
||||
onChange={handleChangeShouldSnapToGrid}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>
|
||||
{t('unifiedCanvas.darkenOutsideSelection')}
|
||||
</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldDarkenOutsideBoundingBox}
|
||||
onChange={handleChangeShouldDarkenOutsideBoundingBox}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.autoSaveToGallery')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldAutoSave}
|
||||
onChange={handleChangeShouldAutoSave}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.saveBoxRegionOnly')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldCropToBoundingBoxOnSave}
|
||||
onChange={handleChangeShouldCropToBoundingBoxOnSave}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.limitStrokesToBox')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldRestrictStrokesToBox}
|
||||
onChange={handleChangeShouldRestrictStrokesToBox}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.showCanvasDebugInfo')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldShowCanvasDebugInfo}
|
||||
onChange={handleChangeShouldShowCanvasDebugInfo}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('unifiedCanvas.antialiasing')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={shouldAntialias}
|
||||
onChange={handleChangeShouldAntialias}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormControlGroup>
|
||||
<ClearCanvasHistoryButtonModal />
|
||||
</Flex>
|
||||
</PopoverBody>
|
||||
|
@ -276,9 +276,9 @@ const IAICanvasToolChooserOptions = () => {
|
||||
</Flex>
|
||||
<Box w="full" pt={2} pb={2}>
|
||||
<IAIColorPicker
|
||||
withNumberInput={true}
|
||||
color={brushColor}
|
||||
onChange={handleChangeBrushColor}
|
||||
withNumberInput
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Icon,
|
||||
IconButton,
|
||||
Switch,
|
||||
} from '@invoke-ai/ui';
|
||||
@ -19,7 +19,7 @@ import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCopyBold, PiTrashSimpleBold } from 'react-icons/pi';
|
||||
import { PiCaretUpBold, PiCopyBold, PiTrashSimpleBold } from 'react-icons/pi';
|
||||
import { useToggle } from 'react-use';
|
||||
|
||||
import ControlAdapterImagePreview from './ControlAdapterImagePreview';
|
||||
@ -130,7 +130,9 @@ const ControlAdapterConfig = (props: { id: string; number: number }) => {
|
||||
onClick={toggleIsExpanded}
|
||||
variant="ghost"
|
||||
icon={
|
||||
<ChevronUpIcon
|
||||
<Icon
|
||||
boxSize={4}
|
||||
as={PiCaretUpBold}
|
||||
transform={isExpanded ? 'rotate(0deg)' : 'rotate(180deg)'}
|
||||
transitionProperty="common"
|
||||
transitionDuration="normal"
|
||||
|
@ -5,6 +5,7 @@ import { memo } from 'react';
|
||||
import CannyProcessor from './processors/CannyProcessor';
|
||||
import ColorMapProcessor from './processors/ColorMapProcessor';
|
||||
import ContentShuffleProcessor from './processors/ContentShuffleProcessor';
|
||||
import DepthAnyThingProcessor from './processors/DepthAnyThingProcessor';
|
||||
import HedProcessor from './processors/HedProcessor';
|
||||
import LineartAnimeProcessor from './processors/LineartAnimeProcessor';
|
||||
import LineartProcessor from './processors/LineartProcessor';
|
||||
@ -48,6 +49,16 @@ const ControlAdapterProcessorComponent = ({ id }: Props) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (processorNode.type === 'depth_anything_image_processor') {
|
||||
return (
|
||||
<DepthAnyThingProcessor
|
||||
controlNetId={id}
|
||||
processorNode={processorNode}
|
||||
isEnabled={isEnabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (processorNode.type === 'hed_image_processor') {
|
||||
return (
|
||||
<HedProcessor
|
||||
|
@ -0,0 +1,110 @@
|
||||
import type { ComboboxOnChange } from '@invoke-ai/ui';
|
||||
import {
|
||||
Combobox,
|
||||
CompositeNumberInput,
|
||||
CompositeSlider,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
} from '@invoke-ai/ui';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
||||
import type {
|
||||
DepthAnythingModelSize,
|
||||
RequiredDepthAnythingImageProcessorInvocation,
|
||||
} from 'features/controlAdapters/store/types';
|
||||
import { isDepthAnythingModelSize } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
const DEFAULTS = CONTROLNET_PROCESSORS.midas_depth_image_processor
|
||||
.default as RequiredDepthAnythingImageProcessorInvocation;
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredDepthAnythingImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const DepthAnythingProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { model_size, resolution } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleModelSizeChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
if (!isDepthAnythingModelSize(v?.value)) {
|
||||
return;
|
||||
}
|
||||
processorChanged(controlNetId, {
|
||||
model_size: v.value,
|
||||
});
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const options: { label: string; value: DepthAnythingModelSize }[] = useMemo(
|
||||
() => [
|
||||
{ label: t('controlnet.small'), value: 'small' },
|
||||
{ label: t('controlnet.base'), value: 'base' },
|
||||
{ label: t('controlnet.large'), value: 'large' },
|
||||
],
|
||||
[t]
|
||||
);
|
||||
|
||||
const value = useMemo(
|
||||
() => options.filter((o) => o.value === model_size)[0],
|
||||
[options, model_size]
|
||||
);
|
||||
|
||||
const handleResolutionChange = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleResolutionDefaultChange = useCallback(() => {
|
||||
processorChanged(controlNetId, { resolution: 512 });
|
||||
}, [controlNetId, processorChanged]);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.modelSize')}</FormLabel>
|
||||
<Combobox
|
||||
value={value}
|
||||
defaultInputValue={DEFAULTS.model_size}
|
||||
options={options}
|
||||
onChange={handleModelSizeChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={resolution}
|
||||
onChange={handleResolutionChange}
|
||||
defaultValue={DEFAULTS.resolution}
|
||||
min={64}
|
||||
max={4096}
|
||||
step={64}
|
||||
marks
|
||||
onReset={handleResolutionDefaultChange}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={resolution}
|
||||
onChange={handleResolutionChange}
|
||||
defaultValue={DEFAULTS.resolution}
|
||||
min={64}
|
||||
max={4096}
|
||||
step={64}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(DepthAnythingProcessor);
|
@ -16,7 +16,7 @@ export const useAddControlAdapter = (type: ControlAdapterType) => {
|
||||
const firstCompatibleModel = models.filter((m) =>
|
||||
baseModel ? m.base_model === baseModel : true
|
||||
)[0];
|
||||
console.log("test")
|
||||
|
||||
if (firstCompatibleModel) {
|
||||
return firstCompatibleModel;
|
||||
}
|
||||
|
@ -83,6 +83,22 @@ export const CONTROLNET_PROCESSORS: ControlNetProcessorsDict = {
|
||||
f: 256,
|
||||
},
|
||||
},
|
||||
depth_anything_image_processor: {
|
||||
type: 'depth_anything_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.depthAnything');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.depthAnythingDescription');
|
||||
},
|
||||
default: {
|
||||
id: 'depth_anything_image_processor',
|
||||
type: 'depth_anything_image_processor',
|
||||
model_size: 'small',
|
||||
resolution: 512,
|
||||
offload: false,
|
||||
},
|
||||
},
|
||||
hed_image_processor: {
|
||||
type: 'hed_image_processor',
|
||||
get label() {
|
||||
@ -245,7 +261,7 @@ export const CONTROLNET_MODEL_DEFAULT_PROCESSORS: {
|
||||
} = {
|
||||
canny: 'canny_image_processor',
|
||||
mlsd: 'mlsd_image_processor',
|
||||
depth: 'midas_depth_image_processor',
|
||||
depth: 'depth_anything_image_processor',
|
||||
bae: 'normalbae_image_processor',
|
||||
sketch: 'pidi_image_processor',
|
||||
scribble: 'lineart_image_processor',
|
||||
|
@ -10,6 +10,7 @@ import type {
|
||||
CannyImageProcessorInvocation,
|
||||
ColorMapImageProcessorInvocation,
|
||||
ContentShuffleImageProcessorInvocation,
|
||||
DepthAnythingImageProcessorInvocation,
|
||||
HedImageProcessorInvocation,
|
||||
LineartAnimeImageProcessorInvocation,
|
||||
LineartImageProcessorInvocation,
|
||||
@ -31,6 +32,7 @@ export type ControlAdapterProcessorNode =
|
||||
| CannyImageProcessorInvocation
|
||||
| ColorMapImageProcessorInvocation
|
||||
| ContentShuffleImageProcessorInvocation
|
||||
| DepthAnythingImageProcessorInvocation
|
||||
| HedImageProcessorInvocation
|
||||
| LineartAnimeImageProcessorInvocation
|
||||
| LineartImageProcessorInvocation
|
||||
@ -73,6 +75,20 @@ export type RequiredContentShuffleImageProcessorInvocation = O.Required<
|
||||
'type' | 'detect_resolution' | 'image_resolution' | 'w' | 'h' | 'f'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The DepthAnything processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredDepthAnythingImageProcessorInvocation = O.Required<
|
||||
DepthAnythingImageProcessorInvocation,
|
||||
'type' | 'model_size' | 'resolution' | 'offload'
|
||||
>;
|
||||
|
||||
export const zDepthAnythingModelSize = z.enum(['large', 'base', 'small']);
|
||||
export type DepthAnythingModelSize = z.infer<typeof zDepthAnythingModelSize>;
|
||||
export const isDepthAnythingModelSize = (
|
||||
v: unknown
|
||||
): v is DepthAnythingModelSize => zDepthAnythingModelSize.safeParse(v).success;
|
||||
|
||||
/**
|
||||
* The HED processor node, with parameters flagged as required
|
||||
*/
|
||||
@ -161,6 +177,7 @@ export type RequiredControlAdapterProcessorNode =
|
||||
| RequiredCannyImageProcessorInvocation
|
||||
| RequiredColorMapImageProcessorInvocation
|
||||
| RequiredContentShuffleImageProcessorInvocation
|
||||
| RequiredDepthAnythingImageProcessorInvocation
|
||||
| RequiredHedImageProcessorInvocation
|
||||
| RequiredLineartAnimeImageProcessorInvocation
|
||||
| RequiredLineartImageProcessorInvocation
|
||||
@ -219,6 +236,22 @@ export const isContentShuffleImageProcessorInvocation = (
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Type guard for DepthAnythingImageProcessorInvocation
|
||||
*/
|
||||
export const isDepthAnythingImageProcessorInvocation = (
|
||||
obj: unknown
|
||||
): obj is DepthAnythingImageProcessorInvocation => {
|
||||
if (
|
||||
isObject(obj) &&
|
||||
'type' in obj &&
|
||||
obj.type === 'depth_anything_image_processor'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Type guard for HedImageprocessorInvocation
|
||||
*/
|
||||
|
@ -61,7 +61,12 @@ const ParamDynamicPromptsPreview = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl orientation="vertical" w="full" h="full">
|
||||
<FormControl
|
||||
orientation="vertical"
|
||||
w="full"
|
||||
h="full"
|
||||
isInvalid={Boolean(parsingError || isError)}
|
||||
>
|
||||
<InformationalPopover feature="dynamicPrompts" inPortal={false}>
|
||||
<FormLabel>{label}</FormLabel>
|
||||
</InformationalPopover>
|
||||
|
@ -13,7 +13,11 @@ const loadingStyles: SystemStyleObject = {
|
||||
export const ShowDynamicPromptsPreviewButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isLoading = useAppSelector((s) => s.dynamicPrompts.isLoading);
|
||||
const isError = useAppSelector((s) =>
|
||||
Boolean(s.dynamicPrompts.isError || s.dynamicPrompts.parsingError)
|
||||
);
|
||||
const { isOpen, onOpen } = useDynamicPromptsModal();
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
label={
|
||||
@ -30,6 +34,7 @@ export const ShowDynamicPromptsPreviewButton = memo(() => {
|
||||
icon={<BsBracesAsterisk />}
|
||||
onClick={onOpen}
|
||||
sx={isLoading ? loadingStyles : undefined}
|
||||
colorScheme={isError && !isLoading ? 'error' : 'base'}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
|
@ -47,6 +47,7 @@ export const dynamicPromptsSlice = createSlice({
|
||||
},
|
||||
promptsChanged: (state, action: PayloadAction<string[]>) => {
|
||||
state.prompts = action.payload;
|
||||
state.isLoading = false;
|
||||
},
|
||||
parsingErrorChanged: (
|
||||
state,
|
||||
|
@ -1,3 +1,3 @@
|
||||
const hasOpenCloseCurlyBracesRegex = /.*\{.*\}.*/;
|
||||
const hasOpenCloseCurlyBracesRegex = /.*\{[\s\S]*\}.*/;
|
||||
export const getShouldProcessPrompt = (prompt: string): boolean =>
|
||||
hasOpenCloseCurlyBracesRegex.test(prompt);
|
||||
|
@ -58,7 +58,7 @@ const BoardsSearch = () => {
|
||||
<IconButton
|
||||
onClick={clearBoardSearch}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
variant="link"
|
||||
aria-label={t('boards.clearSearch')}
|
||||
icon={<PiXBold />}
|
||||
/>
|
||||
|
@ -32,6 +32,7 @@ import { memo, useCallback } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
PiArrowsCounterClockwiseBold,
|
||||
PiAsteriskBold,
|
||||
PiDotsThreeOutlineFill,
|
||||
PiFlowArrowBold,
|
||||
@ -129,6 +130,16 @@ const CurrentImageButtons = () => {
|
||||
|
||||
useHotkeys('p', handleUsePrompt, [metadata]);
|
||||
|
||||
const handleRemixImage = useCallback(() => {
|
||||
// Recalls all metadata parameters except seed
|
||||
recallAllParameters({
|
||||
...metadata,
|
||||
seed: undefined,
|
||||
});
|
||||
}, [metadata, recallAllParameters]);
|
||||
|
||||
useHotkeys('r', handleRemixImage, [metadata]);
|
||||
|
||||
const handleUseSize = useCallback(() => {
|
||||
recallWidthAndHeight(metadata?.width, metadata?.height);
|
||||
}, [metadata?.width, metadata?.height, recallWidthAndHeight]);
|
||||
@ -231,6 +242,14 @@ const CurrentImageButtons = () => {
|
||||
onClick={handleLoadWorkflow}
|
||||
isLoading={getAndLoadEmbeddedWorkflowResult.isLoading}
|
||||
/>
|
||||
<IconButton
|
||||
isLoading={isLoadingMetadata}
|
||||
icon={<PiArrowsCounterClockwiseBold />}
|
||||
tooltip={`${t('parameters.remixImage')} (R)`}
|
||||
aria-label={`${t('parameters.remixImage')} (R)`}
|
||||
isDisabled={!metadata?.positive_prompt}
|
||||
onClick={handleRemixImage}
|
||||
/>
|
||||
<IconButton
|
||||
isLoading={isLoadingMetadata}
|
||||
icon={<PiQuotesBold />}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||
import { Button, Flex, Spacer } from '@invoke-ai/ui';
|
||||
import { Button, Flex, Icon, Spacer } from '@invoke-ai/ui';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { PiCaretUpBold } from 'react-icons/pi';
|
||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
||||
|
||||
type Props = {
|
||||
@ -36,7 +36,9 @@ const GalleryBoardName = (props: Props) => {
|
||||
<Spacer />
|
||||
{formattedBoardName}
|
||||
<Spacer />
|
||||
<ChevronUpIcon
|
||||
<Icon
|
||||
as={PiCaretUpBold}
|
||||
boxSize={4}
|
||||
transform={isOpen ? 'rotate(0deg)' : 'rotate(180deg)'}
|
||||
transitionProperty="common"
|
||||
transitionDuration="normal"
|
||||
|
@ -1,8 +1,10 @@
|
||||
import type { FormLabelProps } from '@invoke-ai/ui';
|
||||
import {
|
||||
Checkbox,
|
||||
CompositeSlider,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormControlGroup,
|
||||
FormLabel,
|
||||
IconButton,
|
||||
Popover,
|
||||
@ -24,6 +26,10 @@ import { RiSettings4Fill } from 'react-icons/ri';
|
||||
|
||||
import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
|
||||
|
||||
const formLabelProps: FormLabelProps = {
|
||||
flexGrow: 1,
|
||||
};
|
||||
|
||||
const GallerySettingsPopover = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
@ -78,20 +84,22 @@ const GallerySettingsPopover = () => {
|
||||
defaultValue={90}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('gallery.autoSwitchNewImages')}</FormLabel>
|
||||
<Switch
|
||||
isChecked={shouldAutoSwitch}
|
||||
onChange={handleChangeAutoSwitch}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('gallery.autoAssignBoardOnClick')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={autoAssignBoardOnClick}
|
||||
onChange={handleChangeAutoAssignBoardOnClick}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControlGroup formLabelProps={formLabelProps}>
|
||||
<FormControl>
|
||||
<FormLabel>{t('gallery.autoSwitchNewImages')}</FormLabel>
|
||||
<Switch
|
||||
isChecked={shouldAutoSwitch}
|
||||
onChange={handleChangeAutoSwitch}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('gallery.autoAssignBoardOnClick')}</FormLabel>
|
||||
<Checkbox
|
||||
isChecked={autoAssignBoardOnClick}
|
||||
onChange={handleChangeAutoAssignBoardOnClick}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormControlGroup>
|
||||
<BoardAutoAddSelect />
|
||||
</Flex>
|
||||
</PopoverBody>
|
||||
|
@ -24,6 +24,7 @@ import { memo, useCallback } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
PiArrowsCounterClockwiseBold,
|
||||
PiAsteriskBold,
|
||||
PiCopyBold,
|
||||
PiDownloadSimpleBold,
|
||||
@ -127,6 +128,14 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
|
||||
recallAllParameters(metadata);
|
||||
}, [metadata, recallAllParameters]);
|
||||
|
||||
const handleRemixImage = useCallback(() => {
|
||||
// Recalls all metadata parameters except seed
|
||||
recallAllParameters({
|
||||
...metadata,
|
||||
seed: undefined,
|
||||
});
|
||||
}, [metadata, recallAllParameters]);
|
||||
|
||||
const handleChangeBoard = useCallback(() => {
|
||||
dispatch(imagesToChangeSelected([imageDTO]));
|
||||
dispatch(isModalOpenChanged(true));
|
||||
@ -187,6 +196,19 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
|
||||
>
|
||||
{t('nodes.loadWorkflow')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon={
|
||||
isLoadingMetadata ? <SpinnerIcon /> : <PiArrowsCounterClockwiseBold />
|
||||
}
|
||||
onClickCapture={handleRemixImage}
|
||||
isDisabled={
|
||||
isLoadingMetadata ||
|
||||
(metadata?.positive_prompt === undefined &&
|
||||
metadata?.negative_prompt === undefined)
|
||||
}
|
||||
>
|
||||
{t('parameters.remixImage')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon={isLoadingMetadata ? <SpinnerIcon /> : <PiQuotesBold />}
|
||||
onClickCapture={handleRecallPrompt}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Box, Flex, IconButton, Tooltip } from '@invoke-ai/ui';
|
||||
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||
import { getOverlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||
import { isString } from 'lodash-es';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import type { CSSProperties } from 'react';
|
||||
@ -15,6 +15,11 @@ type Props = {
|
||||
withCopy?: boolean;
|
||||
};
|
||||
|
||||
const overlayscrollbarsOptions = getOverlayScrollbarsParams(
|
||||
'scroll',
|
||||
'scroll'
|
||||
).options;
|
||||
|
||||
const DataViewer = (props: Props) => {
|
||||
const { label, data, fileName, withDownload = true, withCopy = true } = props;
|
||||
const dataString = useMemo(
|
||||
@ -60,7 +65,7 @@ const DataViewer = (props: Props) => {
|
||||
<OverlayScrollbarsComponent
|
||||
defer
|
||||
style={overlayScrollbarsStyles}
|
||||
options={overlayScrollbarsParams.options}
|
||||
options={overlayscrollbarsOptions}
|
||||
>
|
||||
<pre>{dataString}</pre>
|
||||
</OverlayScrollbarsComponent>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import { Flex, IconButton, Link, Text, Tooltip } from '@invoke-ai/ui';
|
||||
import { ExternalLink, Flex, IconButton, Text, Tooltip } from '@invoke-ai/ui';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IoArrowUndoCircleOutline } from 'react-icons/io5';
|
||||
@ -67,9 +66,7 @@ const ImageMetadataItem = ({
|
||||
{label}:
|
||||
</Text>
|
||||
{isLink ? (
|
||||
<Link href={value.toString()} isExternal wordBreak="break-all">
|
||||
{value.toString()} <ExternalLinkIcon mx="2px" />
|
||||
</Link>
|
||||
<ExternalLink href={value.toString()} label={value.toString()} />
|
||||
) : (
|
||||
<Text overflowY="scroll" wordBreak="break-all">
|
||||
{value.toString()}
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
ExternalLink,
|
||||
Flex,
|
||||
Link,
|
||||
Tab,
|
||||
TabList,
|
||||
TabPanel,
|
||||
TabPanels,
|
||||
Tabs,
|
||||
Text,
|
||||
} from '@invoke-ai/ui';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
@ -46,13 +44,7 @@ const ImageMetadataViewer = ({ image }: ImageMetadataViewerProps) => {
|
||||
position="absolute"
|
||||
overflow="hidden"
|
||||
>
|
||||
<Flex gap={2}>
|
||||
<Text fontWeight="semibold">{t('common.file')}:</Text>
|
||||
<Link href={image.image_url} isExternal maxW="calc(100% - 3rem)">
|
||||
{image.image_name}
|
||||
<ExternalLinkIcon mx="2px" />
|
||||
</Link>
|
||||
</Flex>
|
||||
<ExternalLink href={image.image_url} label={image.image_name} />
|
||||
|
||||
<Tabs
|
||||
variant="line"
|
||||
|
@ -122,13 +122,10 @@ const AdvancedAddDiffusers = (props: AdvancedAddDiffusersProps) => {
|
||||
<FormErrorMessage>{errors.model_name?.message}</FormErrorMessage>
|
||||
)}
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>{t('modelManager.baseModel')}</FormLabel>
|
||||
<BaseModelSelect<DiffusersModelConfig>
|
||||
control={control}
|
||||
name="base_model"
|
||||
/>
|
||||
</FormControl>
|
||||
<BaseModelSelect<DiffusersModelConfig>
|
||||
control={control}
|
||||
name="base_model"
|
||||
/>
|
||||
<FormControl isInvalid={Boolean(errors.path)}>
|
||||
<FormLabel>{t('modelManager.modelLocation')}</FormLabel>
|
||||
<Input
|
||||
@ -137,7 +134,7 @@ const AdvancedAddDiffusers = (props: AdvancedAddDiffusersProps) => {
|
||||
value.trim().length > 0 || 'Must provide a path',
|
||||
onBlur,
|
||||
})}
|
||||
/>{' '}
|
||||
/>
|
||||
{errors.path?.message && (
|
||||
<FormErrorMessage>{errors.path?.message}</FormErrorMessage>
|
||||
)}
|
||||
|
@ -109,28 +109,28 @@ const InputField = ({ nodeId, fieldName }: Props) => {
|
||||
|
||||
return (
|
||||
<InputFieldWrapper shouldDim={shouldDim}>
|
||||
<FieldContextMenu nodeId={nodeId} fieldName={fieldName} kind="input">
|
||||
{(ref) => (
|
||||
<FormControl
|
||||
ref={ref}
|
||||
isInvalid={isMissingInput}
|
||||
isDisabled={isConnected}
|
||||
orientation="vertical"
|
||||
px={2}
|
||||
>
|
||||
<Flex flexDir="column" w="full" gap={1}>
|
||||
<FormControl
|
||||
isInvalid={isMissingInput}
|
||||
isDisabled={isConnected}
|
||||
orientation="vertical"
|
||||
px={2}
|
||||
>
|
||||
<Flex flexDir="column" w="full" gap={1}>
|
||||
<FieldContextMenu nodeId={nodeId} fieldName={fieldName} kind="input">
|
||||
{(ref) => (
|
||||
<EditableFieldTitle
|
||||
ref={ref}
|
||||
nodeId={nodeId}
|
||||
fieldName={fieldName}
|
||||
kind="input"
|
||||
isMissingInput={isMissingInput}
|
||||
withTooltip
|
||||
/>
|
||||
<InputFieldRenderer nodeId={nodeId} fieldName={fieldName} />
|
||||
</Flex>
|
||||
</FormControl>
|
||||
)}
|
||||
</FieldContextMenu>
|
||||
)}
|
||||
</FieldContextMenu>
|
||||
<InputFieldRenderer nodeId={nodeId} fieldName={fieldName} />
|
||||
</Flex>
|
||||
</FormControl>
|
||||
|
||||
{fieldTemplate.input !== 'direct' && (
|
||||
<FieldHandle
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||
import { IconButton } from '@invoke-ai/ui';
|
||||
import { Icon, IconButton } from '@invoke-ai/ui';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { nodeIsOpenChanged } from 'features/nodes/store/nodesSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { PiCaretUpBold } from 'react-icons/pi';
|
||||
import { useUpdateNodeInternals } from 'reactflow';
|
||||
|
||||
interface Props {
|
||||
@ -29,7 +29,8 @@ const NodeCollapseButton = ({ nodeId, isOpen }: Props) => {
|
||||
h={8}
|
||||
variant="link"
|
||||
icon={
|
||||
<ChevronUpIcon
|
||||
<Icon
|
||||
as={PiCaretUpBold}
|
||||
transform={isOpen ? 'rotate(0deg)' : 'rotate(180deg)'}
|
||||
transitionProperty="common"
|
||||
transitionDuration="normal"
|
||||
|
@ -65,7 +65,7 @@ export const zModelType = z.enum([
|
||||
'controlnet',
|
||||
'embedding',
|
||||
]);
|
||||
export const zModelName = z.string().trim().min(1);
|
||||
export const zModelName = z.string().min(3);
|
||||
export const zModelIdentifier = z.object({
|
||||
model_name: zModelName,
|
||||
base_model: zBaseModel,
|
||||
|
@ -15,7 +15,7 @@ export type XYPosition = z.infer<typeof zXYPosition>;
|
||||
export const zDimension = z.number().gt(0).nullish();
|
||||
export type Dimension = z.infer<typeof zDimension>;
|
||||
|
||||
export const zWorkflowCategory = z.enum(['user', 'default']);
|
||||
export const zWorkflowCategory = z.enum(['user', 'default', 'project']);
|
||||
export type WorkflowCategory = z.infer<typeof zWorkflowCategory>;
|
||||
// #endregion
|
||||
|
||||
|
@ -24,6 +24,7 @@ const workflowKeys = [
|
||||
'notes',
|
||||
'exposedFields',
|
||||
'meta',
|
||||
'id',
|
||||
] satisfies (keyof WorkflowV2)[];
|
||||
|
||||
export type BuildWorkflowFunction = (arg: BuildWorkflowArg) => WorkflowV2;
|
||||
|
@ -34,7 +34,7 @@ import {
|
||||
modelSelected,
|
||||
} from 'features/parameters/store/actions';
|
||||
import {
|
||||
heightChanged,
|
||||
heightRecalled,
|
||||
selectGenerationSlice,
|
||||
setCfgRescaleMultiplier,
|
||||
setCfgScale,
|
||||
@ -45,8 +45,9 @@ import {
|
||||
setSeed,
|
||||
setSteps,
|
||||
vaeSelected,
|
||||
widthChanged,
|
||||
widthRecalled,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
import type { ParameterModel } from 'features/parameters/types/parameterSchemas';
|
||||
import {
|
||||
isParameterCFGRescaleMultiplier,
|
||||
isParameterCFGScale,
|
||||
@ -372,7 +373,7 @@ export const useRecallParameters = () => {
|
||||
parameterNotSetToast();
|
||||
return;
|
||||
}
|
||||
dispatch(widthChanged(width));
|
||||
dispatch(widthRecalled(width));
|
||||
parameterSetToast();
|
||||
},
|
||||
[dispatch, parameterSetToast, parameterNotSetToast]
|
||||
@ -387,7 +388,7 @@ export const useRecallParameters = () => {
|
||||
parameterNotSetToast();
|
||||
return;
|
||||
}
|
||||
dispatch(heightChanged(height));
|
||||
dispatch(heightRecalled(height));
|
||||
parameterSetToast();
|
||||
},
|
||||
[dispatch, parameterSetToast, parameterNotSetToast]
|
||||
@ -406,8 +407,8 @@ export const useRecallParameters = () => {
|
||||
allParameterNotSetToast();
|
||||
return;
|
||||
}
|
||||
dispatch(heightChanged(height));
|
||||
dispatch(widthChanged(width));
|
||||
dispatch(heightRecalled(height));
|
||||
dispatch(widthRecalled(width));
|
||||
allParameterSetToast();
|
||||
},
|
||||
[dispatch, allParameterSetToast, allParameterNotSetToast]
|
||||
@ -480,7 +481,7 @@ export const useRecallParameters = () => {
|
||||
const { data: loraModels } = useGetLoRAModelsQuery(undefined);
|
||||
|
||||
const prepareLoRAMetadataItem = useCallback(
|
||||
(loraMetadataItem: LoRAMetadataItem) => {
|
||||
(loraMetadataItem: LoRAMetadataItem, newModel?: ParameterModel) => {
|
||||
if (!isParameterLoRAModel(loraMetadataItem.lora)) {
|
||||
return { lora: null, error: 'Invalid LoRA model' };
|
||||
}
|
||||
@ -499,7 +500,7 @@ export const useRecallParameters = () => {
|
||||
}
|
||||
|
||||
const isCompatibleBaseModel =
|
||||
matchingLoRA?.base_model === model?.base_model;
|
||||
matchingLoRA?.base_model === (newModel ?? model)?.base_model;
|
||||
|
||||
if (!isCompatibleBaseModel) {
|
||||
return {
|
||||
@ -510,7 +511,7 @@ export const useRecallParameters = () => {
|
||||
|
||||
return { lora: matchingLoRA, error: null };
|
||||
},
|
||||
[loraModels, model?.base_model]
|
||||
[loraModels, model]
|
||||
);
|
||||
|
||||
const recallLoRA = useCallback(
|
||||
@ -538,7 +539,10 @@ export const useRecallParameters = () => {
|
||||
const { data: controlNetModels } = useGetControlNetModelsQuery(undefined);
|
||||
|
||||
const prepareControlNetMetadataItem = useCallback(
|
||||
(controlnetMetadataItem: ControlNetMetadataItem) => {
|
||||
(
|
||||
controlnetMetadataItem: ControlNetMetadataItem,
|
||||
newModel?: ParameterModel
|
||||
) => {
|
||||
if (!isParameterControlNetModel(controlnetMetadataItem.control_model)) {
|
||||
return { controlnet: null, error: 'Invalid ControlNet model' };
|
||||
}
|
||||
@ -565,7 +569,7 @@ export const useRecallParameters = () => {
|
||||
}
|
||||
|
||||
const isCompatibleBaseModel =
|
||||
matchingControlNetModel?.base_model === model?.base_model;
|
||||
matchingControlNetModel?.base_model === (newModel ?? model)?.base_model;
|
||||
|
||||
if (!isCompatibleBaseModel) {
|
||||
return {
|
||||
@ -600,7 +604,7 @@ export const useRecallParameters = () => {
|
||||
|
||||
return { controlnet, error: null };
|
||||
},
|
||||
[controlNetModels, model?.base_model]
|
||||
[controlNetModels, model]
|
||||
);
|
||||
|
||||
const recallControlNet = useCallback(
|
||||
@ -631,7 +635,10 @@ export const useRecallParameters = () => {
|
||||
const { data: t2iAdapterModels } = useGetT2IAdapterModelsQuery(undefined);
|
||||
|
||||
const prepareT2IAdapterMetadataItem = useCallback(
|
||||
(t2iAdapterMetadataItem: T2IAdapterMetadataItem) => {
|
||||
(
|
||||
t2iAdapterMetadataItem: T2IAdapterMetadataItem,
|
||||
newModel?: ParameterModel
|
||||
) => {
|
||||
if (
|
||||
!isParameterControlNetModel(t2iAdapterMetadataItem.t2i_adapter_model)
|
||||
) {
|
||||
@ -659,7 +666,7 @@ export const useRecallParameters = () => {
|
||||
}
|
||||
|
||||
const isCompatibleBaseModel =
|
||||
matchingT2IAdapterModel?.base_model === model?.base_model;
|
||||
matchingT2IAdapterModel?.base_model === (newModel ?? model)?.base_model;
|
||||
|
||||
if (!isCompatibleBaseModel) {
|
||||
return {
|
||||
@ -690,7 +697,7 @@ export const useRecallParameters = () => {
|
||||
|
||||
return { t2iAdapter, error: null };
|
||||
},
|
||||
[model?.base_model, t2iAdapterModels]
|
||||
[model, t2iAdapterModels]
|
||||
);
|
||||
|
||||
const recallT2IAdapter = useCallback(
|
||||
@ -721,7 +728,10 @@ export const useRecallParameters = () => {
|
||||
const { data: ipAdapterModels } = useGetIPAdapterModelsQuery(undefined);
|
||||
|
||||
const prepareIPAdapterMetadataItem = useCallback(
|
||||
(ipAdapterMetadataItem: IPAdapterMetadataItem) => {
|
||||
(
|
||||
ipAdapterMetadataItem: IPAdapterMetadataItem,
|
||||
newModel?: ParameterModel
|
||||
) => {
|
||||
if (!isParameterIPAdapterModel(ipAdapterMetadataItem?.ip_adapter_model)) {
|
||||
return { ipAdapter: null, error: 'Invalid IP Adapter model' };
|
||||
}
|
||||
@ -746,7 +756,7 @@ export const useRecallParameters = () => {
|
||||
}
|
||||
|
||||
const isCompatibleBaseModel =
|
||||
matchingIPAdapterModel?.base_model === model?.base_model;
|
||||
matchingIPAdapterModel?.base_model === (newModel ?? model)?.base_model;
|
||||
|
||||
if (!isCompatibleBaseModel) {
|
||||
return {
|
||||
@ -768,7 +778,7 @@ export const useRecallParameters = () => {
|
||||
|
||||
return { ipAdapter, error: null };
|
||||
},
|
||||
[ipAdapterModels, model?.base_model]
|
||||
[ipAdapterModels, model]
|
||||
);
|
||||
|
||||
const recallIPAdapter = useCallback(
|
||||
@ -840,6 +850,13 @@ export const useRecallParameters = () => {
|
||||
t2iAdapters,
|
||||
} = metadata;
|
||||
|
||||
let newModel: ParameterModel | undefined = undefined;
|
||||
|
||||
if (isParameterModel(model)) {
|
||||
newModel = model;
|
||||
dispatch(modelSelected(model));
|
||||
}
|
||||
|
||||
if (isParameterCFGScale(cfg_scale)) {
|
||||
dispatch(setCfgScale(cfg_scale));
|
||||
}
|
||||
@ -848,10 +865,6 @@ export const useRecallParameters = () => {
|
||||
dispatch(setCfgRescaleMultiplier(cfg_rescale_multiplier));
|
||||
}
|
||||
|
||||
if (isParameterModel(model)) {
|
||||
dispatch(modelSelected(model));
|
||||
}
|
||||
|
||||
if (isParameterPositivePrompt(positive_prompt)) {
|
||||
dispatch(setPositivePrompt(positive_prompt));
|
||||
}
|
||||
@ -880,11 +893,11 @@ export const useRecallParameters = () => {
|
||||
}
|
||||
|
||||
if (isParameterWidth(width)) {
|
||||
dispatch(widthChanged(width));
|
||||
dispatch(widthRecalled(width));
|
||||
}
|
||||
|
||||
if (isParameterHeight(height)) {
|
||||
dispatch(heightChanged(height));
|
||||
dispatch(heightRecalled(height));
|
||||
}
|
||||
|
||||
if (isParameterStrength(strength)) {
|
||||
@ -953,7 +966,7 @@ export const useRecallParameters = () => {
|
||||
|
||||
dispatch(lorasCleared());
|
||||
loras?.forEach((lora) => {
|
||||
const result = prepareLoRAMetadataItem(lora);
|
||||
const result = prepareLoRAMetadataItem(lora, newModel);
|
||||
if (result.lora) {
|
||||
dispatch(loraRecalled({ ...result.lora, weight: lora.weight }));
|
||||
}
|
||||
@ -961,21 +974,21 @@ export const useRecallParameters = () => {
|
||||
|
||||
dispatch(controlAdaptersReset());
|
||||
controlnets?.forEach((controlnet) => {
|
||||
const result = prepareControlNetMetadataItem(controlnet);
|
||||
const result = prepareControlNetMetadataItem(controlnet, newModel);
|
||||
if (result.controlnet) {
|
||||
dispatch(controlAdapterRecalled(result.controlnet));
|
||||
}
|
||||
});
|
||||
|
||||
ipAdapters?.forEach((ipAdapter) => {
|
||||
const result = prepareIPAdapterMetadataItem(ipAdapter);
|
||||
const result = prepareIPAdapterMetadataItem(ipAdapter, newModel);
|
||||
if (result.ipAdapter) {
|
||||
dispatch(controlAdapterRecalled(result.ipAdapter));
|
||||
}
|
||||
});
|
||||
|
||||
t2iAdapters?.forEach((t2iAdapter) => {
|
||||
const result = prepareT2IAdapterMetadataItem(t2iAdapter);
|
||||
const result = prepareT2IAdapterMetadataItem(t2iAdapter, newModel);
|
||||
if (result.t2iAdapter) {
|
||||
dispatch(controlAdapterRecalled(result.t2iAdapter));
|
||||
}
|
||||
|
@ -175,8 +175,15 @@ export const generationSlice = createSlice({
|
||||
}
|
||||
|
||||
// Clamp ClipSkip Based On Selected Model
|
||||
const { maxClip } = CLIP_SKIP_MAP[newModel.base_model];
|
||||
state.clipSkip = clamp(state.clipSkip, 0, maxClip);
|
||||
// TODO(psyche): remove this special handling when https://github.com/invoke-ai/InvokeAI/issues/4583 is resolved
|
||||
// WIP PR here: https://github.com/invoke-ai/InvokeAI/pull/4624
|
||||
if (newModel.base_model === 'sdxl') {
|
||||
// We don't support clip skip for SDXL yet - it's not in the graphs
|
||||
state.clipSkip = 0;
|
||||
} else {
|
||||
const { maxClip } = CLIP_SKIP_MAP[newModel.base_model];
|
||||
state.clipSkip = clamp(state.clipSkip, 0, maxClip);
|
||||
}
|
||||
|
||||
if (action.meta.previousModel?.base_model === newModel.base_model) {
|
||||
// The base model hasn't changed, we don't need to optimize the size
|
||||
@ -223,6 +230,18 @@ export const generationSlice = createSlice({
|
||||
heightChanged: (state, action: PayloadAction<number>) => {
|
||||
state.height = action.payload;
|
||||
},
|
||||
widthRecalled: (state, action: PayloadAction<number>) => {
|
||||
state.width = action.payload;
|
||||
state.aspectRatio.value = action.payload / state.height;
|
||||
state.aspectRatio.id = 'Free';
|
||||
state.aspectRatio.isLocked = false;
|
||||
},
|
||||
heightRecalled: (state, action: PayloadAction<number>) => {
|
||||
state.height = action.payload;
|
||||
state.aspectRatio.value = state.width / action.payload;
|
||||
state.aspectRatio.id = 'Free';
|
||||
state.aspectRatio.isLocked = false;
|
||||
},
|
||||
aspectRatioChanged: (state, action: PayloadAction<AspectRatioState>) => {
|
||||
state.aspectRatio = action.payload;
|
||||
},
|
||||
@ -299,6 +318,8 @@ export const {
|
||||
aspectRatioChanged,
|
||||
widthChanged,
|
||||
heightChanged,
|
||||
widthRecalled,
|
||||
heightRecalled,
|
||||
} = generationSlice.actions;
|
||||
|
||||
export const { selectOptimalDimension } = generationSlice.selectors;
|
||||
|
@ -6,7 +6,6 @@ import {
|
||||
Spinner,
|
||||
Text,
|
||||
} from '@invoke-ai/ui';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||
import { useCancelBatch } from 'features/queue/hooks/useCancelBatch';
|
||||
import { useCancelQueueItem } from 'features/queue/hooks/useCancelQueueItem';
|
||||
@ -127,9 +126,7 @@ const QueueItemComponent = ({ queueItemDTO }: Props) => {
|
||||
justifyContent="center"
|
||||
>
|
||||
{queueItem ? (
|
||||
<ScrollableContent>
|
||||
<DataViewer label="Queue Item" data={queueItem} />
|
||||
</ScrollableContent>
|
||||
<DataViewer label="Queue Item" data={queueItem} />
|
||||
) : (
|
||||
<Spinner opacity={0.5} />
|
||||
)}
|
||||
|
@ -1,23 +1,26 @@
|
||||
import { useDisclosure } from '@invoke-ai/ui';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { expanderToggled } from 'features/settingsAccordions/store/actions';
|
||||
import { useCallback } from 'react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { expanderStateChanged, selectUiSlice } from 'features/ui/store/uiSlice';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
type UseExpanderToggleArg = {
|
||||
defaultIsOpen: boolean;
|
||||
id?: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const useExpanderToggle = (arg: UseExpanderToggleArg) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { isOpen, onToggle: _onToggle } = useDisclosure({
|
||||
defaultIsOpen: arg.defaultIsOpen,
|
||||
});
|
||||
const selectIsOpen = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
selectUiSlice,
|
||||
(ui) => ui.expanders[arg.id] ?? arg.defaultIsOpen
|
||||
),
|
||||
[arg]
|
||||
);
|
||||
const isOpen = useAppSelector(selectIsOpen);
|
||||
const onToggle = useCallback(() => {
|
||||
if (arg.id) {
|
||||
dispatch(expanderToggled({ id: arg.id, isOpen }));
|
||||
}
|
||||
_onToggle();
|
||||
}, [_onToggle, dispatch, arg.id, isOpen]);
|
||||
dispatch(expanderStateChanged({ id: arg.id, isOpen: !isOpen }));
|
||||
}, [dispatch, arg.id, isOpen]);
|
||||
return { isOpen, onToggle };
|
||||
};
|
||||
|
@ -1,25 +1,31 @@
|
||||
import { useDisclosure } from '@invoke-ai/ui';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { standaloneAccordionToggled } from 'features/settingsAccordions/store/actions';
|
||||
import { useCallback } from 'react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
accordionStateChanged,
|
||||
selectUiSlice,
|
||||
} from 'features/ui/store/uiSlice';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
type UseStandaloneAccordionToggleArg = {
|
||||
defaultIsOpen: boolean;
|
||||
id?: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export const useStandaloneAccordionToggle = (
|
||||
arg: UseStandaloneAccordionToggleArg
|
||||
) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { isOpen, onToggle: _onToggle } = useDisclosure({
|
||||
defaultIsOpen: arg.defaultIsOpen,
|
||||
});
|
||||
const selectIsOpen = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
selectUiSlice,
|
||||
(ui) => ui.accordions[arg.id] ?? arg.defaultIsOpen
|
||||
),
|
||||
[arg]
|
||||
);
|
||||
const isOpen = useAppSelector(selectIsOpen);
|
||||
const onToggle = useCallback(() => {
|
||||
if (arg.id) {
|
||||
dispatch(standaloneAccordionToggled({ id: arg.id, isOpen }));
|
||||
}
|
||||
_onToggle();
|
||||
}, [_onToggle, arg.id, dispatch, isOpen]);
|
||||
dispatch(accordionStateChanged({ id: arg.id, isOpen: !isOpen }));
|
||||
}, [arg.id, dispatch, isOpen]);
|
||||
return { isOpen, onToggle };
|
||||
};
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
export const expanderToggled = createAction<{ id: string; isOpen: boolean }>(
|
||||
'parameters/expanderToggled'
|
||||
);
|
||||
|
||||
export const standaloneAccordionToggled = createAction<{
|
||||
id: string;
|
||||
isOpen: boolean;
|
||||
}>('parameters/standaloneAccordionToggled');
|
@ -1,11 +1,10 @@
|
||||
import { ExternalLinkIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
ExternalLink,
|
||||
Flex,
|
||||
Grid,
|
||||
GridItem,
|
||||
Heading,
|
||||
Image,
|
||||
Link,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
@ -103,23 +102,21 @@ const AboutModal = ({ children }: AboutModalProps) => {
|
||||
{appVersion && <Text>{`v${appVersion?.version}`}</Text>}
|
||||
<Grid templateColumns="repeat(2, 1fr)" gap="3">
|
||||
<GridItem>
|
||||
<Link fontSize="sm" href={githubLink} isExternal>
|
||||
{t('common.githubLabel')}
|
||||
<ExternalLinkIcon mx="2px" />
|
||||
</Link>
|
||||
<ExternalLink
|
||||
href={githubLink}
|
||||
label={t('common.githubLabel')}
|
||||
/>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<Link fontSize="sm" href={discordLink} isExternal>
|
||||
{t('common.discordLabel')}
|
||||
<ExternalLinkIcon mx="2px" />
|
||||
</Link>
|
||||
<ExternalLink
|
||||
href={discordLink}
|
||||
label={t('common.discordLabel')}
|
||||
/>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
<Heading fontSize="large">{t('common.aboutHeading')}</Heading>
|
||||
<Text fontSize="sm">{t('common.aboutDesc')}</Text>
|
||||
<Link isExternal href={websiteLink} fontSize="sm">
|
||||
{websiteLink} <ExternalLinkIcon mx="2px" />
|
||||
</Link>
|
||||
<ExternalLink href={websiteLink} label={websiteLink} />
|
||||
</Flex>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { CloseIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Divider,
|
||||
Flex,
|
||||
@ -30,6 +29,7 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiXBold } from 'react-icons/pi';
|
||||
|
||||
import HotkeyListItem from './HotkeyListItem';
|
||||
|
||||
@ -103,7 +103,8 @@ const HotkeysModal = ({ children }: HotkeysModalProps) => {
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
aria-label={t('hotkeys.clearSearch')}
|
||||
icon={<CloseIcon boxSize={3} />}
|
||||
boxSize={4}
|
||||
icon={<PiXBold />}
|
||||
/>
|
||||
</InputRightElement>
|
||||
)}
|
||||
|
@ -81,6 +81,11 @@ export const useHotkeyData = (): HotkeyGroup[] => {
|
||||
() => ({
|
||||
title: t('hotkeys.generalHotkeys'),
|
||||
hotkeyListItems: [
|
||||
{
|
||||
title: t('hotkeys.remixImage.title'),
|
||||
desc: t('hotkeys.remixImage.desc'),
|
||||
hotkeys: [['R']],
|
||||
},
|
||||
{
|
||||
title: t('hotkeys.setPrompt.title'),
|
||||
desc: t('hotkeys.setPrompt.desc'),
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { SpinnerIcon } from '@chakra-ui/icons';
|
||||
import type { SystemStyleObject } from '@invoke-ai/ui';
|
||||
import {
|
||||
ButtonGroup,
|
||||
Flex,
|
||||
Icon,
|
||||
IconButton,
|
||||
Portal,
|
||||
spinAnimation,
|
||||
@ -14,7 +14,7 @@ import { useQueueBack } from 'features/queue/hooks/useQueueBack';
|
||||
import type { UsePanelReturn } from 'features/ui/hooks/usePanel';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiSlidersHorizontalBold } from 'react-icons/pi';
|
||||
import { PiCircleNotchBold, PiSlidersHorizontalBold } from 'react-icons/pi';
|
||||
import { RiSparklingFill } from 'react-icons/ri';
|
||||
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
|
||||
|
||||
@ -35,7 +35,7 @@ const FloatingSidePanelButtons = (props: Props) => {
|
||||
const queueButtonIcon = useMemo(
|
||||
() =>
|
||||
!isDisabled && queueStatus?.processor.is_processing ? (
|
||||
<SpinnerIcon animation={spinAnimation} />
|
||||
<Icon boxSize={6} as={PiCircleNotchBold} animation={spinAnimation} />
|
||||
) : (
|
||||
<RiSparklingFill size="16px" />
|
||||
),
|
||||
|
@ -10,10 +10,10 @@ export const initialUIState: UIState = {
|
||||
_version: 1,
|
||||
activeTab: 'txt2img',
|
||||
shouldShowImageDetails: false,
|
||||
shouldShowExistingModelsInSearch: false,
|
||||
shouldHidePreview: false,
|
||||
shouldShowProgressInViewer: true,
|
||||
panels: {},
|
||||
accordions: {},
|
||||
expanders: {},
|
||||
};
|
||||
|
||||
export const uiSlice = createSlice({
|
||||
@ -26,15 +26,6 @@ export const uiSlice = createSlice({
|
||||
setShouldShowImageDetails: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowImageDetails = action.payload;
|
||||
},
|
||||
setShouldHidePreview: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldHidePreview = action.payload;
|
||||
},
|
||||
setShouldShowExistingModelsInSearch: (
|
||||
state,
|
||||
action: PayloadAction<boolean>
|
||||
) => {
|
||||
state.shouldShowExistingModelsInSearch = action.payload;
|
||||
},
|
||||
setShouldShowProgressInViewer: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowProgressInViewer = action.payload;
|
||||
},
|
||||
@ -44,6 +35,20 @@ export const uiSlice = createSlice({
|
||||
) => {
|
||||
state.panels[action.payload.name] = action.payload.value;
|
||||
},
|
||||
accordionStateChanged: (
|
||||
state,
|
||||
action: PayloadAction<{ id: string; isOpen: boolean }>
|
||||
) => {
|
||||
const { id, isOpen } = action.payload;
|
||||
state.accordions[id] = isOpen;
|
||||
},
|
||||
expanderStateChanged: (
|
||||
state,
|
||||
action: PayloadAction<{ id: string; isOpen: boolean }>
|
||||
) => {
|
||||
const { id, isOpen } = action.payload;
|
||||
state.expanders[id] = isOpen;
|
||||
},
|
||||
},
|
||||
extraReducers(builder) {
|
||||
builder.addCase(initialImageChanged, (state) => {
|
||||
@ -55,10 +60,10 @@ export const uiSlice = createSlice({
|
||||
export const {
|
||||
setActiveTab,
|
||||
setShouldShowImageDetails,
|
||||
setShouldShowExistingModelsInSearch,
|
||||
setShouldHidePreview,
|
||||
setShouldShowProgressInViewer,
|
||||
panelsChanged,
|
||||
accordionStateChanged,
|
||||
expanderStateChanged,
|
||||
} = uiSlice.actions;
|
||||
|
||||
export default uiSlice.reducer;
|
||||
|
@ -1,11 +1,32 @@
|
||||
import type { InvokeTabName } from './tabMap';
|
||||
|
||||
export interface UIState {
|
||||
/**
|
||||
* Slice schema version.
|
||||
*/
|
||||
_version: 1;
|
||||
/**
|
||||
* The currently active tab.
|
||||
*/
|
||||
activeTab: InvokeTabName;
|
||||
/**
|
||||
* Whether or not to show image details, e.g. metadata, workflow, etc.
|
||||
*/
|
||||
shouldShowImageDetails: boolean;
|
||||
shouldShowExistingModelsInSearch: boolean;
|
||||
shouldHidePreview: boolean;
|
||||
/**
|
||||
* Whether or not to show progress in the viewer.
|
||||
*/
|
||||
shouldShowProgressInViewer: boolean;
|
||||
/**
|
||||
* The react-resizable-panels state. The shape is managed by react-resizable-panels.
|
||||
*/
|
||||
panels: Record<string, string>;
|
||||
/**
|
||||
* The state of accordions. The key is the id of the accordion, and the value is a boolean representing the open state.
|
||||
*/
|
||||
accordions: Record<string, boolean>;
|
||||
/**
|
||||
* The state of expanders. The key is the id of the expander, and the value is a boolean representing the open state.
|
||||
*/
|
||||
expanders: Record<string, boolean>;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { CloseIcon } from '@chakra-ui/icons';
|
||||
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui';
|
||||
import {
|
||||
Button,
|
||||
@ -14,6 +13,8 @@ import {
|
||||
InputRightElement,
|
||||
Spacer,
|
||||
} from '@invoke-ai/ui';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { $projectId } from 'app/store/nanostores/projectId';
|
||||
import {
|
||||
IAINoContentFallback,
|
||||
IAINoContentFallbackWithSpinner,
|
||||
@ -25,6 +26,7 @@ import WorkflowLibraryPagination from 'features/workflowLibrary/components/Workf
|
||||
import type { ChangeEvent, KeyboardEvent } from 'react';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiXBold } from 'react-icons/pi';
|
||||
import { useListWorkflowsQuery } from 'services/api/endpoints/workflows';
|
||||
import type {
|
||||
SQLiteDirection,
|
||||
@ -62,6 +64,7 @@ const WorkflowLibraryList = () => {
|
||||
const [order_by, setOrderBy] = useState<WorkflowRecordOrderBy>('opened_at');
|
||||
const [direction, setDirection] = useState<SQLiteDirection>('ASC');
|
||||
const [debouncedQuery] = useDebounce(query, 500);
|
||||
const projectId = useStore($projectId);
|
||||
|
||||
const queryArg = useMemo<Parameters<typeof useListWorkflowsQuery>[0]>(() => {
|
||||
if (category === 'user') {
|
||||
@ -142,13 +145,8 @@ const WorkflowLibraryList = () => {
|
||||
[]
|
||||
);
|
||||
|
||||
const handleSetUserCategory = useCallback(() => {
|
||||
setCategory('user');
|
||||
setPage(0);
|
||||
}, []);
|
||||
|
||||
const handleSetDefaultCategory = useCallback(() => {
|
||||
setCategory('default');
|
||||
const handleSetCategory = useCallback((category: WorkflowCategory) => {
|
||||
setCategory(category);
|
||||
setPage(0);
|
||||
}, []);
|
||||
|
||||
@ -158,21 +156,31 @@ const WorkflowLibraryList = () => {
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
variant={category === 'user' ? undefined : 'ghost'}
|
||||
onClick={handleSetUserCategory}
|
||||
onClick={handleSetCategory.bind(null, 'user')}
|
||||
isChecked={category === 'user'}
|
||||
>
|
||||
{t('workflows.userWorkflows')}
|
||||
</Button>
|
||||
<Button
|
||||
variant={category === 'default' ? undefined : 'ghost'}
|
||||
onClick={handleSetDefaultCategory}
|
||||
isChecked={category === 'default'}
|
||||
>
|
||||
{t('workflows.defaultWorkflows')}
|
||||
</Button>
|
||||
{projectId ? (
|
||||
<Button
|
||||
variant={category === 'project' ? undefined : 'ghost'}
|
||||
onClick={handleSetCategory.bind(null, 'project')}
|
||||
isChecked={category === 'project'}
|
||||
>
|
||||
{t('workflows.projectWorkflows')}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant={category === 'default' ? undefined : 'ghost'}
|
||||
onClick={handleSetCategory.bind(null, 'default')}
|
||||
isChecked={category === 'default'}
|
||||
>
|
||||
{t('workflows.defaultWorkflows')}
|
||||
</Button>
|
||||
)}
|
||||
</ButtonGroup>
|
||||
<Spacer />
|
||||
{category === 'user' && (
|
||||
{category !== 'default' && (
|
||||
<>
|
||||
<FormControl isDisabled={isFetching} w={64} minW={56}>
|
||||
<FormLabel>{t('common.orderBy')}</FormLabel>
|
||||
@ -202,14 +210,13 @@ const WorkflowLibraryList = () => {
|
||||
minW={64}
|
||||
/>
|
||||
{query.trim().length && (
|
||||
<InputRightElement>
|
||||
<InputRightElement h="full" pe={2}>
|
||||
<IconButton
|
||||
onClick={resetFilterText}
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
variant="link"
|
||||
aria-label={t('workflows.clearWorkflowSearchFilter')}
|
||||
opacity={0.5}
|
||||
icon={<CloseIcon boxSize={2} />}
|
||||
icon={<PiXBold />}
|
||||
/>
|
||||
</InputRightElement>
|
||||
)}
|
||||
@ -229,7 +236,7 @@ const WorkflowLibraryList = () => {
|
||||
</Flex>
|
||||
</ScrollableContent>
|
||||
) : (
|
||||
<IAINoContentFallback label={t('workflows.noUserWorkflows')} />
|
||||
<IAINoContentFallback label={t('workflows.noWorkflows')} />
|
||||
)}
|
||||
<Divider />
|
||||
{data && (
|
||||
|
@ -52,7 +52,7 @@ const WorkflowLibraryListItem = ({ workflowDTO }: Props) => {
|
||||
{workflowDTO.name || t('workflows.unnamedWorkflow')}
|
||||
</Heading>
|
||||
<Spacer />
|
||||
{workflowDTO.category === 'user' && (
|
||||
{workflowDTO.category !== 'default' && (
|
||||
<Text
|
||||
fontSize="sm"
|
||||
variant="subtext"
|
||||
@ -81,7 +81,7 @@ const WorkflowLibraryListItem = ({ workflowDTO }: Props) => {
|
||||
</Text>
|
||||
)}
|
||||
<Spacer />
|
||||
{workflowDTO.category === 'user' && (
|
||||
{workflowDTO.category !== 'default' && (
|
||||
<Text
|
||||
fontSize="sm"
|
||||
variant="subtext"
|
||||
@ -104,7 +104,7 @@ const WorkflowLibraryListItem = ({ workflowDTO }: Props) => {
|
||||
>
|
||||
{t('common.load')}
|
||||
</Button>
|
||||
{workflowDTO.category === 'user' && (
|
||||
{workflowDTO.category !== 'default' && (
|
||||
<Button
|
||||
flexShrink={0}
|
||||
colorScheme="error"
|
||||
|
@ -32,7 +32,7 @@ if (import.meta.env.MODE === 'package') {
|
||||
fallbackLng: 'en',
|
||||
debug: false,
|
||||
backend: {
|
||||
loadPath: '/locales/{{lng}}.json',
|
||||
loadPath: `${window.location.href.replace(/\/$/, '')}/locales/{{lng}}.json`,
|
||||
},
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
|
@ -57,7 +57,9 @@ const dynamicBaseQuery: BaseQueryFn<
|
||||
const projectId = $projectId.get();
|
||||
|
||||
const rawBaseQuery = fetchBaseQuery({
|
||||
baseUrl: `${baseUrl ?? ''}/api/v1`,
|
||||
baseUrl: baseUrl
|
||||
? `${baseUrl}/api/v1`
|
||||
: `${window.location.href.replace(/\/$/, '')}/api/v1`,
|
||||
prepareHeaders: (headers) => {
|
||||
if (authToken) {
|
||||
headers.set('Authorization', `Bearer ${authToken}`);
|
||||
|
File diff suppressed because one or more lines are too long
@ -26,8 +26,9 @@ export const receivedOpenAPISchema = createAsyncThunk(
|
||||
'nodes/receivedOpenAPISchema',
|
||||
async (_, { rejectWithValue }) => {
|
||||
try {
|
||||
const url = [window.location.origin, 'openapi.json'].join('/');
|
||||
const response = await fetch(url);
|
||||
const response = await fetch(
|
||||
`${window.location.href.replace(/\/$/, '')}/openapi.json`
|
||||
);
|
||||
const openAPISchema = await response.json();
|
||||
|
||||
const schemaJSON = JSON.parse(
|
||||
|
@ -164,6 +164,8 @@ export type ColorMapImageProcessorInvocation =
|
||||
s['ColorMapImageProcessorInvocation'];
|
||||
export type ContentShuffleImageProcessorInvocation =
|
||||
s['ContentShuffleImageProcessorInvocation'];
|
||||
export type DepthAnythingImageProcessorInvocation =
|
||||
s['DepthAnythingImageProcessorInvocation'];
|
||||
export type HedImageProcessorInvocation = s['HedImageProcessorInvocation'];
|
||||
export type LineartAnimeImageProcessorInvocation =
|
||||
s['LineartAnimeImageProcessorInvocation'];
|
||||
|
@ -1 +1 @@
|
||||
__version__ = "3.6.0"
|
||||
__version__ = "3.6.2"
|
||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "InvokeAI"
|
||||
description = "An test implementation of Stable Diffusion which provides various new features and options to aid the image generation process"
|
||||
description = "An implementation of Stable Diffusion which provides various new features and options to aid the image generation process"
|
||||
requires-python = ">=3.10, <3.12"
|
||||
readme = { content-type = "text/markdown", file = "README.md" }
|
||||
keywords = ["stable-diffusion", "AI"]
|
||||
@ -33,12 +33,12 @@ classifiers = [
|
||||
]
|
||||
dependencies = [
|
||||
# Core generation dependencies, pinned for reproducible builds.
|
||||
"accelerate==0.25.0",
|
||||
"accelerate==0.26.1",
|
||||
"basicsr==1.4.2",
|
||||
"clip_anytorch==2.5.2", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip",
|
||||
"compel==2.0.2",
|
||||
"controlnet-aux==0.0.7",
|
||||
"diffusers[torch]==0.25.0",
|
||||
"diffusers[torch]==0.25.1",
|
||||
"invisible-watermark==0.2.0", # needed to install SDXL base and refiner using their repo_ids
|
||||
"mediapipe==0.10.7", # needed for "mediapipeface" controlnet model
|
||||
"numpy==1.26.3", # >1.24.0 is needed to use the 'strict' argument to np.testing.assert_array_equal()
|
||||
@ -52,7 +52,7 @@ dependencies = [
|
||||
"torchmetrics==0.11.4",
|
||||
"torchsde==0.2.6",
|
||||
"torchvision==0.16.2",
|
||||
"transformers==4.36.2",
|
||||
"transformers==4.37.0",
|
||||
|
||||
# Core application dependencies, pinned for reproducible builds.
|
||||
"fastapi-events==0.10.0",
|
||||
|
Reference in New Issue
Block a user