mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Compare commits
239 Commits
feat/diffu
...
v3.6.0rc6
Author | SHA1 | Date | |
---|---|---|---|
6ccd72349d | |||
30e12376d3 | |||
23c8a893e1 | |||
7d93329401 | |||
968fb655a4 | |||
80ec9f4131 | |||
f19def5f7b | |||
9e1dd8ac9c | |||
ebd68b7a6c | |||
68a231afea | |||
21ab650ac0 | |||
b501bd709f | |||
4082f25062 | |||
63d74b4ba6 | |||
da5907613b | |||
3a9201bd31 | |||
d6e2cb7cef | |||
0809e832d4 | |||
7269c9f02e | |||
d86d7e5c33 | |||
5d87578746 | |||
04aef021fc | |||
0fc08bb384 | |||
5779542084 | |||
ebda81e96e | |||
3fe332e85f | |||
3428ea1b3c | |||
6024fc7baf | |||
75c1c4ce5a | |||
ffa05a0bb3 | |||
a20e17330b | |||
4e83644433 | |||
604f0083f2 | |||
2a8a158823 | |||
f8c3db72e9 | |||
60815807f9 | |||
196fb0e014 | |||
eba668956d | |||
ee5ec023f4 | |||
d59661e0af | |||
f51e8eeae1 | |||
6e06935e75 | |||
f7f697849c | |||
8e17e29a5c | |||
12e9f17f7a | |||
cb7e56a9a3 | |||
1a710a4c12 | |||
d8d266d3be | |||
4716632c23 | |||
3c4150d153 | |||
b71b14d582 | |||
73481d4aec | |||
2c049a3b94 | |||
367de44a8b | |||
f5f378d04b | |||
823edbfdef | |||
29bbb27289 | |||
a23502f7ff | |||
ce64dbefce | |||
b47afdc3b5 | |||
cde9c3090f | |||
6924b04d7c | |||
83fbd4bdf2 | |||
6460dcc7e0 | |||
59aa009c93 | |||
59d2a012cd | |||
7e3b620830 | |||
e16b55816f | |||
895cb8637e | |||
fe5bceb1ed | |||
5d475a40f5 | |||
bca7ea1674 | |||
f27bb402fb | |||
dd32c632cd | |||
9e2e740033 | |||
d6362ce0bd | |||
2347a00a70 | |||
0b7dc721cf | |||
ac04a834ef | |||
bbca053b48 | |||
fcf2006502 | |||
ac0d0019bd | |||
2d922a0a65 | |||
8db14911d7 | |||
01bab58b20 | |||
7a57bc99cf | |||
d3b6d86e74 | |||
360b6cb286 | |||
8f9e9e639e | |||
6930d8ba41 | |||
7ad74e680d | |||
c56a6a4ddd | |||
afad764a00 | |||
49a72bd714 | |||
8cf14287b6 | |||
0db47dd5e7 | |||
71f6f77ae8 | |||
6f16229c41 | |||
0cc0d794d1 | |||
535639cb95 | |||
2250bca8d9 | |||
4ce39a5974 | |||
644e9287f0 | |||
6a5e0be022 | |||
707f0f7091 | |||
8e709fe05a | |||
154da609cb | |||
21975d6268 | |||
31035b3e63 | |||
6c05818887 | |||
77c5b051f0 | |||
4fdc4c15f9 | |||
1a4be78013 | |||
eb16ad3d6f | |||
1fee08639d | |||
7caaf40835 | |||
6bfe994622 | |||
8a6f03cd46 | |||
4ce9f9dc36 | |||
00297716d6 | |||
50c0dc71eb | |||
29ccc6a3d8 | |||
f92a5cbabc | |||
acbf10f7ba | |||
46d830b9fa | |||
db17ec7a4b | |||
6320d18846 | |||
37c8b9d06a | |||
7ba2108eb0 | |||
8aeeee4752 | |||
930de51910 | |||
b1b5c0d3b2 | |||
ebe717099e | |||
06245bc761 | |||
b4c0dafdc8 | |||
0cefacb3a2 | |||
baa5f75976 | |||
989aaedc7f | |||
93e08df849 | |||
4a43e1c1b8 | |||
2bbab9d94e | |||
a456f6e6f0 | |||
a408f562d6 | |||
cefdf9ed00 | |||
5413bf07e2 | |||
4cffe282bd | |||
ae8ffe9d51 | |||
870cc5b733 | |||
0b4eb888c5 | |||
11f1cb5391 | |||
1e2e26cfc2 | |||
e9bce6e1c3 | |||
799ef0e7c1 | |||
61c10a7ca8 | |||
93880223e6 | |||
271456b745 | |||
cecee33bc0 | |||
4f43eda09b | |||
011757c497 | |||
2700d0e769 | |||
d256d93a2a | |||
f3c8e986a5 | |||
48f5e4f313 | |||
5950ffe064 | |||
49ca949cd6 | |||
5d69f1cbf5 | |||
9169006171 | |||
28b74523d0 | |||
9359c03c3c | |||
598241e0f2 | |||
e698a8006c | |||
34e7b5a7fb | |||
5c3dd62ae0 | |||
7e2eeec1f3 | |||
7eb79266c4 | |||
5d4610d981 | |||
7c548c5bf3 | |||
2a38606342 | |||
793cf39964 | |||
ab3e689ee0 | |||
20f497054f | |||
6209fef63d | |||
5168415999 | |||
b490c8ae27 | |||
6f354f16ba | |||
e108a2302e | |||
2ffecef792 | |||
2663a07e94 | |||
8d2ef5afc3 | |||
539887b215 | |||
2ba505cce9 | |||
bd92a31d15 | |||
ee2529f3fd | |||
89b7082bc0 | |||
55dfabb892 | |||
2a41fd0b29 | |||
966919ea4a | |||
d3acdcf12f | |||
52f9749bf5 | |||
2a661450c3 | |||
2d96c62fdb | |||
3e6173ee8c | |||
4e9841c924 | |||
f4ea495d23 | |||
43a4b815e8 | |||
4134f18319 | |||
cd292f6c1c | |||
3ce8f3d6fe | |||
10fd4f6a61 | |||
47b1fd4bce | |||
300805a25a | |||
56527da73e | |||
ca4b8e65c1 | |||
f5194f9e2d | |||
ccbbb417f9 | |||
37786a26a5 | |||
4f2930412e | |||
83049a3a5b | |||
38256f97b3 | |||
77f2aabda4 | |||
e32eb2a649 | |||
f4cdfa3b9c | |||
e99b715e9e | |||
ed96c40239 | |||
1b3bb932b9 | |||
f0b102d830 | |||
a47d91f0e7 | |||
358c1f5791 | |||
faec320d48 | |||
fd074abdc4 | |||
d8eb58cd58 | |||
8937d66412 | |||
a6935ae7fb | |||
69968eb67b | |||
e57f5f129c | |||
1b8651fa26 | |||
f6664960ca | |||
84a001720c | |||
c9951cd86b |
8
.github/CODEOWNERS
vendored
8
.github/CODEOWNERS
vendored
@ -1,5 +1,5 @@
|
|||||||
# continuous integration
|
# continuous integration
|
||||||
/.github/workflows/ @lstein @blessedcoolant @hipsterusername
|
/.github/workflows/ @lstein @blessedcoolant @hipsterusername @ebr
|
||||||
|
|
||||||
# documentation
|
# documentation
|
||||||
/docs/ @lstein @blessedcoolant @hipsterusername @Millu
|
/docs/ @lstein @blessedcoolant @hipsterusername @Millu
|
||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
# installation and configuration
|
# installation and configuration
|
||||||
/pyproject.toml @lstein @blessedcoolant @hipsterusername
|
/pyproject.toml @lstein @blessedcoolant @hipsterusername
|
||||||
/docker/ @lstein @blessedcoolant @hipsterusername
|
/docker/ @lstein @blessedcoolant @hipsterusername @ebr
|
||||||
/scripts/ @ebr @lstein @hipsterusername
|
/scripts/ @ebr @lstein @hipsterusername
|
||||||
/installer/ @lstein @ebr @hipsterusername
|
/installer/ @lstein @ebr @hipsterusername
|
||||||
/invokeai/assets @lstein @ebr @hipsterusername
|
/invokeai/assets @lstein @ebr @hipsterusername
|
||||||
@ -26,9 +26,7 @@
|
|||||||
|
|
||||||
# front ends
|
# front ends
|
||||||
/invokeai/frontend/CLI @lstein @hipsterusername
|
/invokeai/frontend/CLI @lstein @hipsterusername
|
||||||
/invokeai/frontend/install @lstein @ebr @hipsterusername
|
/invokeai/frontend/install @lstein @ebr @hipsterusername
|
||||||
/invokeai/frontend/merge @lstein @blessedcoolant @hipsterusername
|
/invokeai/frontend/merge @lstein @blessedcoolant @hipsterusername
|
||||||
/invokeai/frontend/training @lstein @blessedcoolant @hipsterusername
|
/invokeai/frontend/training @lstein @blessedcoolant @hipsterusername
|
||||||
/invokeai/frontend/web @psychedelicious @blessedcoolant @maryhipp @hipsterusername
|
/invokeai/frontend/web @psychedelicious @blessedcoolant @maryhipp @hipsterusername
|
||||||
|
|
||||||
|
|
||||||
|
5
.github/workflows/build-container.yml
vendored
5
.github/workflows/build-container.yml
vendored
@ -40,10 +40,14 @@ jobs:
|
|||||||
- name: Free up more disk space on the runner
|
- name: Free up more disk space on the runner
|
||||||
# https://github.com/actions/runner-images/issues/2840#issuecomment-1284059930
|
# https://github.com/actions/runner-images/issues/2840#issuecomment-1284059930
|
||||||
run: |
|
run: |
|
||||||
|
echo "----- Free space before cleanup"
|
||||||
|
df -h
|
||||||
sudo rm -rf /usr/share/dotnet
|
sudo rm -rf /usr/share/dotnet
|
||||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||||
sudo swapoff /mnt/swapfile
|
sudo swapoff /mnt/swapfile
|
||||||
sudo rm -rf /mnt/swapfile
|
sudo rm -rf /mnt/swapfile
|
||||||
|
echo "----- Free space after cleanup"
|
||||||
|
df -h
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@ -91,6 +95,7 @@ jobs:
|
|||||||
# password: ${{ secrets.DOCKERHUB_TOKEN }}
|
# password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build container
|
- name: Build container
|
||||||
|
timeout-minutes: 40
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
|
12
README.md
12
README.md
@ -1,10 +1,10 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
# Invoke AI - Generative AI for Professional Creatives
|
# Invoke - Professional Creative AI Tools for Visual Media
|
||||||
## Professional Creative Tools for Stable Diffusion, Custom-Trained Models, and more.
|
## To learn more about Invoke, or implement our Business solutions, visit [invoke.com](https://www.invoke.com/about)
|
||||||
To learn more about Invoke AI, get started instantly, or implement our Business solutions, visit [invoke.ai](https://invoke.ai)
|
|
||||||
|
|
||||||
|
|
||||||
[![discord badge]][discord link]
|
[![discord badge]][discord link]
|
||||||
@ -56,7 +56,9 @@ the foundation for multiple commercial products.
|
|||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
## Any environment variables supported by InvokeAI can be specified here,
|
## Any environment variables supported by InvokeAI can be specified here,
|
||||||
## in addition to the examples below.
|
## in addition to the examples below.
|
||||||
|
|
||||||
# INVOKEAI_ROOT is the path to a path on the local filesystem where InvokeAI will store data.
|
# HOST_INVOKEAI_ROOT is the path on the docker host's filesystem where InvokeAI will store data.
|
||||||
# Outputs will also be stored here by default.
|
# Outputs will also be stored here by default.
|
||||||
# This **must** be an absolute path.
|
# If relative, it will be relative to the docker directory in which the docker-compose.yml file is located
|
||||||
INVOKEAI_ROOT=
|
#HOST_INVOKEAI_ROOT=../../invokeai-data
|
||||||
|
|
||||||
|
# INVOKEAI_ROOT is the path to the root of the InvokeAI repository within the container.
|
||||||
|
# INVOKEAI_ROOT=~/invokeai
|
||||||
|
|
||||||
# Get this value from your HuggingFace account settings page.
|
# Get this value from your HuggingFace account settings page.
|
||||||
# HUGGING_FACE_HUB_TOKEN=
|
# HUGGING_FACE_HUB_TOKEN=
|
||||||
|
@ -59,7 +59,7 @@ RUN --mount=type=cache,target=/root/.cache/pip \
|
|||||||
|
|
||||||
# #### Build the Web UI ------------------------------------
|
# #### Build the Web UI ------------------------------------
|
||||||
|
|
||||||
FROM node:18-slim AS web-builder
|
FROM node:20-slim AS web-builder
|
||||||
ENV PNPM_HOME="/pnpm"
|
ENV PNPM_HOME="/pnpm"
|
||||||
ENV PATH="$PNPM_HOME:$PATH"
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
@ -68,7 +68,7 @@ WORKDIR /build
|
|||||||
COPY invokeai/frontend/web/ ./
|
COPY invokeai/frontend/web/ ./
|
||||||
RUN --mount=type=cache,target=/pnpm/store \
|
RUN --mount=type=cache,target=/pnpm/store \
|
||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
RUN pnpm run build
|
RUN npx vite build
|
||||||
|
|
||||||
#### Runtime stage ---------------------------------------
|
#### Runtime stage ---------------------------------------
|
||||||
|
|
||||||
|
@ -21,7 +21,9 @@ x-invokeai: &invokeai
|
|||||||
ports:
|
ports:
|
||||||
- "${INVOKEAI_PORT:-9090}:9090"
|
- "${INVOKEAI_PORT:-9090}:9090"
|
||||||
volumes:
|
volumes:
|
||||||
- ${INVOKEAI_ROOT:-~/invokeai}:${INVOKEAI_ROOT:-/invokeai}
|
- type: bind
|
||||||
|
source: ${HOST_INVOKEAI_ROOT:-${INVOKEAI_ROOT:-~/invokeai}}
|
||||||
|
target: ${INVOKEAI_ROOT:-/invokeai}
|
||||||
- ${HF_HOME:-~/.cache/huggingface}:${HF_HOME:-/invokeai/.cache/huggingface}
|
- ${HF_HOME:-~/.cache/huggingface}:${HF_HOME:-/invokeai/.cache/huggingface}
|
||||||
# - ${INVOKEAI_MODELS_DIR:-${INVOKEAI_ROOT:-/invokeai/models}}
|
# - ${INVOKEAI_MODELS_DIR:-${INVOKEAI_ROOT:-/invokeai/models}}
|
||||||
# - ${INVOKEAI_MODELS_CONFIG_PATH:-${INVOKEAI_ROOT:-/invokeai/configs/models.yaml}}
|
# - ${INVOKEAI_MODELS_CONFIG_PATH:-${INVOKEAI_ROOT:-/invokeai/configs/models.yaml}}
|
||||||
|
@ -36,7 +36,8 @@ To use a community workflow, download the the `.json` node graph file and load i
|
|||||||
+ [Mask Operations](#mask-operations)
|
+ [Mask Operations](#mask-operations)
|
||||||
+ [Match Histogram](#match-histogram)
|
+ [Match Histogram](#match-histogram)
|
||||||
+ [Metadata-Linked](#metadata-linked-nodes)
|
+ [Metadata-Linked](#metadata-linked-nodes)
|
||||||
+ [Negative Image](#negative-image)
|
+ [Negative Image](#negative-image)
|
||||||
|
+ [Nightmare Promptgen](#nightmare-promptgen)
|
||||||
+ [Oobabooga](#oobabooga)
|
+ [Oobabooga](#oobabooga)
|
||||||
+ [Prompt Tools](#prompt-tools)
|
+ [Prompt Tools](#prompt-tools)
|
||||||
+ [Remote Image](#remote-image)
|
+ [Remote Image](#remote-image)
|
||||||
@ -346,6 +347,13 @@ Node Link: https://github.com/VeyDlin/negative-image-node
|
|||||||
View:
|
View:
|
||||||
</br><img src="https://raw.githubusercontent.com/VeyDlin/negative-image-node/master/.readme/node.png" width="500" />
|
</br><img src="https://raw.githubusercontent.com/VeyDlin/negative-image-node/master/.readme/node.png" width="500" />
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
### Nightmare Promptgen
|
||||||
|
|
||||||
|
**Description:** Nightmare Prompt Generator - Uses a local text generation model to create unique imaginative (but usually nightmarish) prompts for InvokeAI. By default, it allows you to choose from some gpt-neo models I finetuned on over 2500 of my own InvokeAI prompts in Compel format, but you're able to add your own, as well. Offers support for replacing any troublesome words with a random choice from list you can also define.
|
||||||
|
|
||||||
|
**Node Link:** [https://github.com/gogurtenjoyer/nightmare-promptgen](https://github.com/gogurtenjoyer/nightmare-promptgen)
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
### Oobabooga
|
### Oobabooga
|
||||||
|
|
||||||
|
@ -241,12 +241,12 @@ class InvokeAiInstance:
|
|||||||
pip[
|
pip[
|
||||||
"install",
|
"install",
|
||||||
"--require-virtualenv",
|
"--require-virtualenv",
|
||||||
"numpy~=1.24.0", # choose versions that won't be uninstalled during phase 2
|
"numpy==1.26.3", # choose versions that won't be uninstalled during phase 2
|
||||||
"urllib3~=1.26.0",
|
"urllib3~=1.26.0",
|
||||||
"requests~=2.28.0",
|
"requests~=2.28.0",
|
||||||
"torch==2.1.2",
|
"torch==2.1.2",
|
||||||
"torchmetrics==0.11.4",
|
"torchmetrics==0.11.4",
|
||||||
"torchvision>=0.16.2",
|
"torchvision==0.16.2",
|
||||||
"--force-reinstall",
|
"--force-reinstall",
|
||||||
"--find-links" if find_links is not None else None,
|
"--find-links" if find_links is not None else None,
|
||||||
find_links,
|
find_links,
|
||||||
|
@ -23,10 +23,11 @@ class DynamicPromptsResponse(BaseModel):
|
|||||||
)
|
)
|
||||||
async def parse_dynamicprompts(
|
async def parse_dynamicprompts(
|
||||||
prompt: str = Body(description="The prompt to parse with dynamicprompts"),
|
prompt: str = Body(description="The prompt to parse with dynamicprompts"),
|
||||||
max_prompts: int = Body(default=1000, description="The max number of prompts to generate"),
|
max_prompts: int = Body(ge=1, le=10000, default=1000, description="The max number of prompts to generate"),
|
||||||
combinatorial: bool = Body(default=True, description="Whether to use the combinatorial generator"),
|
combinatorial: bool = Body(default=True, description="Whether to use the combinatorial generator"),
|
||||||
) -> DynamicPromptsResponse:
|
) -> DynamicPromptsResponse:
|
||||||
"""Creates a batch process"""
|
"""Creates a batch process"""
|
||||||
|
max_prompts = min(max_prompts, 10000)
|
||||||
generator: Union[RandomPromptGenerator, CombinatorialPromptGenerator]
|
generator: Union[RandomPromptGenerator, CombinatorialPromptGenerator]
|
||||||
try:
|
try:
|
||||||
error: Optional[str] = None
|
error: Optional[str] = None
|
||||||
|
@ -24,9 +24,10 @@ from controlnet_aux import (
|
|||||||
)
|
)
|
||||||
from controlnet_aux.util import HWC3, ade_palette
|
from controlnet_aux.util import HWC3, ade_palette
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||||
|
|
||||||
from invokeai.app.invocations.primitives import ImageField, ImageOutput
|
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.services.image_records.image_records_common import ImageCategory, ResourceOrigin
|
||||||
from invokeai.app.shared.fields import FieldDescriptions
|
from invokeai.app.shared.fields import FieldDescriptions
|
||||||
|
|
||||||
@ -75,17 +76,16 @@ class ControlField(BaseModel):
|
|||||||
resize_mode: CONTROLNET_RESIZE_VALUES = Field(default="just_resize", description="The resize mode to use")
|
resize_mode: CONTROLNET_RESIZE_VALUES = Field(default="just_resize", description="The resize mode to use")
|
||||||
|
|
||||||
@field_validator("control_weight")
|
@field_validator("control_weight")
|
||||||
|
@classmethod
|
||||||
def validate_control_weight(cls, v):
|
def validate_control_weight(cls, v):
|
||||||
"""Validate that all control weights in the valid range"""
|
validate_weights(v)
|
||||||
if isinstance(v, list):
|
|
||||||
for i in v:
|
|
||||||
if i < -1 or i > 2:
|
|
||||||
raise ValueError("Control weights must be within -1 to 2 range")
|
|
||||||
else:
|
|
||||||
if v < -1 or v > 2:
|
|
||||||
raise ValueError("Control weights must be within -1 to 2 range")
|
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def validate_begin_end_step_percent(self):
|
||||||
|
validate_begin_end_step(self.begin_step_percent, self.end_step_percent)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
@invocation_output("control_output")
|
@invocation_output("control_output")
|
||||||
class ControlOutput(BaseInvocationOutput):
|
class ControlOutput(BaseInvocationOutput):
|
||||||
@ -95,17 +95,17 @@ class ControlOutput(BaseInvocationOutput):
|
|||||||
control: ControlField = OutputField(description=FieldDescriptions.control)
|
control: ControlField = OutputField(description=FieldDescriptions.control)
|
||||||
|
|
||||||
|
|
||||||
@invocation("controlnet", title="ControlNet", tags=["controlnet"], category="controlnet", version="1.1.0")
|
@invocation("controlnet", title="ControlNet", tags=["controlnet"], category="controlnet", version="1.1.1")
|
||||||
class ControlNetInvocation(BaseInvocation):
|
class ControlNetInvocation(BaseInvocation):
|
||||||
"""Collects ControlNet info to pass to other nodes"""
|
"""Collects ControlNet info to pass to other nodes"""
|
||||||
|
|
||||||
image: ImageField = InputField(description="The control image")
|
image: ImageField = InputField(description="The control image")
|
||||||
control_model: ControlNetModelField = InputField(description=FieldDescriptions.controlnet_model, input=Input.Direct)
|
control_model: ControlNetModelField = InputField(description=FieldDescriptions.controlnet_model, input=Input.Direct)
|
||||||
control_weight: Union[float, List[float]] = InputField(
|
control_weight: Union[float, List[float]] = InputField(
|
||||||
default=1.0, description="The weight given to the ControlNet"
|
default=1.0, ge=-1, le=2, description="The weight given to the ControlNet"
|
||||||
)
|
)
|
||||||
begin_step_percent: float = InputField(
|
begin_step_percent: float = InputField(
|
||||||
default=0, ge=-1, le=2, description="When the ControlNet is first applied (% of total steps)"
|
default=0, ge=0, le=1, description="When the ControlNet is first applied (% of total steps)"
|
||||||
)
|
)
|
||||||
end_step_percent: float = InputField(
|
end_step_percent: float = InputField(
|
||||||
default=1, ge=0, le=1, description="When the ControlNet is last applied (% of total steps)"
|
default=1, ge=0, le=1, description="When the ControlNet is last applied (% of total steps)"
|
||||||
@ -113,6 +113,17 @@ class ControlNetInvocation(BaseInvocation):
|
|||||||
control_mode: CONTROLNET_MODE_VALUES = InputField(default="balanced", description="The control mode used")
|
control_mode: CONTROLNET_MODE_VALUES = InputField(default="balanced", description="The control mode used")
|
||||||
resize_mode: CONTROLNET_RESIZE_VALUES = InputField(default="just_resize", description="The resize mode used")
|
resize_mode: CONTROLNET_RESIZE_VALUES = InputField(default="just_resize", description="The resize mode used")
|
||||||
|
|
||||||
|
@field_validator("control_weight")
|
||||||
|
@classmethod
|
||||||
|
def validate_control_weight(cls, v):
|
||||||
|
validate_weights(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def validate_begin_end_step_percent(self) -> "ControlNetInvocation":
|
||||||
|
validate_begin_end_step(self.begin_step_percent, self.end_step_percent)
|
||||||
|
return self
|
||||||
|
|
||||||
def invoke(self, context: InvocationContext) -> ControlOutput:
|
def invoke(self, context: InvocationContext) -> ControlOutput:
|
||||||
return ControlOutput(
|
return ControlOutput(
|
||||||
control=ControlField(
|
control=ControlField(
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
from builtins import float
|
from builtins import float
|
||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||||
|
|
||||||
from invokeai.app.invocations.baseinvocation import (
|
from invokeai.app.invocations.baseinvocation import (
|
||||||
BaseInvocation,
|
BaseInvocation,
|
||||||
@ -15,6 +15,7 @@ from invokeai.app.invocations.baseinvocation import (
|
|||||||
invocation_output,
|
invocation_output,
|
||||||
)
|
)
|
||||||
from invokeai.app.invocations.primitives import ImageField
|
from invokeai.app.invocations.primitives import ImageField
|
||||||
|
from invokeai.app.invocations.util import validate_begin_end_step, validate_weights
|
||||||
from invokeai.app.shared.fields import FieldDescriptions
|
from invokeai.app.shared.fields import FieldDescriptions
|
||||||
from invokeai.backend.model_management.models.base import BaseModelType, ModelType
|
from invokeai.backend.model_management.models.base import BaseModelType, ModelType
|
||||||
from invokeai.backend.model_management.models.ip_adapter import get_ip_adapter_image_encoder_model_id
|
from invokeai.backend.model_management.models.ip_adapter import get_ip_adapter_image_encoder_model_id
|
||||||
@ -39,7 +40,6 @@ class IPAdapterField(BaseModel):
|
|||||||
ip_adapter_model: IPAdapterModelField = Field(description="The IP-Adapter model to use.")
|
ip_adapter_model: IPAdapterModelField = Field(description="The IP-Adapter model to use.")
|
||||||
image_encoder_model: CLIPVisionModelField = Field(description="The name of the CLIP image encoder model.")
|
image_encoder_model: CLIPVisionModelField = Field(description="The name of the CLIP image encoder model.")
|
||||||
weight: Union[float, List[float]] = Field(default=1, description="The weight given to the ControlNet")
|
weight: Union[float, List[float]] = Field(default=1, description="The weight given to the ControlNet")
|
||||||
# weight: float = Field(default=1.0, ge=0, description="The weight of the IP-Adapter.")
|
|
||||||
begin_step_percent: float = Field(
|
begin_step_percent: float = Field(
|
||||||
default=0, ge=0, le=1, description="When the IP-Adapter is first applied (% of total steps)"
|
default=0, ge=0, le=1, description="When the IP-Adapter is first applied (% of total steps)"
|
||||||
)
|
)
|
||||||
@ -47,6 +47,17 @@ class IPAdapterField(BaseModel):
|
|||||||
default=1, ge=0, le=1, description="When the IP-Adapter is last applied (% of total steps)"
|
default=1, ge=0, le=1, description="When the IP-Adapter is last applied (% of total steps)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@field_validator("weight")
|
||||||
|
@classmethod
|
||||||
|
def validate_ip_adapter_weight(cls, v):
|
||||||
|
validate_weights(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def validate_begin_end_step_percent(self):
|
||||||
|
validate_begin_end_step(self.begin_step_percent, self.end_step_percent)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
@invocation_output("ip_adapter_output")
|
@invocation_output("ip_adapter_output")
|
||||||
class IPAdapterOutput(BaseInvocationOutput):
|
class IPAdapterOutput(BaseInvocationOutput):
|
||||||
@ -54,7 +65,7 @@ class IPAdapterOutput(BaseInvocationOutput):
|
|||||||
ip_adapter: IPAdapterField = OutputField(description=FieldDescriptions.ip_adapter, title="IP-Adapter")
|
ip_adapter: IPAdapterField = OutputField(description=FieldDescriptions.ip_adapter, title="IP-Adapter")
|
||||||
|
|
||||||
|
|
||||||
@invocation("ip_adapter", title="IP-Adapter", tags=["ip_adapter", "control"], category="ip_adapter", version="1.1.0")
|
@invocation("ip_adapter", title="IP-Adapter", tags=["ip_adapter", "control"], category="ip_adapter", version="1.1.1")
|
||||||
class IPAdapterInvocation(BaseInvocation):
|
class IPAdapterInvocation(BaseInvocation):
|
||||||
"""Collects IP-Adapter info to pass to other nodes."""
|
"""Collects IP-Adapter info to pass to other nodes."""
|
||||||
|
|
||||||
@ -64,18 +75,27 @@ class IPAdapterInvocation(BaseInvocation):
|
|||||||
description="The IP-Adapter model.", title="IP-Adapter Model", input=Input.Direct, ui_order=-1
|
description="The IP-Adapter model.", title="IP-Adapter Model", input=Input.Direct, ui_order=-1
|
||||||
)
|
)
|
||||||
|
|
||||||
# weight: float = InputField(default=1.0, description="The weight of the IP-Adapter.", ui_type=UIType.Float)
|
|
||||||
weight: Union[float, List[float]] = InputField(
|
weight: Union[float, List[float]] = InputField(
|
||||||
default=1, ge=-1, description="The weight given to the IP-Adapter", title="Weight"
|
default=1, description="The weight given to the IP-Adapter", title="Weight"
|
||||||
)
|
)
|
||||||
|
|
||||||
begin_step_percent: float = InputField(
|
begin_step_percent: float = InputField(
|
||||||
default=0, ge=-1, le=2, description="When the IP-Adapter is first applied (% of total steps)"
|
default=0, ge=0, le=1, description="When the IP-Adapter is first applied (% of total steps)"
|
||||||
)
|
)
|
||||||
end_step_percent: float = InputField(
|
end_step_percent: float = InputField(
|
||||||
default=1, ge=0, le=1, description="When the IP-Adapter is last applied (% of total steps)"
|
default=1, ge=0, le=1, description="When the IP-Adapter is last applied (% of total steps)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@field_validator("weight")
|
||||||
|
@classmethod
|
||||||
|
def validate_ip_adapter_weight(cls, v):
|
||||||
|
validate_weights(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def validate_begin_end_step_percent(self):
|
||||||
|
validate_begin_end_step(self.begin_step_percent, self.end_step_percent)
|
||||||
|
return self
|
||||||
|
|
||||||
def invoke(self, context: InvocationContext) -> IPAdapterOutput:
|
def invoke(self, context: InvocationContext) -> IPAdapterOutput:
|
||||||
# Lookup the CLIP Vision encoder that is intended to be used with the IP-Adapter model.
|
# Lookup the CLIP Vision encoder that is intended to be used with the IP-Adapter model.
|
||||||
ip_adapter_info = context.services.model_manager.model_info(
|
ip_adapter_info = context.services.model_manager.model_info(
|
||||||
|
@ -220,7 +220,7 @@ def get_scheduler(
|
|||||||
title="Denoise Latents",
|
title="Denoise Latents",
|
||||||
tags=["latents", "denoise", "txt2img", "t2i", "t2l", "img2img", "i2i", "l2l"],
|
tags=["latents", "denoise", "txt2img", "t2i", "t2l", "img2img", "i2i", "l2l"],
|
||||||
category="latents",
|
category="latents",
|
||||||
version="1.5.0",
|
version="1.5.1",
|
||||||
)
|
)
|
||||||
class DenoiseLatentsInvocation(BaseInvocation):
|
class DenoiseLatentsInvocation(BaseInvocation):
|
||||||
"""Denoises noisy latents to decodable images"""
|
"""Denoises noisy latents to decodable images"""
|
||||||
@ -279,7 +279,7 @@ class DenoiseLatentsInvocation(BaseInvocation):
|
|||||||
ui_order=7,
|
ui_order=7,
|
||||||
)
|
)
|
||||||
cfg_rescale_multiplier: float = InputField(
|
cfg_rescale_multiplier: float = InputField(
|
||||||
default=0, ge=0, lt=1, description=FieldDescriptions.cfg_rescale_multiplier
|
title="CFG Rescale Multiplier", default=0, ge=0, lt=1, description=FieldDescriptions.cfg_rescale_multiplier
|
||||||
)
|
)
|
||||||
latents: Optional[LatentsField] = InputField(
|
latents: Optional[LatentsField] = InputField(
|
||||||
default=None,
|
default=None,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||||
|
|
||||||
from invokeai.app.invocations.baseinvocation import (
|
from invokeai.app.invocations.baseinvocation import (
|
||||||
BaseInvocation,
|
BaseInvocation,
|
||||||
@ -14,6 +14,7 @@ from invokeai.app.invocations.baseinvocation import (
|
|||||||
)
|
)
|
||||||
from invokeai.app.invocations.controlnet_image_processors import CONTROLNET_RESIZE_VALUES
|
from invokeai.app.invocations.controlnet_image_processors import CONTROLNET_RESIZE_VALUES
|
||||||
from invokeai.app.invocations.primitives import ImageField
|
from invokeai.app.invocations.primitives import ImageField
|
||||||
|
from invokeai.app.invocations.util import validate_begin_end_step, validate_weights
|
||||||
from invokeai.app.shared.fields import FieldDescriptions
|
from invokeai.app.shared.fields import FieldDescriptions
|
||||||
from invokeai.backend.model_management.models.base import BaseModelType
|
from invokeai.backend.model_management.models.base import BaseModelType
|
||||||
|
|
||||||
@ -37,6 +38,17 @@ class T2IAdapterField(BaseModel):
|
|||||||
)
|
)
|
||||||
resize_mode: CONTROLNET_RESIZE_VALUES = Field(default="just_resize", description="The resize mode to use")
|
resize_mode: CONTROLNET_RESIZE_VALUES = Field(default="just_resize", description="The resize mode to use")
|
||||||
|
|
||||||
|
@field_validator("weight")
|
||||||
|
@classmethod
|
||||||
|
def validate_ip_adapter_weight(cls, v):
|
||||||
|
validate_weights(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def validate_begin_end_step_percent(self):
|
||||||
|
validate_begin_end_step(self.begin_step_percent, self.end_step_percent)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
@invocation_output("t2i_adapter_output")
|
@invocation_output("t2i_adapter_output")
|
||||||
class T2IAdapterOutput(BaseInvocationOutput):
|
class T2IAdapterOutput(BaseInvocationOutput):
|
||||||
@ -44,7 +56,7 @@ class T2IAdapterOutput(BaseInvocationOutput):
|
|||||||
|
|
||||||
|
|
||||||
@invocation(
|
@invocation(
|
||||||
"t2i_adapter", title="T2I-Adapter", tags=["t2i_adapter", "control"], category="t2i_adapter", version="1.0.0"
|
"t2i_adapter", title="T2I-Adapter", tags=["t2i_adapter", "control"], category="t2i_adapter", version="1.0.1"
|
||||||
)
|
)
|
||||||
class T2IAdapterInvocation(BaseInvocation):
|
class T2IAdapterInvocation(BaseInvocation):
|
||||||
"""Collects T2I-Adapter info to pass to other nodes."""
|
"""Collects T2I-Adapter info to pass to other nodes."""
|
||||||
@ -61,7 +73,7 @@ class T2IAdapterInvocation(BaseInvocation):
|
|||||||
default=1, ge=0, description="The weight given to the T2I-Adapter", title="Weight"
|
default=1, ge=0, description="The weight given to the T2I-Adapter", title="Weight"
|
||||||
)
|
)
|
||||||
begin_step_percent: float = InputField(
|
begin_step_percent: float = InputField(
|
||||||
default=0, ge=-1, le=2, description="When the T2I-Adapter is first applied (% of total steps)"
|
default=0, ge=0, le=1, description="When the T2I-Adapter is first applied (% of total steps)"
|
||||||
)
|
)
|
||||||
end_step_percent: float = InputField(
|
end_step_percent: float = InputField(
|
||||||
default=1, ge=0, le=1, description="When the T2I-Adapter is last applied (% of total steps)"
|
default=1, ge=0, le=1, description="When the T2I-Adapter is last applied (% of total steps)"
|
||||||
@ -71,6 +83,17 @@ class T2IAdapterInvocation(BaseInvocation):
|
|||||||
description="The resize mode applied to the T2I-Adapter input image so that it matches the target output size.",
|
description="The resize mode applied to the T2I-Adapter input image so that it matches the target output size.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@field_validator("weight")
|
||||||
|
@classmethod
|
||||||
|
def validate_ip_adapter_weight(cls, v):
|
||||||
|
validate_weights(v)
|
||||||
|
return v
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def validate_begin_end_step_percent(self):
|
||||||
|
validate_begin_end_step(self.begin_step_percent, self.end_step_percent)
|
||||||
|
return self
|
||||||
|
|
||||||
def invoke(self, context: InvocationContext) -> T2IAdapterOutput:
|
def invoke(self, context: InvocationContext) -> T2IAdapterOutput:
|
||||||
return T2IAdapterOutput(
|
return T2IAdapterOutput(
|
||||||
t2i_adapter=T2IAdapterField(
|
t2i_adapter=T2IAdapterField(
|
||||||
|
14
invokeai/app/invocations/util.py
Normal file
14
invokeai/app/invocations/util.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
def validate_weights(weights: Union[float, list[float]]) -> None:
|
||||||
|
"""Validate that all control weights in the valid range"""
|
||||||
|
to_validate = weights if isinstance(weights, list) else [weights]
|
||||||
|
if any(i < -1 or i > 2 for i in to_validate):
|
||||||
|
raise ValueError("Control weights must be within -1 to 2 range")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_begin_end_step(begin_step_percent: float, end_step_percent: float) -> None:
|
||||||
|
"""Validate that begin_step_percent is less than end_step_percent"""
|
||||||
|
if begin_step_percent >= end_step_percent:
|
||||||
|
raise ValueError("Begin step percent must be less than or equal to end step percent")
|
File diff suppressed because it is too large
Load Diff
31
invokeai/backend/model_management/detect_baked_in_vae.py
Normal file
31
invokeai/backend/model_management/detect_baked_in_vae.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (c) 2024 Lincoln Stein and the InvokeAI Development Team
|
||||||
|
"""
|
||||||
|
This module exports the function has_baked_in_sdxl_vae().
|
||||||
|
It returns True if an SDXL checkpoint model has the original SDXL 1.0 VAE,
|
||||||
|
which doesn't work properly in fp16 mode.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from safetensors.torch import load_file
|
||||||
|
|
||||||
|
SDXL_1_0_VAE_HASH = "bc40b16c3a0fa4625abdfc01c04ffc21bf3cefa6af6c7768ec61eb1f1ac0da51"
|
||||||
|
|
||||||
|
|
||||||
|
def has_baked_in_sdxl_vae(checkpoint_path: Path) -> bool:
|
||||||
|
"""Return true if the checkpoint contains a custom (non SDXL-1.0) VAE."""
|
||||||
|
hash = _vae_hash(checkpoint_path)
|
||||||
|
return hash != SDXL_1_0_VAE_HASH
|
||||||
|
|
||||||
|
|
||||||
|
def _vae_hash(checkpoint_path: Path) -> str:
|
||||||
|
checkpoint = load_file(checkpoint_path, device="cpu")
|
||||||
|
vae_keys = [x for x in checkpoint.keys() if x.startswith("first_stage_model.")]
|
||||||
|
hash = hashlib.new("sha256")
|
||||||
|
for key in vae_keys:
|
||||||
|
value = checkpoint[key]
|
||||||
|
hash.update(bytes(key, "UTF-8"))
|
||||||
|
hash.update(bytes(str(value), "UTF-8"))
|
||||||
|
|
||||||
|
return hash.hexdigest()
|
@ -13,6 +13,7 @@ from safetensors.torch import load_file
|
|||||||
from transformers import CLIPTextModel, CLIPTokenizer
|
from transformers import CLIPTextModel, CLIPTokenizer
|
||||||
|
|
||||||
from invokeai.app.shared.models import FreeUConfig
|
from invokeai.app.shared.models import FreeUConfig
|
||||||
|
from invokeai.backend.model_management.model_load_optimizations import skip_torch_weight_init
|
||||||
|
|
||||||
from .models.lora import LoRAModel
|
from .models.lora import LoRAModel
|
||||||
|
|
||||||
@ -211,8 +212,12 @@ class ModelPatcher:
|
|||||||
for i in range(ti_embedding.shape[0]):
|
for i in range(ti_embedding.shape[0]):
|
||||||
new_tokens_added += ti_tokenizer.add_tokens(_get_trigger(ti_name, i))
|
new_tokens_added += ti_tokenizer.add_tokens(_get_trigger(ti_name, i))
|
||||||
|
|
||||||
# modify text_encoder
|
# Modify text_encoder.
|
||||||
text_encoder.resize_token_embeddings(init_tokens_count + new_tokens_added, pad_to_multiple_of)
|
# resize_token_embeddings(...) constructs a new torch.nn.Embedding internally. Initializing the weights of
|
||||||
|
# this embedding is slow and unnecessary, so we wrap this step in skip_torch_weight_init() to save some
|
||||||
|
# time.
|
||||||
|
with skip_torch_weight_init():
|
||||||
|
text_encoder.resize_token_embeddings(init_tokens_count + new_tokens_added, pad_to_multiple_of)
|
||||||
model_embeddings = text_encoder.get_input_embeddings()
|
model_embeddings = text_encoder.get_input_embeddings()
|
||||||
|
|
||||||
for ti_name, ti in ti_list:
|
for ti_name, ti in ti_list:
|
||||||
|
@ -370,6 +370,8 @@ class LoRACheckpointProbe(CheckpointProbeBase):
|
|||||||
return BaseModelType.StableDiffusion1
|
return BaseModelType.StableDiffusion1
|
||||||
elif token_vector_length == 1024:
|
elif token_vector_length == 1024:
|
||||||
return BaseModelType.StableDiffusion2
|
return BaseModelType.StableDiffusion2
|
||||||
|
elif token_vector_length == 1280:
|
||||||
|
return BaseModelType.StableDiffusionXL # recognizes format at https://civitai.com/models/224641
|
||||||
elif token_vector_length == 2048:
|
elif token_vector_length == 2048:
|
||||||
return BaseModelType.StableDiffusionXL
|
return BaseModelType.StableDiffusionXL
|
||||||
else:
|
else:
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from pathlib import Path
|
||||||
from typing import Literal, Optional
|
from typing import Literal, Optional
|
||||||
|
|
||||||
from omegaconf import OmegaConf
|
from omegaconf import OmegaConf
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
|
from invokeai.app.services.config import InvokeAIAppConfig
|
||||||
|
from invokeai.backend.model_management.detect_baked_in_vae import has_baked_in_sdxl_vae
|
||||||
|
from invokeai.backend.util.logging import InvokeAILogger
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
BaseModelType,
|
BaseModelType,
|
||||||
DiffusersModel,
|
DiffusersModel,
|
||||||
@ -116,14 +121,28 @@ class StableDiffusionXLModel(DiffusersModel):
|
|||||||
# The convert script adapted from the diffusers package uses
|
# The convert script adapted from the diffusers package uses
|
||||||
# strings for the base model type. To avoid making too many
|
# strings for the base model type. To avoid making too many
|
||||||
# source code changes, we simply translate here
|
# source code changes, we simply translate here
|
||||||
|
if Path(output_path).exists():
|
||||||
|
return output_path
|
||||||
|
|
||||||
if isinstance(config, cls.CheckpointConfig):
|
if isinstance(config, cls.CheckpointConfig):
|
||||||
from invokeai.backend.model_management.models.stable_diffusion import _convert_ckpt_and_cache
|
from invokeai.backend.model_management.models.stable_diffusion import _convert_ckpt_and_cache
|
||||||
|
|
||||||
|
# Hack in VAE-fp16 fix - If model sdxl-vae-fp16-fix is installed,
|
||||||
|
# then we bake it into the converted model unless there is already
|
||||||
|
# a nonstandard VAE installed.
|
||||||
|
kwargs = {}
|
||||||
|
app_config = InvokeAIAppConfig.get_config()
|
||||||
|
vae_path = app_config.models_path / "sdxl/vae/sdxl-vae-fp16-fix"
|
||||||
|
if vae_path.exists() and not has_baked_in_sdxl_vae(Path(model_path)):
|
||||||
|
InvokeAILogger.get_logger().warning("No baked-in VAE detected. Inserting sdxl-vae-fp16-fix.")
|
||||||
|
kwargs["vae_path"] = vae_path
|
||||||
|
|
||||||
return _convert_ckpt_and_cache(
|
return _convert_ckpt_and_cache(
|
||||||
version=base_model,
|
version=base_model,
|
||||||
model_config=config,
|
model_config=config,
|
||||||
output_path=output_path,
|
output_path=output_path,
|
||||||
use_safetensors=False, # corrupts sdxl models for some reason
|
use_safetensors=False, # corrupts sdxl models for some reason
|
||||||
|
**kwargs,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return model_path
|
return model_path
|
||||||
|
@ -44,7 +44,7 @@ def torch_dtype(device: torch.device) -> torch.dtype:
|
|||||||
if config.full_precision:
|
if config.full_precision:
|
||||||
return torch.float32
|
return torch.float32
|
||||||
if choose_precision(device) == "float16":
|
if choose_precision(device) == "float16":
|
||||||
return torch.float16
|
return torch.bfloat16 if device.type == "cuda" else torch.float16
|
||||||
else:
|
else:
|
||||||
return torch.float32
|
return torch.float32
|
||||||
|
|
||||||
|
@ -68,12 +68,9 @@ def welcome(latest_release: str, latest_prerelease: str):
|
|||||||
yield ""
|
yield ""
|
||||||
yield "This script will update InvokeAI to the latest release, or to the development version of your choice."
|
yield "This script will update InvokeAI to the latest release, or to the development version of your choice."
|
||||||
yield ""
|
yield ""
|
||||||
yield "When updating to an arbitrary tag or branch, be aware that the front end may be mismatched to the backend,"
|
|
||||||
yield "making the web frontend unusable. Please downgrade to the latest release if this happens."
|
|
||||||
yield ""
|
|
||||||
yield "[bold yellow]Options:"
|
yield "[bold yellow]Options:"
|
||||||
yield f"""[1] Update to the latest [bold]official release[/bold] ([italic]{latest_release}[/italic])
|
yield f"""[1] Update to the latest [bold]official release[/bold] ([italic]{latest_release}[/italic])
|
||||||
[2] Update to the latest [bold]pre-release[/bold] (may be buggy; caveat emptor!) ([italic]{latest_prerelease}[/italic])
|
[2] Update to the latest [bold]pre-release[/bold] (may be buggy, database backups are recommended before installation; caveat emptor!) ([italic]{latest_prerelease}[/italic])
|
||||||
[3] Manually enter the [bold]version[/bold] you wish to update to"""
|
[3] Manually enter the [bold]version[/bold] you wish to update to"""
|
||||||
|
|
||||||
console.rule()
|
console.rule()
|
||||||
|
@ -7,4 +7,4 @@ stats.html
|
|||||||
index.html
|
index.html
|
||||||
.yarn/
|
.yarn/
|
||||||
*.scss
|
*.scss
|
||||||
src/services/api/schema.d.ts
|
src/services/api/schema.ts
|
||||||
|
@ -28,12 +28,16 @@ module.exports = {
|
|||||||
'i18next',
|
'i18next',
|
||||||
'path',
|
'path',
|
||||||
'unused-imports',
|
'unused-imports',
|
||||||
|
'simple-import-sort',
|
||||||
|
'eslint-plugin-import',
|
||||||
|
// These rules are too strict for normal usage, but are useful for optimizing rerenders
|
||||||
|
// '@arthurgeron/react-usememo',
|
||||||
],
|
],
|
||||||
root: true,
|
root: true,
|
||||||
rules: {
|
rules: {
|
||||||
'path/no-relative-imports': ['error', { maxDepth: 0 }],
|
'path/no-relative-imports': ['error', { maxDepth: 0 }],
|
||||||
curly: 'error',
|
curly: 'error',
|
||||||
'i18next/no-literal-string': 2,
|
'i18next/no-literal-string': 'warn',
|
||||||
'react/jsx-no-bind': ['error', { allowBind: true }],
|
'react/jsx-no-bind': ['error', { allowBind: true }],
|
||||||
'react/jsx-curly-brace-presence': [
|
'react/jsx-curly-brace-presence': [
|
||||||
'error',
|
'error',
|
||||||
@ -43,6 +47,7 @@ module.exports = {
|
|||||||
'no-var': 'error',
|
'no-var': 'error',
|
||||||
'brace-style': 'error',
|
'brace-style': 'error',
|
||||||
'prefer-template': 'error',
|
'prefer-template': 'error',
|
||||||
|
'import/no-duplicates': 'error',
|
||||||
radix: 'error',
|
radix: 'error',
|
||||||
'space-before-blocks': 'error',
|
'space-before-blocks': 'error',
|
||||||
'import/prefer-default-export': 'off',
|
'import/prefer-default-export': 'off',
|
||||||
@ -57,6 +62,18 @@ module.exports = {
|
|||||||
argsIgnorePattern: '^_',
|
argsIgnorePattern: '^_',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
// These rules are too strict for normal usage, but are useful for optimizing rerenders
|
||||||
|
// '@arthurgeron/react-usememo/require-usememo': [
|
||||||
|
// 'warn',
|
||||||
|
// {
|
||||||
|
// strict: false,
|
||||||
|
// checkHookReturnObject: false,
|
||||||
|
// fix: { addImports: true },
|
||||||
|
// checkHookCalls: false,
|
||||||
|
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// '@arthurgeron/react-usememo/require-memo': 'warn',
|
||||||
'@typescript-eslint/ban-ts-comment': 'warn',
|
'@typescript-eslint/ban-ts-comment': 'warn',
|
||||||
'@typescript-eslint/no-explicit-any': 'warn',
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
'@typescript-eslint/no-empty-interface': [
|
'@typescript-eslint/no-empty-interface': [
|
||||||
@ -65,7 +82,26 @@ module.exports = {
|
|||||||
allowSingleExtends: true,
|
allowSingleExtends: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'@typescript-eslint/consistent-type-imports': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
prefer: 'type-imports',
|
||||||
|
fixStyle: 'separate-type-imports',
|
||||||
|
disallowTypeAnnotations: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-import-type-side-effects': 'error',
|
||||||
|
'simple-import-sort/imports': 'error',
|
||||||
|
'simple-import-sort/exports': 'error',
|
||||||
},
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['*.stories.tsx'],
|
||||||
|
rules: {
|
||||||
|
'i18next/no-literal-string': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
version: 'detect',
|
version: 'detect',
|
||||||
|
1
invokeai/frontend/web/.gitignore
vendored
1
invokeai/frontend/web/.gitignore
vendored
@ -8,6 +8,7 @@ pnpm-debug.log*
|
|||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
|
||||||
node_modules
|
node_modules
|
||||||
|
.pnpm-store
|
||||||
# We want to distribute the repo
|
# We want to distribute the repo
|
||||||
dist
|
dist
|
||||||
dist/**
|
dist/**
|
||||||
|
@ -9,7 +9,8 @@ index.html
|
|||||||
.yarn/
|
.yarn/
|
||||||
.yalc/
|
.yalc/
|
||||||
*.scss
|
*.scss
|
||||||
src/services/api/schema.d.ts
|
src/services/api/schema.ts
|
||||||
static/
|
static/
|
||||||
src/theme/css/overlayscrollbars.css
|
src/theme/css/overlayscrollbars.css
|
||||||
|
src/theme_/css/overlayscrollbars.css
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
|
25
invokeai/frontend/web/.storybook/ReduxInit.tsx
Normal file
25
invokeai/frontend/web/.storybook/ReduxInit.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { PropsWithChildren, memo, useEffect } from 'react';
|
||||||
|
import { modelChanged } from '../src/features/parameters/store/generationSlice';
|
||||||
|
import { useAppDispatch } from '../src/app/store/storeHooks';
|
||||||
|
import { useGlobalModifiersInit } from '../src/common/hooks/useGlobalModifiers';
|
||||||
|
/**
|
||||||
|
* Initializes some state for storybook. Must be in a different component
|
||||||
|
* so that it is run inside the redux context.
|
||||||
|
*/
|
||||||
|
export const ReduxInit = memo((props: PropsWithChildren) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
useGlobalModifiersInit();
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(
|
||||||
|
modelChanged({
|
||||||
|
model_name: 'test_model',
|
||||||
|
base_model: 'sd-1',
|
||||||
|
model_type: 'main',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return props.children;
|
||||||
|
});
|
||||||
|
|
||||||
|
ReduxInit.displayName = 'ReduxInit';
|
@ -6,6 +6,7 @@ const config: StorybookConfig = {
|
|||||||
'@storybook/addon-links',
|
'@storybook/addon-links',
|
||||||
'@storybook/addon-essentials',
|
'@storybook/addon-essentials',
|
||||||
'@storybook/addon-interactions',
|
'@storybook/addon-interactions',
|
||||||
|
'@storybook/addon-storysource',
|
||||||
],
|
],
|
||||||
framework: {
|
framework: {
|
||||||
name: '@storybook/react-vite',
|
name: '@storybook/react-vite',
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { Preview } from '@storybook/react';
|
import { Preview } from '@storybook/react';
|
||||||
import { themes } from '@storybook/theming';
|
import { themes } from '@storybook/theming';
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
import React from 'react';
|
|
||||||
import { initReactI18next } from 'react-i18next';
|
import { initReactI18next } from 'react-i18next';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import GlobalHotkeys from '../src/app/components/GlobalHotkeys';
|
|
||||||
import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider';
|
import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider';
|
||||||
|
import { $baseUrl } from '../src/app/store/nanostores/baseUrl';
|
||||||
import { createStore } from '../src/app/store/store';
|
import { createStore } from '../src/app/store/store';
|
||||||
|
import { Container } from '@chakra-ui/react';
|
||||||
// TODO: Disabled for IDE performance issues with our translation JSON
|
// TODO: Disabled for IDE performance issues with our translation JSON
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import translationEN from '../public/locales/en.json';
|
import translationEN from '../public/locales/en.json';
|
||||||
|
import { ReduxInit } from './ReduxInit';
|
||||||
|
|
||||||
i18n.use(initReactI18next).init({
|
i18n.use(initReactI18next).init({
|
||||||
lng: 'en',
|
lng: 'en',
|
||||||
@ -25,17 +26,21 @@ i18n.use(initReactI18next).init({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const store = createStore(undefined, false);
|
const store = createStore(undefined, false);
|
||||||
|
$baseUrl.set('http://localhost:9090');
|
||||||
|
|
||||||
const preview: Preview = {
|
const preview: Preview = {
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story) => (
|
(Story) => {
|
||||||
<Provider store={store}>
|
return (
|
||||||
<ThemeLocaleProvider>
|
<Provider store={store}>
|
||||||
<GlobalHotkeys />
|
<ThemeLocaleProvider>
|
||||||
<Story />
|
<ReduxInit>
|
||||||
</ThemeLocaleProvider>
|
<Story />
|
||||||
</Provider>
|
</ReduxInit>
|
||||||
),
|
</ThemeLocaleProvider>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
},
|
||||||
],
|
],
|
||||||
parameters: {
|
parameters: {
|
||||||
docs: {
|
docs: {
|
||||||
|
15
invokeai/frontend/web/.unimportedrc.json
Normal file
15
invokeai/frontend/web/.unimportedrc.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"entry": ["src/main.tsx"],
|
||||||
|
"extensions": [".ts", ".tsx"],
|
||||||
|
"ignorePatterns": [
|
||||||
|
"**/node_modules/**",
|
||||||
|
"dist/**",
|
||||||
|
"public/**",
|
||||||
|
"**/*.stories.tsx",
|
||||||
|
"config/**"
|
||||||
|
],
|
||||||
|
"ignoreUnresolved": [],
|
||||||
|
"ignoreUnimported": ["src/i18.d.ts", "vite.config.ts", "src/vite-env.d.ts"],
|
||||||
|
"respectGitignore": true,
|
||||||
|
"ignoreUnused": []
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import react from '@vitejs/plugin-react-swc';
|
import react from '@vitejs/plugin-react-swc';
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import { visualizer } from 'rollup-plugin-visualizer';
|
||||||
import { PluginOption, UserConfig } from 'vite';
|
import type { PluginOption, UserConfig } from 'vite';
|
||||||
import eslint from 'vite-plugin-eslint';
|
import eslint from 'vite-plugin-eslint';
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
import { UserConfig } from 'vite';
|
import type { UserConfig } from 'vite';
|
||||||
import { commonPlugins } from './common';
|
|
||||||
|
import { commonPlugins } from './common.mjs';
|
||||||
|
|
||||||
export const appConfig: UserConfig = {
|
export const appConfig: UserConfig = {
|
||||||
base: './',
|
base: './',
|
@ -1,8 +1,9 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { UserConfig } from 'vite';
|
import type { UserConfig } from 'vite';
|
||||||
import dts from 'vite-plugin-dts';
|
|
||||||
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
|
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
|
||||||
import { commonPlugins } from './common';
|
import dts from 'vite-plugin-dts';
|
||||||
|
|
||||||
|
import { commonPlugins } from './common.mjs';
|
||||||
|
|
||||||
export const packageConfig: UserConfig = {
|
export const packageConfig: UserConfig = {
|
||||||
base: './',
|
base: './',
|
4
invokeai/frontend/web/favicon-key.svg
Normal file
4
invokeai/frontend/web/favicon-key.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="32" height="32" rx="6" fill="#E6FD13"/>
|
||||||
|
<path d="M19.2378 10.9H25V7H7V10.9H12.7622L19.2378 21.1H25V25H7V21.1H12.7622" stroke="#181818" stroke-width="1.5"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 272 B |
3
invokeai/frontend/web/favicon-outline.svg
Normal file
3
invokeai/frontend/web/favicon-outline.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M29.1951 10.6667H42V2H2V10.6667H14.8049L29.1951 33.3333H42V42H2V33.3333H14.8049" stroke="#E6FD13" stroke-width="2.8"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 231 B |
Binary file not shown.
Before Width: | Height: | Size: 116 KiB |
@ -1,24 +1,27 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
|
||||||
<meta http-equiv="Pragma" content="no-cache">
|
|
||||||
<meta http-equiv="Expires" content="0">
|
|
||||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
|
||||||
<link rel="shortcut icon" type="icon" href="favicon.ico" />
|
|
||||||
<style>
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body dir="ltr">
|
<head>
|
||||||
<div id="root"></div>
|
<meta charset="UTF-8" />
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
</body>
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
</html>
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
|
<meta http-equiv="Expires" content="0">
|
||||||
|
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||||
|
<link rel="mask-icon" type="icon" href="favicon-outline.svg" color="#E6FD13" sizes="any" />
|
||||||
|
<link rel="icon" type="icon" href="favicon-key.svg" />
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body dir="ltr">
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -31,13 +31,17 @@
|
|||||||
"lint": "concurrently -g -n eslint,prettier,tsc,madge -c cyan,green,magenta,yellow \"pnpm run lint:eslint\" \"pnpm run lint:prettier\" \"pnpm run lint:tsc\" \"pnpm run lint:madge\"",
|
"lint": "concurrently -g -n eslint,prettier,tsc,madge -c cyan,green,magenta,yellow \"pnpm run lint:eslint\" \"pnpm run lint:prettier\" \"pnpm run lint:tsc\" \"pnpm run lint:madge\"",
|
||||||
"fix": "eslint --fix . && prettier --log-level warn --write .",
|
"fix": "eslint --fix . && prettier --log-level warn --write .",
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
"postinstall": "patch-package && pnpm run theme",
|
"postinstall": "pnpm run theme",
|
||||||
"theme": "chakra-cli tokens src/theme/theme.ts",
|
"theme": "chakra-cli tokens src/theme/theme.ts",
|
||||||
"theme:watch": "chakra-cli tokens src/theme/theme.ts --watch",
|
"theme:watch": "chakra-cli tokens src/theme/theme.ts --watch",
|
||||||
"storybook": "storybook dev -p 6006",
|
"storybook": "storybook dev -p 6006",
|
||||||
"build-storybook": "storybook build"
|
"build-storybook": "storybook build",
|
||||||
|
"unimported": "npx unimported"
|
||||||
},
|
},
|
||||||
"madge": {
|
"madge": {
|
||||||
|
"excludeRegExp": [
|
||||||
|
"^index.ts$"
|
||||||
|
],
|
||||||
"detectiveOptions": {
|
"detectiveOptions": {
|
||||||
"ts": {
|
"ts": {
|
||||||
"skipTypeImports": true
|
"skipTypeImports": true
|
||||||
@ -53,56 +57,57 @@
|
|||||||
"@chakra-ui/layout": "^2.3.1",
|
"@chakra-ui/layout": "^2.3.1",
|
||||||
"@chakra-ui/portal": "^2.1.0",
|
"@chakra-ui/portal": "^2.1.0",
|
||||||
"@chakra-ui/react": "^2.8.2",
|
"@chakra-ui/react": "^2.8.2",
|
||||||
|
"@chakra-ui/react-use-size": "^2.1.0",
|
||||||
"@chakra-ui/styled-system": "^2.9.2",
|
"@chakra-ui/styled-system": "^2.9.2",
|
||||||
"@chakra-ui/theme-tools": "^2.1.2",
|
"@chakra-ui/theme-tools": "^2.1.2",
|
||||||
"@dagrejs/graphlib": "^2.1.13",
|
"@dagrejs/graphlib": "^2.1.13",
|
||||||
"@dnd-kit/core": "^6.1.0",
|
"@dnd-kit/core": "^6.1.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.3",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@fontsource-variable/inter": "^5.0.16",
|
"@fontsource-variable/inter": "^5.0.16",
|
||||||
"@mantine/core": "^6.0.19",
|
"@mantine/form": "6.0.21",
|
||||||
"@mantine/form": "^6.0.19",
|
|
||||||
"@mantine/hooks": "^6.0.19",
|
|
||||||
"@nanostores/react": "^0.7.1",
|
"@nanostores/react": "^0.7.1",
|
||||||
"@reduxjs/toolkit": "^2.0.1",
|
"@reduxjs/toolkit": "2.0.1",
|
||||||
"@roarr/browser-log-writer": "^1.3.0",
|
"@roarr/browser-log-writer": "^1.3.0",
|
||||||
"@storybook/manager-api": "^7.6.4",
|
"chakra-react-select": "^4.7.6",
|
||||||
"@storybook/theming": "^7.6.4",
|
|
||||||
"compare-versions": "^6.1.0",
|
"compare-versions": "^6.1.0",
|
||||||
"dateformat": "^5.0.3",
|
"dateformat": "^5.0.3",
|
||||||
"framer-motion": "^10.16.15",
|
"framer-motion": "^10.17.9",
|
||||||
"i18next": "^23.7.8",
|
"i18next": "^23.7.16",
|
||||||
"i18next-http-backend": "^2.4.2",
|
"i18next-http-backend": "^2.4.2",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"konva": "^9.2.3",
|
"jsondiffpatch": "^0.6.0",
|
||||||
|
"konva": "^9.3.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"nanostores": "^0.9.5",
|
"nanostores": "^0.9.5",
|
||||||
"new-github-issue-url": "^1.0.0",
|
"new-github-issue-url": "^1.0.0",
|
||||||
"overlayscrollbars": "^2.4.5",
|
"overlayscrollbars": "^2.4.6",
|
||||||
"overlayscrollbars-react": "^0.5.3",
|
"overlayscrollbars-react": "^0.5.3",
|
||||||
"patch-package": "^8.0.0",
|
|
||||||
"query-string": "^8.1.0",
|
"query-string": "^8.1.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-colorful": "^5.6.1",
|
"react-colorful": "^5.6.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-dropzone": "^14.2.3",
|
"react-dropzone": "^14.2.3",
|
||||||
"react-error-boundary": "^4.0.11",
|
"react-error-boundary": "^4.0.12",
|
||||||
"react-hotkeys-hook": "4.4.1",
|
"react-hook-form": "^7.49.2",
|
||||||
"react-i18next": "^13.5.0",
|
"react-hotkeys-hook": "4.4.3",
|
||||||
|
"react-i18next": "^14.0.0",
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-redux": "^9.0.2",
|
"react-redux": "9.0.4",
|
||||||
"react-resizable-panels": "^0.0.55",
|
"react-resizable-panels": "^1.0.7",
|
||||||
|
"react-select": "5.8.0",
|
||||||
|
"react-textarea-autosize": "^8.5.3",
|
||||||
"react-use": "^17.4.2",
|
"react-use": "^17.4.2",
|
||||||
"react-virtuoso": "^4.6.2",
|
"react-virtuoso": "^4.6.2",
|
||||||
"reactflow": "^11.10.1",
|
"reactflow": "^11.10.1",
|
||||||
"redux-dynamic-middlewares": "^2.2.0",
|
"redux-dynamic-middlewares": "^2.2.0",
|
||||||
"redux-remember": "^5.0.0",
|
"redux-remember": "^5.1.0",
|
||||||
"roarr": "^7.21.0",
|
"roarr": "^7.21.0",
|
||||||
"serialize-error": "^11.0.3",
|
"serialize-error": "^11.0.3",
|
||||||
"socket.io-client": "^4.7.2",
|
"socket.io-client": "^4.7.3",
|
||||||
"type-fest": "^4.8.3",
|
"type-fest": "^4.9.0",
|
||||||
"use-debounce": "^10.0.0",
|
"use-debounce": "^10.0.0",
|
||||||
"use-image": "^1.1.1",
|
"use-image": "^1.1.1",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
@ -117,44 +122,56 @@
|
|||||||
"ts-toolbelt": "^9.6.0"
|
"ts-toolbelt": "^9.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@arthurgeron/eslint-plugin-react-usememo": "^2.2.3",
|
||||||
"@chakra-ui/cli": "^2.4.1",
|
"@chakra-ui/cli": "^2.4.1",
|
||||||
"@storybook/addon-essentials": "^7.6.4",
|
"@storybook/addon-docs": "^7.6.7",
|
||||||
"@storybook/addon-interactions": "^7.6.4",
|
"@storybook/addon-essentials": "^7.6.7",
|
||||||
"@storybook/addon-links": "^7.6.4",
|
"@storybook/addon-interactions": "^7.6.7",
|
||||||
"@storybook/blocks": "^7.6.4",
|
"@storybook/addon-links": "^7.6.7",
|
||||||
"@storybook/react": "^7.6.4",
|
"@storybook/addon-storysource": "^7.6.7",
|
||||||
"@storybook/react-vite": "^7.6.4",
|
"@storybook/blocks": "^7.6.7",
|
||||||
"@storybook/test": "^7.6.4",
|
"@storybook/manager-api": "^7.6.7",
|
||||||
|
"@storybook/react": "^7.6.7",
|
||||||
|
"@storybook/react-vite": "^7.6.7",
|
||||||
|
"@storybook/test": "^7.6.7",
|
||||||
|
"@storybook/theming": "^7.6.7",
|
||||||
"@types/dateformat": "^5.0.2",
|
"@types/dateformat": "^5.0.2",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.9.0",
|
"@types/node": "^20.10.7",
|
||||||
"@types/react": "^18.2.37",
|
"@types/react": "^18.2.47",
|
||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.18",
|
||||||
"@types/uuid": "^9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
||||||
"@typescript-eslint/parser": "^6.13.2",
|
"@typescript-eslint/parser": "^6.18.0",
|
||||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-i18next": "^6.0.3",
|
"eslint-plugin-i18next": "^6.0.3",
|
||||||
"eslint-plugin-path": "^1.2.2",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-path": "^1.2.3",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||||
"eslint-plugin-storybook": "^0.6.15",
|
"eslint-plugin-storybook": "^0.6.15",
|
||||||
"eslint-plugin-unused-imports": "^3.0.0",
|
"eslint-plugin-unused-imports": "^3.0.0",
|
||||||
"madge": "^6.1.0",
|
"madge": "^6.1.0",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
"openapi-typescript": "^6.7.2",
|
"openapi-typescript": "^6.7.3",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.1",
|
||||||
"rollup-plugin-visualizer": "^5.10.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"storybook": "^7.6.4",
|
"storybook": "^7.6.7",
|
||||||
"ts-toolbelt": "^9.6.0",
|
"ts-toolbelt": "^9.6.0",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"vite": "^4.5.1",
|
"vite": "^5.0.11",
|
||||||
"vite-plugin-css-injected-by-js": "^3.3.0",
|
"vite-plugin-css-injected-by-js": "^3.3.1",
|
||||||
"vite-plugin-dts": "^3.6.4",
|
"vite-plugin-dts": "^3.7.0",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-tsconfig-paths": "^4.2.2"
|
"vite-tsconfig-paths": "^4.2.3"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"patchedDependencies": {
|
||||||
|
"reselect@5.0.1": "patches/reselect@5.0.1.patch"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
241
invokeai/frontend/web/patches/reselect@5.0.1.patch
Normal file
241
invokeai/frontend/web/patches/reselect@5.0.1.patch
Normal file
File diff suppressed because one or more lines are too long
4775
invokeai/frontend/web/pnpm-lock.yaml
generated
4775
invokeai/frontend/web/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -83,10 +83,6 @@
|
|||||||
"title": "خيارات التثبيت",
|
"title": "خيارات التثبيت",
|
||||||
"desc": "ثبت لوحة الخيارات"
|
"desc": "ثبت لوحة الخيارات"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "تبديل العارض",
|
|
||||||
"desc": "فتح وإغلاق مشاهد الصور"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "تبديل المعرض",
|
"title": "تبديل المعرض",
|
||||||
"desc": "فتح وإغلاق درابزين المعرض"
|
"desc": "فتح وإغلاق درابزين المعرض"
|
||||||
@ -147,10 +143,6 @@
|
|||||||
"title": "الصورة التالية",
|
"title": "الصورة التالية",
|
||||||
"desc": "عرض الصورة التالية في الصالة"
|
"desc": "عرض الصورة التالية في الصالة"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "تبديل تثبيت الصالة",
|
|
||||||
"desc": "يثبت ويفتح تثبيت الصالة على الواجهة الرسومية"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "زيادة حجم صورة الصالة",
|
"title": "زيادة حجم صورة الصالة",
|
||||||
"desc": "يزيد حجم الصور المصغرة في الصالة"
|
"desc": "يزيد حجم الصور المصغرة في الصالة"
|
||||||
|
@ -168,10 +168,6 @@
|
|||||||
"title": "Optionen anheften",
|
"title": "Optionen anheften",
|
||||||
"desc": "Anheften des Optionsfeldes"
|
"desc": "Anheften des Optionsfeldes"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Bildbetrachter umschalten",
|
|
||||||
"desc": "Bildbetrachter öffnen und schließen"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Galerie umschalten",
|
"title": "Galerie umschalten",
|
||||||
"desc": "Öffnen und Schließen des Galerie-Schubfachs"
|
"desc": "Öffnen und Schließen des Galerie-Schubfachs"
|
||||||
@ -232,10 +228,6 @@
|
|||||||
"title": "Nächstes Bild",
|
"title": "Nächstes Bild",
|
||||||
"desc": "Nächstes Bild in Galerie anzeigen"
|
"desc": "Nächstes Bild in Galerie anzeigen"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Galerie anheften umschalten",
|
|
||||||
"desc": "Heftet die Galerie an die Benutzeroberfläche bzw. löst die sie"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Größe der Galeriebilder erhöhen",
|
"title": "Größe der Galeriebilder erhöhen",
|
||||||
"desc": "Vergrößert die Galerie-Miniaturansichten"
|
"desc": "Vergrößert die Galerie-Miniaturansichten"
|
||||||
@ -760,7 +752,6 @@
|
|||||||
"w": "W",
|
"w": "W",
|
||||||
"addControlNet": "$t(common.controlNet) hinzufügen",
|
"addControlNet": "$t(common.controlNet) hinzufügen",
|
||||||
"none": "Kein",
|
"none": "Kein",
|
||||||
"incompatibleBaseModel": "Inkompatibles Basismodell:",
|
|
||||||
"enableControlnet": "Aktiviere ControlNet",
|
"enableControlnet": "Aktiviere ControlNet",
|
||||||
"detectResolution": "Auflösung erkennen",
|
"detectResolution": "Auflösung erkennen",
|
||||||
"controlNetT2IMutexDesc": "$t(common.controlNet) und $t(common.t2iAdapter) zur gleichen Zeit wird nicht unterstützt.",
|
"controlNetT2IMutexDesc": "$t(common.controlNet) und $t(common.t2iAdapter) zur gleichen Zeit wird nicht unterstützt.",
|
||||||
|
@ -50,9 +50,33 @@
|
|||||||
"uncategorized": "Uncategorized",
|
"uncategorized": "Uncategorized",
|
||||||
"downloadBoard": "Download Board"
|
"downloadBoard": "Download Board"
|
||||||
},
|
},
|
||||||
|
"accordions": {
|
||||||
|
"generation": {
|
||||||
|
"title": "Generation",
|
||||||
|
"modelTab": "Model",
|
||||||
|
"conceptsTab": "Concepts"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"title": "Image"
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"title": "Advanced"
|
||||||
|
},
|
||||||
|
"control": {
|
||||||
|
"title": "Control",
|
||||||
|
"controlAdaptersTab": "Control Adapters",
|
||||||
|
"ipTab": "Image Prompts"
|
||||||
|
},
|
||||||
|
"compositing": {
|
||||||
|
"title": "Compositing",
|
||||||
|
"coherenceTab": "Coherence Pass",
|
||||||
|
"infillTab": "Infill"
|
||||||
|
}
|
||||||
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"accept": "Accept",
|
"accept": "Accept",
|
||||||
"advanced": "Advanced",
|
"advanced": "Advanced",
|
||||||
|
"advancedOptions": "Advanced Options",
|
||||||
"ai": "ai",
|
"ai": "ai",
|
||||||
"areYouSure": "Are you sure?",
|
"areYouSure": "Are you sure?",
|
||||||
"auto": "Auto",
|
"auto": "Auto",
|
||||||
@ -62,6 +86,7 @@
|
|||||||
"copyError": "$t(gallery.copy) Error",
|
"copyError": "$t(gallery.copy) Error",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"on": "On",
|
"on": "On",
|
||||||
|
"or": "or",
|
||||||
"checkpoint": "Checkpoint",
|
"checkpoint": "Checkpoint",
|
||||||
"communityLabel": "Community",
|
"communityLabel": "Community",
|
||||||
"controlNet": "ControlNet",
|
"controlNet": "ControlNet",
|
||||||
@ -79,6 +104,7 @@
|
|||||||
"file": "File",
|
"file": "File",
|
||||||
"folder": "Folder",
|
"folder": "Folder",
|
||||||
"format": "format",
|
"format": "format",
|
||||||
|
"free": "Free",
|
||||||
"generate": "Generate",
|
"generate": "Generate",
|
||||||
"githubLabel": "Github",
|
"githubLabel": "Github",
|
||||||
"hotkeysLabel": "Hotkeys",
|
"hotkeysLabel": "Hotkeys",
|
||||||
@ -131,6 +157,7 @@
|
|||||||
"save": "Save",
|
"save": "Save",
|
||||||
"saveAs": "Save As",
|
"saveAs": "Save As",
|
||||||
"settingsLabel": "Settings",
|
"settingsLabel": "Settings",
|
||||||
|
"preferencesLabel": "Preferences",
|
||||||
"simple": "Simple",
|
"simple": "Simple",
|
||||||
"somethingWentWrong": "Something went wrong",
|
"somethingWentWrong": "Something went wrong",
|
||||||
"statusConnected": "Connected",
|
"statusConnected": "Connected",
|
||||||
@ -221,7 +248,6 @@
|
|||||||
"colorMapTileSize": "Tile Size",
|
"colorMapTileSize": "Tile Size",
|
||||||
"importImageFromCanvas": "Import Image From Canvas",
|
"importImageFromCanvas": "Import Image From Canvas",
|
||||||
"importMaskFromCanvas": "Import Mask From Canvas",
|
"importMaskFromCanvas": "Import Mask From Canvas",
|
||||||
"incompatibleBaseModel": "Incompatible base model:",
|
|
||||||
"lineart": "Lineart",
|
"lineart": "Lineart",
|
||||||
"lineartAnime": "Lineart Anime",
|
"lineartAnime": "Lineart Anime",
|
||||||
"lineartAnimeDescription": "Anime-style lineart processing",
|
"lineartAnimeDescription": "Anime-style lineart processing",
|
||||||
@ -246,6 +272,7 @@
|
|||||||
"prompt": "Prompt",
|
"prompt": "Prompt",
|
||||||
"resetControlImage": "Reset Control Image",
|
"resetControlImage": "Reset Control Image",
|
||||||
"resize": "Resize",
|
"resize": "Resize",
|
||||||
|
"resizeSimple": "Resize (Simple)",
|
||||||
"resizeMode": "Resize Mode",
|
"resizeMode": "Resize Mode",
|
||||||
"safe": "Safe",
|
"safe": "Safe",
|
||||||
"saveControlImage": "Save Control Image",
|
"saveControlImage": "Save Control Image",
|
||||||
@ -284,7 +311,7 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"queueFront": "Add to Front of Queue",
|
"queueFront": "Add to Front of Queue",
|
||||||
"queueBack": "Add to Queue",
|
"queueBack": "Add to Queue",
|
||||||
"queueCountPrediction": "Add {{predicted}} to Queue",
|
"queueCountPrediction": "{{promptsCount}} prompts × {{iterations}} iterations -> {{count}} generations",
|
||||||
"queueMaxExceeded": "Max of {{max_queue_size}} exceeded, would skip {{skip}}",
|
"queueMaxExceeded": "Max of {{max_queue_size}} exceeded, would skip {{skip}}",
|
||||||
"queuedCount": "{{pending}} Pending",
|
"queuedCount": "{{pending}} Pending",
|
||||||
"queueTotal": "{{total}} Total",
|
"queueTotal": "{{total}} Total",
|
||||||
@ -340,7 +367,8 @@
|
|||||||
"back": "back",
|
"back": "back",
|
||||||
"batchFailedToQueue": "Failed to Queue Batch",
|
"batchFailedToQueue": "Failed to Queue Batch",
|
||||||
"graphQueued": "Graph queued",
|
"graphQueued": "Graph queued",
|
||||||
"graphFailedToQueue": "Failed to queue graph"
|
"graphFailedToQueue": "Failed to queue graph",
|
||||||
|
"openQueue": "Open Queue"
|
||||||
},
|
},
|
||||||
"invocationCache": {
|
"invocationCache": {
|
||||||
"invocationCache": "Invocation Cache",
|
"invocationCache": "Invocation Cache",
|
||||||
@ -400,6 +428,9 @@
|
|||||||
"problemDeletingImagesDesc": "One or more images could not be deleted"
|
"problemDeletingImagesDesc": "One or more images could not be deleted"
|
||||||
},
|
},
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
|
"searchHotkeys": "Search Hotkeys",
|
||||||
|
"clearSearch": "Clear Search",
|
||||||
|
"noHotkeysFound": "No Hotkeys Found",
|
||||||
"acceptStagingImage": {
|
"acceptStagingImage": {
|
||||||
"desc": "Accept Current Staging Area Image",
|
"desc": "Accept Current Staging Area Image",
|
||||||
"title": "Accept Staging Image"
|
"title": "Accept Staging Image"
|
||||||
@ -408,11 +439,15 @@
|
|||||||
"desc": "Opens the add node menu",
|
"desc": "Opens the add node menu",
|
||||||
"title": "Add Nodes"
|
"title": "Add Nodes"
|
||||||
},
|
},
|
||||||
"appHotkeys": "App Hotkeys",
|
"appHotkeys": "App",
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"desc": "Cancel image generation",
|
"desc": "Cancel current queue item",
|
||||||
"title": "Cancel"
|
"title": "Cancel"
|
||||||
},
|
},
|
||||||
|
"cancelAndClear": {
|
||||||
|
"desc": "Cancel current queue item and clear all pending items",
|
||||||
|
"title": "Cancel and Clear"
|
||||||
|
},
|
||||||
"changeTabs": {
|
"changeTabs": {
|
||||||
"desc": "Switch to another workspace",
|
"desc": "Switch to another workspace",
|
||||||
"title": "Change Tabs"
|
"title": "Change Tabs"
|
||||||
@ -469,8 +504,8 @@
|
|||||||
"desc": "Focus the prompt input area",
|
"desc": "Focus the prompt input area",
|
||||||
"title": "Focus Prompt"
|
"title": "Focus Prompt"
|
||||||
},
|
},
|
||||||
"galleryHotkeys": "Gallery Hotkeys",
|
"galleryHotkeys": "Gallery",
|
||||||
"generalHotkeys": "General Hotkeys",
|
"generalHotkeys": "General",
|
||||||
"hideMask": {
|
"hideMask": {
|
||||||
"desc": "Hide and unhide mask",
|
"desc": "Hide and unhide mask",
|
||||||
"title": "Hide Mask"
|
"title": "Hide Mask"
|
||||||
@ -491,7 +526,7 @@
|
|||||||
"desc": "Generate an image",
|
"desc": "Generate an image",
|
||||||
"title": "Invoke"
|
"title": "Invoke"
|
||||||
},
|
},
|
||||||
"keyboardShortcuts": "Keyboard Shortcuts",
|
"keyboardShortcuts": "Hotkeys",
|
||||||
"maximizeWorkSpace": {
|
"maximizeWorkSpace": {
|
||||||
"desc": "Close panels and maximize work area",
|
"desc": "Close panels and maximize work area",
|
||||||
"title": "Maximize Workspace"
|
"title": "Maximize Workspace"
|
||||||
@ -512,7 +547,7 @@
|
|||||||
"desc": "Next Staging Area Image",
|
"desc": "Next Staging Area Image",
|
||||||
"title": "Next Staging Image"
|
"title": "Next Staging Image"
|
||||||
},
|
},
|
||||||
"nodesHotkeys": "Nodes Hotkeys",
|
"nodesHotkeys": "Nodes",
|
||||||
"pinOptions": {
|
"pinOptions": {
|
||||||
"desc": "Pin the options panel",
|
"desc": "Pin the options panel",
|
||||||
"title": "Pin Options"
|
"title": "Pin Options"
|
||||||
@ -581,31 +616,31 @@
|
|||||||
"desc": "Open and close the gallery drawer",
|
"desc": "Open and close the gallery drawer",
|
||||||
"title": "Toggle Gallery"
|
"title": "Toggle Gallery"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
"toggleOptions": {
|
||||||
"desc": "Pins and unpins the gallery to the UI",
|
"desc": "Open and close the options panel",
|
||||||
"title": "Toggle Gallery Pin"
|
"title": "Toggle Options"
|
||||||
|
},
|
||||||
|
"toggleOptionsAndGallery": {
|
||||||
|
"desc": "Open and close the options and gallery panels",
|
||||||
|
"title": "Toggle Options and Gallery"
|
||||||
|
},
|
||||||
|
"resetOptionsAndGallery": {
|
||||||
|
"desc": "Resets the options and gallery panels",
|
||||||
|
"title": "Reset Options and Gallery"
|
||||||
},
|
},
|
||||||
"toggleLayer": {
|
"toggleLayer": {
|
||||||
"desc": "Toggles mask/base layer selection",
|
"desc": "Toggles mask/base layer selection",
|
||||||
"title": "Toggle Layer"
|
"title": "Toggle Layer"
|
||||||
},
|
},
|
||||||
"toggleOptions": {
|
|
||||||
"desc": "Open and close the options panel",
|
|
||||||
"title": "Toggle Options"
|
|
||||||
},
|
|
||||||
"toggleSnap": {
|
"toggleSnap": {
|
||||||
"desc": "Toggles Snap to Grid",
|
"desc": "Toggles Snap to Grid",
|
||||||
"title": "Toggle Snap"
|
"title": "Toggle Snap"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"desc": "Open and close Image Viewer",
|
|
||||||
"title": "Toggle Viewer"
|
|
||||||
},
|
|
||||||
"undoStroke": {
|
"undoStroke": {
|
||||||
"desc": "Undo a brush stroke",
|
"desc": "Undo a brush stroke",
|
||||||
"title": "Undo Stroke"
|
"title": "Undo Stroke"
|
||||||
},
|
},
|
||||||
"unifiedCanvasHotkeys": "Unified Canvas Hotkeys",
|
"unifiedCanvasHotkeys": "Unified Canvas",
|
||||||
"upscale": {
|
"upscale": {
|
||||||
"desc": "Upscale the current image",
|
"desc": "Upscale the current image",
|
||||||
"title": "Upscale"
|
"title": "Upscale"
|
||||||
@ -788,17 +823,23 @@
|
|||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"addLora": "Add LoRA",
|
"addLora": "Add LoRA",
|
||||||
|
"allLoRAsAdded": "All LoRAs added",
|
||||||
|
"loraAlreadyAdded": "LoRA already added",
|
||||||
"esrganModel": "ESRGAN Model",
|
"esrganModel": "ESRGAN Model",
|
||||||
"loading": "loading",
|
"loading": "loading",
|
||||||
|
"incompatibleBaseModel": "Incompatible base model",
|
||||||
|
"noMainModelSelected": "No main model selected",
|
||||||
"noLoRAsAvailable": "No LoRAs available",
|
"noLoRAsAvailable": "No LoRAs available",
|
||||||
"noLoRAsLoaded": "No LoRAs Loaded",
|
"noLoRAsLoaded": "No LoRAs Loaded",
|
||||||
"noMatchingLoRAs": "No matching LoRAs",
|
"noMatchingLoRAs": "No matching LoRAs",
|
||||||
"noMatchingModels": "No matching Models",
|
"noMatchingModels": "No matching Models",
|
||||||
"noModelsAvailable": "No models available",
|
"noModelsAvailable": "No models available",
|
||||||
|
"lora": "LoRA",
|
||||||
"selectLoRA": "Select a LoRA",
|
"selectLoRA": "Select a LoRA",
|
||||||
"selectModel": "Select a Model",
|
"selectModel": "Select a Model",
|
||||||
"noLoRAsInstalled": "No LoRAs installed",
|
"noLoRAsInstalled": "No LoRAs installed",
|
||||||
"noRefinerModelsInstalled": "No SDXL Refiner models installed"
|
"noRefinerModelsInstalled": "No SDXL Refiner models installed",
|
||||||
|
"defaultVAE": "Default VAE"
|
||||||
},
|
},
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"addNode": "Add Node",
|
"addNode": "Add Node",
|
||||||
@ -1037,8 +1078,14 @@
|
|||||||
"prototypeDesc": "This invocation is a prototype. It may have breaking changes during app updates and may be removed at any time."
|
"prototypeDesc": "This invocation is a prototype. It may have breaking changes during app updates and may be removed at any time."
|
||||||
},
|
},
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
"aspect": "Aspect",
|
||||||
"aspectRatio": "Aspect Ratio",
|
"aspectRatio": "Aspect Ratio",
|
||||||
"aspectRatioFree": "Free",
|
"aspectRatioFree": "Free",
|
||||||
|
"lockAspectRatio": "Lock Aspect Ratio",
|
||||||
|
"swapDimensions": "Swap Dimensions",
|
||||||
|
"setToOptimalSize": "Optimize size for model",
|
||||||
|
"setToOptimalSizeTooSmall": "$t(parameters.setToOptimalSize) (may be too small)",
|
||||||
|
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (may be too large)",
|
||||||
"boundingBoxHeader": "Bounding Box",
|
"boundingBoxHeader": "Bounding Box",
|
||||||
"boundingBoxHeight": "Bounding Box Height",
|
"boundingBoxHeight": "Bounding Box Height",
|
||||||
"boundingBoxWidth": "Bounding Box Width",
|
"boundingBoxWidth": "Bounding Box Width",
|
||||||
@ -1077,6 +1124,7 @@
|
|||||||
"imageFit": "Fit Initial Image To Output Size",
|
"imageFit": "Fit Initial Image To Output Size",
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
"imageToImage": "Image to Image",
|
"imageToImage": "Image to Image",
|
||||||
|
"imageSize": "Image Size",
|
||||||
"img2imgStrength": "Image To Image Strength",
|
"img2imgStrength": "Image To Image Strength",
|
||||||
"infillMethod": "Infill Method",
|
"infillMethod": "Infill Method",
|
||||||
"infillScalingHeader": "Infill and Scaling",
|
"infillScalingHeader": "Infill and Scaling",
|
||||||
@ -1091,7 +1139,7 @@
|
|||||||
"noControlImageForControlAdapter": "Control Adapter #{{number}} has no control image",
|
"noControlImageForControlAdapter": "Control Adapter #{{number}} has no control image",
|
||||||
"noInitialImageSelected": "No initial image selected",
|
"noInitialImageSelected": "No initial image selected",
|
||||||
"noModelForControlAdapter": "Control Adapter #{{number}} has no model selected.",
|
"noModelForControlAdapter": "Control Adapter #{{number}} has no model selected.",
|
||||||
"incompatibleBaseModelForControlAdapter": "Control Adapter #{{number}} model is invalid with main model.",
|
"incompatibleBaseModelForControlAdapter": "Control Adapter #{{number}} model is incompatible with main model.",
|
||||||
"noModelSelected": "No model selected",
|
"noModelSelected": "No model selected",
|
||||||
"noPrompts": "No prompts generated",
|
"noPrompts": "No prompts generated",
|
||||||
"noNodesInGraph": "No nodes in graph",
|
"noNodesInGraph": "No nodes in graph",
|
||||||
@ -1127,8 +1175,8 @@
|
|||||||
"seamCorrectionHeader": "Seam Correction",
|
"seamCorrectionHeader": "Seam Correction",
|
||||||
"seamHighThreshold": "High",
|
"seamHighThreshold": "High",
|
||||||
"seamlessTiling": "Seamless Tiling",
|
"seamlessTiling": "Seamless Tiling",
|
||||||
"seamlessXAxis": "X Axis",
|
"seamlessXAxis": "Seamless Tiling X Axis",
|
||||||
"seamlessYAxis": "Y Axis",
|
"seamlessYAxis": "Seamless Tiling Y Axis",
|
||||||
"seamlessX": "Seamless X",
|
"seamlessX": "Seamless X",
|
||||||
"seamlessY": "Seamless Y",
|
"seamlessY": "Seamless Y",
|
||||||
"seamlessX&Y": "Seamless X & Y",
|
"seamlessX&Y": "Seamless X & Y",
|
||||||
@ -1171,6 +1219,7 @@
|
|||||||
},
|
},
|
||||||
"dynamicPrompts": {
|
"dynamicPrompts": {
|
||||||
"combinatorial": "Combinatorial Generation",
|
"combinatorial": "Combinatorial Generation",
|
||||||
|
"showDynamicPrompts": "Show Dynamic Prompts",
|
||||||
"dynamicPrompts": "Dynamic Prompts",
|
"dynamicPrompts": "Dynamic Prompts",
|
||||||
"enableDynamicPrompts": "Enable Dynamic Prompts",
|
"enableDynamicPrompts": "Enable Dynamic Prompts",
|
||||||
"maxPrompts": "Max Prompts",
|
"maxPrompts": "Max Prompts",
|
||||||
@ -1183,11 +1232,13 @@
|
|||||||
"perIterationDesc": "Use a different seed for each iteration",
|
"perIterationDesc": "Use a different seed for each iteration",
|
||||||
"perPromptLabel": "Seed per Image",
|
"perPromptLabel": "Seed per Image",
|
||||||
"perPromptDesc": "Use a different seed for each image"
|
"perPromptDesc": "Use a different seed for each image"
|
||||||
}
|
},
|
||||||
|
"loading": "Generating Dynamic Prompts..."
|
||||||
},
|
},
|
||||||
"sdxl": {
|
"sdxl": {
|
||||||
"cfgScale": "CFG Scale",
|
"cfgScale": "CFG Scale",
|
||||||
"concatPromptStyle": "Concatenate Prompt & Style",
|
"concatPromptStyle": "Linking Prompt & Style",
|
||||||
|
"freePromptStyle": "Manual Style Prompting",
|
||||||
"denoisingStrength": "Denoising Strength",
|
"denoisingStrength": "Denoising Strength",
|
||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
"negAestheticScore": "Negative Aesthetic Score",
|
"negAestheticScore": "Negative Aesthetic Score",
|
||||||
|
@ -127,10 +127,6 @@
|
|||||||
"title": "Fijar opciones",
|
"title": "Fijar opciones",
|
||||||
"desc": "Fijar el panel de opciones"
|
"desc": "Fijar el panel de opciones"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Alternar visor",
|
|
||||||
"desc": "Mostar y ocultar el visor de imágenes"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Alternar galería",
|
"title": "Alternar galería",
|
||||||
"desc": "Mostar y ocultar la galería de imágenes"
|
"desc": "Mostar y ocultar la galería de imágenes"
|
||||||
@ -191,10 +187,6 @@
|
|||||||
"title": "Imagen siguiente",
|
"title": "Imagen siguiente",
|
||||||
"desc": "Muetra la imagen siguiente en la galería"
|
"desc": "Muetra la imagen siguiente en la galería"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Alternar fijado de galería",
|
|
||||||
"desc": "Fijar o desfijar la galería en la interfaz"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Aumentar imagen en galería",
|
"title": "Aumentar imagen en galería",
|
||||||
"desc": "Aumenta el tamaño de las miniaturas de la galería"
|
"desc": "Aumenta el tamaño de las miniaturas de la galería"
|
||||||
|
@ -96,10 +96,6 @@
|
|||||||
"title": "Epinglage des options",
|
"title": "Epinglage des options",
|
||||||
"desc": "Epingler le panneau d'options"
|
"desc": "Epingler le panneau d'options"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Affichage de la visionneuse",
|
|
||||||
"desc": "Afficher et masquer la visionneuse d'image"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Affichage de la galerie",
|
"title": "Affichage de la galerie",
|
||||||
"desc": "Afficher et masquer la galerie"
|
"desc": "Afficher et masquer la galerie"
|
||||||
@ -160,10 +156,6 @@
|
|||||||
"title": "Image suivante",
|
"title": "Image suivante",
|
||||||
"desc": "Afficher l'image suivante dans la galerie"
|
"desc": "Afficher l'image suivante dans la galerie"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Activer/désactiver l'épinglage de la galerie",
|
|
||||||
"desc": "Épingle ou dépingle la galerie à l'interface"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Augmenter la taille des miniatures de la galerie",
|
"title": "Augmenter la taille des miniatures de la galerie",
|
||||||
"desc": "Augmente la taille des miniatures de la galerie"
|
"desc": "Augmente la taille des miniatures de la galerie"
|
||||||
|
@ -192,10 +192,6 @@
|
|||||||
"title": "הצמד הגדרות",
|
"title": "הצמד הגדרות",
|
||||||
"desc": "הצמד את פאנל ההגדרות"
|
"desc": "הצמד את פאנל ההגדרות"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "הצג את חלון ההצגה",
|
|
||||||
"desc": "פתח וסגור את מציג התמונות"
|
|
||||||
},
|
|
||||||
"changeTabs": {
|
"changeTabs": {
|
||||||
"title": "החלף לשוניות",
|
"title": "החלף לשוניות",
|
||||||
"desc": "החלף לאיזור עבודה אחר"
|
"desc": "החלף לאיזור עבודה אחר"
|
||||||
@ -236,10 +232,6 @@
|
|||||||
"title": "תמונה קודמת",
|
"title": "תמונה קודמת",
|
||||||
"desc": "הצג את התמונה הקודמת בגלריה"
|
"desc": "הצג את התמונה הקודמת בגלריה"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "הצג את מצמיד הגלריה",
|
|
||||||
"desc": "הצמדה וביטול הצמדה של הגלריה לממשק המשתמש"
|
|
||||||
},
|
|
||||||
"decreaseGalleryThumbSize": {
|
"decreaseGalleryThumbSize": {
|
||||||
"title": "הקטנת גודל תמונת גלריה",
|
"title": "הקטנת גודל תמונת גלריה",
|
||||||
"desc": "מקטין את גודל התמונות הממוזערות של הגלריה"
|
"desc": "מקטין את גודל התמונות הממוזערות של הגלריה"
|
||||||
|
@ -114,7 +114,9 @@
|
|||||||
"nextPage": "Pagina successiva",
|
"nextPage": "Pagina successiva",
|
||||||
"saveAs": "Salva come",
|
"saveAs": "Salva come",
|
||||||
"unsaved": "Non salvato",
|
"unsaved": "Non salvato",
|
||||||
"direction": "Direzione"
|
"direction": "Direzione",
|
||||||
|
"advancedOptions": "Opzioni avanzate",
|
||||||
|
"free": "Libero"
|
||||||
},
|
},
|
||||||
"gallery": {
|
"gallery": {
|
||||||
"generations": "Generazioni",
|
"generations": "Generazioni",
|
||||||
@ -132,7 +134,7 @@
|
|||||||
"noImagesInGallery": "Nessuna immagine da visualizzare",
|
"noImagesInGallery": "Nessuna immagine da visualizzare",
|
||||||
"deleteImage": "Elimina l'immagine",
|
"deleteImage": "Elimina l'immagine",
|
||||||
"deleteImagePermanent": "Le immagini eliminate non possono essere ripristinate.",
|
"deleteImagePermanent": "Le immagini eliminate non possono essere ripristinate.",
|
||||||
"deleteImageBin": "Le immagini eliminate verranno spostate nel Cestino del tuo sistema operativo.",
|
"deleteImageBin": "Le immagini eliminate verranno spostate nel cestino del tuo sistema operativo.",
|
||||||
"assets": "Risorse",
|
"assets": "Risorse",
|
||||||
"autoAssignBoardOnClick": "Assegna automaticamente la bacheca al clic",
|
"autoAssignBoardOnClick": "Assegna automaticamente la bacheca al clic",
|
||||||
"featuresWillReset": "Se elimini questa immagine, quelle funzionalità verranno immediatamente ripristinate.",
|
"featuresWillReset": "Se elimini questa immagine, quelle funzionalità verranno immediatamente ripristinate.",
|
||||||
@ -157,18 +159,18 @@
|
|||||||
"problemDeletingImages": "Problema durante l'eliminazione delle immagini"
|
"problemDeletingImages": "Problema durante l'eliminazione delle immagini"
|
||||||
},
|
},
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"keyboardShortcuts": "Tasti rapidi",
|
"keyboardShortcuts": "Tasti di scelta rapida",
|
||||||
"appHotkeys": "Tasti di scelta rapida dell'applicazione",
|
"appHotkeys": "Applicazione",
|
||||||
"generalHotkeys": "Tasti di scelta rapida generali",
|
"generalHotkeys": "Generale",
|
||||||
"galleryHotkeys": "Tasti di scelta rapida della galleria",
|
"galleryHotkeys": "Galleria",
|
||||||
"unifiedCanvasHotkeys": "Tasti di scelta rapida Tela Unificata",
|
"unifiedCanvasHotkeys": "Tela Unificata",
|
||||||
"invoke": {
|
"invoke": {
|
||||||
"title": "Invoke",
|
"title": "Invoke",
|
||||||
"desc": "Genera un'immagine"
|
"desc": "Genera un'immagine"
|
||||||
},
|
},
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"title": "Annulla",
|
"title": "Annulla",
|
||||||
"desc": "Annulla la generazione dell'immagine"
|
"desc": "Annulla l'elemento della coda corrente"
|
||||||
},
|
},
|
||||||
"focusPrompt": {
|
"focusPrompt": {
|
||||||
"title": "Metti a fuoco il Prompt",
|
"title": "Metti a fuoco il Prompt",
|
||||||
@ -182,12 +184,8 @@
|
|||||||
"title": "Appunta le opzioni",
|
"title": "Appunta le opzioni",
|
||||||
"desc": "Blocca il pannello delle opzioni"
|
"desc": "Blocca il pannello delle opzioni"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Attiva/disattiva visualizzatore",
|
|
||||||
"desc": "Apre e chiude il visualizzatore immagini"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Attiva/disattiva Galleria",
|
"title": "Attiva/disattiva galleria",
|
||||||
"desc": "Apre e chiude il pannello della galleria"
|
"desc": "Apre e chiude il pannello della galleria"
|
||||||
},
|
},
|
||||||
"maximizeWorkSpace": {
|
"maximizeWorkSpace": {
|
||||||
@ -246,10 +244,6 @@
|
|||||||
"title": "Immagine successiva",
|
"title": "Immagine successiva",
|
||||||
"desc": "Visualizza l'immagine successiva nella galleria"
|
"desc": "Visualizza l'immagine successiva nella galleria"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Attiva/disattiva il blocco della galleria",
|
|
||||||
"desc": "Blocca/sblocca la galleria dall'interfaccia utente"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Aumenta dimensione immagini nella galleria",
|
"title": "Aumenta dimensione immagini nella galleria",
|
||||||
"desc": "Aumenta la dimensione delle miniature della galleria"
|
"desc": "Aumenta la dimensione delle miniature della galleria"
|
||||||
@ -362,11 +356,26 @@
|
|||||||
"title": "Accetta l'immagine della sessione",
|
"title": "Accetta l'immagine della sessione",
|
||||||
"desc": "Accetta l'immagine dell'area della sessione corrente"
|
"desc": "Accetta l'immagine dell'area della sessione corrente"
|
||||||
},
|
},
|
||||||
"nodesHotkeys": "Tasti di scelta rapida dei Nodi",
|
"nodesHotkeys": "Nodi",
|
||||||
"addNodes": {
|
"addNodes": {
|
||||||
"title": "Aggiungi Nodi",
|
"title": "Aggiungi Nodi",
|
||||||
"desc": "Apre il menu Aggiungi Nodi"
|
"desc": "Apre il menu Aggiungi Nodi"
|
||||||
}
|
},
|
||||||
|
"cancelAndClear": {
|
||||||
|
"desc": "Annulla l'elemento della coda corrente e cancella tutti gli elementi in sospeso",
|
||||||
|
"title": "Annulla e cancella"
|
||||||
|
},
|
||||||
|
"resetOptionsAndGallery": {
|
||||||
|
"title": "Ripristina Opzioni e Galleria",
|
||||||
|
"desc": "Reimposta le opzioni e i pannelli della galleria"
|
||||||
|
},
|
||||||
|
"searchHotkeys": "Cerca tasti di scelta rapida",
|
||||||
|
"noHotkeysFound": "Nessun tasto di scelta rapida trovato",
|
||||||
|
"toggleOptionsAndGallery": {
|
||||||
|
"desc": "Apre e chiude le opzioni e i pannelli della galleria",
|
||||||
|
"title": "Attiva/disattiva le Opzioni e la Galleria"
|
||||||
|
},
|
||||||
|
"clearSearch": "Cancella ricerca"
|
||||||
},
|
},
|
||||||
"modelManager": {
|
"modelManager": {
|
||||||
"modelManager": "Gestione Modelli",
|
"modelManager": "Gestione Modelli",
|
||||||
@ -581,8 +590,8 @@
|
|||||||
"hidePreview": "Nascondi l'anteprima",
|
"hidePreview": "Nascondi l'anteprima",
|
||||||
"showPreview": "Mostra l'anteprima",
|
"showPreview": "Mostra l'anteprima",
|
||||||
"noiseSettings": "Rumore",
|
"noiseSettings": "Rumore",
|
||||||
"seamlessXAxis": "Asse X",
|
"seamlessXAxis": "Piastrella senza cucitura Asse X",
|
||||||
"seamlessYAxis": "Asse Y",
|
"seamlessYAxis": "Piastrella senza cucitura Asse Y",
|
||||||
"scheduler": "Campionatore",
|
"scheduler": "Campionatore",
|
||||||
"boundingBoxWidth": "Larghezza riquadro di delimitazione",
|
"boundingBoxWidth": "Larghezza riquadro di delimitazione",
|
||||||
"boundingBoxHeight": "Altezza riquadro di delimitazione",
|
"boundingBoxHeight": "Altezza riquadro di delimitazione",
|
||||||
@ -642,7 +651,14 @@
|
|||||||
"unmasked": "No maschera",
|
"unmasked": "No maschera",
|
||||||
"cfgRescaleMultiplier": "Moltiplicatore riscala CFG",
|
"cfgRescaleMultiplier": "Moltiplicatore riscala CFG",
|
||||||
"cfgRescale": "Riscala CFG",
|
"cfgRescale": "Riscala CFG",
|
||||||
"useSize": "Usa Dimensioni"
|
"useSize": "Usa Dimensioni",
|
||||||
|
"setToOptimalSize": "Ottimizza le dimensioni per il modello",
|
||||||
|
"setToOptimalSizeTooSmall": "$t(parameters.setToOptimalSize) (potrebbe essere troppo piccolo)",
|
||||||
|
"imageSize": "Dimensione dell'immagine",
|
||||||
|
"lockAspectRatio": "Blocca proporzioni",
|
||||||
|
"swapDimensions": "Scambia dimensioni",
|
||||||
|
"aspect": "Aspetto",
|
||||||
|
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (potrebbe essere troppo grande)"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"models": "Modelli",
|
"models": "Modelli",
|
||||||
@ -1178,7 +1194,6 @@
|
|||||||
"w": "W",
|
"w": "W",
|
||||||
"processor": "Processore",
|
"processor": "Processore",
|
||||||
"none": "Nessuno",
|
"none": "Nessuno",
|
||||||
"incompatibleBaseModel": "Modello base incompatibile:",
|
|
||||||
"pidiDescription": "Elaborazione immagini PIDI",
|
"pidiDescription": "Elaborazione immagini PIDI",
|
||||||
"fill": "Riempie",
|
"fill": "Riempie",
|
||||||
"colorMapDescription": "Genera una mappa dei colori dall'immagine",
|
"colorMapDescription": "Genera una mappa dei colori dall'immagine",
|
||||||
@ -1214,12 +1229,13 @@
|
|||||||
"minConfidence": "Confidenza minima",
|
"minConfidence": "Confidenza minima",
|
||||||
"scribble": "Scribble",
|
"scribble": "Scribble",
|
||||||
"amult": "Angolo di illuminazione",
|
"amult": "Angolo di illuminazione",
|
||||||
"coarse": "Approssimativo"
|
"coarse": "Approssimativo",
|
||||||
|
"resizeSimple": "Ridimensiona (semplice)"
|
||||||
},
|
},
|
||||||
"queue": {
|
"queue": {
|
||||||
"queueFront": "Aggiungi all'inizio della coda",
|
"queueFront": "Aggiungi all'inizio della coda",
|
||||||
"queueBack": "Aggiungi alla coda",
|
"queueBack": "Aggiungi alla coda",
|
||||||
"queueCountPrediction": "Aggiungi {{predicted}} alla coda",
|
"queueCountPrediction": "{{promptsCount}} prompt × {{iterations}} iterazioni -> {{count}} generazioni",
|
||||||
"queue": "Coda",
|
"queue": "Coda",
|
||||||
"status": "Stato",
|
"status": "Stato",
|
||||||
"pruneSucceeded": "Rimossi {{item_count}} elementi completati dalla coda",
|
"pruneSucceeded": "Rimossi {{item_count}} elementi completati dalla coda",
|
||||||
@ -1277,7 +1293,8 @@
|
|||||||
"graphFailedToQueue": "Impossibile mettere in coda il grafico",
|
"graphFailedToQueue": "Impossibile mettere in coda il grafico",
|
||||||
"queueMaxExceeded": "È stato superato il limite massimo di {{max_queue_size}} e {{skip}} elementi verrebbero saltati",
|
"queueMaxExceeded": "È stato superato il limite massimo di {{max_queue_size}} e {{skip}} elementi verrebbero saltati",
|
||||||
"batchFieldValues": "Valori Campi Lotto",
|
"batchFieldValues": "Valori Campi Lotto",
|
||||||
"time": "Tempo"
|
"time": "Tempo",
|
||||||
|
"openQueue": "Apri coda"
|
||||||
},
|
},
|
||||||
"embedding": {
|
"embedding": {
|
||||||
"noMatchingEmbedding": "Nessun Incorporamento corrispondente",
|
"noMatchingEmbedding": "Nessun Incorporamento corrispondente",
|
||||||
@ -1297,7 +1314,12 @@
|
|||||||
"noLoRAsInstalled": "Nessun LoRA installato",
|
"noLoRAsInstalled": "Nessun LoRA installato",
|
||||||
"esrganModel": "Modello ESRGAN",
|
"esrganModel": "Modello ESRGAN",
|
||||||
"addLora": "Aggiungi LoRA",
|
"addLora": "Aggiungi LoRA",
|
||||||
"noLoRAsLoaded": "Nessuna LoRA caricata"
|
"noLoRAsLoaded": "Nessun LoRA caricato",
|
||||||
|
"noMainModelSelected": "Nessun modello principale selezionato",
|
||||||
|
"allLoRAsAdded": "Tutti i LoRA aggiunti",
|
||||||
|
"defaultVAE": "VAE predefinito",
|
||||||
|
"incompatibleBaseModel": "Modello base incompatibile",
|
||||||
|
"loraAlreadyAdded": "LoRA già aggiunto"
|
||||||
},
|
},
|
||||||
"invocationCache": {
|
"invocationCache": {
|
||||||
"disable": "Disabilita",
|
"disable": "Disabilita",
|
||||||
@ -1331,7 +1353,9 @@
|
|||||||
"promptsWithCount_many": "{{count}} Prompt",
|
"promptsWithCount_many": "{{count}} Prompt",
|
||||||
"promptsWithCount_other": "{{count}} Prompt",
|
"promptsWithCount_other": "{{count}} Prompt",
|
||||||
"dynamicPrompts": "Prompt dinamici",
|
"dynamicPrompts": "Prompt dinamici",
|
||||||
"promptsPreview": "Anteprima dei prompt"
|
"promptsPreview": "Anteprima dei prompt",
|
||||||
|
"showDynamicPrompts": "Mostra prompt dinamici",
|
||||||
|
"loading": "Generazione prompt dinamici..."
|
||||||
},
|
},
|
||||||
"popovers": {
|
"popovers": {
|
||||||
"paramScheduler": {
|
"paramScheduler": {
|
||||||
@ -1557,7 +1581,7 @@
|
|||||||
"scheduler": "Campionatore",
|
"scheduler": "Campionatore",
|
||||||
"noModelsAvailable": "Nessun modello disponibile",
|
"noModelsAvailable": "Nessun modello disponibile",
|
||||||
"denoisingStrength": "Forza di riduzione del rumore",
|
"denoisingStrength": "Forza di riduzione del rumore",
|
||||||
"concatPromptStyle": "Concatena Prompt & Stile",
|
"concatPromptStyle": "Collega Prompt & Stile",
|
||||||
"loading": "Caricamento...",
|
"loading": "Caricamento...",
|
||||||
"steps": "Passi",
|
"steps": "Passi",
|
||||||
"refinerStart": "Inizio Affinamento",
|
"refinerStart": "Inizio Affinamento",
|
||||||
@ -1568,7 +1592,8 @@
|
|||||||
"useRefiner": "Utilizza l'affinatore",
|
"useRefiner": "Utilizza l'affinatore",
|
||||||
"refinermodel": "Modello Affinatore",
|
"refinermodel": "Modello Affinatore",
|
||||||
"posAestheticScore": "Punteggio estetico positivo",
|
"posAestheticScore": "Punteggio estetico positivo",
|
||||||
"posStylePrompt": "Prompt Stile positivo"
|
"posStylePrompt": "Prompt Stile positivo",
|
||||||
|
"freePromptStyle": "Prompt di stile manuale"
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"initImage": "Immagine iniziale",
|
"initImage": "Immagine iniziale",
|
||||||
@ -1641,5 +1666,28 @@
|
|||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"storeNotInitialized": "Il negozio non è inizializzato"
|
"storeNotInitialized": "Il negozio non è inizializzato"
|
||||||
|
},
|
||||||
|
"accordions": {
|
||||||
|
"compositing": {
|
||||||
|
"infillTab": "Riempimento",
|
||||||
|
"coherenceTab": "Passaggio di coerenza",
|
||||||
|
"title": "Composizione"
|
||||||
|
},
|
||||||
|
"control": {
|
||||||
|
"controlAdaptersTab": "Adattatori di Controllo",
|
||||||
|
"ipTab": "Prompt immagine",
|
||||||
|
"title": "Controllo"
|
||||||
|
},
|
||||||
|
"generation": {
|
||||||
|
"title": "Generazione",
|
||||||
|
"conceptsTab": "Concetti",
|
||||||
|
"modelTab": "Modello"
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"title": "Avanzate"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"title": "Immagine"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,10 +133,6 @@
|
|||||||
"title": "ピン",
|
"title": "ピン",
|
||||||
"desc": "オプションパネルを固定"
|
"desc": "オプションパネルを固定"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "ビュワーのトグル",
|
|
||||||
"desc": "ビュワーを開閉"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "ギャラリーのトグル",
|
"title": "ギャラリーのトグル",
|
||||||
"desc": "ギャラリードロワーの開閉"
|
"desc": "ギャラリードロワーの開閉"
|
||||||
@ -197,10 +193,6 @@
|
|||||||
"title": "次の画像",
|
"title": "次の画像",
|
||||||
"desc": "ギャラリー内の1つ後の画像を表示"
|
"desc": "ギャラリー内の1つ後の画像を表示"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "ギャラリードロワーの固定",
|
|
||||||
"desc": "ギャラリーをUIにピン留め/解除"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "ギャラリーの画像を拡大",
|
"title": "ギャラリーの画像を拡大",
|
||||||
"desc": "ギャラリーのサムネイル画像を拡大"
|
"desc": "ギャラリーのサムネイル画像を拡大"
|
||||||
@ -590,7 +582,6 @@
|
|||||||
"processor": "プロセッサー",
|
"processor": "プロセッサー",
|
||||||
"addControlNet": "$t(common.controlNet)を追加",
|
"addControlNet": "$t(common.controlNet)を追加",
|
||||||
"none": "なし",
|
"none": "なし",
|
||||||
"incompatibleBaseModel": "互換性のないベースモデル:",
|
|
||||||
"enableControlnet": "コントロールネットを有効化",
|
"enableControlnet": "コントロールネットを有効化",
|
||||||
"detectResolution": "検出解像度",
|
"detectResolution": "検出解像度",
|
||||||
"controlNetT2IMutexDesc": "$t(common.controlNet)と$t(common.t2iAdapter)の同時使用は現在サポートされていません。",
|
"controlNetT2IMutexDesc": "$t(common.controlNet)と$t(common.t2iAdapter)の同時使用は現在サポートされていません。",
|
||||||
|
@ -363,7 +363,6 @@
|
|||||||
"processor": "프로세서",
|
"processor": "프로세서",
|
||||||
"addControlNet": "$t(common.controlNet) 추가",
|
"addControlNet": "$t(common.controlNet) 추가",
|
||||||
"none": "해당없음",
|
"none": "해당없음",
|
||||||
"incompatibleBaseModel": "호환되지 않는 기본 모델:",
|
|
||||||
"enableControlnet": "사용 가능한 ControlNet",
|
"enableControlnet": "사용 가능한 ControlNet",
|
||||||
"detectResolution": "해상도 탐지",
|
"detectResolution": "해상도 탐지",
|
||||||
"controlNetT2IMutexDesc": "$t(common.controlNet)와 $t(common.t2iAdapter)는 현재 동시에 지원되지 않습니다.",
|
"controlNetT2IMutexDesc": "$t(common.controlNet)와 $t(common.t2iAdapter)는 현재 동시에 지원되지 않습니다.",
|
||||||
@ -408,10 +407,6 @@
|
|||||||
"maxFaces": "Max Faces"
|
"maxFaces": "Max Faces"
|
||||||
},
|
},
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Gallery Pin 전환",
|
|
||||||
"desc": "갤러리를 UI에 고정했다가 풉니다"
|
|
||||||
},
|
|
||||||
"toggleSnap": {
|
"toggleSnap": {
|
||||||
"desc": "Snap을 Grid로 전환",
|
"desc": "Snap을 Grid로 전환",
|
||||||
"title": "Snap 전환"
|
"title": "Snap 전환"
|
||||||
@ -601,10 +596,6 @@
|
|||||||
"desc": "노드 추가 메뉴 열기",
|
"desc": "노드 추가 메뉴 열기",
|
||||||
"title": "노드 추가"
|
"title": "노드 추가"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"desc": "이미지 뷰어 열기 및 닫기",
|
|
||||||
"title": "Viewer 전환"
|
|
||||||
},
|
|
||||||
"undoStroke": {
|
"undoStroke": {
|
||||||
"title": "Stroke 실행 취소",
|
"title": "Stroke 실행 취소",
|
||||||
"desc": "brush stroke 실행 취소"
|
"desc": "brush stroke 실행 취소"
|
||||||
|
@ -148,10 +148,6 @@
|
|||||||
"title": "Zet Opties vast",
|
"title": "Zet Opties vast",
|
||||||
"desc": "Zet het deelscherm Opties vast"
|
"desc": "Zet het deelscherm Opties vast"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Zet Viewer vast",
|
|
||||||
"desc": "Opent of sluit Afbeeldingsviewer"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Zet Galerij vast",
|
"title": "Zet Galerij vast",
|
||||||
"desc": "Opent of sluit het deelscherm Galerij"
|
"desc": "Opent of sluit het deelscherm Galerij"
|
||||||
@ -212,10 +208,6 @@
|
|||||||
"title": "Volgende afbeelding",
|
"title": "Volgende afbeelding",
|
||||||
"desc": "Toont de volgende afbeelding in de galerij"
|
"desc": "Toont de volgende afbeelding in de galerij"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Zet galerij vast/los",
|
|
||||||
"desc": "Zet de galerij vast of los aan de gebruikersinterface"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Vergroot afbeeldingsgrootte galerij",
|
"title": "Vergroot afbeeldingsgrootte galerij",
|
||||||
"desc": "Vergroot de grootte van de galerijminiaturen"
|
"desc": "Vergroot de grootte van de galerijminiaturen"
|
||||||
@ -1071,7 +1063,6 @@
|
|||||||
"processor": "Verwerker",
|
"processor": "Verwerker",
|
||||||
"addControlNet": "Voeg $t(common.controlNet) toe",
|
"addControlNet": "Voeg $t(common.controlNet) toe",
|
||||||
"none": "Geen",
|
"none": "Geen",
|
||||||
"incompatibleBaseModel": "Niet-compatibel basismodel:",
|
|
||||||
"enableControlnet": "Schakel ControlNet in",
|
"enableControlnet": "Schakel ControlNet in",
|
||||||
"detectResolution": "Herken resolutie",
|
"detectResolution": "Herken resolutie",
|
||||||
"controlNetT2IMutexDesc": "Gelijktijdig gebruik van $t(common.controlNet) en $t(common.t2iAdapter) wordt op dit moment niet ondersteund.",
|
"controlNetT2IMutexDesc": "Gelijktijdig gebruik van $t(common.controlNet) en $t(common.t2iAdapter) wordt op dit moment niet ondersteund.",
|
||||||
|
@ -86,10 +86,6 @@
|
|||||||
"title": "Przypnij opcje",
|
"title": "Przypnij opcje",
|
||||||
"desc": "Przypina panel opcji"
|
"desc": "Przypina panel opcji"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Przełącz podgląd",
|
|
||||||
"desc": "Otwiera lub zamyka widok podglądu"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Przełącz galerię",
|
"title": "Przełącz galerię",
|
||||||
"desc": "Wysuwa lub chowa galerię"
|
"desc": "Wysuwa lub chowa galerię"
|
||||||
@ -150,10 +146,6 @@
|
|||||||
"title": "Następny obraz",
|
"title": "Następny obraz",
|
||||||
"desc": "Aktywuje następny obraz z galerii"
|
"desc": "Aktywuje następny obraz z galerii"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Przypnij galerię",
|
|
||||||
"desc": "Przypina lub odpina widok galerii"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Powiększ obrazy",
|
"title": "Powiększ obrazy",
|
||||||
"desc": "Powiększa rozmiar obrazów w galerii"
|
"desc": "Powiększa rozmiar obrazów w galerii"
|
||||||
|
@ -81,10 +81,6 @@
|
|||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"generalHotkeys": "Atalhos Gerais",
|
"generalHotkeys": "Atalhos Gerais",
|
||||||
"galleryHotkeys": "Atalhos da Galeria",
|
"galleryHotkeys": "Atalhos da Galeria",
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Ativar Visualizador",
|
|
||||||
"desc": "Abrir e fechar o Visualizador de Imagens"
|
|
||||||
},
|
|
||||||
"maximizeWorkSpace": {
|
"maximizeWorkSpace": {
|
||||||
"desc": "Fechar painéis e maximixar área de trabalho",
|
"desc": "Fechar painéis e maximixar área de trabalho",
|
||||||
"title": "Maximizar a Área de Trabalho"
|
"title": "Maximizar a Área de Trabalho"
|
||||||
@ -232,10 +228,6 @@
|
|||||||
"title": "Apagar Imagem",
|
"title": "Apagar Imagem",
|
||||||
"desc": "Apaga a imagem atual"
|
"desc": "Apaga a imagem atual"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Ativar Fixar Galeria",
|
|
||||||
"desc": "Fixa e desafixa a galeria na interface"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Aumentar Tamanho da Galeria de Imagem",
|
"title": "Aumentar Tamanho da Galeria de Imagem",
|
||||||
"desc": "Aumenta o tamanho das thumbs na galeria"
|
"desc": "Aumenta o tamanho das thumbs na galeria"
|
||||||
|
@ -103,10 +103,6 @@
|
|||||||
"title": "Fixar Opções",
|
"title": "Fixar Opções",
|
||||||
"desc": "Fixar o painel de opções"
|
"desc": "Fixar o painel de opções"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Ativar Visualizador",
|
|
||||||
"desc": "Abrir e fechar o Visualizador de Imagens"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Ativar Galeria",
|
"title": "Ativar Galeria",
|
||||||
"desc": "Abrir e fechar a gaveta da galeria"
|
"desc": "Abrir e fechar a gaveta da galeria"
|
||||||
@ -167,10 +163,6 @@
|
|||||||
"title": "Próxima Imagem",
|
"title": "Próxima Imagem",
|
||||||
"desc": "Mostra a próxima imagem na galeria"
|
"desc": "Mostra a próxima imagem na galeria"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Ativar Fixar Galeria",
|
|
||||||
"desc": "Fixa e desafixa a galeria na interface"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Aumentar Tamanho da Galeria de Imagem",
|
"title": "Aumentar Tamanho da Galeria de Imagem",
|
||||||
"desc": "Aumenta o tamanho das thumbs na galeria"
|
"desc": "Aumenta o tamanho das thumbs na galeria"
|
||||||
|
@ -121,7 +121,11 @@
|
|||||||
"unsaved": "несохраненный",
|
"unsaved": "несохраненный",
|
||||||
"input": "Вход",
|
"input": "Вход",
|
||||||
"details": "Детали",
|
"details": "Детали",
|
||||||
"notInstalled": "Нет $t(common.installed)"
|
"notInstalled": "Нет $t(common.installed)",
|
||||||
|
"preferencesLabel": "Предпочтения",
|
||||||
|
"or": "или",
|
||||||
|
"advancedOptions": "Расширенные настройки",
|
||||||
|
"free": "Свободно"
|
||||||
},
|
},
|
||||||
"gallery": {
|
"gallery": {
|
||||||
"generations": "Генерации",
|
"generations": "Генерации",
|
||||||
@ -189,10 +193,6 @@
|
|||||||
"title": "Закрепить параметры",
|
"title": "Закрепить параметры",
|
||||||
"desc": "Закрепить панель параметров"
|
"desc": "Закрепить панель параметров"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Показать просмотр",
|
|
||||||
"desc": "Открывать и закрывать просмотрщик изображений"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Показать галерею",
|
"title": "Показать галерею",
|
||||||
"desc": "Открывать и закрывать ящик галереи"
|
"desc": "Открывать и закрывать ящик галереи"
|
||||||
@ -253,10 +253,6 @@
|
|||||||
"title": "Следующее изображение",
|
"title": "Следующее изображение",
|
||||||
"desc": "Отображение следующего изображения в галерее"
|
"desc": "Отображение следующего изображения в галерее"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Закрепить галерею",
|
|
||||||
"desc": "Закрепляет и открепляет галерею"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Увеличить размер миниатюр галереи",
|
"title": "Увеличить размер миниатюр галереи",
|
||||||
"desc": "Увеличивает размер миниатюр галереи"
|
"desc": "Увеличивает размер миниатюр галереи"
|
||||||
@ -373,7 +369,22 @@
|
|||||||
"desc": "Открывает меню добавления узла",
|
"desc": "Открывает меню добавления узла",
|
||||||
"title": "Добавление узлов"
|
"title": "Добавление узлов"
|
||||||
},
|
},
|
||||||
"nodesHotkeys": "Горячие клавиши узлов"
|
"nodesHotkeys": "Горячие клавиши узлов",
|
||||||
|
"cancelAndClear": {
|
||||||
|
"desc": "Отмена текущего элемента очереди и очистка всех ожидающих элементов",
|
||||||
|
"title": "Отменить и очистить"
|
||||||
|
},
|
||||||
|
"resetOptionsAndGallery": {
|
||||||
|
"title": "Сброс настроек и галереи",
|
||||||
|
"desc": "Сброс панелей галереи и настроек"
|
||||||
|
},
|
||||||
|
"searchHotkeys": "Поиск горячих клавиш",
|
||||||
|
"noHotkeysFound": "Горячие клавиши не найдены",
|
||||||
|
"toggleOptionsAndGallery": {
|
||||||
|
"desc": "Открытие и закрытие панели опций и галереи",
|
||||||
|
"title": "Переключить опции и галерею"
|
||||||
|
},
|
||||||
|
"clearSearch": "Очистить поиск"
|
||||||
},
|
},
|
||||||
"modelManager": {
|
"modelManager": {
|
||||||
"modelManager": "Менеджер моделей",
|
"modelManager": "Менеджер моделей",
|
||||||
@ -523,7 +534,7 @@
|
|||||||
"parameters": {
|
"parameters": {
|
||||||
"images": "Изображения",
|
"images": "Изображения",
|
||||||
"steps": "Шаги",
|
"steps": "Шаги",
|
||||||
"cfgScale": "Точность следования запросу (CFG)",
|
"cfgScale": "Шкала точности (CFG)",
|
||||||
"width": "Ширина",
|
"width": "Ширина",
|
||||||
"height": "Высота",
|
"height": "Высота",
|
||||||
"seed": "Сид",
|
"seed": "Сид",
|
||||||
@ -1162,7 +1173,6 @@
|
|||||||
"processor": "Процессор",
|
"processor": "Процессор",
|
||||||
"addControlNet": "Добавить $t(common.controlNet)",
|
"addControlNet": "Добавить $t(common.controlNet)",
|
||||||
"none": "ничего",
|
"none": "ничего",
|
||||||
"incompatibleBaseModel": "Несовместимая базовая модель:",
|
|
||||||
"controlNetT2IMutexDesc": "$t(common.controlNet) и $t(common.t2iAdapter) одновременно в настоящее время не поддерживаются.",
|
"controlNetT2IMutexDesc": "$t(common.controlNet) и $t(common.t2iAdapter) одновременно в настоящее время не поддерживаются.",
|
||||||
"ip_adapter": "$t(controlnet.controlAdapter_one) №{{number}} $t(common.ipAdapter)",
|
"ip_adapter": "$t(controlnet.controlAdapter_one) №{{number}} $t(common.ipAdapter)",
|
||||||
"pidiDescription": "PIDI-обработка изображений",
|
"pidiDescription": "PIDI-обработка изображений",
|
||||||
@ -1197,7 +1207,8 @@
|
|||||||
"handAndFace": "Руки и Лицо",
|
"handAndFace": "Руки и Лицо",
|
||||||
"enableIPAdapter": "Включить IP Adapter",
|
"enableIPAdapter": "Включить IP Adapter",
|
||||||
"maxFaces": "Макс Лица",
|
"maxFaces": "Макс Лица",
|
||||||
"mlsdDescription": "Минималистичный детектор отрезков линии"
|
"mlsdDescription": "Минималистичный детектор отрезков линии",
|
||||||
|
"resizeSimple": "Изменить размер (простой)"
|
||||||
},
|
},
|
||||||
"boards": {
|
"boards": {
|
||||||
"autoAddBoard": "Авто добавление Доски",
|
"autoAddBoard": "Авто добавление Доски",
|
||||||
@ -1549,7 +1560,8 @@
|
|||||||
"cancelBatchFailed": "Проблема с отменой пакета",
|
"cancelBatchFailed": "Проблема с отменой пакета",
|
||||||
"clearQueueAlertDialog2": "Вы уверены, что хотите очистить очередь?",
|
"clearQueueAlertDialog2": "Вы уверены, что хотите очистить очередь?",
|
||||||
"item": "Элемент",
|
"item": "Элемент",
|
||||||
"graphFailedToQueue": "Не удалось поставить график в очередь"
|
"graphFailedToQueue": "Не удалось поставить график в очередь",
|
||||||
|
"openQueue": "Открыть очередь"
|
||||||
},
|
},
|
||||||
"sdxl": {
|
"sdxl": {
|
||||||
"refinerStart": "Запуск перерисовщика",
|
"refinerStart": "Запуск перерисовщика",
|
||||||
@ -1644,9 +1656,38 @@
|
|||||||
"selectModel": "Выберите модель",
|
"selectModel": "Выберите модель",
|
||||||
"noRefinerModelsInstalled": "Модели SDXL Refiner не установлены",
|
"noRefinerModelsInstalled": "Модели SDXL Refiner не установлены",
|
||||||
"noLoRAsInstalled": "Нет установленных LoRA",
|
"noLoRAsInstalled": "Нет установленных LoRA",
|
||||||
"selectLoRA": "Выберите LoRA"
|
"selectLoRA": "Выберите LoRA",
|
||||||
|
"noMainModelSelected": "Базовая модель не выбрана",
|
||||||
|
"lora": "LoRA",
|
||||||
|
"allLoRAsAdded": "Все LoRA добавлены",
|
||||||
|
"defaultVAE": "Стандартное VAE",
|
||||||
|
"incompatibleBaseModel": "Несовместимая базовая модель",
|
||||||
|
"loraAlreadyAdded": "LoRA уже добавлена"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"storeNotInitialized": "Магазин не инициализирован"
|
"storeNotInitialized": "Магазин не инициализирован"
|
||||||
|
},
|
||||||
|
"accordions": {
|
||||||
|
"compositing": {
|
||||||
|
"infillTab": "Заполнение",
|
||||||
|
"coherenceTab": "Согласованность",
|
||||||
|
"title": "Композиция"
|
||||||
|
},
|
||||||
|
"control": {
|
||||||
|
"controlAdaptersTab": "Адаптеры контроля",
|
||||||
|
"ipTab": "Запросы изображений",
|
||||||
|
"title": "Контроль"
|
||||||
|
},
|
||||||
|
"generation": {
|
||||||
|
"title": "Генерация",
|
||||||
|
"conceptsTab": "Концепты",
|
||||||
|
"modelTab": "Модель"
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"title": "Расширенные"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"title": "Изображение"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,10 +129,6 @@
|
|||||||
"title": "Växla inställningar",
|
"title": "Växla inställningar",
|
||||||
"desc": "Öppna och stäng alternativpanelen"
|
"desc": "Öppna och stäng alternativpanelen"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Växla visaren",
|
|
||||||
"desc": "Öppna och stäng bildvisaren"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Växla galleri",
|
"title": "Växla galleri",
|
||||||
"desc": "Öppna eller stäng galleribyrån"
|
"desc": "Öppna eller stäng galleribyrån"
|
||||||
@ -193,10 +189,6 @@
|
|||||||
"title": "Nästa bild",
|
"title": "Nästa bild",
|
||||||
"desc": "Visa nästa bild"
|
"desc": "Visa nästa bild"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Växla gallerinål",
|
|
||||||
"desc": "Nålar fast eller nålar av galleriet i gränssnittet"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Förstora galleriets bildstorlek",
|
"title": "Förstora galleriets bildstorlek",
|
||||||
"desc": "Förstora miniatyrbildernas storlek"
|
"desc": "Förstora miniatyrbildernas storlek"
|
||||||
|
@ -111,10 +111,6 @@
|
|||||||
"title": "Закріпити параметри",
|
"title": "Закріпити параметри",
|
||||||
"desc": "Закріпити панель параметрів"
|
"desc": "Закріпити панель параметрів"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "Показати перегляд",
|
|
||||||
"desc": "Відкривати і закривати переглядач зображень"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "Показати галерею",
|
"title": "Показати галерею",
|
||||||
"desc": "Відкривати і закривати скриньку галереї"
|
"desc": "Відкривати і закривати скриньку галереї"
|
||||||
@ -175,10 +171,6 @@
|
|||||||
"title": "Наступне зображення",
|
"title": "Наступне зображення",
|
||||||
"desc": "Відображення наступного зображення в галереї"
|
"desc": "Відображення наступного зображення в галереї"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "Закріпити галерею",
|
|
||||||
"desc": "Закріплює і відкріплює галерею"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "Збільшити розмір мініатюр галереї",
|
"title": "Збільшити розмір мініатюр галереї",
|
||||||
"desc": "Збільшує розмір мініатюр галереї"
|
"desc": "Збільшує розмір мініатюр галереї"
|
||||||
|
@ -121,7 +121,11 @@
|
|||||||
"nextPage": "下一页",
|
"nextPage": "下一页",
|
||||||
"saveAs": "保存为",
|
"saveAs": "保存为",
|
||||||
"unsaved": "未保存",
|
"unsaved": "未保存",
|
||||||
"ai": "ai"
|
"ai": "ai",
|
||||||
|
"preferencesLabel": "首选项",
|
||||||
|
"or": "或",
|
||||||
|
"advancedOptions": "高级选项",
|
||||||
|
"free": "自由"
|
||||||
},
|
},
|
||||||
"gallery": {
|
"gallery": {
|
||||||
"generations": "生成的图像",
|
"generations": "生成的图像",
|
||||||
@ -164,18 +168,18 @@
|
|||||||
"starImage": "收藏图像"
|
"starImage": "收藏图像"
|
||||||
},
|
},
|
||||||
"hotkeys": {
|
"hotkeys": {
|
||||||
"keyboardShortcuts": "键盘快捷键",
|
"keyboardShortcuts": "快捷键",
|
||||||
"appHotkeys": "应用快捷键",
|
"appHotkeys": "应用",
|
||||||
"generalHotkeys": "一般快捷键",
|
"generalHotkeys": "一般",
|
||||||
"galleryHotkeys": "图库快捷键",
|
"galleryHotkeys": "图库",
|
||||||
"unifiedCanvasHotkeys": "统一画布快捷键",
|
"unifiedCanvasHotkeys": "统一画布",
|
||||||
"invoke": {
|
"invoke": {
|
||||||
"title": "Invoke",
|
"title": "Invoke",
|
||||||
"desc": "生成图像"
|
"desc": "生成图像"
|
||||||
},
|
},
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"title": "取消",
|
"title": "取消",
|
||||||
"desc": "取消图像生成"
|
"desc": "取消当前队列项目"
|
||||||
},
|
},
|
||||||
"focusPrompt": {
|
"focusPrompt": {
|
||||||
"title": "打开提示词框",
|
"title": "打开提示词框",
|
||||||
@ -189,10 +193,6 @@
|
|||||||
"title": "常开选项卡",
|
"title": "常开选项卡",
|
||||||
"desc": "保持选项浮窗常开"
|
"desc": "保持选项浮窗常开"
|
||||||
},
|
},
|
||||||
"toggleViewer": {
|
|
||||||
"title": "切换图像查看器",
|
|
||||||
"desc": "打开或关闭图像查看器"
|
|
||||||
},
|
|
||||||
"toggleGallery": {
|
"toggleGallery": {
|
||||||
"title": "切换图库",
|
"title": "切换图库",
|
||||||
"desc": "打开或关闭图库"
|
"desc": "打开或关闭图库"
|
||||||
@ -253,10 +253,6 @@
|
|||||||
"title": "下一张图像",
|
"title": "下一张图像",
|
||||||
"desc": "显示图库中的下一张图像"
|
"desc": "显示图库中的下一张图像"
|
||||||
},
|
},
|
||||||
"toggleGalleryPin": {
|
|
||||||
"title": "切换图库常开",
|
|
||||||
"desc": "开关图库在界面中的常开模式"
|
|
||||||
},
|
|
||||||
"increaseGalleryThumbSize": {
|
"increaseGalleryThumbSize": {
|
||||||
"title": "增大预览尺寸",
|
"title": "增大预览尺寸",
|
||||||
"desc": "增大图库中预览的尺寸"
|
"desc": "增大图库中预览的尺寸"
|
||||||
@ -369,11 +365,26 @@
|
|||||||
"title": "接受暂存图像",
|
"title": "接受暂存图像",
|
||||||
"desc": "接受当前暂存区中的图像"
|
"desc": "接受当前暂存区中的图像"
|
||||||
},
|
},
|
||||||
"nodesHotkeys": "节点快捷键",
|
"nodesHotkeys": "节点",
|
||||||
"addNodes": {
|
"addNodes": {
|
||||||
"title": "添加节点",
|
"title": "添加节点",
|
||||||
"desc": "打开添加节点菜单"
|
"desc": "打开添加节点菜单"
|
||||||
}
|
},
|
||||||
|
"cancelAndClear": {
|
||||||
|
"desc": "取消当前队列项目并且清除所有待定项目",
|
||||||
|
"title": "取消和清除"
|
||||||
|
},
|
||||||
|
"resetOptionsAndGallery": {
|
||||||
|
"title": "重置选项和图库",
|
||||||
|
"desc": "重置选项和图库面板"
|
||||||
|
},
|
||||||
|
"searchHotkeys": "检索快捷键",
|
||||||
|
"noHotkeysFound": "未找到快捷键",
|
||||||
|
"toggleOptionsAndGallery": {
|
||||||
|
"desc": "打开和关闭选项和图库面板",
|
||||||
|
"title": "开关选项和图库"
|
||||||
|
},
|
||||||
|
"clearSearch": "清除检索项"
|
||||||
},
|
},
|
||||||
"modelManager": {
|
"modelManager": {
|
||||||
"modelManager": "模型管理器",
|
"modelManager": "模型管理器",
|
||||||
@ -571,8 +582,8 @@
|
|||||||
"info": "信息",
|
"info": "信息",
|
||||||
"initialImage": "初始图像",
|
"initialImage": "初始图像",
|
||||||
"showOptionsPanel": "显示侧栏浮窗 (O 或 T)",
|
"showOptionsPanel": "显示侧栏浮窗 (O 或 T)",
|
||||||
"seamlessYAxis": "Y 轴",
|
"seamlessYAxis": "无缝平铺 Y 轴",
|
||||||
"seamlessXAxis": "X 轴",
|
"seamlessXAxis": "无缝平铺 X 轴",
|
||||||
"boundingBoxWidth": "边界框宽度",
|
"boundingBoxWidth": "边界框宽度",
|
||||||
"boundingBoxHeight": "边界框高度",
|
"boundingBoxHeight": "边界框高度",
|
||||||
"denoisingStrength": "去噪强度",
|
"denoisingStrength": "去噪强度",
|
||||||
@ -619,7 +630,7 @@
|
|||||||
"readyToInvoke": "准备调用",
|
"readyToInvoke": "准备调用",
|
||||||
"noControlImageForControlAdapter": "有 #{{number}} 个 Control Adapter 缺失控制图像",
|
"noControlImageForControlAdapter": "有 #{{number}} 个 Control Adapter 缺失控制图像",
|
||||||
"noModelForControlAdapter": "有 #{{number}} 个 Control Adapter 没有选择模型。",
|
"noModelForControlAdapter": "有 #{{number}} 个 Control Adapter 没有选择模型。",
|
||||||
"incompatibleBaseModelForControlAdapter": "有 #{{number}} 个 Control Adapter 模型与主模型不匹配。"
|
"incompatibleBaseModelForControlAdapter": "有 #{{number}} 个 Control Adapter 模型与主模型不兼容。"
|
||||||
},
|
},
|
||||||
"patchmatchDownScaleSize": "缩小",
|
"patchmatchDownScaleSize": "缩小",
|
||||||
"coherenceSteps": "步数",
|
"coherenceSteps": "步数",
|
||||||
@ -650,7 +661,14 @@
|
|||||||
"unmasked": "取消遮罩",
|
"unmasked": "取消遮罩",
|
||||||
"cfgRescaleMultiplier": "CFG 重缩放倍数",
|
"cfgRescaleMultiplier": "CFG 重缩放倍数",
|
||||||
"cfgRescale": "CFG 重缩放",
|
"cfgRescale": "CFG 重缩放",
|
||||||
"useSize": "使用尺寸"
|
"useSize": "使用尺寸",
|
||||||
|
"setToOptimalSize": "优化模型大小",
|
||||||
|
"setToOptimalSizeTooSmall": "$t(parameters.setToOptimalSize) (可能过小)",
|
||||||
|
"imageSize": "图像尺寸",
|
||||||
|
"lockAspectRatio": "锁定纵横比",
|
||||||
|
"swapDimensions": "交换尺寸",
|
||||||
|
"aspect": "纵横",
|
||||||
|
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (可能过大)"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"models": "模型",
|
"models": "模型",
|
||||||
@ -1149,7 +1167,6 @@
|
|||||||
"crop": "裁剪",
|
"crop": "裁剪",
|
||||||
"processor": "处理器",
|
"processor": "处理器",
|
||||||
"none": "无",
|
"none": "无",
|
||||||
"incompatibleBaseModel": "不兼容的基础模型:",
|
|
||||||
"enableControlnet": "启用 ControlNet",
|
"enableControlnet": "启用 ControlNet",
|
||||||
"detectResolution": "检测分辨率",
|
"detectResolution": "检测分辨率",
|
||||||
"pidiDescription": "像素差分 (PIDI) 图像处理",
|
"pidiDescription": "像素差分 (PIDI) 图像处理",
|
||||||
@ -1210,7 +1227,8 @@
|
|||||||
"openPose": "Openpose",
|
"openPose": "Openpose",
|
||||||
"controlAdapter_other": "Control Adapters",
|
"controlAdapter_other": "Control Adapters",
|
||||||
"lineartAnime": "Lineart Anime",
|
"lineartAnime": "Lineart Anime",
|
||||||
"canny": "Canny"
|
"canny": "Canny",
|
||||||
|
"resizeSimple": "缩放(简单)"
|
||||||
},
|
},
|
||||||
"queue": {
|
"queue": {
|
||||||
"status": "状态",
|
"status": "状态",
|
||||||
@ -1257,7 +1275,7 @@
|
|||||||
"notReady": "无法排队",
|
"notReady": "无法排队",
|
||||||
"batchFailedToQueue": "批次加入队列失败",
|
"batchFailedToQueue": "批次加入队列失败",
|
||||||
"batchValues": "批次数",
|
"batchValues": "批次数",
|
||||||
"queueCountPrediction": "添加 {{predicted}} 到队列",
|
"queueCountPrediction": "{{promptsCount}} 提示词 × {{iterations}} 迭代次数 -> {{count}} 次生成",
|
||||||
"batchQueued": "加入队列的批次",
|
"batchQueued": "加入队列的批次",
|
||||||
"queuedCount": "{{pending}} 待处理",
|
"queuedCount": "{{pending}} 待处理",
|
||||||
"front": "前",
|
"front": "前",
|
||||||
@ -1271,7 +1289,8 @@
|
|||||||
"queueMaxExceeded": "超出最大值 {{max_queue_size}},将跳过 {{skip}}",
|
"queueMaxExceeded": "超出最大值 {{max_queue_size}},将跳过 {{skip}}",
|
||||||
"graphFailedToQueue": "节点图加入队列失败",
|
"graphFailedToQueue": "节点图加入队列失败",
|
||||||
"batchFieldValues": "批处理值",
|
"batchFieldValues": "批处理值",
|
||||||
"time": "时间"
|
"time": "时间",
|
||||||
|
"openQueue": "打开队列"
|
||||||
},
|
},
|
||||||
"sdxl": {
|
"sdxl": {
|
||||||
"refinerStart": "Refiner 开始作用时机",
|
"refinerStart": "Refiner 开始作用时机",
|
||||||
@ -1285,11 +1304,12 @@
|
|||||||
"denoisingStrength": "去噪强度",
|
"denoisingStrength": "去噪强度",
|
||||||
"refinermodel": "Refiner 模型",
|
"refinermodel": "Refiner 模型",
|
||||||
"posAestheticScore": "正向美学评分",
|
"posAestheticScore": "正向美学评分",
|
||||||
"concatPromptStyle": "连接提示词 & 样式",
|
"concatPromptStyle": "链接提示词 & 样式",
|
||||||
"loading": "加载中...",
|
"loading": "加载中...",
|
||||||
"steps": "步数",
|
"steps": "步数",
|
||||||
"posStylePrompt": "正向样式提示词",
|
"posStylePrompt": "正向样式提示词",
|
||||||
"refiner": "Refiner"
|
"refiner": "Refiner",
|
||||||
|
"freePromptStyle": "手动输入样式提示词"
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"positivePrompt": "正向提示词",
|
"positivePrompt": "正向提示词",
|
||||||
@ -1333,7 +1353,13 @@
|
|||||||
"noLoRAsInstalled": "无已安装的 LoRA",
|
"noLoRAsInstalled": "无已安装的 LoRA",
|
||||||
"esrganModel": "ESRGAN 模型",
|
"esrganModel": "ESRGAN 模型",
|
||||||
"addLora": "添加 LoRA",
|
"addLora": "添加 LoRA",
|
||||||
"noLoRAsLoaded": "无已加载的 LoRA"
|
"noLoRAsLoaded": "无已加载的 LoRA",
|
||||||
|
"noMainModelSelected": "未选择主模型",
|
||||||
|
"lora": "LoRA",
|
||||||
|
"allLoRAsAdded": "已添加所有 LoRA",
|
||||||
|
"defaultVAE": "默认 VAE",
|
||||||
|
"incompatibleBaseModel": "不兼容基础模型",
|
||||||
|
"loraAlreadyAdded": "LoRA 已经被添加"
|
||||||
},
|
},
|
||||||
"boards": {
|
"boards": {
|
||||||
"autoAddBoard": "自动添加面板",
|
"autoAddBoard": "自动添加面板",
|
||||||
@ -1377,7 +1403,9 @@
|
|||||||
"maxPrompts": "最大提示词数",
|
"maxPrompts": "最大提示词数",
|
||||||
"dynamicPrompts": "动态提示词",
|
"dynamicPrompts": "动态提示词",
|
||||||
"promptsWithCount_other": "{{count}} 个提示词",
|
"promptsWithCount_other": "{{count}} 个提示词",
|
||||||
"promptsPreview": "提示词预览"
|
"promptsPreview": "提示词预览",
|
||||||
|
"showDynamicPrompts": "显示动态提示词",
|
||||||
|
"loading": "生成动态提示词中..."
|
||||||
},
|
},
|
||||||
"popovers": {
|
"popovers": {
|
||||||
"compositingMaskAdjustments": {
|
"compositingMaskAdjustments": {
|
||||||
@ -1659,5 +1687,28 @@
|
|||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"storeNotInitialized": "商店尚未初始化"
|
"storeNotInitialized": "商店尚未初始化"
|
||||||
|
},
|
||||||
|
"accordions": {
|
||||||
|
"compositing": {
|
||||||
|
"infillTab": "内补",
|
||||||
|
"coherenceTab": "一致性层",
|
||||||
|
"title": "合成"
|
||||||
|
},
|
||||||
|
"control": {
|
||||||
|
"controlAdaptersTab": "Control Adapters",
|
||||||
|
"ipTab": "图像提示",
|
||||||
|
"title": "Control"
|
||||||
|
},
|
||||||
|
"generation": {
|
||||||
|
"title": "生成",
|
||||||
|
"conceptsTab": "概念",
|
||||||
|
"modelTab": "模型"
|
||||||
|
},
|
||||||
|
"advanced": {
|
||||||
|
"title": "高级"
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"title": "图像"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
|
||||||
import openapiTS from 'openapi-typescript';
|
import openapiTS from 'openapi-typescript';
|
||||||
|
|
||||||
const OPENAPI_URL = 'http://127.0.0.1:9090/openapi.json';
|
const OPENAPI_URL = 'http://127.0.0.1:9090/openapi.json';
|
||||||
const OUTPUT_FILE = 'src/services/api/schema.d.ts';
|
const OUTPUT_FILE = 'src/services/api/schema.ts';
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
|
@ -1,27 +1,29 @@
|
|||||||
import { Flex, Grid } from '@chakra-ui/react';
|
import { Box } from '@chakra-ui/react';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useSocketIO } from 'app/hooks/useSocketIO';
|
||||||
import { useLogger } from 'app/logging/useLogger';
|
import { useLogger } from 'app/logging/useLogger';
|
||||||
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
|
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
|
||||||
import { $headerComponent } from 'app/store/nanostores/headerComponent';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { PartialAppConfig } from 'app/types/invokeai';
|
import type { PartialAppConfig } from 'app/types/invokeai';
|
||||||
import ImageUploader from 'common/components/ImageUploader';
|
import ImageUploadOverlay from 'common/components/ImageUploadOverlay';
|
||||||
|
import { useClearStorage } from 'common/hooks/useClearStorage';
|
||||||
|
import { useFullscreenDropzone } from 'common/hooks/useFullscreenDropzone';
|
||||||
|
import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
|
||||||
|
import { useGlobalModifiersInit } from 'common/hooks/useGlobalModifiers';
|
||||||
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
|
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
|
||||||
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
|
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
|
||||||
import SiteHeader from 'features/system/components/SiteHeader';
|
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
|
||||||
import { configChanged } from 'features/system/store/configSlice';
|
import { configChanged } from 'features/system/store/configSlice';
|
||||||
import { languageSelector } from 'features/system/store/systemSelectors';
|
import { languageSelector } from 'features/system/store/systemSelectors';
|
||||||
import InvokeTabs from 'features/ui/components/InvokeTabs';
|
import InvokeTabs from 'features/ui/components/InvokeTabs';
|
||||||
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import i18n from 'i18n';
|
import i18n from 'i18n';
|
||||||
import { size } from 'lodash-es';
|
import { size } from 'lodash-es';
|
||||||
import { memo, useCallback, useEffect } from 'react';
|
import { memo, useCallback, useEffect } from 'react';
|
||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
|
|
||||||
import AppErrorBoundaryFallback from './AppErrorBoundaryFallback';
|
import AppErrorBoundaryFallback from './AppErrorBoundaryFallback';
|
||||||
import GlobalHotkeys from './GlobalHotkeys';
|
|
||||||
import PreselectedImage from './PreselectedImage';
|
import PreselectedImage from './PreselectedImage';
|
||||||
import Toaster from './Toaster';
|
import Toaster from './Toaster';
|
||||||
import { useSocketIO } from 'app/hooks/useSocketIO';
|
|
||||||
import { useClearStorage } from 'common/hooks/useClearStorage';
|
|
||||||
|
|
||||||
const DEFAULT_CONFIG = {};
|
const DEFAULT_CONFIG = {};
|
||||||
|
|
||||||
@ -41,6 +43,11 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
|
|||||||
|
|
||||||
// singleton!
|
// singleton!
|
||||||
useSocketIO();
|
useSocketIO();
|
||||||
|
useGlobalModifiersInit();
|
||||||
|
useGlobalHotkeys();
|
||||||
|
|
||||||
|
const { dropzone, isHandlingUpload, setIsHandlingUpload } =
|
||||||
|
useFullscreenDropzone();
|
||||||
|
|
||||||
const handleReset = useCallback(() => {
|
const handleReset = useCallback(() => {
|
||||||
clearStorage();
|
clearStorage();
|
||||||
@ -63,41 +70,34 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
|
|||||||
dispatch(appStarted());
|
dispatch(appStarted());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const headerComponent = useStore($headerComponent);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
onReset={handleReset}
|
onReset={handleReset}
|
||||||
FallbackComponent={AppErrorBoundaryFallback}
|
FallbackComponent={AppErrorBoundaryFallback}
|
||||||
>
|
>
|
||||||
<Grid w="100vw" h="100vh" position="relative" overflow="hidden">
|
<Box
|
||||||
<ImageUploader>
|
id="invoke-app-wrapper"
|
||||||
<Grid
|
w="100vw"
|
||||||
sx={{
|
h="100vh"
|
||||||
gap: 4,
|
position="relative"
|
||||||
p: 4,
|
overflow="hidden"
|
||||||
gridAutoRows: 'min-content auto',
|
{...dropzone.getRootProps()}
|
||||||
w: 'full',
|
>
|
||||||
h: 'full',
|
<input {...dropzone.getInputProps()} />
|
||||||
}}
|
<InvokeTabs />
|
||||||
>
|
<AnimatePresence>
|
||||||
{headerComponent || <SiteHeader />}
|
{dropzone.isDragActive && isHandlingUpload && (
|
||||||
<Flex
|
<ImageUploadOverlay
|
||||||
sx={{
|
dropzone={dropzone}
|
||||||
gap: 4,
|
setIsHandlingUpload={setIsHandlingUpload}
|
||||||
w: 'full',
|
/>
|
||||||
h: 'full',
|
)}
|
||||||
}}
|
</AnimatePresence>
|
||||||
>
|
</Box>
|
||||||
<InvokeTabs />
|
|
||||||
</Flex>
|
|
||||||
</Grid>
|
|
||||||
</ImageUploader>
|
|
||||||
</Grid>
|
|
||||||
<DeleteImageModal />
|
<DeleteImageModal />
|
||||||
<ChangeBoardModal />
|
<ChangeBoardModal />
|
||||||
|
<DynamicPromptsModal />
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<GlobalHotkeys />
|
|
||||||
<PreselectedImage selectedImage={selectedImage} />
|
<PreselectedImage selectedImage={selectedImage} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Flex, Heading, Link, Text, useToast } from '@chakra-ui/react';
|
import { Flex, Heading, Link, useToast } from '@chakra-ui/react';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import { InvButton } from 'common/components/InvButton/InvButton';
|
||||||
|
import { InvText } from 'common/components/InvText/wrapper';
|
||||||
import newGithubIssueUrl from 'new-github-issue-url';
|
import newGithubIssueUrl from 'new-github-issue-url';
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -37,60 +38,48 @@ const AppErrorBoundaryFallback = ({ error, resetErrorBoundary }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
layerStyle="body"
|
layerStyle="body"
|
||||||
sx={{
|
w="100vw"
|
||||||
w: '100vw',
|
h="100vh"
|
||||||
h: '100vh',
|
alignItems="center"
|
||||||
alignItems: 'center',
|
justifyContent="center"
|
||||||
justifyContent: 'center',
|
p={4}
|
||||||
p: 4,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
layerStyle="first"
|
layerStyle="first"
|
||||||
sx={{
|
flexDir="column"
|
||||||
flexDir: 'column',
|
borderRadius="base"
|
||||||
borderRadius: 'base',
|
justifyContent="center"
|
||||||
justifyContent: 'center',
|
gap={8}
|
||||||
gap: 8,
|
p={16}
|
||||||
p: 16,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Heading>{t('common.somethingWentWrong')}</Heading>
|
<Heading>{t('common.somethingWentWrong')}</Heading>
|
||||||
<Flex
|
<Flex
|
||||||
layerStyle="second"
|
layerStyle="second"
|
||||||
sx={{
|
px={8}
|
||||||
px: 8,
|
py={4}
|
||||||
py: 4,
|
gap={4}
|
||||||
borderRadius: 'base',
|
borderRadius="base"
|
||||||
gap: 4,
|
justifyContent="space-between"
|
||||||
justifyContent: 'space-between',
|
alignItems="center"
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Text
|
<InvText fontWeight="semibold" color="error.400">
|
||||||
sx={{
|
|
||||||
fontWeight: 600,
|
|
||||||
color: 'error.500',
|
|
||||||
_dark: { color: 'error.400' },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{error.name}: {error.message}
|
{error.name}: {error.message}
|
||||||
</Text>
|
</InvText>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex sx={{ gap: 4 }}>
|
<Flex gap={4}>
|
||||||
<IAIButton
|
<InvButton
|
||||||
leftIcon={<FaArrowRotateLeft />}
|
leftIcon={<FaArrowRotateLeft />}
|
||||||
onClick={resetErrorBoundary}
|
onClick={resetErrorBoundary}
|
||||||
>
|
>
|
||||||
{t('accessibility.resetUI')}
|
{t('accessibility.resetUI')}
|
||||||
</IAIButton>
|
</InvButton>
|
||||||
<IAIButton leftIcon={<FaCopy />} onClick={handleCopy}>
|
<InvButton leftIcon={<FaCopy />} onClick={handleCopy}>
|
||||||
{t('common.copyError')}
|
{t('common.copyError')}
|
||||||
</IAIButton>
|
</InvButton>
|
||||||
<Link href={url} isExternal>
|
<Link href={url} isExternal>
|
||||||
<IAIButton leftIcon={<FaExternalLinkAlt />}>
|
<InvButton leftIcon={<FaExternalLinkAlt />}>
|
||||||
{t('accessibility.createIssue')}
|
{t('accessibility.createIssue')}
|
||||||
</IAIButton>
|
</InvButton>
|
||||||
</Link>
|
</Link>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { useQueueBack } from 'features/queue/hooks/useQueueBack';
|
|
||||||
import { useQueueFront } from 'features/queue/hooks/useQueueFront';
|
|
||||||
import {
|
|
||||||
ctrlKeyPressed,
|
|
||||||
metaKeyPressed,
|
|
||||||
shiftKeyPressed,
|
|
||||||
} from 'features/ui/store/hotkeysSlice';
|
|
||||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
|
||||||
import React, { memo } from 'react';
|
|
||||||
import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook';
|
|
||||||
|
|
||||||
const globalHotkeysSelector = createMemoizedSelector(
|
|
||||||
[stateSelector],
|
|
||||||
({ hotkeys }) => {
|
|
||||||
const { shift, ctrl, meta } = hotkeys;
|
|
||||||
return { shift, ctrl, meta };
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: Does not catch keypresses while focused in an input. Maybe there is a way?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logical component. Handles app-level global hotkeys.
|
|
||||||
* @returns null
|
|
||||||
*/
|
|
||||||
const GlobalHotkeys: React.FC = () => {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { shift, ctrl, meta } = useAppSelector(globalHotkeysSelector);
|
|
||||||
const {
|
|
||||||
queueBack,
|
|
||||||
isDisabled: isDisabledQueueBack,
|
|
||||||
isLoading: isLoadingQueueBack,
|
|
||||||
} = useQueueBack();
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['ctrl+enter', 'meta+enter'],
|
|
||||||
queueBack,
|
|
||||||
{
|
|
||||||
enabled: () => !isDisabledQueueBack && !isLoadingQueueBack,
|
|
||||||
preventDefault: true,
|
|
||||||
enableOnFormTags: ['input', 'textarea', 'select'],
|
|
||||||
},
|
|
||||||
[queueBack, isDisabledQueueBack, isLoadingQueueBack]
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
|
||||||
queueFront,
|
|
||||||
isDisabled: isDisabledQueueFront,
|
|
||||||
isLoading: isLoadingQueueFront,
|
|
||||||
} = useQueueFront();
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
['ctrl+shift+enter', 'meta+shift+enter'],
|
|
||||||
queueFront,
|
|
||||||
{
|
|
||||||
enabled: () => !isDisabledQueueFront && !isLoadingQueueFront,
|
|
||||||
preventDefault: true,
|
|
||||||
enableOnFormTags: ['input', 'textarea', 'select'],
|
|
||||||
},
|
|
||||||
[queueFront, isDisabledQueueFront, isLoadingQueueFront]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
'*',
|
|
||||||
() => {
|
|
||||||
if (isHotkeyPressed('shift')) {
|
|
||||||
!shift && dispatch(shiftKeyPressed(true));
|
|
||||||
} else {
|
|
||||||
shift && dispatch(shiftKeyPressed(false));
|
|
||||||
}
|
|
||||||
if (isHotkeyPressed('ctrl')) {
|
|
||||||
!ctrl && dispatch(ctrlKeyPressed(true));
|
|
||||||
} else {
|
|
||||||
ctrl && dispatch(ctrlKeyPressed(false));
|
|
||||||
}
|
|
||||||
if (isHotkeyPressed('meta')) {
|
|
||||||
!meta && dispatch(metaKeyPressed(true));
|
|
||||||
} else {
|
|
||||||
meta && dispatch(metaKeyPressed(false));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ keyup: true, keydown: true },
|
|
||||||
[shift, ctrl, meta]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys('1', () => {
|
|
||||||
dispatch(setActiveTab('txt2img'));
|
|
||||||
});
|
|
||||||
|
|
||||||
useHotkeys('2', () => {
|
|
||||||
dispatch(setActiveTab('img2img'));
|
|
||||||
});
|
|
||||||
|
|
||||||
useHotkeys('3', () => {
|
|
||||||
dispatch(setActiveTab('unifiedCanvas'));
|
|
||||||
});
|
|
||||||
|
|
||||||
useHotkeys('4', () => {
|
|
||||||
dispatch(setActiveTab('nodes'));
|
|
||||||
});
|
|
||||||
|
|
||||||
useHotkeys('5', () => {
|
|
||||||
dispatch(setActiveTab('modelManager'));
|
|
||||||
});
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(GlobalHotkeys);
|
|
@ -1,29 +1,27 @@
|
|||||||
import { Middleware } from '@reduxjs/toolkit';
|
import 'i18n';
|
||||||
|
|
||||||
|
import type { Middleware } from '@reduxjs/toolkit';
|
||||||
import { $socketOptions } from 'app/hooks/useSocketIO';
|
import { $socketOptions } from 'app/hooks/useSocketIO';
|
||||||
import { $authToken } from 'app/store/nanostores/authToken';
|
import { $authToken } from 'app/store/nanostores/authToken';
|
||||||
import { $baseUrl } from 'app/store/nanostores/baseUrl';
|
import { $baseUrl } from 'app/store/nanostores/baseUrl';
|
||||||
import { $customStarUI, CustomStarUi } from 'app/store/nanostores/customStarUI';
|
import { $customNavComponent } from 'app/store/nanostores/customNavComponent';
|
||||||
import { $headerComponent } from 'app/store/nanostores/headerComponent';
|
import type { CustomStarUi } from 'app/store/nanostores/customStarUI';
|
||||||
|
import { $customStarUI } from 'app/store/nanostores/customStarUI';
|
||||||
|
import { $galleryHeader } from 'app/store/nanostores/galleryHeader';
|
||||||
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
||||||
|
import { $logo } from 'app/store/nanostores/logo';
|
||||||
import { $projectId } from 'app/store/nanostores/projectId';
|
import { $projectId } from 'app/store/nanostores/projectId';
|
||||||
import { $queueId, DEFAULT_QUEUE_ID } from 'app/store/nanostores/queueId';
|
import { $queueId, DEFAULT_QUEUE_ID } from 'app/store/nanostores/queueId';
|
||||||
import { $store } from 'app/store/nanostores/store';
|
import { $store } from 'app/store/nanostores/store';
|
||||||
import { createStore } from 'app/store/store';
|
import { createStore } from 'app/store/store';
|
||||||
import { PartialAppConfig } from 'app/types/invokeai';
|
import type { PartialAppConfig } from 'app/types/invokeai';
|
||||||
import Loading from 'common/components/Loading/Loading';
|
import Loading from 'common/components/Loading/Loading';
|
||||||
import AppDndContext from 'features/dnd/components/AppDndContext';
|
import AppDndContext from 'features/dnd/components/AppDndContext';
|
||||||
import 'i18n';
|
import type { PropsWithChildren, ReactNode } from 'react';
|
||||||
import React, {
|
import React, { lazy, memo, useEffect, useMemo } from 'react';
|
||||||
PropsWithChildren,
|
|
||||||
ReactNode,
|
|
||||||
lazy,
|
|
||||||
memo,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
} from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
|
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
|
||||||
import { ManagerOptions, SocketOptions } from 'socket.io-client';
|
import type { ManagerOptions, SocketOptions } from 'socket.io-client';
|
||||||
|
|
||||||
const App = lazy(() => import('./App'));
|
const App = lazy(() => import('./App'));
|
||||||
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
|
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
|
||||||
@ -32,9 +30,10 @@ interface Props extends PropsWithChildren {
|
|||||||
apiUrl?: string;
|
apiUrl?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
config?: PartialAppConfig;
|
config?: PartialAppConfig;
|
||||||
headerComponent?: ReactNode;
|
customNavComponent?: ReactNode;
|
||||||
middleware?: Middleware[];
|
middleware?: Middleware[];
|
||||||
projectId?: string;
|
projectId?: string;
|
||||||
|
galleryHeader?: ReactNode;
|
||||||
queueId?: string;
|
queueId?: string;
|
||||||
selectedImage?: {
|
selectedImage?: {
|
||||||
imageName: string;
|
imageName: string;
|
||||||
@ -43,20 +42,23 @@ interface Props extends PropsWithChildren {
|
|||||||
customStarUi?: CustomStarUi;
|
customStarUi?: CustomStarUi;
|
||||||
socketOptions?: Partial<ManagerOptions & SocketOptions>;
|
socketOptions?: Partial<ManagerOptions & SocketOptions>;
|
||||||
isDebugging?: boolean;
|
isDebugging?: boolean;
|
||||||
|
logo?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InvokeAIUI = ({
|
const InvokeAIUI = ({
|
||||||
apiUrl,
|
apiUrl,
|
||||||
token,
|
token,
|
||||||
config,
|
config,
|
||||||
headerComponent,
|
customNavComponent,
|
||||||
middleware,
|
middleware,
|
||||||
projectId,
|
projectId,
|
||||||
|
galleryHeader,
|
||||||
queueId,
|
queueId,
|
||||||
selectedImage,
|
selectedImage,
|
||||||
customStarUi,
|
customStarUi,
|
||||||
socketOptions,
|
socketOptions,
|
||||||
isDebugging = false,
|
isDebugging = false,
|
||||||
|
logo,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// configure API client token
|
// configure API client token
|
||||||
@ -112,14 +114,34 @@ const InvokeAIUI = ({
|
|||||||
}, [customStarUi]);
|
}, [customStarUi]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (headerComponent) {
|
if (customNavComponent) {
|
||||||
$headerComponent.set(headerComponent);
|
$customNavComponent.set(customNavComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
$headerComponent.set(undefined);
|
$customNavComponent.set(undefined);
|
||||||
};
|
};
|
||||||
}, [headerComponent]);
|
}, [customNavComponent]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (galleryHeader) {
|
||||||
|
$galleryHeader.set(galleryHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
$galleryHeader.set(undefined);
|
||||||
|
};
|
||||||
|
}, [galleryHeader]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (logo) {
|
||||||
|
$logo.set(logo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
$logo.set(undefined);
|
||||||
|
};
|
||||||
|
}, [logo]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socketOptions) {
|
if (socketOptions) {
|
||||||
@ -145,6 +167,15 @@ const InvokeAIUI = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
$store.set(store);
|
$store.set(store);
|
||||||
|
if (import.meta.env.MODE === 'development') {
|
||||||
|
window.$store = $store;
|
||||||
|
}
|
||||||
|
() => {
|
||||||
|
$store.set(undefined);
|
||||||
|
if (import.meta.env.MODE === 'development') {
|
||||||
|
window.$store = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
}, [store]);
|
}, [store]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,24 +1,17 @@
|
|||||||
import {
|
|
||||||
ChakraProvider,
|
|
||||||
createLocalStorageManager,
|
|
||||||
extendTheme,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { ReactNode, memo, useEffect, useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { TOAST_OPTIONS, theme as invokeAITheme } from 'theme/theme';
|
|
||||||
|
|
||||||
import '@fontsource-variable/inter';
|
import '@fontsource-variable/inter';
|
||||||
import { MantineProvider } from '@mantine/core';
|
|
||||||
import { useMantineTheme } from 'mantine-theme/theme';
|
|
||||||
import 'overlayscrollbars/overlayscrollbars.css';
|
import 'overlayscrollbars/overlayscrollbars.css';
|
||||||
import 'theme/css/overlayscrollbars.css';
|
import 'common/components/OverlayScrollbars/overlayscrollbars.css';
|
||||||
|
|
||||||
|
import { ChakraProvider, extendTheme } from '@chakra-ui/react';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import { memo, useEffect, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { theme as invokeAITheme, TOAST_OPTIONS } from 'theme/theme';
|
||||||
|
|
||||||
type ThemeLocaleProviderProps = {
|
type ThemeLocaleProviderProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const manager = createLocalStorageManager('@@invokeai-color-mode');
|
|
||||||
|
|
||||||
function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
|
function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
@ -35,18 +28,10 @@ function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
|
|||||||
document.body.dir = direction;
|
document.body.dir = direction;
|
||||||
}, [direction]);
|
}, [direction]);
|
||||||
|
|
||||||
const mantineTheme = useMantineTheme();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineProvider theme={mantineTheme}>
|
<ChakraProvider theme={theme} toastOptions={TOAST_OPTIONS}>
|
||||||
<ChakraProvider
|
{children}
|
||||||
theme={theme}
|
</ChakraProvider>
|
||||||
colorModeManager={manager}
|
|
||||||
toastOptions={TOAST_OPTIONS}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</ChakraProvider>
|
|
||||||
</MantineProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { useToast } from '@chakra-ui/react';
|
import { useToast } from '@chakra-ui/react';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
|
import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
|
||||||
import { MakeToastArg, makeToast } from 'features/system/util/makeToast';
|
import type { MakeToastArg } from 'features/system/util/makeToast';
|
||||||
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { memo, useCallback, useEffect } from 'react';
|
import { memo, useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,7 +11,7 @@ import { memo, useCallback, useEffect } from 'react';
|
|||||||
*/
|
*/
|
||||||
const Toaster = () => {
|
const Toaster = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const toastQueue = useAppSelector((state) => state.system.toastQueue);
|
const toastQueue = useAppSelector((s) => s.system.toastQueue);
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
toastQueue.forEach((t) => {
|
toastQueue.forEach((t) => {
|
||||||
|
@ -1,94 +0,0 @@
|
|||||||
import { useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
type FeatureHelpInfo = {
|
|
||||||
text: string;
|
|
||||||
href: string;
|
|
||||||
guideImage: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum Feature {
|
|
||||||
PROMPT,
|
|
||||||
GALLERY,
|
|
||||||
OTHER,
|
|
||||||
SEED,
|
|
||||||
VARIATIONS,
|
|
||||||
UPSCALE,
|
|
||||||
FACE_CORRECTION,
|
|
||||||
IMAGE_TO_IMAGE,
|
|
||||||
BOUNDING_BOX,
|
|
||||||
SEAM_CORRECTION,
|
|
||||||
INFILL_AND_SCALING,
|
|
||||||
}
|
|
||||||
/** For each tooltip in the UI, the below feature definitions & props will pull relevant information into the tooltip.
|
|
||||||
*
|
|
||||||
* To-do: href & GuideImages are placeholders, and are not currently utilized, but will be updated (along with the tooltip UI) as feature and UI develop and we get a better idea on where things "forever homes" will be .
|
|
||||||
*/
|
|
||||||
const useFeatures = (): Record<Feature, FeatureHelpInfo> => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return useMemo(
|
|
||||||
() => ({
|
|
||||||
[Feature.PROMPT]: {
|
|
||||||
text: t('tooltip.feature.prompt'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.GALLERY]: {
|
|
||||||
text: t('tooltip.feature.gallery'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.OTHER]: {
|
|
||||||
text: t('tooltip.feature.other'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.SEED]: {
|
|
||||||
text: t('tooltip.feature.seed'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.VARIATIONS]: {
|
|
||||||
text: t('tooltip.feature.variations'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.UPSCALE]: {
|
|
||||||
text: t('tooltip.feature.upscale'),
|
|
||||||
href: 'link/to/docs/feature1.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.FACE_CORRECTION]: {
|
|
||||||
text: t('tooltip.feature.faceCorrection'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.IMAGE_TO_IMAGE]: {
|
|
||||||
text: t('tooltip.feature.imageToImage'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.BOUNDING_BOX]: {
|
|
||||||
text: t('tooltip.feature.boundingBox'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.SEAM_CORRECTION]: {
|
|
||||||
text: t('tooltip.feature.seamCorrection'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
[Feature.INFILL_AND_SCALING]: {
|
|
||||||
text: t('tooltip.feature.infillAndScaling'),
|
|
||||||
href: 'link/to/docs/feature3.html',
|
|
||||||
guideImage: 'asset/path.gif',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[t]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useFeatureHelpInfo = (feature: Feature): FeatureHelpInfo => {
|
|
||||||
const features = useFeatures();
|
|
||||||
return features[feature];
|
|
||||||
};
|
|
@ -3,14 +3,16 @@ import { $authToken } from 'app/store/nanostores/authToken';
|
|||||||
import { $baseUrl } from 'app/store/nanostores/baseUrl';
|
import { $baseUrl } from 'app/store/nanostores/baseUrl';
|
||||||
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
import { $isDebugging } from 'app/store/nanostores/isDebugging';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import { MapStore, atom, map } from 'nanostores';
|
import type { MapStore } from 'nanostores';
|
||||||
|
import { atom, map } from 'nanostores';
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import {
|
import type {
|
||||||
ClientToServerEvents,
|
ClientToServerEvents,
|
||||||
ServerToClientEvents,
|
ServerToClientEvents,
|
||||||
} from 'services/events/types';
|
} from 'services/events/types';
|
||||||
import { setEventListeners } from 'services/events/util/setEventListeners';
|
import { setEventListeners } from 'services/events/util/setEventListeners';
|
||||||
import { ManagerOptions, Socket, SocketOptions, io } from 'socket.io-client';
|
import type { ManagerOptions, Socket, SocketOptions } from 'socket.io-client';
|
||||||
|
import { io } from 'socket.io-client';
|
||||||
|
|
||||||
// Inject socket options and url into window for debugging
|
// Inject socket options and url into window for debugging
|
||||||
declare global {
|
declare global {
|
||||||
@ -41,7 +43,7 @@ export const useSocketIO = () => {
|
|||||||
}, [baseUrl]);
|
}, [baseUrl]);
|
||||||
|
|
||||||
const socketOptions = useMemo(() => {
|
const socketOptions = useMemo(() => {
|
||||||
const options: Parameters<typeof io>[0] = {
|
const options: Partial<ManagerOptions & SocketOptions> = {
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
path: '/ws/socket.io',
|
path: '/ws/socket.io',
|
||||||
autoConnect: false, // achtung! removing this breaks the dynamic middleware
|
autoConnect: false, // achtung! removing this breaks the dynamic middleware
|
||||||
@ -69,7 +71,7 @@ export const useSocketIO = () => {
|
|||||||
setEventListeners({ dispatch, socket });
|
setEventListeners({ dispatch, socket });
|
||||||
socket.connect();
|
socket.connect();
|
||||||
|
|
||||||
if ($isDebugging.get()) {
|
if ($isDebugging.get() || import.meta.env.MODE === 'development') {
|
||||||
window.$socketOptions = $socketOptions;
|
window.$socketOptions = $socketOptions;
|
||||||
console.log('Socket initialized', socket);
|
console.log('Socket initialized', socket);
|
||||||
}
|
}
|
||||||
@ -77,7 +79,7 @@ export const useSocketIO = () => {
|
|||||||
$isSocketInitialized.set(true);
|
$isSocketInitialized.set(true);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if ($isDebugging.get()) {
|
if ($isDebugging.get() || import.meta.env.MODE === 'development') {
|
||||||
window.$socketOptions = undefined;
|
window.$socketOptions = undefined;
|
||||||
console.log('Socket teardown', socket);
|
console.log('Socket teardown', socket);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import { createLogWriter } from '@roarr/browser-log-writer';
|
import { createLogWriter } from '@roarr/browser-log-writer';
|
||||||
import { atom } from 'nanostores';
|
import { atom } from 'nanostores';
|
||||||
import { Logger, ROARR, Roarr } from 'roarr';
|
import type { Logger, MessageSerializer } from 'roarr';
|
||||||
|
import { ROARR, Roarr } from 'roarr';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
const serializeMessage: MessageSerializer = (message) => {
|
||||||
|
return JSON.stringify(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
ROARR.serializeMessage = serializeMessage;
|
||||||
ROARR.write = createLogWriter();
|
ROARR.write = createLogWriter();
|
||||||
|
|
||||||
export const BASE_CONTEXT = {};
|
export const BASE_CONTEXT = {};
|
||||||
@ -26,19 +33,20 @@ export type LoggerNamespace =
|
|||||||
export const logger = (namespace: LoggerNamespace) =>
|
export const logger = (namespace: LoggerNamespace) =>
|
||||||
$logger.get().child({ namespace });
|
$logger.get().child({ namespace });
|
||||||
|
|
||||||
export const VALID_LOG_LEVELS = [
|
export const zLogLevel = z.enum([
|
||||||
'trace',
|
'trace',
|
||||||
'debug',
|
'debug',
|
||||||
'info',
|
'info',
|
||||||
'warn',
|
'warn',
|
||||||
'error',
|
'error',
|
||||||
'fatal',
|
'fatal',
|
||||||
] as const;
|
]);
|
||||||
|
export type LogLevel = z.infer<typeof zLogLevel>;
|
||||||
export type InvokeLogLevel = (typeof VALID_LOG_LEVELS)[number];
|
export const isLogLevel = (v: unknown): v is LogLevel =>
|
||||||
|
zLogLevel.safeParse(v).success;
|
||||||
|
|
||||||
// Translate human-readable log levels to numbers, used for log filtering
|
// Translate human-readable log levels to numbers, used for log filtering
|
||||||
export const LOG_LEVEL_MAP: Record<InvokeLogLevel, number> = {
|
export const LOG_LEVEL_MAP: Record<LogLevel, number> = {
|
||||||
trace: 10,
|
trace: 10,
|
||||||
debug: 20,
|
debug: 20,
|
||||||
info: 30,
|
info: 30,
|
||||||
|
@ -1,28 +1,14 @@
|
|||||||
import { createLogWriter } from '@roarr/browser-log-writer';
|
import { createLogWriter } from '@roarr/browser-log-writer';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { ROARR, Roarr } from 'roarr';
|
import { ROARR, Roarr } from 'roarr';
|
||||||
import {
|
|
||||||
$logger,
|
|
||||||
BASE_CONTEXT,
|
|
||||||
LOG_LEVEL_MAP,
|
|
||||||
LoggerNamespace,
|
|
||||||
logger,
|
|
||||||
} from './logger';
|
|
||||||
|
|
||||||
const selector = createMemoizedSelector(stateSelector, ({ system }) => {
|
import type { LoggerNamespace } from './logger';
|
||||||
const { consoleLogLevel, shouldLogToConsole } = system;
|
import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP, logger } from './logger';
|
||||||
|
|
||||||
return {
|
|
||||||
consoleLogLevel,
|
|
||||||
shouldLogToConsole,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const useLogger = (namespace: LoggerNamespace) => {
|
export const useLogger = (namespace: LoggerNamespace) => {
|
||||||
const { consoleLogLevel, shouldLogToConsole } = useAppSelector(selector);
|
const consoleLogLevel = useAppSelector((s) => s.system.consoleLogLevel);
|
||||||
|
const shouldLogToConsole = useAppSelector((s) => s.system.shouldLogToConsole);
|
||||||
|
|
||||||
// The provided Roarr browser log writer uses localStorage to config logging to console
|
// The provided Roarr browser log writer uses localStorage to config logging to console
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { InvokeTabName } from 'features/ui/store/tabMap';
|
import type { InvokeTabName } from 'features/ui/store/tabMap';
|
||||||
import { BatchConfig } from 'services/api/types';
|
import type { BatchConfig } from 'services/api/types';
|
||||||
|
|
||||||
export const enqueueRequested = createAction<{
|
export const enqueueRequested = createAction<{
|
||||||
tabName: InvokeTabName;
|
tabName: InvokeTabName;
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { createSelectorCreator, lruMemoize } from '@reduxjs/toolkit';
|
import {
|
||||||
|
createDraftSafeSelectorCreator,
|
||||||
|
createSelectorCreator,
|
||||||
|
lruMemoize,
|
||||||
|
} from '@reduxjs/toolkit';
|
||||||
|
import type { GetSelectorsOptions } from '@reduxjs/toolkit/dist/entities/state_selectors';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,4 +14,22 @@ export const createMemoizedSelector = createSelectorCreator({
|
|||||||
memoizeOptions: {
|
memoizeOptions: {
|
||||||
resultEqualityCheck: isEqual,
|
resultEqualityCheck: isEqual,
|
||||||
},
|
},
|
||||||
|
argsMemoize: lruMemoize,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A memoized selector creator that uses LRU cache default shallow equality check.
|
||||||
|
*/
|
||||||
|
export const createLruSelector = createSelectorCreator({
|
||||||
|
memoize: lruMemoize,
|
||||||
|
argsMemoize: lruMemoize,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createLruDraftSafeSelector = createDraftSafeSelectorCreator({
|
||||||
|
memoize: lruMemoize,
|
||||||
|
argsMemoize: lruMemoize,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getSelectorsOptions: GetSelectorsOptions = {
|
||||||
|
createSelector: createLruDraftSafeSelector,
|
||||||
|
};
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
import { StorageError } from 'app/store/enhancers/reduxRemember/errors';
|
||||||
|
import type { UseStore } from 'idb-keyval';
|
||||||
|
import {
|
||||||
|
clear,
|
||||||
|
createStore as createIDBKeyValStore,
|
||||||
|
get,
|
||||||
|
set,
|
||||||
|
} from 'idb-keyval';
|
||||||
|
import { action, atom } from 'nanostores';
|
||||||
|
import type { Driver } from 'redux-remember';
|
||||||
|
|
||||||
|
// Create a custom idb-keyval store (just needed to customize the name)
|
||||||
|
export const $idbKeyValStore = atom<UseStore>(
|
||||||
|
createIDBKeyValStore('invoke', 'invoke-store')
|
||||||
|
);
|
||||||
|
|
||||||
|
export const clearIdbKeyValStore = action($idbKeyValStore, 'clear', (store) => {
|
||||||
|
clear(store.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create redux-remember driver, wrapping idb-keyval
|
||||||
|
export const idbKeyValDriver: Driver = {
|
||||||
|
getItem: (key) => {
|
||||||
|
try {
|
||||||
|
return get(key, $idbKeyValStore.get());
|
||||||
|
} catch (originalError) {
|
||||||
|
throw new StorageError({ key, originalError });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setItem: (key, value) => {
|
||||||
|
try {
|
||||||
|
return set(key, value, $idbKeyValStore.get());
|
||||||
|
} catch (originalError) {
|
||||||
|
throw new StorageError({ key, value, originalError });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,41 @@
|
|||||||
|
import { logger } from 'app/logging/logger';
|
||||||
|
import { parseify } from 'common/util/serialize';
|
||||||
|
import { PersistError, RehydrateError } from 'redux-remember';
|
||||||
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
|
export type StorageErrorArgs = {
|
||||||
|
key: string;
|
||||||
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ // any is correct
|
||||||
|
value?: any;
|
||||||
|
originalError?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class StorageError extends Error {
|
||||||
|
key: string;
|
||||||
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ // any is correct
|
||||||
|
value?: any;
|
||||||
|
originalError?: Error;
|
||||||
|
|
||||||
|
constructor({ key, value, originalError }: StorageErrorArgs) {
|
||||||
|
super(`Error setting ${key}`);
|
||||||
|
this.name = 'StorageSetError';
|
||||||
|
this.key = key;
|
||||||
|
if (value !== undefined) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
if (originalError instanceof Error) {
|
||||||
|
this.originalError = originalError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const errorHandler = (err: PersistError | RehydrateError) => {
|
||||||
|
const log = logger('system');
|
||||||
|
if (err instanceof PersistError) {
|
||||||
|
log.error({ error: serializeError(err) }, 'Problem persisting state');
|
||||||
|
} else if (err instanceof RehydrateError) {
|
||||||
|
log.error({ error: serializeError(err) }, 'Problem rehydrating state');
|
||||||
|
} else {
|
||||||
|
log.error({ error: parseify(err) }, 'Problem in persistence layer');
|
||||||
|
}
|
||||||
|
};
|
@ -1,30 +0,0 @@
|
|||||||
import { canvasPersistDenylist } from 'features/canvas/store/canvasPersistDenylist';
|
|
||||||
import { controlAdaptersPersistDenylist } from 'features/controlAdapters/store/controlAdaptersPersistDenylist';
|
|
||||||
import { dynamicPromptsPersistDenylist } from 'features/dynamicPrompts/store/dynamicPromptsPersistDenylist';
|
|
||||||
import { galleryPersistDenylist } from 'features/gallery/store/galleryPersistDenylist';
|
|
||||||
import { nodesPersistDenylist } from 'features/nodes/store/nodesPersistDenylist';
|
|
||||||
import { generationPersistDenylist } from 'features/parameters/store/generationPersistDenylist';
|
|
||||||
import { postprocessingPersistDenylist } from 'features/parameters/store/postprocessingPersistDenylist';
|
|
||||||
import { systemPersistDenylist } from 'features/system/store/systemPersistDenylist';
|
|
||||||
import { uiPersistDenylist } from 'features/ui/store/uiPersistDenylist';
|
|
||||||
import { omit } from 'lodash-es';
|
|
||||||
import { SerializeFunction } from 'redux-remember';
|
|
||||||
|
|
||||||
const serializationDenylist: {
|
|
||||||
[key: string]: string[];
|
|
||||||
} = {
|
|
||||||
canvas: canvasPersistDenylist,
|
|
||||||
gallery: galleryPersistDenylist,
|
|
||||||
generation: generationPersistDenylist,
|
|
||||||
nodes: nodesPersistDenylist,
|
|
||||||
postprocessing: postprocessingPersistDenylist,
|
|
||||||
system: systemPersistDenylist,
|
|
||||||
ui: uiPersistDenylist,
|
|
||||||
controlNet: controlAdaptersPersistDenylist,
|
|
||||||
dynamicPrompts: dynamicPromptsPersistDenylist,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const serialize: SerializeFunction = (data, key) => {
|
|
||||||
const result = omit(data, serializationDenylist[key] ?? []);
|
|
||||||
return JSON.stringify(result);
|
|
||||||
};
|
|
@ -1,36 +0,0 @@
|
|||||||
import { initialCanvasState } from 'features/canvas/store/canvasSlice';
|
|
||||||
import { initialControlAdapterState } from 'features/controlAdapters/store/controlAdaptersSlice';
|
|
||||||
import { initialDynamicPromptsState } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
|
||||||
import { initialGalleryState } from 'features/gallery/store/gallerySlice';
|
|
||||||
import { initialNodesState } from 'features/nodes/store/nodesSlice';
|
|
||||||
import { initialGenerationState } from 'features/parameters/store/generationSlice';
|
|
||||||
import { initialPostprocessingState } from 'features/parameters/store/postprocessingSlice';
|
|
||||||
import { initialSDXLState } from 'features/sdxl/store/sdxlSlice';
|
|
||||||
import { initialConfigState } from 'features/system/store/configSlice';
|
|
||||||
import { initialSystemState } from 'features/system/store/systemSlice';
|
|
||||||
import { initialHotkeysState } from 'features/ui/store/hotkeysSlice';
|
|
||||||
import { initialUIState } from 'features/ui/store/uiSlice';
|
|
||||||
import { defaultsDeep } from 'lodash-es';
|
|
||||||
import { UnserializeFunction } from 'redux-remember';
|
|
||||||
|
|
||||||
const initialStates: {
|
|
||||||
[key: string]: object; // TODO: type this properly
|
|
||||||
} = {
|
|
||||||
canvas: initialCanvasState,
|
|
||||||
gallery: initialGalleryState,
|
|
||||||
generation: initialGenerationState,
|
|
||||||
nodes: initialNodesState,
|
|
||||||
postprocessing: initialPostprocessingState,
|
|
||||||
system: initialSystemState,
|
|
||||||
config: initialConfigState,
|
|
||||||
ui: initialUIState,
|
|
||||||
hotkeys: initialHotkeysState,
|
|
||||||
controlAdapters: initialControlAdapterState,
|
|
||||||
dynamicPrompts: initialDynamicPromptsState,
|
|
||||||
sdxl: initialSDXLState,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const unserialize: UnserializeFunction = (data, key) => {
|
|
||||||
const result = defaultsDeep(JSON.parse(data), initialStates[key]);
|
|
||||||
return result;
|
|
||||||
};
|
|
@ -0,0 +1,16 @@
|
|||||||
|
import type { Middleware, MiddlewareAPI } from '@reduxjs/toolkit';
|
||||||
|
import { diff } from 'jsondiffpatch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Super simple logger middleware. Useful for debugging when the redux devtools are awkward.
|
||||||
|
*/
|
||||||
|
export const debugLoggerMiddleware: Middleware =
|
||||||
|
(api: MiddlewareAPI) => (next) => (action) => {
|
||||||
|
const originalState = api.getState();
|
||||||
|
console.log('REDUX: dispatching', action);
|
||||||
|
const result = next(action);
|
||||||
|
const nextState = api.getState();
|
||||||
|
console.log('REDUX: next state', nextState);
|
||||||
|
console.log('REDUX: diff', diff(originalState, nextState));
|
||||||
|
return result;
|
||||||
|
};
|
@ -1,8 +1,10 @@
|
|||||||
import { UnknownAction } from '@reduxjs/toolkit';
|
import type { UnknownAction } from '@reduxjs/toolkit';
|
||||||
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
import { nodeTemplatesBuilt } from 'features/nodes/store/nodeTemplatesSlice';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||||
import { Graph } from 'services/api/types';
|
import type { Graph } from 'services/api/types';
|
||||||
|
import { socketGeneratorProgress } from 'services/events/actions';
|
||||||
|
|
||||||
export const actionSanitizer = <A extends UnknownAction>(action: A): A => {
|
export const actionSanitizer = <A extends UnknownAction>(action: A): A => {
|
||||||
if (isAnyGraphBuilt(action)) {
|
if (isAnyGraphBuilt(action)) {
|
||||||
@ -30,5 +32,14 @@ export const actionSanitizer = <A extends UnknownAction>(action: A): A => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (socketGeneratorProgress.match(action)) {
|
||||||
|
const sanitized = cloneDeep(action);
|
||||||
|
if (sanitized.payload.data.progress_image) {
|
||||||
|
sanitized.payload.data.progress_image.dataURL =
|
||||||
|
'<Progress image omitted>';
|
||||||
|
}
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
};
|
};
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
/**
|
/**
|
||||||
* This is a list of actions that should be excluded in the Redux DevTools.
|
* This is a list of actions that should be excluded in the Redux DevTools.
|
||||||
*/
|
*/
|
||||||
export const actionsDenylist = [
|
export const actionsDenylist: string[] = [
|
||||||
// very spammy canvas actions
|
// very spammy canvas actions
|
||||||
'canvas/setCursorPosition',
|
// 'canvas/setStageCoordinates',
|
||||||
'canvas/setStageCoordinates',
|
// 'canvas/setStageScale',
|
||||||
'canvas/setStageScale',
|
// 'canvas/setBoundingBoxCoordinates',
|
||||||
'canvas/setIsDrawing',
|
// 'canvas/setBoundingBoxDimensions',
|
||||||
'canvas/setBoundingBoxCoordinates',
|
// 'canvas/addPointToCurrentLine',
|
||||||
'canvas/setBoundingBoxDimensions',
|
|
||||||
'canvas/setIsDrawing',
|
|
||||||
'canvas/addPointToCurrentLine',
|
|
||||||
// bazillions during generation
|
// bazillions during generation
|
||||||
'socket/socketGeneratorProgress',
|
// 'socket/socketGeneratorProgress',
|
||||||
'socket/appSocketGeneratorProgress',
|
// 'socket/appSocketGeneratorProgress',
|
||||||
// every time user presses shift
|
|
||||||
// 'hotkeys/shiftKeyPressed',
|
|
||||||
// this happens after every state change
|
// this happens after every state change
|
||||||
'@@REMEMBER_PERSISTED',
|
// '@@REMEMBER_PERSISTED',
|
||||||
];
|
];
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import type { TypedAddListener, TypedStartListening } from '@reduxjs/toolkit';
|
import type {
|
||||||
import {
|
|
||||||
UnknownAction,
|
|
||||||
ListenerEffect,
|
ListenerEffect,
|
||||||
addListener,
|
TypedAddListener,
|
||||||
createListenerMiddleware,
|
TypedStartListening,
|
||||||
|
UnknownAction,
|
||||||
} from '@reduxjs/toolkit';
|
} from '@reduxjs/toolkit';
|
||||||
|
import { addListener, createListenerMiddleware } from '@reduxjs/toolkit';
|
||||||
|
import { addGalleryImageClickedListener } from 'app/store/middleware/listenerMiddleware/listeners/galleryImageClicked';
|
||||||
import type { AppDispatch, RootState } from 'app/store/store';
|
import type { AppDispatch, RootState } from 'app/store/store';
|
||||||
|
|
||||||
import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener';
|
import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener';
|
||||||
import { addFirstListImagesListener } from './listeners/addFirstListImagesListener.ts';
|
import { addFirstListImagesListener } from './listeners/addFirstListImagesListener.ts';
|
||||||
import { addAnyEnqueuedListener } from './listeners/anyEnqueued';
|
import { addAnyEnqueuedListener } from './listeners/anyEnqueued';
|
||||||
@ -42,13 +44,13 @@ import {
|
|||||||
addImageRemovedFromBoardFulfilledListener,
|
addImageRemovedFromBoardFulfilledListener,
|
||||||
addImageRemovedFromBoardRejectedListener,
|
addImageRemovedFromBoardRejectedListener,
|
||||||
} from './listeners/imageRemovedFromBoard';
|
} from './listeners/imageRemovedFromBoard';
|
||||||
|
import { addImagesStarredListener } from './listeners/imagesStarred';
|
||||||
|
import { addImagesUnstarredListener } from './listeners/imagesUnstarred';
|
||||||
import { addImageToDeleteSelectedListener } from './listeners/imageToDeleteSelected';
|
import { addImageToDeleteSelectedListener } from './listeners/imageToDeleteSelected';
|
||||||
import {
|
import {
|
||||||
addImageUploadedFulfilledListener,
|
addImageUploadedFulfilledListener,
|
||||||
addImageUploadedRejectedListener,
|
addImageUploadedRejectedListener,
|
||||||
} from './listeners/imageUploaded';
|
} from './listeners/imageUploaded';
|
||||||
import { addImagesStarredListener } from './listeners/imagesStarred';
|
|
||||||
import { addImagesUnstarredListener } from './listeners/imagesUnstarred';
|
|
||||||
import { addInitialImageSelectedListener } from './listeners/initialImageSelected';
|
import { addInitialImageSelectedListener } from './listeners/initialImageSelected';
|
||||||
import { addModelSelectedListener } from './listeners/modelSelected';
|
import { addModelSelectedListener } from './listeners/modelSelected';
|
||||||
import { addModelsLoadedListener } from './listeners/modelsLoaded';
|
import { addModelsLoadedListener } from './listeners/modelsLoaded';
|
||||||
@ -68,10 +70,9 @@ import { addSessionRetrievalErrorEventListener } from './listeners/socketio/sock
|
|||||||
import { addSocketSubscribedEventListener as addSocketSubscribedListener } from './listeners/socketio/socketSubscribed';
|
import { addSocketSubscribedEventListener as addSocketSubscribedListener } from './listeners/socketio/socketSubscribed';
|
||||||
import { addSocketUnsubscribedEventListener as addSocketUnsubscribedListener } from './listeners/socketio/socketUnsubscribed';
|
import { addSocketUnsubscribedEventListener as addSocketUnsubscribedListener } from './listeners/socketio/socketUnsubscribed';
|
||||||
import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSaved';
|
import { addStagingAreaImageSavedListener } from './listeners/stagingAreaImageSaved';
|
||||||
import { addTabChangedListener } from './listeners/tabChanged';
|
import { addUpdateAllNodesRequestedListener } from './listeners/updateAllNodesRequested';
|
||||||
import { addUpscaleRequestedListener } from './listeners/upscaleRequested';
|
import { addUpscaleRequestedListener } from './listeners/upscaleRequested';
|
||||||
import { addWorkflowLoadRequestedListener } from './listeners/workflowLoadRequested';
|
import { addWorkflowLoadRequestedListener } from './listeners/workflowLoadRequested';
|
||||||
import { addUpdateAllNodesRequestedListener } from './listeners/updateAllNodesRequested';
|
|
||||||
|
|
||||||
export const listenerMiddleware = createListenerMiddleware();
|
export const listenerMiddleware = createListenerMiddleware();
|
||||||
|
|
||||||
@ -117,6 +118,9 @@ addImageToDeleteSelectedListener();
|
|||||||
addImagesStarredListener();
|
addImagesStarredListener();
|
||||||
addImagesUnstarredListener();
|
addImagesUnstarredListener();
|
||||||
|
|
||||||
|
// Gallery
|
||||||
|
addGalleryImageClickedListener();
|
||||||
|
|
||||||
// User Invoked
|
// User Invoked
|
||||||
addEnqueueRequestedCanvasListener();
|
addEnqueueRequestedCanvasListener();
|
||||||
addEnqueueRequestedNodes();
|
addEnqueueRequestedNodes();
|
||||||
@ -135,19 +139,7 @@ addCanvasMergedListener();
|
|||||||
addStagingAreaImageSavedListener();
|
addStagingAreaImageSavedListener();
|
||||||
addCommitStagingAreaImageListener();
|
addCommitStagingAreaImageListener();
|
||||||
|
|
||||||
/**
|
// Socket.IO
|
||||||
* Socket.IO Events - these handle SIO events directly and pass on internal application actions.
|
|
||||||
* We don't handle SIO events in slices via `extraReducers` because some of these events shouldn't
|
|
||||||
* actually be handled at all.
|
|
||||||
*
|
|
||||||
* For example, we don't want to respond to progress events for canceled sessions. To avoid
|
|
||||||
* duplicating the logic to determine if an event should be responded to, we handle all of that
|
|
||||||
* "is this session canceled?" logic in these listeners.
|
|
||||||
*
|
|
||||||
* The `socketGeneratorProgress` listener will then only dispatch the `appSocketGeneratorProgress`
|
|
||||||
* action if it should be handled by the rest of the application. It is this `appSocketGeneratorProgress`
|
|
||||||
* action that is handled by reducers in slices.
|
|
||||||
*/
|
|
||||||
addGeneratorProgressListener();
|
addGeneratorProgressListener();
|
||||||
addGraphExecutionStateCompleteListener();
|
addGraphExecutionStateCompleteListener();
|
||||||
addInvocationCompleteListener();
|
addInvocationCompleteListener();
|
||||||
@ -195,8 +187,5 @@ addFirstListImagesListener();
|
|||||||
// Ad-hoc upscale workflwo
|
// Ad-hoc upscale workflwo
|
||||||
addUpscaleRequestedListener();
|
addUpscaleRequestedListener();
|
||||||
|
|
||||||
// Tab Change
|
|
||||||
addTabChangedListener();
|
|
||||||
|
|
||||||
// Dynamic prompts
|
// Dynamic prompts
|
||||||
addDynamicPromptsListener();
|
addDynamicPromptsListener();
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
const matcher = isAnyOf(commitStagingAreaImage, discardStagedImages);
|
const matcher = isAnyOf(commitStagingAreaImage, discardStagedImages);
|
||||||
|
@ -2,9 +2,10 @@ import { createAction } from '@reduxjs/toolkit';
|
|||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
import { IMAGE_CATEGORIES } from 'features/gallery/store/types';
|
import { IMAGE_CATEGORIES } from 'features/gallery/store/types';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
import type { ImageCache } from 'services/api/types';
|
||||||
|
import { getListImagesUrl, imagesSelectors } from 'services/api/util';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { getListImagesUrl, imagesAdapter } from 'services/api/util';
|
|
||||||
import { ImageCache } from 'services/api/types';
|
|
||||||
|
|
||||||
export const appStarted = createAction('app/appStarted');
|
export const appStarted = createAction('app/appStarted');
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ export const addFirstListImagesListener = () => {
|
|||||||
|
|
||||||
if (data.ids.length > 0) {
|
if (data.ids.length > 0) {
|
||||||
// Select the first image
|
// Select the first image
|
||||||
const firstImage = imagesAdapter.getSelectors().selectAll(data)[0];
|
const firstImage = imagesSelectors.selectAll(data)[0];
|
||||||
dispatch(imageSelected(firstImage ?? null));
|
dispatch(imageSelected(firstImage ?? null));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addAnyEnqueuedListener = () => {
|
export const addAnyEnqueuedListener = () => {
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
shouldUseWatermarkerChanged,
|
shouldUseWatermarkerChanged,
|
||||||
} from 'features/system/store/systemSlice';
|
} from 'features/system/store/systemSlice';
|
||||||
import { appInfoApi } from 'services/api/endpoints/appInfo';
|
import { appInfoApi } from 'services/api/endpoints/appInfo';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addAppConfigReceivedListener = () => {
|
export const addAppConfigReceivedListener = () => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const appStarted = createAction('app/appStarted');
|
export const appStarted = createAction('app/appStarted');
|
||||||
|
@ -5,7 +5,8 @@ import { zPydanticValidationError } from 'features/system/store/zodSchemas';
|
|||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { truncate, upperFirst } from 'lodash-es';
|
import { truncate, upperFirst } from 'lodash-es';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
import { TOAST_OPTIONS, theme } from 'theme/theme';
|
import { theme, TOAST_OPTIONS } from 'theme/theme';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
const { toast } = createStandaloneToast({
|
const { toast } = createStandaloneToast({
|
||||||
|
@ -4,6 +4,7 @@ import { getImageUsage } from 'features/deleteImageModal/store/selectors';
|
|||||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||||
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addDeleteBoardAndImagesFulfilledListener = () => {
|
export const addDeleteBoardAndImagesFulfilledListener = () => {
|
||||||
@ -19,9 +20,15 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
|
|||||||
let wasNodeEditorReset = false;
|
let wasNodeEditorReset = false;
|
||||||
let wereControlAdaptersReset = false;
|
let wereControlAdaptersReset = false;
|
||||||
|
|
||||||
const state = getState();
|
const { generation, canvas, nodes, controlAdapters } = getState();
|
||||||
deleted_images.forEach((image_name) => {
|
deleted_images.forEach((image_name) => {
|
||||||
const imageUsage = getImageUsage(state, image_name);
|
const imageUsage = getImageUsage(
|
||||||
|
generation,
|
||||||
|
canvas,
|
||||||
|
nodes,
|
||||||
|
controlAdapters,
|
||||||
|
image_name
|
||||||
|
);
|
||||||
|
|
||||||
if (imageUsage.isInitialImage && !wasInitialImageReset) {
|
if (imageUsage.isInitialImage && !wasInitialImageReset) {
|
||||||
dispatch(clearInitialImage());
|
dispatch(clearInitialImage());
|
||||||
|
@ -9,9 +9,10 @@ import {
|
|||||||
IMAGE_CATEGORIES,
|
IMAGE_CATEGORIES,
|
||||||
} from 'features/gallery/store/types';
|
} from 'features/gallery/store/types';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { imagesSelectors } from 'services/api/util';
|
import { imagesSelectors } from 'services/api/util';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addBoardIdSelectedListener = () => {
|
export const addBoardIdSelectedListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
matcher: isAnyOf(boardIdSelected, galleryViewChanged),
|
matcher: isAnyOf(boardIdSelected, galleryViewChanged),
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { canvasCopiedToClipboard } from 'features/canvas/store/actions';
|
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { $logger } from 'app/logging/logger';
|
import { $logger } from 'app/logging/logger';
|
||||||
|
import { canvasCopiedToClipboard } from 'features/canvas/store/actions';
|
||||||
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { copyBlobToClipboard } from 'features/system/util/copyBlobToClipboard';
|
import { copyBlobToClipboard } from 'features/system/util/copyBlobToClipboard';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addCanvasCopiedToClipboardListener = () => {
|
export const addCanvasCopiedToClipboardListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: canvasCopiedToClipboard,
|
actionCreator: canvasCopiedToClipboard,
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { canvasDownloadedAsImage } from 'features/canvas/store/actions';
|
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { $logger } from 'app/logging/logger';
|
import { $logger } from 'app/logging/logger';
|
||||||
|
import { canvasDownloadedAsImage } from 'features/canvas/store/actions';
|
||||||
import { downloadBlob } from 'features/canvas/util/downloadBlob';
|
import { downloadBlob } from 'features/canvas/util/downloadBlob';
|
||||||
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addCanvasDownloadedAsImageListener = () => {
|
export const addCanvasDownloadedAsImageListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: canvasDownloadedAsImage,
|
actionCreator: canvasDownloadedAsImage,
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
|
import { canvasImageToControlAdapter } from 'features/canvas/store/actions';
|
||||||
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
||||||
import { controlAdapterImageChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
import { controlAdapterImageChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { canvasImageToControlAdapter } from 'features/canvas/store/actions';
|
|
||||||
|
|
||||||
export const addCanvasImageToControlNetListener = () => {
|
export const addCanvasImageToControlNetListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
|
@ -2,9 +2,10 @@ import { logger } from 'app/logging/logger';
|
|||||||
import { canvasMaskSavedToGallery } from 'features/canvas/store/actions';
|
import { canvasMaskSavedToGallery } from 'features/canvas/store/actions';
|
||||||
import { getCanvasData } from 'features/canvas/util/getCanvasData';
|
import { getCanvasData } from 'features/canvas/util/getCanvasData';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addCanvasMaskSavedToGalleryListener = () => {
|
export const addCanvasMaskSavedToGalleryListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
|
@ -5,6 +5,7 @@ import { controlAdapterImageChanged } from 'features/controlAdapters/store/contr
|
|||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addCanvasMaskToControlNetListener = () => {
|
export const addCanvasMaskToControlNetListener = () => {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { $logger } from 'app/logging/logger';
|
import { $logger } from 'app/logging/logger';
|
||||||
import { canvasMerged } from 'features/canvas/store/actions';
|
import { canvasMerged } from 'features/canvas/store/actions';
|
||||||
|
import { $canvasBaseLayer } from 'features/canvas/store/canvasNanostore';
|
||||||
import { setMergedCanvas } from 'features/canvas/store/canvasSlice';
|
import { setMergedCanvas } from 'features/canvas/store/canvasSlice';
|
||||||
import { getFullBaseLayerBlob } from 'features/canvas/util/getFullBaseLayerBlob';
|
import { getFullBaseLayerBlob } from 'features/canvas/util/getFullBaseLayerBlob';
|
||||||
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addCanvasMergedListener = () => {
|
export const addCanvasMergedListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
@ -29,7 +30,7 @@ export const addCanvasMergedListener = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvasBaseLayer = getCanvasBaseLayer();
|
const canvasBaseLayer = $canvasBaseLayer.get();
|
||||||
|
|
||||||
if (!canvasBaseLayer) {
|
if (!canvasBaseLayer) {
|
||||||
moduleLog.error('Problem getting canvas base layer');
|
moduleLog.error('Problem getting canvas base layer');
|
||||||
|
@ -2,9 +2,10 @@ import { logger } from 'app/logging/logger';
|
|||||||
import { canvasSavedToGallery } from 'features/canvas/store/actions';
|
import { canvasSavedToGallery } from 'features/canvas/store/actions';
|
||||||
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addCanvasSavedToGalleryListener = () => {
|
export const addCanvasSavedToGalleryListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { AnyListenerPredicate } from '@reduxjs/toolkit';
|
import type { AnyListenerPredicate } from '@reduxjs/toolkit';
|
||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import { controlAdapterImageProcessed } from 'features/controlAdapters/store/actions';
|
import { controlAdapterImageProcessed } from 'features/controlAdapters/store/actions';
|
||||||
import {
|
import {
|
||||||
controlAdapterAutoConfigToggled,
|
controlAdapterAutoConfigToggled,
|
||||||
@ -10,9 +10,10 @@ import {
|
|||||||
controlAdapterProcessortTypeChanged,
|
controlAdapterProcessortTypeChanged,
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { startAppListening } from '..';
|
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
type AnyControlAdapterParamChangeAction =
|
type AnyControlAdapterParamChangeAction =
|
||||||
| ReturnType<typeof controlAdapterProcessorParamsChanged>
|
| ReturnType<typeof controlAdapterProcessorParamsChanged>
|
||||||
| ReturnType<typeof controlAdapterModelChanged>
|
| ReturnType<typeof controlAdapterModelChanged>
|
||||||
@ -68,10 +69,12 @@ const predicate: AnyListenerPredicate<RootState> = (
|
|||||||
return isProcessorSelected && hasControlImage;
|
return isProcessorSelected && hasControlImage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DEBOUNCE_MS = 300;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener that automatically processes a ControlNet image when its processor parameters are changed.
|
* Listener that automatically processes a ControlNet image when its processor parameters are changed.
|
||||||
*
|
*
|
||||||
* The network request is debounced by 1 second.
|
* The network request is debounced.
|
||||||
*/
|
*/
|
||||||
export const addControlNetAutoProcessListener = () => {
|
export const addControlNetAutoProcessListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
@ -84,7 +87,7 @@ export const addControlNetAutoProcessListener = () => {
|
|||||||
cancelActiveListeners();
|
cancelActiveListeners();
|
||||||
log.trace('ControlNet auto-process triggered');
|
log.trace('ControlNet auto-process triggered');
|
||||||
// Delay before starting actual work
|
// Delay before starting actual work
|
||||||
await delay(300);
|
await delay(DEBOUNCE_MS);
|
||||||
|
|
||||||
dispatch(controlAdapterImageProcessed({ id }));
|
dispatch(controlAdapterImageProcessed({ id }));
|
||||||
},
|
},
|
||||||
|
@ -8,14 +8,15 @@ import {
|
|||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
|
import { isImageOutput } from 'features/nodes/types/common';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
import { BatchConfig, ImageDTO } from 'services/api/types';
|
import type { BatchConfig, ImageDTO } from 'services/api/types';
|
||||||
import { socketInvocationComplete } from 'services/events/actions';
|
import { socketInvocationComplete } from 'services/events/actions';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { isImageOutput } from 'features/nodes/types/common';
|
|
||||||
|
|
||||||
export const addControlNetImageProcessedListener = () => {
|
export const addControlNetImageProcessedListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
|
@ -14,7 +14,8 @@ import { buildCanvasGraph } from 'features/nodes/util/graph/buildCanvasGraph';
|
|||||||
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
|
import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
import { ImageDTO } from 'services/api/types';
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,6 +5,7 @@ import { buildLinearSDXLImageToImageGraph } from 'features/nodes/util/graph/buil
|
|||||||
import { buildLinearSDXLTextToImageGraph } from 'features/nodes/util/graph/buildLinearSDXLTextToImageGraph';
|
import { buildLinearSDXLTextToImageGraph } from 'features/nodes/util/graph/buildLinearSDXLTextToImageGraph';
|
||||||
import { buildLinearTextToImageGraph } from 'features/nodes/util/graph/buildLinearTextToImageGraph';
|
import { buildLinearTextToImageGraph } from 'features/nodes/util/graph/buildLinearTextToImageGraph';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addEnqueueRequestedLinear = () => {
|
export const addEnqueueRequestedLinear = () => {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { enqueueRequested } from 'app/store/actions';
|
import { enqueueRequested } from 'app/store/actions';
|
||||||
import { buildNodesGraph } from 'features/nodes/util/graph/buildNodesGraph';
|
import { buildNodesGraph } from 'features/nodes/util/graph/buildNodesGraph';
|
||||||
import { buildWorkflow } from 'features/nodes/util/workflow/buildWorkflow';
|
import { buildWorkflowWithValidation } from 'features/nodes/util/workflow/buildWorkflow';
|
||||||
import { queueApi } from 'services/api/endpoints/queue';
|
import { queueApi } from 'services/api/endpoints/queue';
|
||||||
import { BatchConfig } from 'services/api/types';
|
import type { BatchConfig } from 'services/api/types';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addEnqueueRequestedNodes = () => {
|
export const addEnqueueRequestedNodes = () => {
|
||||||
@ -14,14 +15,16 @@ export const addEnqueueRequestedNodes = () => {
|
|||||||
const { nodes, edges } = state.nodes;
|
const { nodes, edges } = state.nodes;
|
||||||
const workflow = state.workflow;
|
const workflow = state.workflow;
|
||||||
const graph = buildNodesGraph(state.nodes);
|
const graph = buildNodesGraph(state.nodes);
|
||||||
const builtWorkflow = buildWorkflow({
|
const builtWorkflow = buildWorkflowWithValidation({
|
||||||
nodes,
|
nodes,
|
||||||
edges,
|
edges,
|
||||||
workflow,
|
workflow,
|
||||||
});
|
});
|
||||||
|
|
||||||
// embedded workflows don't have an id
|
if (builtWorkflow) {
|
||||||
delete builtWorkflow.id;
|
// embedded workflows don't have an id
|
||||||
|
delete builtWorkflow.id;
|
||||||
|
}
|
||||||
|
|
||||||
const batchConfig: BatchConfig = {
|
const batchConfig: BatchConfig = {
|
||||||
batch: {
|
batch: {
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
|
import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
|
||||||
|
import { selectionChanged } from 'features/gallery/store/gallerySlice';
|
||||||
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
import { imagesSelectors } from 'services/api/util';
|
||||||
|
|
||||||
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
|
export const galleryImageClicked = createAction<{
|
||||||
|
imageDTO: ImageDTO;
|
||||||
|
shiftKey: boolean;
|
||||||
|
ctrlKey: boolean;
|
||||||
|
metaKey: boolean;
|
||||||
|
}>('gallery/imageClicked');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This listener handles the logic for selecting images in the gallery.
|
||||||
|
*
|
||||||
|
* Previously, this logic was in a `useCallback` with the whole gallery selection as a dependency. Every time
|
||||||
|
* the selection changed, the callback got recreated and all images rerendered. This could easily block for
|
||||||
|
* hundreds of ms, more for lower end devices.
|
||||||
|
*
|
||||||
|
* Moving this logic into a listener means we don't need to recalculate anything dynamically and the gallery
|
||||||
|
* is much more responsive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const addGalleryImageClickedListener = () => {
|
||||||
|
startAppListening({
|
||||||
|
actionCreator: galleryImageClicked,
|
||||||
|
effect: async (action, { dispatch, getState }) => {
|
||||||
|
const { imageDTO, shiftKey, ctrlKey, metaKey } = action.payload;
|
||||||
|
const state = getState();
|
||||||
|
const queryArgs = selectListImagesQueryArgs(state);
|
||||||
|
const { data: listImagesData } =
|
||||||
|
imagesApi.endpoints.listImages.select(queryArgs)(state);
|
||||||
|
|
||||||
|
if (!listImagesData) {
|
||||||
|
// Should never happen if we have clicked a gallery image
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageDTOs = imagesSelectors.selectAll(listImagesData);
|
||||||
|
const selection = state.gallery.selection;
|
||||||
|
|
||||||
|
if (shiftKey) {
|
||||||
|
const rangeEndImageName = imageDTO.image_name;
|
||||||
|
const lastSelectedImage = selection[selection.length - 1]?.image_name;
|
||||||
|
const lastClickedIndex = imageDTOs.findIndex(
|
||||||
|
(n) => n.image_name === lastSelectedImage
|
||||||
|
);
|
||||||
|
const currentClickedIndex = imageDTOs.findIndex(
|
||||||
|
(n) => n.image_name === rangeEndImageName
|
||||||
|
);
|
||||||
|
if (lastClickedIndex > -1 && currentClickedIndex > -1) {
|
||||||
|
// We have a valid range!
|
||||||
|
const start = Math.min(lastClickedIndex, currentClickedIndex);
|
||||||
|
const end = Math.max(lastClickedIndex, currentClickedIndex);
|
||||||
|
const imagesToSelect = imageDTOs.slice(start, end + 1);
|
||||||
|
dispatch(selectionChanged(selection.concat(imagesToSelect)));
|
||||||
|
}
|
||||||
|
} else if (ctrlKey || metaKey) {
|
||||||
|
if (
|
||||||
|
selection.some((i) => i.image_name === imageDTO.image_name) &&
|
||||||
|
selection.length > 1
|
||||||
|
) {
|
||||||
|
dispatch(
|
||||||
|
selectionChanged(
|
||||||
|
selection.filter((n) => n.image_name !== imageDTO.image_name)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
dispatch(selectionChanged(selection.concat(imageDTO)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispatch(selectionChanged([imageDTO]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
@ -1,5 +1,6 @@
|
|||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addImageAddedToBoardFulfilledListener = () => {
|
export const addImageAddedToBoardFulfilledListener = () => {
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||||
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
||||||
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
|
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
|
||||||
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
|
||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
|
import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
|
||||||
import { isImageFieldInputInstance } from 'features/nodes/types/field';
|
import { isImageFieldInputInstance } from 'features/nodes/types/field';
|
||||||
@ -17,7 +17,8 @@ import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
|||||||
import { clamp, forEach } from 'lodash-es';
|
import { clamp, forEach } from 'lodash-es';
|
||||||
import { api } from 'services/api';
|
import { api } from 'services/api';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
import { imagesAdapter } from 'services/api/util';
|
import { imagesSelectors } from 'services/api/util';
|
||||||
|
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
export const addRequestedSingleImageDeletionListener = () => {
|
export const addRequestedSingleImageDeletionListener = () => {
|
||||||
@ -48,13 +49,11 @@ export const addRequestedSingleImageDeletionListener = () => {
|
|||||||
if (imageDTO && imageDTO?.image_name === lastSelectedImage) {
|
if (imageDTO && imageDTO?.image_name === lastSelectedImage) {
|
||||||
const { image_name } = imageDTO;
|
const { image_name } = imageDTO;
|
||||||
|
|
||||||
const baseQueryArgs = selectListImagesBaseQueryArgs(state);
|
const baseQueryArgs = selectListImagesQueryArgs(state);
|
||||||
const { data } =
|
const { data } =
|
||||||
imagesApi.endpoints.listImages.select(baseQueryArgs)(state);
|
imagesApi.endpoints.listImages.select(baseQueryArgs)(state);
|
||||||
|
|
||||||
const cachedImageDTOs = data
|
const cachedImageDTOs = data ? imagesSelectors.selectAll(data) : [];
|
||||||
? imagesAdapter.getSelectors().selectAll(data)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const deletedImageIndex = cachedImageDTOs.findIndex(
|
const deletedImageIndex = cachedImageDTOs.findIndex(
|
||||||
(i) => i.image_name === image_name
|
(i) => i.image_name === image_name
|
||||||
@ -181,12 +180,12 @@ export const addRequestedMultipleImageDeletionListener = () => {
|
|||||||
imagesApi.endpoints.deleteImages.initiate({ imageDTOs })
|
imagesApi.endpoints.deleteImages.initiate({ imageDTOs })
|
||||||
).unwrap();
|
).unwrap();
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const baseQueryArgs = selectListImagesBaseQueryArgs(state);
|
const queryArgs = selectListImagesQueryArgs(state);
|
||||||
const { data } =
|
const { data } =
|
||||||
imagesApi.endpoints.listImages.select(baseQueryArgs)(state);
|
imagesApi.endpoints.listImages.select(queryArgs)(state);
|
||||||
|
|
||||||
const newSelectedImageDTO = data
|
const newSelectedImageDTO = data
|
||||||
? imagesAdapter.getSelectors().selectAll(data)[0]
|
? imagesSelectors.selectAll(data)[0]
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
if (newSelectedImageDTO) {
|
if (newSelectedImageDTO) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user