Compare commits

..

1 Commits

Author SHA1 Message Date
7487f96da2 Update diffuses to 0.25 2023-12-29 11:34:02 +11:00
965 changed files with 20886 additions and 25765 deletions

View File

@ -2,13 +2,10 @@
## 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.
# HOST_INVOKEAI_ROOT is the path on the docker host's filesystem where InvokeAI will store data. # INVOKEAI_ROOT is the path to a path on the local filesystem where InvokeAI will store data.
# Outputs will also be stored here by default. # Outputs will also be stored here by default.
# If relative, it will be relative to the docker directory in which the docker-compose.yml file is located # This **must** be an absolute path.
#HOST_INVOKEAI_ROOT=../../invokeai-data INVOKEAI_ROOT=
# 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=

View File

@ -21,9 +21,7 @@ x-invokeai: &invokeai
ports: ports:
- "${INVOKEAI_PORT:-9090}:9090" - "${INVOKEAI_PORT:-9090}:9090"
volumes: volumes:
- type: bind - ${INVOKEAI_ROOT:-~/invokeai}:${INVOKEAI_ROOT:-/invokeai}
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}}

View File

@ -37,7 +37,6 @@ To use a community workflow, download the the `.json` node graph file and load i
+ [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)
@ -347,13 +346,6 @@ 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

View File

@ -23,11 +23,10 @@ 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(ge=1, le=10000, default=1000, description="The max number of prompts to generate"), max_prompts: int = Body(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

View File

@ -24,10 +24,9 @@ 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, model_validator from pydantic import BaseModel, ConfigDict, Field, field_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
@ -76,16 +75,17 @@ 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_weights(v) """Validate that all control weights in the valid range"""
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.1") @invocation("controlnet", title="ControlNet", tags=["controlnet"], category="controlnet", version="1.1.0")
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, ge=-1, le=2, description="The weight given to the ControlNet" default=1.0, description="The weight given to the ControlNet"
) )
begin_step_percent: float = InputField( begin_step_percent: float = InputField(
default=0, ge=0, le=1, description="When the ControlNet is first applied (% of total steps)" default=0, ge=-1, le=2, 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,17 +113,6 @@ 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(

View File

@ -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, field_validator, model_validator from pydantic import BaseModel, ConfigDict, Field
from invokeai.app.invocations.baseinvocation import ( from invokeai.app.invocations.baseinvocation import (
BaseInvocation, BaseInvocation,
@ -15,7 +15,6 @@ 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
@ -40,6 +39,7 @@ 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,17 +47,6 @@ 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):
@ -65,7 +54,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.1") @invocation("ip_adapter", title="IP-Adapter", tags=["ip_adapter", "control"], category="ip_adapter", version="1.1.0")
class IPAdapterInvocation(BaseInvocation): class IPAdapterInvocation(BaseInvocation):
"""Collects IP-Adapter info to pass to other nodes.""" """Collects IP-Adapter info to pass to other nodes."""
@ -75,27 +64,18 @@ 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, description="The weight given to the IP-Adapter", title="Weight" default=1, ge=-1, description="The weight given to the IP-Adapter", title="Weight"
) )
begin_step_percent: float = InputField( begin_step_percent: float = InputField(
default=0, ge=0, le=1, description="When the IP-Adapter is first applied (% of total steps)" default=0, ge=-1, le=2, 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(

View File

@ -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.1", version="1.5.0",
) )
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(
title="CFG Rescale Multiplier", default=0, ge=0, lt=1, description=FieldDescriptions.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,

View File

@ -1,6 +1,6 @@
from typing import Union from typing import Union
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from pydantic import BaseModel, ConfigDict, Field
from invokeai.app.invocations.baseinvocation import ( from invokeai.app.invocations.baseinvocation import (
BaseInvocation, BaseInvocation,
@ -14,7 +14,6 @@ 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
@ -38,17 +37,6 @@ 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):
@ -56,7 +44,7 @@ class T2IAdapterOutput(BaseInvocationOutput):
@invocation( @invocation(
"t2i_adapter", title="T2I-Adapter", tags=["t2i_adapter", "control"], category="t2i_adapter", version="1.0.1" "t2i_adapter", title="T2I-Adapter", tags=["t2i_adapter", "control"], category="t2i_adapter", version="1.0.0"
) )
class T2IAdapterInvocation(BaseInvocation): class T2IAdapterInvocation(BaseInvocation):
"""Collects T2I-Adapter info to pass to other nodes.""" """Collects T2I-Adapter info to pass to other nodes."""
@ -73,7 +61,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=0, le=1, description="When the T2I-Adapter is first applied (% of total steps)" default=0, ge=-1, le=2, 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)"
@ -83,17 +71,6 @@ 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(

View File

@ -1,14 +0,0 @@
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")

View File

@ -68,9 +68,12 @@ 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, database backups are recommended before installation; caveat emptor!) ([italic]{latest_prerelease}[/italic]) [2] Update to the latest [bold]pre-release[/bold] (may be buggy; 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()

View File

@ -7,4 +7,4 @@ stats.html
index.html index.html
.yarn/ .yarn/
*.scss *.scss
src/services/api/schema.ts src/services/api/schema.d.ts

View File

@ -28,16 +28,12 @@ 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': 'warn', 'i18next/no-literal-string': 2,
'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',
@ -47,7 +43,6 @@ 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',
@ -62,18 +57,6 @@ 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': [
@ -82,26 +65,7 @@ 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',

View File

@ -9,8 +9,7 @@ index.html
.yarn/ .yarn/
.yalc/ .yalc/
*.scss *.scss
src/services/api/schema.ts src/services/api/schema.d.ts
static/ static/
src/theme/css/overlayscrollbars.css src/theme/css/overlayscrollbars.css
src/theme_/css/overlayscrollbars.css
pnpm-lock.yaml pnpm-lock.yaml

View File

@ -1,25 +0,0 @@
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';

View File

@ -6,7 +6,6 @@ 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',

View File

@ -1,17 +1,16 @@
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',
@ -26,21 +25,17 @@ 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) => (
return (
<Provider store={store}> <Provider store={store}>
<ThemeLocaleProvider> <ThemeLocaleProvider>
<ReduxInit> <GlobalHotkeys />
<Story /> <Story />
</ReduxInit>
</ThemeLocaleProvider> </ThemeLocaleProvider>
</Provider> </Provider>
); ),
},
], ],
parameters: { parameters: {
docs: { docs: {

View File

@ -1,15 +0,0 @@
{
"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": []
}

View File

@ -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 type { PluginOption, UserConfig } from 'vite'; import { 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';

View File

@ -1,6 +1,5 @@
import type { UserConfig } from 'vite'; import { UserConfig } from 'vite';
import { commonPlugins } from './common';
import { commonPlugins } from './common.mjs';
export const appConfig: UserConfig = { export const appConfig: UserConfig = {
base: './', base: './',

View File

@ -1,9 +1,8 @@
import path from 'path'; import path from 'path';
import type { UserConfig } from 'vite'; import { UserConfig } from 'vite';
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
import dts from 'vite-plugin-dts'; import dts from 'vite-plugin-dts';
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
import { commonPlugins } from './common.mjs'; import { commonPlugins } from './common';
export const packageConfig: UserConfig = { export const packageConfig: UserConfig = {
base: './', base: './',

View File

@ -31,17 +31,13 @@
"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": "pnpm run theme", "postinstall": "patch-package && 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
@ -57,56 +53,56 @@
"@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.3", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@fontsource-variable/inter": "^5.0.16", "@fontsource-variable/inter": "^5.0.16",
"@mantine/form": "6.0.21", "@mantine/core": "^6.0.19",
"@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",
"chakra-react-select": "^4.7.6", "@storybook/manager-api": "^7.6.4",
"@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.16", "framer-motion": "^10.16.15",
"i18next": "^23.7.13", "i18next": "^23.7.8",
"i18next-http-backend": "^2.4.2", "i18next-http-backend": "^2.4.2",
"idb-keyval": "^6.2.1", "idb-keyval": "^6.2.1",
"konva": "^9.3.0", "konva": "^9.2.3",
"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.6", "overlayscrollbars": "^2.4.5",
"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.12", "react-error-boundary": "^4.0.11",
"react-hook-form": "^7.49.2",
"react-hotkeys-hook": "4.4.1", "react-hotkeys-hook": "4.4.1",
"react-i18next": "^14.0.0", "react-i18next": "^13.5.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.4", "react-redux": "^9.0.2",
"react-resizable-panels": "^1.0.7", "react-resizable-panels": "^0.0.55",
"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.1", "redux-remember": "^5.0.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.2",
"type-fest": "^4.9.0", "type-fest": "^4.8.3",
"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",
@ -121,51 +117,44 @@
"ts-toolbelt": "^9.6.0" "ts-toolbelt": "^9.6.0"
}, },
"devDependencies": { "devDependencies": {
"@arthurgeron/eslint-plugin-react-usememo": "^2.2.2",
"@chakra-ui/cli": "^2.4.1", "@chakra-ui/cli": "^2.4.1",
"@storybook/addon-docs": "^7.6.6", "@storybook/addon-essentials": "^7.6.4",
"@storybook/addon-essentials": "^7.6.6", "@storybook/addon-interactions": "^7.6.4",
"@storybook/addon-interactions": "^7.6.6", "@storybook/addon-links": "^7.6.4",
"@storybook/addon-links": "^7.6.6", "@storybook/blocks": "^7.6.4",
"@storybook/addon-storysource": "^7.6.6", "@storybook/react": "^7.6.4",
"@storybook/blocks": "^7.6.6", "@storybook/react-vite": "^7.6.4",
"@storybook/manager-api": "^7.6.6", "@storybook/test": "^7.6.4",
"@storybook/react": "^7.6.6",
"@storybook/react-vite": "^7.6.6",
"@storybook/test": "^7.6.6",
"@storybook/theming": "^7.6.6",
"@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.10.6", "@types/node": "^20.9.0",
"@types/react": "^18.2.46", "@types/react": "^18.2.37",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.17",
"@types/uuid": "^9.0.7", "@types/uuid": "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.16.0", "@typescript-eslint/parser": "^6.13.2",
"@vitejs/plugin-react-swc": "^3.5.0", "@vitejs/plugin-react-swc": "^3.5.0",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"eslint": "^8.56.0", "eslint": "^8.55.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-import": "^2.29.1", "eslint-plugin-path": "^1.2.2",
"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.3", "openapi-typescript": "^6.7.2",
"prettier": "^3.1.1", "prettier": "^3.1.0",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.10.0",
"storybook": "^7.6.6", "storybook": "^7.6.4",
"ts-toolbelt": "^9.6.0", "ts-toolbelt": "^9.6.0",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.10", "vite": "^4.5.1",
"vite-plugin-css-injected-by-js": "^3.3.1", "vite-plugin-css-injected-by-js": "^3.3.0",
"vite-plugin-dts": "^3.7.0", "vite-plugin-dts": "^3.6.4",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.2.3" "vite-tsconfig-paths": "^4.2.2"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -760,6 +760,7 @@
"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.",

View File

@ -50,33 +50,9 @@
"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",
@ -103,7 +79,6 @@
"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",
@ -246,6 +221,7 @@
"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",
@ -270,7 +246,6 @@
"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",
@ -309,7 +284,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": "{{promptsCount}} prompts × {{iterations}} iterations -> {{count}} generations", "queueCountPrediction": "Add {{predicted}} to Queue",
"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",
@ -365,8 +340,7 @@
"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",
@ -436,13 +410,9 @@
}, },
"appHotkeys": "App Hotkeys", "appHotkeys": "App Hotkeys",
"cancel": { "cancel": {
"desc": "Cancel current queue item", "desc": "Cancel image generation",
"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"
@ -818,23 +788,17 @@
}, },
"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",
@ -1073,7 +1037,6 @@
"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",
"boundingBoxHeader": "Bounding Box", "boundingBoxHeader": "Bounding Box",
@ -1114,7 +1077,6 @@
"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",
@ -1129,7 +1091,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 incompatible with main model.", "incompatibleBaseModelForControlAdapter": "Control Adapter #{{number}} model is invalid 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",
@ -1165,8 +1127,8 @@
"seamCorrectionHeader": "Seam Correction", "seamCorrectionHeader": "Seam Correction",
"seamHighThreshold": "High", "seamHighThreshold": "High",
"seamlessTiling": "Seamless Tiling", "seamlessTiling": "Seamless Tiling",
"seamlessXAxis": "Seamless Tiling X Axis", "seamlessXAxis": "X Axis",
"seamlessYAxis": "Seamless Tiling Y Axis", "seamlessYAxis": "Y Axis",
"seamlessX": "Seamless X", "seamlessX": "Seamless X",
"seamlessY": "Seamless Y", "seamlessY": "Seamless Y",
"seamlessX&Y": "Seamless X & Y", "seamlessX&Y": "Seamless X & Y",
@ -1209,7 +1171,6 @@
}, },
"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",
@ -1222,13 +1183,11 @@
"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": "Linking Prompt & Style", "concatPromptStyle": "Concatenate Prompt & Style",
"freePromptStyle": "Manual Style Prompting",
"denoisingStrength": "Denoising Strength", "denoisingStrength": "Denoising Strength",
"loading": "Loading...", "loading": "Loading...",
"negAestheticScore": "Negative Aesthetic Score", "negAestheticScore": "Negative Aesthetic Score",

View File

@ -1178,6 +1178,7 @@
"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",

View File

@ -590,6 +590,7 @@
"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)の同時使用は現在サポートされていません。",

View File

@ -363,6 +363,7 @@
"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)는 현재 동시에 지원되지 않습니다.",

View File

@ -1071,6 +1071,7 @@
"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.",

View File

@ -523,7 +523,7 @@
"parameters": { "parameters": {
"images": "Изображения", "images": "Изображения",
"steps": "Шаги", "steps": "Шаги",
"cfgScale": "Шкала точности (CFG)", "cfgScale": "Точность следования запросу (CFG)",
"width": "Ширина", "width": "Ширина",
"height": "Высота", "height": "Высота",
"seed": "Сид", "seed": "Сид",
@ -1162,6 +1162,7 @@
"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-обработка изображений",

View File

@ -1149,6 +1149,7 @@
"crop": "裁剪", "crop": "裁剪",
"processor": "处理器", "processor": "处理器",
"none": "无", "none": "无",
"incompatibleBaseModel": "不兼容的基础模型:",
"enableControlnet": "启用 ControlNet", "enableControlnet": "启用 ControlNet",
"detectResolution": "检测分辨率", "detectResolution": "检测分辨率",
"pidiDescription": "像素差分 (PIDI) 图像处理", "pidiDescription": "像素差分 (PIDI) 图像处理",

View File

@ -1,9 +1,8 @@
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.ts'; const OUTPUT_FILE = 'src/services/api/schema.d.ts';
async function main() { async function main() {
process.stdout.write( process.stdout.write(

View File

@ -1,18 +1,13 @@
import { Flex, Grid } from '@chakra-ui/react'; import { Flex, Grid } from '@chakra-ui/react';
import { useStore } from '@nanostores/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 { $headerComponent } from 'app/store/nanostores/headerComponent';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import type { PartialAppConfig } from 'app/types/invokeai'; import { PartialAppConfig } from 'app/types/invokeai';
import ImageUploader from 'common/components/ImageUploader'; import ImageUploader from 'common/components/ImageUploader';
import { useClearStorage } from 'common/hooks/useClearStorage';
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 { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
import SiteHeader from 'features/system/components/SiteHeader'; import SiteHeader from 'features/system/components/SiteHeader';
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';
@ -21,10 +16,12 @@ 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 = {};
@ -44,8 +41,6 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
// singleton! // singleton!
useSocketIO(); useSocketIO();
useGlobalModifiersInit();
useGlobalHotkeys();
const handleReset = useCallback(() => { const handleReset = useCallback(() => {
clearStorage(); clearStorage();
@ -77,9 +72,23 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
> >
<Grid w="100vw" h="100vh" position="relative" overflow="hidden"> <Grid w="100vw" h="100vh" position="relative" overflow="hidden">
<ImageUploader> <ImageUploader>
<Grid p={4} gridAutoRows="min-content auto" w="full" h="full"> <Grid
sx={{
gap: 4,
p: 4,
gridAutoRows: 'min-content auto',
w: 'full',
h: 'full',
}}
>
{headerComponent || <SiteHeader />} {headerComponent || <SiteHeader />}
<Flex gap={4} w="full" h="full"> <Flex
sx={{
gap: 4,
w: 'full',
h: 'full',
}}
>
<InvokeTabs /> <InvokeTabs />
</Flex> </Flex>
</Grid> </Grid>
@ -87,8 +96,8 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
</Grid> </Grid>
<DeleteImageModal /> <DeleteImageModal />
<ChangeBoardModal /> <ChangeBoardModal />
<DynamicPromptsModal />
<Toaster /> <Toaster />
<GlobalHotkeys />
<PreselectedImage selectedImage={selectedImage} /> <PreselectedImage selectedImage={selectedImage} />
</ErrorBoundary> </ErrorBoundary>
); );

View File

@ -1,6 +1,5 @@
import { Flex, Heading, Link, useToast } from '@chakra-ui/react'; import { Flex, Heading, Link, Text, useToast } from '@chakra-ui/react';
import { InvButton } from 'common/components/InvButton/InvButton'; import IAIButton from 'common/components/IAIButton';
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';
@ -38,48 +37,60 @@ const AppErrorBoundaryFallback = ({ error, resetErrorBoundary }: Props) => {
return ( return (
<Flex <Flex
layerStyle="body" layerStyle="body"
w="100vw" sx={{
h="100vh" w: '100vw',
alignItems="center" h: '100vh',
justifyContent="center" alignItems: 'center',
p={4} justifyContent: 'center',
p: 4,
}}
> >
<Flex <Flex
layerStyle="first" layerStyle="first"
flexDir="column" sx={{
borderRadius="base" flexDir: 'column',
justifyContent="center" borderRadius: 'base',
gap={8} justifyContent: 'center',
p={16} gap: 8,
p: 16,
}}
> >
<Heading>{t('common.somethingWentWrong')}</Heading> <Heading>{t('common.somethingWentWrong')}</Heading>
<Flex <Flex
layerStyle="second" layerStyle="second"
px={8} sx={{
py={4} px: 8,
gap={4} py: 4,
borderRadius="base" borderRadius: 'base',
justifyContent="space-between" gap: 4,
alignItems="center" justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Text
sx={{
fontWeight: 600,
color: 'error.500',
_dark: { color: 'error.400' },
}}
> >
<InvText fontWeight="semibold" color="error.400">
{error.name}: {error.message} {error.name}: {error.message}
</InvText> </Text>
</Flex> </Flex>
<Flex gap={4}> <Flex sx={{ gap: 4 }}>
<InvButton <IAIButton
leftIcon={<FaArrowRotateLeft />} leftIcon={<FaArrowRotateLeft />}
onClick={resetErrorBoundary} onClick={resetErrorBoundary}
> >
{t('accessibility.resetUI')} {t('accessibility.resetUI')}
</InvButton> </IAIButton>
<InvButton leftIcon={<FaCopy />} onClick={handleCopy}> <IAIButton leftIcon={<FaCopy />} onClick={handleCopy}>
{t('common.copyError')} {t('common.copyError')}
</InvButton> </IAIButton>
<Link href={url} isExternal> <Link href={url} isExternal>
<InvButton leftIcon={<FaExternalLinkAlt />}> <IAIButton leftIcon={<FaExternalLinkAlt />}>
{t('accessibility.createIssue')} {t('accessibility.createIssue')}
</InvButton> </IAIButton>
</Link> </Link>
</Flex> </Flex>
</Flex> </Flex>

View File

@ -0,0 +1,112 @@
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);

View File

@ -1,25 +1,29 @@
import 'i18n'; import { Middleware } from '@reduxjs/toolkit';
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 type { CustomStarUi } from 'app/store/nanostores/customStarUI'; import { $customStarUI, CustomStarUi } from 'app/store/nanostores/customStarUI';
import { $customStarUI } from 'app/store/nanostores/customStarUI';
import { $headerComponent } from 'app/store/nanostores/headerComponent'; import { $headerComponent } from 'app/store/nanostores/headerComponent';
import { $isDebugging } from 'app/store/nanostores/isDebugging'; import { $isDebugging } from 'app/store/nanostores/isDebugging';
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 type { PartialAppConfig } from 'app/types/invokeai'; import { 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 type { PropsWithChildren, ReactNode } from 'react'; import 'i18n';
import React, { lazy, memo, useEffect, useMemo } from 'react'; import 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 type { ManagerOptions, SocketOptions } from 'socket.io-client'; import { 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'));
@ -141,15 +145,6 @@ 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 (

View File

@ -1,17 +1,24 @@
import '@fontsource-variable/inter'; import {
import 'overlayscrollbars/overlayscrollbars.css'; ChakraProvider,
import 'common/components/OverlayScrollbars/overlayscrollbars.css'; createLocalStorageManager,
extendTheme,
import { ChakraProvider, extendTheme } from '@chakra-ui/react'; } from '@chakra-ui/react';
import type { ReactNode } from 'react'; import { ReactNode, memo, useEffect, useMemo } from 'react';
import { memo, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { theme as invokeAITheme, TOAST_OPTIONS } from 'theme/theme'; import { TOAST_OPTIONS, theme as invokeAITheme } from 'theme/theme';
import '@fontsource-variable/inter';
import { MantineProvider } from '@mantine/core';
import { useMantineTheme } from 'mantine-theme/theme';
import 'overlayscrollbars/overlayscrollbars.css';
import 'theme/css/overlayscrollbars.css';
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();
@ -28,10 +35,18 @@ function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
document.body.dir = direction; document.body.dir = direction;
}, [direction]); }, [direction]);
const mantineTheme = useMantineTheme();
return ( return (
<ChakraProvider theme={theme} toastOptions={TOAST_OPTIONS}> <MantineProvider theme={mantineTheme}>
<ChakraProvider
theme={theme}
colorModeManager={manager}
toastOptions={TOAST_OPTIONS}
>
{children} {children}
</ChakraProvider> </ChakraProvider>
</MantineProvider>
); );
} }

View File

@ -1,8 +1,7 @@
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 type { MakeToastArg } from 'features/system/util/makeToast'; import { MakeToastArg, makeToast } from 'features/system/util/makeToast';
import { makeToast } from 'features/system/util/makeToast';
import { memo, useCallback, useEffect } from 'react'; import { memo, useCallback, useEffect } from 'react';
/** /**

View File

@ -0,0 +1,94 @@
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];
};

View File

@ -3,16 +3,14 @@ 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 type { MapStore } from 'nanostores'; import { MapStore, atom, map } from 'nanostores';
import { atom, map } from 'nanostores';
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import type { import {
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 type { ManagerOptions, Socket, SocketOptions } from 'socket.io-client'; import { ManagerOptions, Socket, SocketOptions, io } 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 {

View File

@ -1,8 +1,6 @@
import { createLogWriter } from '@roarr/browser-log-writer'; import { createLogWriter } from '@roarr/browser-log-writer';
import { atom } from 'nanostores'; import { atom } from 'nanostores';
import type { Logger } from 'roarr'; import { Logger, ROARR, Roarr } from 'roarr';
import { ROARR, Roarr } from 'roarr';
import { z } from 'zod';
ROARR.write = createLogWriter(); ROARR.write = createLogWriter();
@ -28,20 +26,19 @@ export type LoggerNamespace =
export const logger = (namespace: LoggerNamespace) => export const logger = (namespace: LoggerNamespace) =>
$logger.get().child({ namespace }); $logger.get().child({ namespace });
export const zLogLevel = z.enum([ export const VALID_LOG_LEVELS = [
'trace', 'trace',
'debug', 'debug',
'info', 'info',
'warn', 'warn',
'error', 'error',
'fatal', 'fatal',
]); ] as const;
export type LogLevel = z.infer<typeof zLogLevel>;
export const isLogLevel = (v: unknown): v is LogLevel => export type InvokeLogLevel = (typeof VALID_LOG_LEVELS)[number];
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<LogLevel, number> = { export const LOG_LEVEL_MAP: Record<InvokeLogLevel, number> = {
trace: 10, trace: 10,
debug: 20, debug: 20,
info: 30, info: 30,

View File

@ -4,9 +4,13 @@ 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 {
import type { LoggerNamespace } from './logger'; $logger,
import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP, logger } from './logger'; BASE_CONTEXT,
LOG_LEVEL_MAP,
LoggerNamespace,
logger,
} from './logger';
const selector = createMemoizedSelector(stateSelector, ({ system }) => { const selector = createMemoizedSelector(stateSelector, ({ system }) => {
const { consoleLogLevel, shouldLogToConsole } = system; const { consoleLogLevel, shouldLogToConsole } = system;

View File

@ -1,6 +1,6 @@
import { createAction } from '@reduxjs/toolkit'; import { createAction } from '@reduxjs/toolkit';
import type { InvokeTabName } from 'features/ui/store/tabMap'; import { InvokeTabName } from 'features/ui/store/tabMap';
import type { BatchConfig } from 'services/api/types'; import { BatchConfig } from 'services/api/types';
export const enqueueRequested = createAction<{ export const enqueueRequested = createAction<{
tabName: InvokeTabName; tabName: InvokeTabName;

View File

@ -9,13 +9,4 @@ 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,
}); });

View File

@ -8,7 +8,7 @@ import { postprocessingPersistDenylist } from 'features/parameters/store/postpro
import { systemPersistDenylist } from 'features/system/store/systemPersistDenylist'; import { systemPersistDenylist } from 'features/system/store/systemPersistDenylist';
import { uiPersistDenylist } from 'features/ui/store/uiPersistDenylist'; import { uiPersistDenylist } from 'features/ui/store/uiPersistDenylist';
import { omit } from 'lodash-es'; import { omit } from 'lodash-es';
import type { SerializeFunction } from 'redux-remember'; import { SerializeFunction } from 'redux-remember';
const serializationDenylist: { const serializationDenylist: {
[key: string]: string[]; [key: string]: string[];

View File

@ -11,7 +11,7 @@ import { initialSystemState } from 'features/system/store/systemSlice';
import { initialHotkeysState } from 'features/ui/store/hotkeysSlice'; import { initialHotkeysState } from 'features/ui/store/hotkeysSlice';
import { initialUIState } from 'features/ui/store/uiSlice'; import { initialUIState } from 'features/ui/store/uiSlice';
import { defaultsDeep } from 'lodash-es'; import { defaultsDeep } from 'lodash-es';
import type { UnserializeFunction } from 'redux-remember'; import { UnserializeFunction } from 'redux-remember';
const initialStates: { const initialStates: {
[key: string]: object; // TODO: type this properly [key: string]: object; // TODO: type this properly

View File

@ -1,8 +1,8 @@
import type { UnknownAction } from '@reduxjs/toolkit'; import { UnknownAction } from '@reduxjs/toolkit';
import { isAnyGraphBuilt } from 'features/nodes/store/actions'; import { isAnyGraphBuilt } from 'features/nodes/store/actions';
import { nodeTemplatesBuilt } from 'features/nodes/store/nodeTemplatesSlice'; import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
import { receivedOpenAPISchema } from 'services/api/thunks/schema'; import { receivedOpenAPISchema } from 'services/api/thunks/schema';
import type { Graph } from 'services/api/types'; import { Graph } from 'services/api/types';
export const actionSanitizer = <A extends UnknownAction>(action: A): A => { export const actionSanitizer = <A extends UnknownAction>(action: A): A => {
if (isAnyGraphBuilt(action)) { if (isAnyGraphBuilt(action)) {

View File

@ -1,12 +1,11 @@
import type { import type { TypedAddListener, TypedStartListening } from '@reduxjs/toolkit';
ListenerEffect, import {
TypedAddListener,
TypedStartListening,
UnknownAction, UnknownAction,
ListenerEffect,
addListener,
createListenerMiddleware,
} from '@reduxjs/toolkit'; } from '@reduxjs/toolkit';
import { addListener, createListenerMiddleware } from '@reduxjs/toolkit';
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';
@ -43,13 +42,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';
@ -70,9 +69,9 @@ import { addSocketSubscribedEventListener as addSocketSubscribedListener } from
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 { 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();

View File

@ -8,7 +8,6 @@ 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);

View File

@ -2,10 +2,9 @@ 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, imagesAdapter } 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');

View File

@ -1,5 +1,4 @@
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 = () => {

View File

@ -4,7 +4,6 @@ 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 = () => {

View File

@ -1,5 +1,4 @@
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');

View File

@ -5,8 +5,7 @@ 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 { theme, TOAST_OPTIONS } from 'theme/theme'; import { TOAST_OPTIONS, theme } from 'theme/theme';
import { startAppListening } from '..'; import { startAppListening } from '..';
const { toast } = createStandaloneToast({ const { toast } = createStandaloneToast({

View File

@ -4,7 +4,6 @@ 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 = () => {

View File

@ -9,9 +9,8 @@ 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 { imagesSelectors } from 'services/api/util';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { imagesSelectors } from 'services/api/util';
export const addBoardIdSelectedListener = () => { export const addBoardIdSelectedListener = () => {
startAppListening({ startAppListening({

View File

@ -1,12 +1,11 @@
import { $logger } from 'app/logging/logger';
import { canvasCopiedToClipboard } from 'features/canvas/store/actions'; import { canvasCopiedToClipboard } from 'features/canvas/store/actions';
import { startAppListening } from '..';
import { $logger } from 'app/logging/logger';
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,

View File

@ -1,12 +1,11 @@
import { $logger } from 'app/logging/logger';
import { canvasDownloadedAsImage } from 'features/canvas/store/actions'; import { canvasDownloadedAsImage } from 'features/canvas/store/actions';
import { startAppListening } from '..';
import { $logger } from 'app/logging/logger';
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,

View File

@ -1,12 +1,11 @@
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({

View File

@ -2,10 +2,9 @@ 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 { t } from 'i18next';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { t } from 'i18next';
export const addCanvasMaskSavedToGalleryListener = () => { export const addCanvasMaskSavedToGalleryListener = () => {
startAppListening({ startAppListening({

View File

@ -5,7 +5,6 @@ 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 = () => {

View File

@ -4,10 +4,9 @@ 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 { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
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 { t } from 'i18next';
export const addCanvasMergedListener = () => { export const addCanvasMergedListener = () => {
startAppListening({ startAppListening({

View File

@ -2,10 +2,9 @@ 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 { t } from 'i18next';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { t } from 'i18next';
export const addCanvasSavedToGalleryListener = () => { export const addCanvasSavedToGalleryListener = () => {
startAppListening({ startAppListening({

View File

@ -1,6 +1,6 @@
import type { AnyListenerPredicate } from '@reduxjs/toolkit'; import { AnyListenerPredicate } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import type { RootState } from 'app/store/store'; import { 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,8 @@ import {
controlAdapterProcessortTypeChanged, controlAdapterProcessortTypeChanged,
selectControlAdapterById, selectControlAdapterById,
} from 'features/controlAdapters/store/controlAdaptersSlice'; } from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
type AnyControlAdapterParamChangeAction = type AnyControlAdapterParamChangeAction =
| ReturnType<typeof controlAdapterProcessorParamsChanged> | ReturnType<typeof controlAdapterProcessorParamsChanged>

View File

@ -8,15 +8,14 @@ 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 type { BatchConfig, ImageDTO } from 'services/api/types'; import { 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({

View File

@ -14,8 +14,7 @@ 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 type { ImageDTO } from 'services/api/types'; import { ImageDTO } from 'services/api/types';
import { startAppListening } from '..'; import { startAppListening } from '..';
/** /**

View File

@ -5,7 +5,6 @@ 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 = () => {

View File

@ -1,9 +1,8 @@
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 { buildWorkflowRight } from 'features/nodes/util/workflow/buildWorkflow'; import { buildWorkflow } from 'features/nodes/util/workflow/buildWorkflow';
import { queueApi } from 'services/api/endpoints/queue'; import { queueApi } from 'services/api/endpoints/queue';
import type { BatchConfig } from 'services/api/types'; import { BatchConfig } from 'services/api/types';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addEnqueueRequestedNodes = () => { export const addEnqueueRequestedNodes = () => {
@ -15,16 +14,14 @@ 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 = buildWorkflowRight({ const builtWorkflow = buildWorkflow({
nodes, nodes,
edges, edges,
workflow, workflow,
}); });
if (builtWorkflow) {
// embedded workflows don't have an id // embedded workflows don't have an id
delete builtWorkflow.id; delete builtWorkflow.id;
}
const batchConfig: BatchConfig = { const batchConfig: BatchConfig = {
batch: { batch: {

View File

@ -1,6 +1,5 @@
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 = () => {

View File

@ -18,7 +18,6 @@ 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 { imagesAdapter } from 'services/api/util';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addRequestedSingleImageDeletionListener = () => { export const addRequestedSingleImageDeletionListener = () => {

View File

@ -6,17 +6,16 @@ import {
controlAdapterImageChanged, controlAdapterImageChanged,
controlAdapterIsEnabledChanged, controlAdapterIsEnabledChanged,
} from 'features/controlAdapters/store/controlAdaptersSlice'; } from 'features/controlAdapters/store/controlAdaptersSlice';
import type { import {
TypesafeDraggableData, TypesafeDraggableData,
TypesafeDroppableData, TypesafeDroppableData,
} from 'features/dnd/types'; } from 'features/dnd/types';
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 { workflowExposedFieldAdded } from 'features/nodes/store/workflowSlice';
import { initialImageChanged } from 'features/parameters/store/generationSlice'; import { initialImageChanged } 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 '../';
import { workflowExposedFieldAdded } from 'features/nodes/store/workflowSlice';
export const dndDropped = createAction<{ export const dndDropped = createAction<{
overData: TypesafeDroppableData; overData: TypesafeDroppableData;

View File

@ -1,6 +1,5 @@
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 addImageRemovedFromBoardFulfilledListener = () => { export const addImageRemovedFromBoardFulfilledListener = () => {

View File

@ -4,7 +4,6 @@ import {
imagesToDeleteSelected, imagesToDeleteSelected,
isModalOpenChanged, isModalOpenChanged,
} from 'features/deleteImageModal/store/slice'; } from 'features/deleteImageModal/store/slice';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addImageToDeleteSelectedListener = () => { export const addImageToDeleteSelectedListener = () => {

View File

@ -1,4 +1,4 @@
import type { UseToastOptions } from '@chakra-ui/react'; import { UseToastOptions } from '@chakra-ui/react';
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
import { import {
@ -11,9 +11,8 @@ import { addToast } from 'features/system/store/systemSlice';
import { t } from 'i18next'; import { t } from 'i18next';
import { omit } from 'lodash-es'; import { omit } from 'lodash-es';
import { boardsApi } from 'services/api/endpoints/boards'; import { boardsApi } from 'services/api/endpoints/boards';
import { imagesApi } from 'services/api/endpoints/images';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { imagesApi } from 'services/api/endpoints/images';
export const addImageUploadedFulfilledListener = () => { export const addImageUploadedFulfilledListener = () => {
startAppListening({ startAppListening({

View File

@ -1,8 +1,7 @@
import { selectionChanged } from 'features/gallery/store/gallerySlice';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { selectionChanged } from 'features/gallery/store/gallerySlice';
import { ImageDTO } from 'services/api/types';
export const addImagesStarredListener = () => { export const addImagesStarredListener = () => {
startAppListening({ startAppListening({

View File

@ -1,8 +1,7 @@
import { selectionChanged } from 'features/gallery/store/gallerySlice';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { selectionChanged } from 'features/gallery/store/gallerySlice';
import { ImageDTO } from 'services/api/types';
export const addImagesUnstarredListener = () => { export const addImagesUnstarredListener = () => {
startAppListening({ startAppListening({

View File

@ -3,7 +3,6 @@ import { initialImageChanged } from 'features/parameters/store/generationSlice';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast'; import { makeToast } from 'features/system/util/makeToast';
import { t } from 'i18next'; import { t } from 'i18next';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addInitialImageSelectedListener = () => { export const addInitialImageSelectedListener = () => {

View File

@ -7,18 +7,17 @@ import {
import { loraRemoved } from 'features/lora/store/loraSlice'; import { loraRemoved } from 'features/lora/store/loraSlice';
import { modelSelected } from 'features/parameters/store/actions'; import { modelSelected } from 'features/parameters/store/actions';
import { import {
heightChanged,
modelChanged, modelChanged,
setHeight,
setWidth,
vaeSelected, vaeSelected,
widthChanged,
} from 'features/parameters/store/generationSlice'; } from 'features/parameters/store/generationSlice';
import { zParameterModel } from 'features/parameters/types/parameterSchemas';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast'; import { makeToast } from 'features/system/util/makeToast';
import { t } from 'i18next'; import { t } from 'i18next';
import { forEach } from 'lodash-es'; import { forEach } from 'lodash-es';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { zParameterModel } from 'features/parameters/types/parameterSchemas';
export const addModelSelectedListener = () => { export const addModelSelectedListener = () => {
startAppListening({ startAppListening({
@ -90,12 +89,12 @@ export const addModelSelectedListener = () => {
state.ui.shouldAutoChangeDimensions state.ui.shouldAutoChangeDimensions
) { ) {
if (['sdxl', 'sdxl-refiner'].includes(newModel.base_model)) { if (['sdxl', 'sdxl-refiner'].includes(newModel.base_model)) {
dispatch(widthChanged(1024)); dispatch(setWidth(1024));
dispatch(heightChanged(1024)); dispatch(setHeight(1024));
dispatch(setBoundingBoxDimensions({ width: 1024, height: 1024 })); dispatch(setBoundingBoxDimensions({ width: 1024, height: 1024 }));
} else { } else {
dispatch(widthChanged(512)); dispatch(setWidth(512));
dispatch(heightChanged(512)); dispatch(setHeight(512));
dispatch(setBoundingBoxDimensions({ width: 512, height: 512 })); dispatch(setBoundingBoxDimensions({ width: 512, height: 512 }));
} }
} }

View File

@ -12,17 +12,20 @@ import {
} from 'features/parameters/store/generationSlice'; } from 'features/parameters/store/generationSlice';
import { import {
zParameterModel, zParameterModel,
zParameterSDXLRefinerModel,
zParameterVAEModel, zParameterVAEModel,
} from 'features/parameters/types/parameterSchemas'; } from 'features/parameters/types/parameterSchemas';
import { refinerModelChanged } from 'features/sdxl/store/sdxlSlice'; import {
refinerModelChanged,
setShouldUseSDXLRefiner,
} from 'features/sdxl/store/sdxlSlice';
import { forEach, some } from 'lodash-es'; import { forEach, some } from 'lodash-es';
import { import {
mainModelsAdapter, mainModelsAdapter,
modelsApi, modelsApi,
vaeModelsAdapter, vaeModelsAdapter,
} from 'services/api/endpoints/models'; } from 'services/api/endpoints/models';
import type { TypeGuardFor } from 'services/api/types'; import { TypeGuardFor } from 'services/api/types';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addModelsLoadedListener = () => { export const addModelsLoadedListener = () => {
@ -99,6 +102,7 @@ export const addModelsLoadedListener = () => {
if (models.length === 0) { if (models.length === 0) {
// No models loaded at all // No models loaded at all
dispatch(refinerModelChanged(null)); dispatch(refinerModelChanged(null));
dispatch(setShouldUseSDXLRefiner(false));
return; return;
} }
@ -111,10 +115,21 @@ export const addModelsLoadedListener = () => {
) )
: false; : false;
if (!isCurrentModelAvailable) { if (isCurrentModelAvailable) {
dispatch(refinerModelChanged(null));
return; return;
} }
const result = zParameterSDXLRefinerModel.safeParse(models[0]);
if (!result.success) {
log.error(
{ error: result.error.format() },
'Failed to parse SDXL Refiner Model'
);
return;
}
dispatch(refinerModelChanged(result.data));
}, },
}); });
startAppListening({ startAppListening({

View File

@ -8,11 +8,9 @@ import {
parsingErrorChanged, parsingErrorChanged,
promptsChanged, promptsChanged,
} from 'features/dynamicPrompts/store/dynamicPromptsSlice'; } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt';
import { setPositivePrompt } from 'features/parameters/store/generationSlice'; import { setPositivePrompt } from 'features/parameters/store/generationSlice';
import { utilitiesApi } from 'services/api/endpoints/utilities'; import { utilitiesApi } from 'services/api/endpoints/utilities';
import { appSocketConnected } from 'services/events/actions'; import { appSocketConnected } from 'services/events/actions';
import { startAppListening } from '..'; import { startAppListening } from '..';
const matcher = isAnyOf( const matcher = isAnyOf(
@ -30,39 +28,20 @@ export const addDynamicPromptsListener = () => {
action, action,
{ dispatch, getState, cancelActiveListeners, delay } { dispatch, getState, cancelActiveListeners, delay }
) => { ) => {
// debounce request
cancelActiveListeners(); cancelActiveListeners();
await delay(1000);
const state = getState(); const state = getState();
const { positivePrompt } = state.generation;
const { maxPrompts } = state.dynamicPrompts;
if (state.config.disabledFeatures.includes('dynamicPrompting')) { if (state.config.disabledFeatures.includes('dynamicPrompting')) {
return; return;
} }
const cachedPrompts = utilitiesApi.endpoints.dynamicPrompts.select({ const { positivePrompt } = state.generation;
prompt: positivePrompt, const { maxPrompts } = state.dynamicPrompts;
max_prompts: maxPrompts,
})(getState()).data;
if (cachedPrompts) {
dispatch(promptsChanged(cachedPrompts.prompts));
return;
}
if (!getShouldProcessPrompt(state.generation.positivePrompt)) {
if (state.dynamicPrompts.isLoading) {
dispatch(isLoadingChanged(false));
}
dispatch(promptsChanged([state.generation.positivePrompt]));
return;
}
if (!state.dynamicPrompts.isLoading) {
dispatch(isLoadingChanged(true)); dispatch(isLoadingChanged(true));
}
// debounce request
await delay(1000);
try { try {
const req = dispatch( const req = dispatch(

View File

@ -1,10 +1,9 @@
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { parseify } from 'common/util/serialize'; import { parseify } from 'common/util/serialize';
import { nodeTemplatesBuilt } from 'features/nodes/store/nodeTemplatesSlice'; import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
import { parseSchema } from 'features/nodes/util/schema/parseSchema'; import { parseSchema } from 'features/nodes/util/schema/parseSchema';
import { size } from 'lodash-es'; import { size } from 'lodash-es';
import { receivedOpenAPISchema } from 'services/api/thunks/schema'; import { receivedOpenAPISchema } from 'services/api/thunks/schema';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addReceivedOpenAPISchemaListener = () => { export const addReceivedOpenAPISchemaListener = () => {

View File

@ -1,11 +1,10 @@
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { isInitializedChanged } from 'features/system/store/systemSlice';
import { size } from 'lodash-es'; import { size } from 'lodash-es';
import { api } from 'services/api'; import { api } from 'services/api';
import { receivedOpenAPISchema } from 'services/api/thunks/schema'; import { receivedOpenAPISchema } from 'services/api/thunks/schema';
import { appSocketConnected, socketConnected } from 'services/events/actions'; import { appSocketConnected, socketConnected } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
import { isInitializedChanged } from 'features/system/store/systemSlice';
export const addSocketConnectedEventListener = () => { export const addSocketConnectedEventListener = () => {
startAppListening({ startAppListening({
@ -15,11 +14,11 @@ export const addSocketConnectedEventListener = () => {
log.debug('Connected'); log.debug('Connected');
const { nodeTemplates, config, system } = getState(); const { nodes, config, system } = getState();
const { disabledTabs } = config; const { disabledTabs } = config;
if (!size(nodeTemplates.templates) && !disabledTabs.includes('nodes')) { if (!size(nodes.nodeTemplates) && !disabledTabs.includes('nodes')) {
dispatch(receivedOpenAPISchema()); dispatch(receivedOpenAPISchema());
} }

View File

@ -3,7 +3,6 @@ import {
appSocketDisconnected, appSocketDisconnected,
socketDisconnected, socketDisconnected,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addSocketDisconnectedEventListener = () => { export const addSocketDisconnectedEventListener = () => {

View File

@ -3,7 +3,6 @@ import {
appSocketGeneratorProgress, appSocketGeneratorProgress,
socketGeneratorProgress, socketGeneratorProgress,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addGeneratorProgressEventListener = () => { export const addGeneratorProgressEventListener = () => {

View File

@ -3,7 +3,6 @@ import {
appSocketGraphExecutionStateComplete, appSocketGraphExecutionStateComplete,
socketGraphExecutionStateComplete, socketGraphExecutionStateComplete,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addGraphExecutionStateCompleteEventListener = () => { export const addGraphExecutionStateCompleteEventListener = () => {

View File

@ -7,7 +7,6 @@ import {
imageSelected, imageSelected,
} from 'features/gallery/store/gallerySlice'; } from 'features/gallery/store/gallerySlice';
import { IMAGE_CATEGORIES } from 'features/gallery/store/types'; import { IMAGE_CATEGORIES } from 'features/gallery/store/types';
import { isImageOutput } from 'features/nodes/types/common';
import { import {
LINEAR_UI_OUTPUT, LINEAR_UI_OUTPUT,
nodeIDDenyList, nodeIDDenyList,
@ -19,8 +18,8 @@ import {
appSocketInvocationComplete, appSocketInvocationComplete,
socketInvocationComplete, socketInvocationComplete,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
import { isImageOutput } from 'features/nodes/types/common';
// These nodes output an image, but do not actually *save* an image, so we don't want to handle the gallery logic on them // These nodes output an image, but do not actually *save* an image, so we don't want to handle the gallery logic on them
const nodeTypeDenylist = ['load_image', 'image']; const nodeTypeDenylist = ['load_image', 'image'];

View File

@ -3,7 +3,6 @@ import {
appSocketInvocationError, appSocketInvocationError,
socketInvocationError, socketInvocationError,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addInvocationErrorEventListener = () => { export const addInvocationErrorEventListener = () => {

View File

@ -3,7 +3,6 @@ import {
appSocketInvocationRetrievalError, appSocketInvocationRetrievalError,
socketInvocationRetrievalError, socketInvocationRetrievalError,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addInvocationRetrievalErrorEventListener = () => { export const addInvocationRetrievalErrorEventListener = () => {

View File

@ -3,7 +3,6 @@ import {
appSocketInvocationStarted, appSocketInvocationStarted,
socketInvocationStarted, socketInvocationStarted,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addInvocationStartedEventListener = () => { export const addInvocationStartedEventListener = () => {

View File

@ -5,7 +5,6 @@ import {
socketModelLoadCompleted, socketModelLoadCompleted,
socketModelLoadStarted, socketModelLoadStarted,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addModelLoadEventListener = () => { export const addModelLoadEventListener = () => {

View File

@ -4,7 +4,6 @@ import {
appSocketQueueItemStatusChanged, appSocketQueueItemStatusChanged,
socketQueueItemStatusChanged, socketQueueItemStatusChanged,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addSocketQueueItemStatusChangedEventListener = () => { export const addSocketQueueItemStatusChangedEventListener = () => {

View File

@ -3,7 +3,6 @@ import {
appSocketSessionRetrievalError, appSocketSessionRetrievalError,
socketSessionRetrievalError, socketSessionRetrievalError,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addSessionRetrievalErrorEventListener = () => { export const addSessionRetrievalErrorEventListener = () => {

View File

@ -3,7 +3,6 @@ import {
appSocketSubscribedSession, appSocketSubscribedSession,
socketSubscribedSession, socketSubscribedSession,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addSocketSubscribedEventListener = () => { export const addSocketSubscribedEventListener = () => {

View File

@ -3,7 +3,6 @@ import {
appSocketUnsubscribedSession, appSocketUnsubscribedSession,
socketUnsubscribedSession, socketUnsubscribedSession,
} from 'services/events/actions'; } from 'services/events/actions';
import { startAppListening } from '../..'; import { startAppListening } from '../..';
export const addSocketUnsubscribedEventListener = () => { export const addSocketUnsubscribedEventListener = () => {

View File

@ -1,9 +1,8 @@
import { stagingAreaImageSaved } from 'features/canvas/store/actions'; import { stagingAreaImageSaved } from 'features/canvas/store/actions';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
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 { t } from 'i18next';
export const addStagingAreaImageSavedListener = () => { export const addStagingAreaImageSavedListener = () => {
startAppListening({ startAppListening({

View File

@ -2,7 +2,6 @@ import { modelChanged } from 'features/parameters/store/generationSlice';
import { setActiveTab } from 'features/ui/store/uiSlice'; import { setActiveTab } from 'features/ui/store/uiSlice';
import { NON_REFINER_BASE_MODELS } from 'services/api/constants'; import { NON_REFINER_BASE_MODELS } from 'services/api/constants';
import { mainModelsAdapter, modelsApi } from 'services/api/endpoints/models'; import { mainModelsAdapter, modelsApi } from 'services/api/endpoints/models';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addTabChangedListener = () => { export const addTabChangedListener = () => {
@ -36,12 +35,12 @@ export const addTabChangedListener = () => {
return; return;
} }
// need to filter out all the invalid canvas models (currently refiner & any) // need to filter out all the invalid canvas models (currently sdxl & refiner)
const validCanvasModels = mainModelsAdapter const validCanvasModels = mainModelsAdapter
.getSelectors() .getSelectors()
.selectAll(models) .selectAll(models)
.filter((model) => .filter((model) =>
['sd-1', 'sd-2', 'sdxl'].includes(model.base_model) ['sd-1', 'sd-2', 'sxdl'].includes(model.base_model)
); );
const firstValidCanvasModel = validCanvasModels[0]; const firstValidCanvasModel = validCanvasModels[0];

View File

@ -1,16 +1,15 @@
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { updateAllNodesRequested } from 'features/nodes/store/actions'; import { updateAllNodesRequested } from 'features/nodes/store/actions';
import { nodeReplaced } from 'features/nodes/store/nodesSlice'; import { nodeReplaced } from 'features/nodes/store/nodesSlice';
import { NodeUpdateError } from 'features/nodes/types/error';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { import {
getNeedsUpdate, getNeedsUpdate,
updateNode, updateNode,
} from 'features/nodes/util/node/nodeUpdate'; } from 'features/nodes/util/node/nodeUpdate';
import { NodeUpdateError } from 'features/nodes/types/error';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast'; import { makeToast } from 'features/system/util/makeToast';
import { t } from 'i18next'; import { t } from 'i18next';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addUpdateAllNodesRequestedListener = () => { export const addUpdateAllNodesRequestedListener = () => {
@ -19,7 +18,7 @@ export const addUpdateAllNodesRequestedListener = () => {
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch, getState }) => {
const log = logger('nodes'); const log = logger('nodes');
const nodes = getState().nodes.nodes; const nodes = getState().nodes.nodes;
const templates = getState().nodeTemplates.templates; const templates = getState().nodes.nodeTemplates;
let unableToUpdateCount = 0; let unableToUpdateCount = 0;

View File

@ -2,13 +2,12 @@ import { createAction } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { parseify } from 'common/util/serialize'; import { parseify } from 'common/util/serialize';
import { buildAdHocUpscaleGraph } from 'features/nodes/util/graph/buildAdHocUpscaleGraph'; import { buildAdHocUpscaleGraph } from 'features/nodes/util/graph/buildAdHocUpscaleGraph';
import { createIsAllowedToUpscaleSelector } from 'features/parameters/hooks/useIsAllowedToUpscale';
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 type { BatchConfig, ImageDTO } from 'services/api/types';
import { startAppListening } from '..'; import { startAppListening } from '..';
import { BatchConfig, ImageDTO } from 'services/api/types';
import { createIsAllowedToUpscaleSelector } from 'features/parameters/hooks/useIsAllowedToUpscale';
export const upscaleRequested = createAction<{ imageDTO: ImageDTO }>( export const upscaleRequested = createAction<{ imageDTO: ImageDTO }>(
`upscale/upscaleRequested` `upscale/upscaleRequested`

View File

@ -1,9 +1,7 @@
import { logger } from 'app/logging/logger'; import { logger } from 'app/logging/logger';
import { parseify } from 'common/util/serialize'; import { parseify } from 'common/util/serialize';
import { import { workflowLoadRequested } from 'features/nodes/store/actions';
workflowLoaded, import { workflowLoaded } from 'features/nodes/store/actions';
workflowLoadRequested,
} from 'features/nodes/store/actions';
import { $flow } from 'features/nodes/store/reactFlowInstance'; import { $flow } from 'features/nodes/store/reactFlowInstance';
import { import {
WorkflowMigrationError, WorkflowMigrationError,
@ -16,7 +14,6 @@ import { setActiveTab } from 'features/ui/store/uiSlice';
import { t } from 'i18next'; import { t } from 'i18next';
import { z } from 'zod'; import { z } from 'zod';
import { fromZodError } from 'zod-validation-error'; import { fromZodError } from 'zod-validation-error';
import { startAppListening } from '..'; import { startAppListening } from '..';
export const addWorkflowLoadRequestedListener = () => { export const addWorkflowLoadRequestedListener = () => {
@ -25,7 +22,7 @@ export const addWorkflowLoadRequestedListener = () => {
effect: (action, { dispatch, getState }) => { effect: (action, { dispatch, getState }) => {
const log = logger('nodes'); const log = logger('nodes');
const { workflow, asCopy } = action.payload; const { workflow, asCopy } = action.payload;
const nodeTemplates = getState().nodeTemplates.templates; const nodeTemplates = getState().nodes.nodeTemplates;
try { try {
const { workflow: validatedWorkflow, warnings } = validateWorkflow( const { workflow: validatedWorkflow, warnings } = validateWorkflow(

View File

@ -1,3 +0,0 @@
# nanostores
For non-serializable data that needs to be available throughout the app, or when redux is not appropriate, use nanostores.

Some files were not shown because too many files have changed in this diff Show More