From 1d2bd6b8f7535b78348777d88dee6eb8eeb517b7 Mon Sep 17 00:00:00 2001 From: Peanut Date: Thu, 1 Feb 2024 17:22:14 +0800 Subject: [PATCH 01/28] perf: TypeAdapter instantiated once --- invokeai/app/services/config/config_default.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index c1364211ae..c1ec5735dd 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -172,11 +172,12 @@ two configs are kept in separate sections of the config file: from __future__ import annotations import os +from functools import lru_cache from pathlib import Path -from typing import Any, ClassVar, Dict, List, Literal, Optional, Union, get_type_hints +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypeVar, Union, get_type_hints from omegaconf import DictConfig, OmegaConf -from pydantic import Field, TypeAdapter +from pydantic import Field, TypeAdapter as PyTypeAdapter from pydantic.config import JsonDict from pydantic_settings import SettingsConfigDict @@ -187,6 +188,13 @@ DB_FILE = Path("invokeai.db") LEGACY_INIT_FILE = Path("invokeai.init") DEFAULT_MAX_VRAM = 0.5 +_T = TypeVar("_T") + + +@lru_cache +def TypeAdapter(type_: type[_T]) -> PyTypeAdapter: + return PyTypeAdapter(type_) + class Categories(object): """Category headers for configuration variable groups.""" From dcfc883ab37b0f90c1bc60a2c02fd3714f5ad9fc Mon Sep 17 00:00:00 2001 From: Peanut Date: Fri, 2 Feb 2024 17:48:05 +0800 Subject: [PATCH 02/28] perf: remove TypeAdapter --- .../app/services/config/config_default.py | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index c1ec5735dd..1403dc321f 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -172,12 +172,11 @@ two configs are kept in separate sections of the config file: from __future__ import annotations import os -from functools import lru_cache from pathlib import Path -from typing import Any, ClassVar, Dict, List, Literal, Optional, TypeVar, Union, get_type_hints +from typing import Any, ClassVar, Dict, List, Literal, Optional, Union from omegaconf import DictConfig, OmegaConf -from pydantic import Field, TypeAdapter as PyTypeAdapter +from pydantic import Field from pydantic.config import JsonDict from pydantic_settings import SettingsConfigDict @@ -188,13 +187,6 @@ DB_FILE = Path("invokeai.db") LEGACY_INIT_FILE = Path("invokeai.init") DEFAULT_MAX_VRAM = 0.5 -_T = TypeVar("_T") - - -@lru_cache -def TypeAdapter(type_: type[_T]) -> PyTypeAdapter: - return PyTypeAdapter(type_) - class Categories(object): """Category headers for configuration variable groups.""" @@ -344,13 +336,8 @@ class InvokeAIAppConfig(InvokeAISettings): super().parse_args(argv) if self.singleton_init and not clobber: - hints = get_type_hints(self.__class__) - for k in self.singleton_init: - setattr( - self, - k, - TypeAdapter(hints[k]).validate_python(self.singleton_init[k]), - ) + for k, v in self.singleton_init.items(): + setattr(self, k, v) @classmethod def get_config(cls, **kwargs: Any) -> InvokeAIAppConfig: From f972fe9836300eb7ee29f14628edf962057ade64 Mon Sep 17 00:00:00 2001 From: Peanut Date: Fri, 2 Feb 2024 17:55:19 +0800 Subject: [PATCH 03/28] pref: annotate --- invokeai/app/services/config/config_default.py | 1 + 1 file changed, 1 insertion(+) diff --git a/invokeai/app/services/config/config_default.py b/invokeai/app/services/config/config_default.py index 1403dc321f..132afc2272 100644 --- a/invokeai/app/services/config/config_default.py +++ b/invokeai/app/services/config/config_default.py @@ -336,6 +336,7 @@ class InvokeAIAppConfig(InvokeAISettings): super().parse_args(argv) if self.singleton_init and not clobber: + # When setting values in this way, set validate_assignment to true if you want to validate the value. for k, v in self.singleton_init.items(): setattr(self, k, v) From c2af124622ca70ce9e48f47a50dd5521bb9e48c9 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 10:50:44 +1100 Subject: [PATCH 04/28] fix(ui): refetch intermediates count when settings modal open The `getIntermediatesCount` query is set to `refetchOnMountOrArgsChange`. The intention was for when the settings modal opens (i.e. mounts), the `getIntermediatesCount` query is refetched. But it doesn't work - modals only mount once, there is no lazy rendering for them. So we have to imperatively refetch, by refetching as we open the modal. Closes #5639 --- .../system/components/SettingsModal/SettingsModal.tsx | 10 ++++++++-- .../components/SettingsModal/useClearIntermediates.ts | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx index 1590ec762f..cc937170a3 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx @@ -81,9 +81,10 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { hasPendingItems, intermediatesCount, isLoading: isLoadingClearIntermediates, + refetchIntermediatesCount, } = useClearIntermediates(shouldShowClearIntermediates); - const { isOpen: isSettingsModalOpen, onOpen: onSettingsModalOpen, onClose: onSettingsModalClose } = useDisclosure(); + const { isOpen: isSettingsModalOpen, onOpen: _onSettingsModalOpen, onClose: onSettingsModalClose } = useDisclosure(); const { isOpen: isRefreshModalOpen, onOpen: onRefreshModalOpen, onClose: onRefreshModalClose } = useDisclosure(); @@ -99,6 +100,11 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { const clearStorage = useClearStorage(); + const handleOpenSettingsModel = useCallback(() => { + refetchIntermediatesCount(); + _onSettingsModalOpen(); + }, [_onSettingsModalOpen, refetchIntermediatesCount]); + const handleClickResetWebUI = useCallback(() => { clearStorage(); onSettingsModalClose(); @@ -171,7 +177,7 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { return ( <> {cloneElement(children, { - onClick: onSettingsModalOpen, + onClick: handleOpenSettingsModel, })} diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/useClearIntermediates.ts b/invokeai/frontend/web/src/features/system/components/SettingsModal/useClearIntermediates.ts index 6d953c3c11..96d3b0f7ee 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/useClearIntermediates.ts +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/useClearIntermediates.ts @@ -12,13 +12,14 @@ export type UseClearIntermediatesReturn = { clearIntermediates: () => void; isLoading: boolean; hasPendingItems: boolean; + refetchIntermediatesCount: () => void; }; export const useClearIntermediates = (shouldShowClearIntermediates: boolean): UseClearIntermediatesReturn => { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const { data: intermediatesCount } = useGetIntermediatesCountQuery(undefined, { + const { data: intermediatesCount, refetch: refetchIntermediatesCount } = useGetIntermediatesCountQuery(undefined, { refetchOnMountOrArgChange: true, skip: !shouldShowClearIntermediates, }); @@ -58,5 +59,5 @@ export const useClearIntermediates = (shouldShowClearIntermediates: boolean): Us }); }, [t, _clearIntermediates, dispatch, hasPendingItems]); - return { intermediatesCount, clearIntermediates, isLoading, hasPendingItems }; + return { intermediatesCount, clearIntermediates, isLoading, hasPendingItems, refetchIntermediatesCount }; }; From 88c08bbfc78b1de2d65d96d26980e94f53f5ef17 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 18:30:41 +1100 Subject: [PATCH 05/28] fix(item-storage-memory): throw when requested item does not exist - `ItemStorageMemory.get` now throws an `ItemNotFoundError` when the requested `item_id` is not found. - Update docstrings in ABC and tests. The new memory item storage implementation implemented the `get` method incorrectly, by returning `None` if the item didn't exist. The ABC typed `get` as returning `T`, while the SQLite implementation typed `get` as returning `Optional[T]`. The SQLite implementation was referenced when writing the memory implementation. This mismatched typing is a violation of the Liskov substitution principle, because the signature of the implementation of `get` in the implementation is wider than the abstract class's definition. Using `pyright` in strict mode catches this. In `invocation_stats_default`, this introduced an error. The `_prune_stats` method calls `get`, expecting the method to throw if the item is not found. If the graph is no longer stored in the bounded item storage, we will call `is_complete()` on `None`, causing the error. Note: This error condition never arose the SQLite implementation because it parsed the item with pydantic before returning it, which would throw if the item was not found. It implicitly threw, while the memory implementation did not. --- .../invocation_stats/invocation_stats_default.py | 3 ++- .../services/item_storage/item_storage_base.py | 15 ++++++++++++--- .../services/item_storage/item_storage_common.py | 5 +++++ .../services/item_storage/item_storage_memory.py | 12 +++++++----- tests/test_item_storage_memory.py | 5 +++-- 5 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 invokeai/app/services/item_storage/item_storage_common.py diff --git a/invokeai/app/services/invocation_stats/invocation_stats_default.py b/invokeai/app/services/invocation_stats/invocation_stats_default.py index 7f3ef3023d..bf4f247b84 100644 --- a/invokeai/app/services/invocation_stats/invocation_stats_default.py +++ b/invokeai/app/services/invocation_stats/invocation_stats_default.py @@ -9,6 +9,7 @@ import torch import invokeai.backend.util.logging as logger from invokeai.app.invocations.baseinvocation import BaseInvocation from invokeai.app.services.invoker import Invoker +from invokeai.app.services.item_storage.item_storage_common import ItemNotFoundError from invokeai.backend.model_management.model_cache import CacheStats from .invocation_stats_base import InvocationStatsServiceBase @@ -82,7 +83,7 @@ class InvocationStatsService(InvocationStatsServiceBase): for graph_execution_state_id in self._stats: try: graph_execution_state = self._invoker.services.graph_execution_manager.get(graph_execution_state_id) - except Exception: + except ItemNotFoundError: # TODO(ryand): What would cause this? Should this exception just be allowed to propagate? logger.warning(f"Failed to get graph state for {graph_execution_state_id}.") continue diff --git a/invokeai/app/services/item_storage/item_storage_base.py b/invokeai/app/services/item_storage/item_storage_base.py index bbe1b3dcff..c93edf5188 100644 --- a/invokeai/app/services/item_storage/item_storage_base.py +++ b/invokeai/app/services/item_storage/item_storage_base.py @@ -20,17 +20,26 @@ class ItemStorageABC(ABC, Generic[T]): @abstractmethod def get(self, item_id: str) -> T: - """Gets the item, parsing it into a Pydantic model""" + """ + Gets the item. + :param item_id: the id of the item to get + :raises ItemNotFoundError: if the item is not found + """ pass @abstractmethod def set(self, item: T) -> None: - """Sets the item""" + """ + Sets the item. The id will be extracted based on id_field. + :param item: the item to set + """ pass @abstractmethod def delete(self, item_id: str) -> None: - """Deletes the item""" + """ + Deletes the item, if it exists. + """ pass def on_changed(self, on_changed: Callable[[T], None]) -> None: diff --git a/invokeai/app/services/item_storage/item_storage_common.py b/invokeai/app/services/item_storage/item_storage_common.py new file mode 100644 index 0000000000..8fd677c71b --- /dev/null +++ b/invokeai/app/services/item_storage/item_storage_common.py @@ -0,0 +1,5 @@ +class ItemNotFoundError(KeyError): + """Raised when an item is not found in storage""" + + def __init__(self, item_id: str) -> None: + super().__init__(f"Item with id {item_id} not found") diff --git a/invokeai/app/services/item_storage/item_storage_memory.py b/invokeai/app/services/item_storage/item_storage_memory.py index 028b4808cf..0ab495271c 100644 --- a/invokeai/app/services/item_storage/item_storage_memory.py +++ b/invokeai/app/services/item_storage/item_storage_memory.py @@ -1,10 +1,11 @@ from collections import OrderedDict from contextlib import suppress -from typing import Generic, Optional, TypeVar +from typing import Generic, TypeVar from pydantic import BaseModel from invokeai.app.services.item_storage.item_storage_base import ItemStorageABC +from invokeai.app.services.item_storage.item_storage_common import ItemNotFoundError T = TypeVar("T", bound=BaseModel) @@ -25,12 +26,13 @@ class ItemStorageMemory(ItemStorageABC, Generic[T]): self._items: OrderedDict[str, T] = OrderedDict() self._max_items = max_items - def get(self, item_id: str) -> Optional[T]: + def get(self, item_id: str) -> T: # If the item exists, move it to the end of the OrderedDict. item = self._items.pop(item_id, None) - if item is not None: - self._items[item_id] = item - return self._items.get(item_id) + if item is None: + raise ItemNotFoundError(item_id) + self._items[item_id] = item + return item def set(self, item: T) -> None: item_id = getattr(item, self._id_field) diff --git a/tests/test_item_storage_memory.py b/tests/test_item_storage_memory.py index cfd1ffb834..23ce1ec3a8 100644 --- a/tests/test_item_storage_memory.py +++ b/tests/test_item_storage_memory.py @@ -3,6 +3,7 @@ import re import pytest from pydantic import BaseModel +from invokeai.app.services.item_storage.item_storage_common import ItemNotFoundError from invokeai.app.services.item_storage.item_storage_memory import ItemStorageMemory @@ -58,8 +59,8 @@ def test_item_storage_memory_gets(item_storage_memory: ItemStorageMemory[MockIte item = item_storage_memory.get("2") assert item == item_2 - item = item_storage_memory.get("3") - assert item is None + with pytest.raises(ItemNotFoundError, match=re.escape("Item with id 3 not found")): + item_storage_memory.get("3") def test_item_storage_memory_deletes(item_storage_memory: ItemStorageMemory[MockItemModel]): From 9f274c79dcb8576aa19a46c5ae511c9420bbf20a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 18:35:46 +1100 Subject: [PATCH 06/28] chore(item-storage): improve types Provide type args to the generics. --- .../app/services/item_storage/item_storage_memory.py | 2 +- tests/test_item_storage_memory.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/invokeai/app/services/item_storage/item_storage_memory.py b/invokeai/app/services/item_storage/item_storage_memory.py index 0ab495271c..d8dd0e0664 100644 --- a/invokeai/app/services/item_storage/item_storage_memory.py +++ b/invokeai/app/services/item_storage/item_storage_memory.py @@ -10,7 +10,7 @@ from invokeai.app.services.item_storage.item_storage_common import ItemNotFoundE T = TypeVar("T", bound=BaseModel) -class ItemStorageMemory(ItemStorageABC, Generic[T]): +class ItemStorageMemory(ItemStorageABC[T], Generic[T]): """ Provides a simple in-memory storage for items, with a maximum number of items to store. The storage uses the LRU strategy to evict items from storage when the max has been reached. diff --git a/tests/test_item_storage_memory.py b/tests/test_item_storage_memory.py index 23ce1ec3a8..15758094d7 100644 --- a/tests/test_item_storage_memory.py +++ b/tests/test_item_storage_memory.py @@ -18,19 +18,19 @@ def item_storage_memory(): def test_item_storage_memory_initializes(): - item_storage_memory = ItemStorageMemory() + item_storage_memory = ItemStorageMemory[MockItemModel]() assert item_storage_memory._items == {} assert item_storage_memory._id_field == "id" assert item_storage_memory._max_items == 10 - item_storage_memory = ItemStorageMemory(id_field="bananas", max_items=20) + item_storage_memory = ItemStorageMemory[MockItemModel](id_field="bananas", max_items=20) assert item_storage_memory._id_field == "bananas" assert item_storage_memory._max_items == 20 with pytest.raises(ValueError, match=re.escape("max_items must be at least 1")): - item_storage_memory = ItemStorageMemory(max_items=0) + item_storage_memory = ItemStorageMemory[MockItemModel](max_items=0) with pytest.raises(ValueError, match=re.escape("id_field must not be empty")): - item_storage_memory = ItemStorageMemory(id_field="") + item_storage_memory = ItemStorageMemory[MockItemModel](id_field="") def test_item_storage_memory_sets(item_storage_memory: ItemStorageMemory[MockItemModel]): @@ -74,7 +74,7 @@ def test_item_storage_memory_deletes(item_storage_memory: ItemStorageMemory[Mock def test_item_storage_memory_respects_max(): - item_storage_memory = ItemStorageMemory(max_items=3) + item_storage_memory = ItemStorageMemory[MockItemModel](max_items=3) for i in range(10): item_storage_memory.set(MockItemModel(id=str(i), value=i)) assert item_storage_memory._items == { From 3ebb8064100ffa775d3160cfb9038068eb33d6de Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 18:37:08 +1100 Subject: [PATCH 07/28] fix(invocation-stats): use appropriate method to get the type of an invocation --- .../app/services/invocation_stats/invocation_stats_default.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/services/invocation_stats/invocation_stats_default.py b/invokeai/app/services/invocation_stats/invocation_stats_default.py index bf4f247b84..b831baa33c 100644 --- a/invokeai/app/services/invocation_stats/invocation_stats_default.py +++ b/invokeai/app/services/invocation_stats/invocation_stats_default.py @@ -64,7 +64,7 @@ class InvocationStatsService(InvocationStatsServiceBase): finally: # Record state after the invocation. node_stats = NodeExecutionStats( - invocation_type=invocation.type, + invocation_type=invocation.get_type(), start_time=start_time, end_time=time.time(), start_ram_gb=start_ram / GB, From 0976ddba2316db04a74fc32cf17fa51a689da91f Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 18:37:24 +1100 Subject: [PATCH 08/28] chore(invocation-stats): improve types in _prune_stale_stats --- .../app/services/invocation_stats/invocation_stats_default.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/app/services/invocation_stats/invocation_stats_default.py b/invokeai/app/services/invocation_stats/invocation_stats_default.py index b831baa33c..501a4c04e5 100644 --- a/invokeai/app/services/invocation_stats/invocation_stats_default.py +++ b/invokeai/app/services/invocation_stats/invocation_stats_default.py @@ -79,7 +79,7 @@ class InvocationStatsService(InvocationStatsServiceBase): This shouldn't be necessary, but we don't have totally robust upstream handling of graph completions/errors, so for now we call this function periodically to prevent them from accumulating. """ - to_prune = [] + to_prune: list[str] = [] for graph_execution_state_id in self._stats: try: graph_execution_state = self._invoker.services.graph_execution_manager.get(graph_execution_state_id) From c1300fa8b1dffb72be92cb64519b7db3a5069cc8 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 20:18:13 +1100 Subject: [PATCH 09/28] refactor(ui): refactor persist config Add more structure around persist configs to avoid bugs from typos and misplaced persist denylists. --- invokeai/frontend/web/src/app/store/store.ts | 162 ++++++------------ .../canvas/store/canvasPersistDenylist.ts | 6 - .../src/features/canvas/store/canvasSlice.ts | 9 +- .../store/controlAdaptersPersistDenylist.ts | 6 - .../store/controlAdaptersSlice.ts | 9 +- .../store/dynamicPromptsPersistDenylist.ts | 3 - .../store/dynamicPromptsSlice.ts | 9 +- .../gallery/store/galleryPersistDenylist.ts | 12 -- .../features/gallery/store/gallerySlice.ts | 9 +- .../web/src/features/hrf/store/hrfSlice.ts | 9 +- .../web/src/features/lora/store/loraSlice.ts | 9 +- .../modelManager/store/modelManagerSlice.ts | 9 +- .../nodes/store/nodesPersistDenylist.ts | 17 -- .../src/features/nodes/store/nodesSlice.ts | 20 ++- .../src/features/nodes/store/workflowSlice.ts | 9 +- .../store/generationPersistDenylist.ts | 6 - .../parameters/store/generationSlice.ts | 9 +- .../store/postprocessingPersistDenylist.ts | 6 - .../parameters/store/postprocessingSlice.ts | 9 +- .../web/src/features/sdxl/store/sdxlSlice.ts | 9 +- .../system/store/systemPersistDenylist.ts | 3 - .../src/features/system/store/systemSlice.ts | 9 +- .../features/ui/store/uiPersistDenylist.ts | 6 - .../web/src/features/ui/store/uiSlice.ts | 9 +- 24 files changed, 175 insertions(+), 189 deletions(-) delete mode 100644 invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/gallery/store/galleryPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/parameters/store/generationPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/parameters/store/postprocessingPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts delete mode 100644 invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts index 81088ffcbb..d838a40eb1 100644 --- a/invokeai/frontend/web/src/app/store/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -3,49 +3,27 @@ import { autoBatchEnhancer, combineReducers, configureStore } from '@reduxjs/too import { logger } from 'app/logging/logger'; import { idbKeyValDriver } from 'app/store/enhancers/reduxRemember/driver'; import { errorHandler } from 'app/store/enhancers/reduxRemember/errors'; -import { canvasPersistDenylist } from 'features/canvas/store/canvasPersistDenylist'; -import canvasReducer, { initialCanvasState, migrateCanvasState } from 'features/canvas/store/canvasSlice'; +import canvasReducer, { canvasPersistConfig } from 'features/canvas/store/canvasSlice'; import changeBoardModalReducer from 'features/changeBoardModal/store/slice'; -import { controlAdaptersPersistDenylist } from 'features/controlAdapters/store/controlAdaptersPersistDenylist'; import controlAdaptersReducer, { - initialControlAdaptersState, - migrateControlAdaptersState, + controlAdaptersPersistConfig, } from 'features/controlAdapters/store/controlAdaptersSlice'; import deleteImageModalReducer from 'features/deleteImageModal/store/slice'; -import { dynamicPromptsPersistDenylist } from 'features/dynamicPrompts/store/dynamicPromptsPersistDenylist'; -import dynamicPromptsReducer, { - initialDynamicPromptsState, - migrateDynamicPromptsState, -} from 'features/dynamicPrompts/store/dynamicPromptsSlice'; -import { galleryPersistDenylist } from 'features/gallery/store/galleryPersistDenylist'; -import galleryReducer, { initialGalleryState, migrateGalleryState } from 'features/gallery/store/gallerySlice'; -import hrfReducer, { initialHRFState, migrateHRFState } from 'features/hrf/store/hrfSlice'; -import loraReducer, { initialLoraState, migrateLoRAState } from 'features/lora/store/loraSlice'; -import modelmanagerReducer, { - initialModelManagerState, - migrateModelManagerState, -} from 'features/modelManager/store/modelManagerSlice'; -import { nodesPersistDenylist } from 'features/nodes/store/nodesPersistDenylist'; -import nodesReducer, { initialNodesState, migrateNodesState } from 'features/nodes/store/nodesSlice'; +import dynamicPromptsReducer, { dynamicPromptsPersistConfig } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; +import galleryReducer, { galleryPersistConfig } from 'features/gallery/store/gallerySlice'; +import hrfReducer, { hrfPersistConfig } from 'features/hrf/store/hrfSlice'; +import loraReducer, { loraPersistConfig } from 'features/lora/store/loraSlice'; +import modelmanagerReducer, { modelManagerPersistConfig } from 'features/modelManager/store/modelManagerSlice'; +import nodesReducer, { nodesPersistConfig } from 'features/nodes/store/nodesSlice'; import nodeTemplatesReducer from 'features/nodes/store/nodeTemplatesSlice'; -import workflowReducer, { initialWorkflowState, migrateWorkflowState } from 'features/nodes/store/workflowSlice'; -import { generationPersistDenylist } from 'features/parameters/store/generationPersistDenylist'; -import generationReducer, { - initialGenerationState, - migrateGenerationState, -} from 'features/parameters/store/generationSlice'; -import { postprocessingPersistDenylist } from 'features/parameters/store/postprocessingPersistDenylist'; -import postprocessingReducer, { - initialPostprocessingState, - migratePostprocessingState, -} from 'features/parameters/store/postprocessingSlice'; +import workflowReducer, { workflowPersistConfig } from 'features/nodes/store/workflowSlice'; +import generationReducer, { generationPersistConfig } from 'features/parameters/store/generationSlice'; +import postprocessingReducer, { postprocessingPersistConfig } from 'features/parameters/store/postprocessingSlice'; import queueReducer from 'features/queue/store/queueSlice'; -import sdxlReducer, { initialSDXLState, migrateSDXLState } from 'features/sdxl/store/sdxlSlice'; +import sdxlReducer, { sdxlPersistConfig } from 'features/sdxl/store/sdxlSlice'; import configReducer from 'features/system/store/configSlice'; -import { systemPersistDenylist } from 'features/system/store/systemPersistDenylist'; -import systemReducer, { initialSystemState, migrateSystemState } from 'features/system/store/systemSlice'; -import { uiPersistDenylist } from 'features/ui/store/uiPersistDenylist'; -import uiReducer, { initialUIState, migrateUIState } from 'features/ui/store/uiSlice'; +import systemReducer, { systemPersistConfig } from 'features/system/store/systemSlice'; +import uiReducer, { uiPersistConfig } from 'features/ui/store/uiSlice'; import { diff } from 'jsondiffpatch'; import { defaultsDeep, keys, omit, pick } from 'lodash-es'; import dynamicMiddlewares from 'redux-dynamic-middlewares'; @@ -88,70 +66,48 @@ const rootReducer = combineReducers(allReducers); const rememberedRootReducer = rememberReducer(rootReducer); -const rememberedKeys = [ - 'canvas', - 'gallery', - 'generation', - 'sdxl', - 'nodes', - 'workflow', - 'postprocessing', - 'system', - 'ui', - 'controlAdapters', - 'dynamicPrompts', - 'lora', - 'modelmanager', - 'hrf', -] satisfies (keyof typeof allReducers)[]; - -type SliceConfig = { - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - initialState: any; - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - migrate: (state: any) => any; +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +export type PersistConfig = { + /** + * The name of the slice. + */ + name: keyof typeof allReducers; + /** + * The initial state of the slice. + */ + initialState: T; + /** + * Migrate the state to the current version during rehydration. + * @param state The rehydrated state. + * @returns A correctly-shaped state. + */ + migrate: (state: unknown) => T; + /** + * Keys to omit from the persisted state. + */ + persistDenylist: (keyof T)[]; }; -const sliceConfigs: { - [key in (typeof rememberedKeys)[number]]: SliceConfig; -} = { - canvas: { initialState: initialCanvasState, migrate: migrateCanvasState }, - gallery: { initialState: initialGalleryState, migrate: migrateGalleryState }, - generation: { - initialState: initialGenerationState, - migrate: migrateGenerationState, - }, - nodes: { initialState: initialNodesState, migrate: migrateNodesState }, - postprocessing: { - initialState: initialPostprocessingState, - migrate: migratePostprocessingState, - }, - system: { initialState: initialSystemState, migrate: migrateSystemState }, - workflow: { - initialState: initialWorkflowState, - migrate: migrateWorkflowState, - }, - ui: { initialState: initialUIState, migrate: migrateUIState }, - controlAdapters: { - initialState: initialControlAdaptersState, - migrate: migrateControlAdaptersState, - }, - dynamicPrompts: { - initialState: initialDynamicPromptsState, - migrate: migrateDynamicPromptsState, - }, - sdxl: { initialState: initialSDXLState, migrate: migrateSDXLState }, - lora: { initialState: initialLoraState, migrate: migrateLoRAState }, - modelmanager: { - initialState: initialModelManagerState, - migrate: migrateModelManagerState, - }, - hrf: { initialState: initialHRFState, migrate: migrateHRFState }, +const persistConfigs: { [key in keyof typeof allReducers]?: PersistConfig } = { + [canvasPersistConfig.name]: canvasPersistConfig, + [galleryPersistConfig.name]: galleryPersistConfig, + [generationPersistConfig.name]: generationPersistConfig, + [nodesPersistConfig.name]: nodesPersistConfig, + [postprocessingPersistConfig.name]: postprocessingPersistConfig, + [systemPersistConfig.name]: systemPersistConfig, + [workflowPersistConfig.name]: workflowPersistConfig, + [uiPersistConfig.name]: uiPersistConfig, + [controlAdaptersPersistConfig.name]: controlAdaptersPersistConfig, + [dynamicPromptsPersistConfig.name]: dynamicPromptsPersistConfig, + [sdxlPersistConfig.name]: sdxlPersistConfig, + [loraPersistConfig.name]: loraPersistConfig, + [modelManagerPersistConfig.name]: modelManagerPersistConfig, + [hrfPersistConfig.name]: hrfPersistConfig, }; const unserialize: UnserializeFunction = (data, key) => { const log = logger('system'); - const config = sliceConfigs[key as keyof typeof sliceConfigs]; + const config = persistConfigs[key as keyof typeof persistConfigs]; if (!config) { throw new Error(`No unserialize config for slice "${key}"`); } @@ -180,22 +136,8 @@ const unserialize: UnserializeFunction = (data, key) => { } }; -const serializationDenylist: { - [key in (typeof rememberedKeys)[number]]?: string[]; -} = { - canvas: canvasPersistDenylist, - gallery: galleryPersistDenylist, - generation: generationPersistDenylist, - nodes: nodesPersistDenylist, - postprocessing: postprocessingPersistDenylist, - system: systemPersistDenylist, - ui: uiPersistDenylist, - controlAdapters: controlAdaptersPersistDenylist, - dynamicPrompts: dynamicPromptsPersistDenylist, -}; - export const serialize: SerializeFunction = (data, key) => { - const result = omit(data, serializationDenylist[key as keyof typeof serializationDenylist] ?? []); + const result = omit(data, persistConfigs[key as keyof typeof persistConfigs]?.persistDenylist ?? []); return JSON.stringify(result); }; @@ -215,7 +157,7 @@ export const createStore = (uniqueStoreKey?: string, persist = true) => const _enhancers = getDefaultEnhancers().concat(autoBatchEnhancer()); if (persist) { _enhancers.push( - rememberEnhancer(idbKeyValDriver, rememberedKeys, { + rememberEnhancer(idbKeyValDriver, keys(persistConfigs), { persistDebounce: 300, serialize, unserialize, diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts b/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts deleted file mode 100644 index 9394b685ca..0000000000 --- a/invokeai/frontend/web/src/features/canvas/store/canvasPersistDenylist.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { CanvasState } from './canvasTypes'; - -/** - * Canvas slice persist denylist - */ -export const canvasPersistDenylist: (keyof CanvasState)[] = []; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts index a049c13419..1a3c6cfd73 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { roundDownToMultiple, roundToMultiple } from 'common/util/roundDownToMultiple'; import calculateCoordinates from 'features/canvas/util/calculateCoordinates'; import calculateScale from 'features/canvas/util/calculateScale'; @@ -731,3 +731,10 @@ export const migrateCanvasState = (state: any): any => { } return state; }; + +export const canvasPersistConfig: PersistConfig = { + name: canvasSlice.name, + initialState: initialCanvasState, + migrate: migrateCanvasState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts deleted file mode 100644 index ff8fcd1594..0000000000 --- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersPersistDenylist.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ControlAdaptersState } from './types'; - -/** - * ControlNet slice persist denylist - */ -export const controlAdaptersPersistDenylist: (keyof ControlAdaptersState)[] = ['pendingControlImages']; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts index fd9a70ef57..e037b871fd 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts @@ -1,7 +1,7 @@ import type { PayloadAction, Update } from '@reduxjs/toolkit'; import { createEntityAdapter, createSlice, isAnyOf } from '@reduxjs/toolkit'; import { getSelectorsOptions } from 'app/store/createMemoizedSelector'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { buildControlAdapter } from 'features/controlAdapters/util/buildControlAdapter'; import type { ParameterControlNetModel, @@ -441,3 +441,10 @@ export const migrateControlAdaptersState = (state: any): any => { } return state; }; + +export const controlAdaptersPersistConfig: PersistConfig = { + name: controlAdaptersSlice.name, + initialState: initialControlAdaptersState, + migrate: migrateControlAdaptersState, + persistDenylist: ['pendingControlImages'], +}; diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsPersistDenylist.ts b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsPersistDenylist.ts deleted file mode 100644 index a411b0beec..0000000000 --- a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsPersistDenylist.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { initialDynamicPromptsState } from './dynamicPromptsSlice'; - -export const dynamicPromptsPersistDenylist: (keyof typeof initialDynamicPromptsState)[] = ['prompts']; diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts index 450dbb9f23..cb4709b711 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts +++ b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { z } from 'zod'; export const zSeedBehaviour = z.enum(['PER_ITERATION', 'PER_PROMPT']); @@ -85,3 +85,10 @@ export const migrateDynamicPromptsState = (state: any): any => { } return state; }; + +export const dynamicPromptsPersistConfig: PersistConfig = { + name: dynamicPromptsSlice.name, + initialState: initialDynamicPromptsState, + migrate: migrateDynamicPromptsState, + persistDenylist: ['prompts'], +}; diff --git a/invokeai/frontend/web/src/features/gallery/store/galleryPersistDenylist.ts b/invokeai/frontend/web/src/features/gallery/store/galleryPersistDenylist.ts deleted file mode 100644 index e39ace1577..0000000000 --- a/invokeai/frontend/web/src/features/gallery/store/galleryPersistDenylist.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { initialGalleryState } from './gallerySlice'; - -/** - * Gallery slice persist denylist - */ -export const galleryPersistDenylist: (keyof typeof initialGalleryState)[] = [ - 'selection', - 'selectedBoardId', - 'galleryView', - 'offset', - 'limit', -]; diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts index 6adad0be70..53b8527b34 100644 --- a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice, isAnyOf } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { uniqBy } from 'lodash-es'; import { boardsApi } from 'services/api/endpoints/boards'; import { imagesApi } from 'services/api/endpoints/images'; @@ -125,3 +125,10 @@ export const migrateGalleryState = (state: any): any => { } return state; }; + +export const galleryPersistConfig: PersistConfig = { + name: gallerySlice.name, + initialState: initialGalleryState, + migrate: migrateGalleryState, + persistDenylist: ['selection', 'selectedBoardId', 'galleryView', 'offset', 'limit'], +}; diff --git a/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts b/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts index ac846ec58e..36eefe0ce6 100644 --- a/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts +++ b/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import type { ParameterHRFMethod, ParameterStrength } from 'features/parameters/types/parameterSchemas'; export interface HRFState { @@ -48,3 +48,10 @@ export const migrateHRFState = (state: any): any => { } return state; }; + +export const hrfPersistConfig: PersistConfig = { + name: hrfSlice.name, + initialState: initialHRFState, + migrate: migrateHRFState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/lora/store/loraSlice.ts b/invokeai/frontend/web/src/features/lora/store/loraSlice.ts index 7906443d7f..2df882a1c5 100644 --- a/invokeai/frontend/web/src/features/lora/store/loraSlice.ts +++ b/invokeai/frontend/web/src/features/lora/store/loraSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import type { ParameterLoRAModel } from 'features/parameters/types/parameterSchemas'; import type { LoRAModelConfigEntity } from 'services/api/endpoints/models'; @@ -92,3 +92,10 @@ export const migrateLoRAState = (state: any): any => { } return state; }; + +export const loraPersistConfig: PersistConfig = { + name: loraSlice.name, + initialState: initialLoraState, + migrate: migrateLoRAState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts b/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts index 5da08d7f54..4f6c5840e7 100644 --- a/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts +++ b/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; type ModelManagerState = { _version: 1; @@ -40,3 +40,10 @@ export const migrateModelManagerState = (state: any): any => { } return state; }; + +export const modelManagerPersistConfig: PersistConfig = { + name: modelManagerSlice.name, + initialState: initialModelManagerState, + migrate: migrateModelManagerState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts b/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts deleted file mode 100644 index 5e3947314a..0000000000 --- a/invokeai/frontend/web/src/features/nodes/store/nodesPersistDenylist.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { NodesState } from './types'; - -/** - * Nodes slice persist denylist - */ -export const nodesPersistDenylist: (keyof NodesState)[] = [ - 'connectionStartParams', - 'connectionStartFieldType', - 'selectedNodes', - 'selectedEdges', - 'isReady', - 'nodesToCopy', - 'edgesToCopy', - 'connectionMade', - 'modifyingEdge', - 'addNewNodePosition', -]; diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts index a0074c1e47..e0291182b4 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice, isAnyOf } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { workflowLoaded } from 'features/nodes/store/actions'; import { nodeTemplatesBuilt } from 'features/nodes/store/nodeTemplatesSlice'; import { SHARED_NODE_PROPERTIES } from 'features/nodes/types/constants'; @@ -863,3 +863,21 @@ export const migrateNodesState = (state: any): any => { } return state; }; + +export const nodesPersistConfig: PersistConfig = { + name: nodesSlice.name, + initialState: initialNodesState, + migrate: migrateNodesState, + persistDenylist: [ + 'connectionStartParams', + 'connectionStartFieldType', + 'selectedNodes', + 'selectedEdges', + 'isReady', + 'nodesToCopy', + 'edgesToCopy', + 'connectionMade', + 'modifyingEdge', + 'addNewNodePosition', + ], +}; diff --git a/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts b/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts index f6ffa20f13..7b33ee4d01 100644 --- a/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { workflowLoaded } from 'features/nodes/store/actions'; import { isAnyNodeOrEdgeMutation, nodeEditorReset, nodesDeleted } from 'features/nodes/store/nodesSlice'; import type { WorkflowsState as WorkflowState } from 'features/nodes/store/types'; @@ -130,3 +130,10 @@ export const migrateWorkflowState = (state: any): any => { } return state; }; + +export const workflowPersistConfig: PersistConfig = { + name: workflowSlice.name, + initialState: initialWorkflowState, + migrate: migrateWorkflowState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/parameters/store/generationPersistDenylist.ts b/invokeai/frontend/web/src/features/parameters/store/generationPersistDenylist.ts deleted file mode 100644 index 2003566bbd..0000000000 --- a/invokeai/frontend/web/src/features/parameters/store/generationPersistDenylist.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { GenerationState } from './types'; - -/** - * Generation slice persist denylist - */ -export const generationPersistDenylist: (keyof GenerationState)[] = []; diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 9359fd4b84..11bd656e6f 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { roundToMultiple } from 'common/util/roundDownToMultiple'; import { isAnyControlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice'; import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize'; @@ -311,3 +311,10 @@ export const migrateGenerationState = (state: any): GenerationState => { } return state; }; + +export const generationPersistConfig: PersistConfig = { + name: generationSlice.name, + initialState: initialGenerationState, + migrate: migrateGenerationState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/parameters/store/postprocessingPersistDenylist.ts b/invokeai/frontend/web/src/features/parameters/store/postprocessingPersistDenylist.ts deleted file mode 100644 index 014a2bbeaf..0000000000 --- a/invokeai/frontend/web/src/features/parameters/store/postprocessingPersistDenylist.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { PostprocessingState } from './postprocessingSlice'; - -/** - * Postprocessing slice persist denylist - */ -export const postprocessingPersistDenylist: (keyof PostprocessingState)[] = []; diff --git a/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts b/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts index bb74c988a0..ee856bcb78 100644 --- a/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { z } from 'zod'; export const zParamESRGANModelName = z.enum([ @@ -46,3 +46,10 @@ export const migratePostprocessingState = (state: any): any => { } return state; }; + +export const postprocessingPersistConfig: PersistConfig = { + name: postprocessingSlice.name, + initialState: initialPostprocessingState, + migrate: migratePostprocessingState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts b/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts index a8f4b45359..b630bc7912 100644 --- a/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts +++ b/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import type { ParameterNegativeStylePromptSDXL, ParameterPositiveStylePromptSDXL, @@ -97,3 +97,10 @@ export const migrateSDXLState = (state: any): any => { } return state; }; + +export const sdxlPersistConfig: PersistConfig = { + name: sdxlSlice.name, + initialState: initialSDXLState, + migrate: migrateSDXLState, + persistDenylist: [], +}; diff --git a/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts b/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts deleted file mode 100644 index 75da6f63a9..0000000000 --- a/invokeai/frontend/web/src/features/system/store/systemPersistDenylist.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { SystemState } from './types'; - -export const systemPersistDenylist: (keyof SystemState)[] = ['isConnected', 'denoiseProgress', 'status']; diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index 4f31ca80f5..edbfa60616 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -1,7 +1,7 @@ import type { UseToastOptions } from '@invoke-ai/ui-library'; import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice, isAnyOf } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { calculateStepPercentage } from 'features/system/util/calculateStepPercentage'; import { makeToast } from 'features/system/util/makeToast'; import { t } from 'i18next'; @@ -207,3 +207,10 @@ export const migrateSystemState = (state: any): any => { } return state; }; + +export const systemPersistConfig: PersistConfig = { + name: systemSlice.name, + initialState: initialSystemState, + migrate: migrateSystemState, + persistDenylist: ['isConnected', 'denoiseProgress', 'status'], +}; diff --git a/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts b/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts deleted file mode 100644 index 815f8dfca5..0000000000 --- a/invokeai/frontend/web/src/features/ui/store/uiPersistDenylist.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { UIState } from './uiTypes'; - -/** - * UI slice persist denylist - */ -export const uiPersistDenylist: (keyof UIState)[] = ['shouldShowImageDetails']; diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index acca0ad67b..b5c748dafd 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -1,6 +1,6 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import type { RootState } from 'app/store/store'; +import type { PersistConfig, RootState } from 'app/store/store'; import { initialImageChanged } from 'features/parameters/store/generationSlice'; import type { InvokeTabName } from './tabMap'; @@ -68,3 +68,10 @@ export const migrateUIState = (state: any): any => { } return state; }; + +export const uiPersistConfig: PersistConfig = { + name: uiSlice.name, + initialState: initialUIState, + migrate: migrateUIState, + persistDenylist: ['shouldShowImageDetails'], +}; From d713620d9e6ee7a1fcd1624b9b7b53d1ff4a2412 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 20:30:18 +1100 Subject: [PATCH 10/28] refactor(ui): refactor reducer list Instead of manually naming reducers, use each slice's `name` property. Makes typos impossible. --- invokeai/frontend/web/src/app/store/store.ts | 78 ++++++++++--------- .../src/features/canvas/store/canvasSlice.ts | 2 - .../features/changeBoardModal/store/slice.ts | 6 +- .../store/controlAdaptersSlice.ts | 2 - .../features/deleteImageModal/store/slice.ts | 6 +- .../store/dynamicPromptsSlice.ts | 2 - .../features/gallery/store/gallerySlice.ts | 2 - .../web/src/features/hrf/store/hrfSlice.ts | 2 - .../web/src/features/lora/store/loraSlice.ts | 2 - .../modelManager/store/modelManagerSlice.ts | 2 - .../nodes/store/nodeTemplatesSlice.ts | 4 +- .../src/features/nodes/store/nodesSlice.ts | 4 +- .../src/features/nodes/store/workflowSlice.ts | 4 +- .../parameters/store/generationSlice.ts | 2 - .../parameters/store/postprocessingSlice.ts | 2 - .../src/features/queue/store/queueSlice.ts | 2 - .../web/src/features/sdxl/store/sdxlSlice.ts | 4 +- .../src/features/system/store/configSlice.ts | 2 - .../src/features/system/store/systemSlice.ts | 2 - .../web/src/features/ui/store/uiSlice.ts | 2 - 20 files changed, 48 insertions(+), 84 deletions(-) diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts index d838a40eb1..7a2b8673a2 100644 --- a/invokeai/frontend/web/src/app/store/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -3,27 +3,28 @@ import { autoBatchEnhancer, combineReducers, configureStore } from '@reduxjs/too import { logger } from 'app/logging/logger'; import { idbKeyValDriver } from 'app/store/enhancers/reduxRemember/driver'; import { errorHandler } from 'app/store/enhancers/reduxRemember/errors'; -import canvasReducer, { canvasPersistConfig } from 'features/canvas/store/canvasSlice'; -import changeBoardModalReducer from 'features/changeBoardModal/store/slice'; -import controlAdaptersReducer, { +import { canvasPersistConfig, canvasSlice } from 'features/canvas/store/canvasSlice'; +import { changeBoardModalSlice } from 'features/changeBoardModal/store/slice'; +import { controlAdaptersPersistConfig, + controlAdaptersSlice, } from 'features/controlAdapters/store/controlAdaptersSlice'; -import deleteImageModalReducer from 'features/deleteImageModal/store/slice'; -import dynamicPromptsReducer, { dynamicPromptsPersistConfig } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; -import galleryReducer, { galleryPersistConfig } from 'features/gallery/store/gallerySlice'; -import hrfReducer, { hrfPersistConfig } from 'features/hrf/store/hrfSlice'; -import loraReducer, { loraPersistConfig } from 'features/lora/store/loraSlice'; -import modelmanagerReducer, { modelManagerPersistConfig } from 'features/modelManager/store/modelManagerSlice'; -import nodesReducer, { nodesPersistConfig } from 'features/nodes/store/nodesSlice'; -import nodeTemplatesReducer from 'features/nodes/store/nodeTemplatesSlice'; -import workflowReducer, { workflowPersistConfig } from 'features/nodes/store/workflowSlice'; -import generationReducer, { generationPersistConfig } from 'features/parameters/store/generationSlice'; -import postprocessingReducer, { postprocessingPersistConfig } from 'features/parameters/store/postprocessingSlice'; -import queueReducer from 'features/queue/store/queueSlice'; -import sdxlReducer, { sdxlPersistConfig } from 'features/sdxl/store/sdxlSlice'; -import configReducer from 'features/system/store/configSlice'; -import systemReducer, { systemPersistConfig } from 'features/system/store/systemSlice'; -import uiReducer, { uiPersistConfig } from 'features/ui/store/uiSlice'; +import { deleteImageModalSlice } from 'features/deleteImageModal/store/slice'; +import { dynamicPromptsPersistConfig, dynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; +import { galleryPersistConfig, gallerySlice } from 'features/gallery/store/gallerySlice'; +import { hrfPersistConfig, hrfSlice } from 'features/hrf/store/hrfSlice'; +import { loraPersistConfig, loraSlice } from 'features/lora/store/loraSlice'; +import { modelManagerPersistConfig, modelManagerSlice } from 'features/modelManager/store/modelManagerSlice'; +import { nodesPersistConfig, nodesSlice } from 'features/nodes/store/nodesSlice'; +import { nodesTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice'; +import { workflowPersistConfig, workflowSlice } from 'features/nodes/store/workflowSlice'; +import { generationPersistConfig, generationSlice } from 'features/parameters/store/generationSlice'; +import { postprocessingPersistConfig, postprocessingSlice } from 'features/parameters/store/postprocessingSlice'; +import { queueSlice } from 'features/queue/store/queueSlice'; +import { sdxlPersistConfig, sdxlSlice } from 'features/sdxl/store/sdxlSlice'; +import { configSlice } from 'features/system/store/configSlice'; +import { systemPersistConfig, systemSlice } from 'features/system/store/systemSlice'; +import { uiPersistConfig, uiSlice } from 'features/ui/store/uiSlice'; import { diff } from 'jsondiffpatch'; import { defaultsDeep, keys, omit, pick } from 'lodash-es'; import dynamicMiddlewares from 'redux-dynamic-middlewares'; @@ -39,26 +40,27 @@ import { actionSanitizer } from './middleware/devtools/actionSanitizer'; import { actionsDenylist } from './middleware/devtools/actionsDenylist'; import { stateSanitizer } from './middleware/devtools/stateSanitizer'; import { listenerMiddleware } from './middleware/listenerMiddleware'; + const allReducers = { - canvas: canvasReducer, - gallery: galleryReducer, - generation: generationReducer, - nodes: nodesReducer, - nodeTemplates: nodeTemplatesReducer, - postprocessing: postprocessingReducer, - system: systemReducer, - config: configReducer, - ui: uiReducer, - controlAdapters: controlAdaptersReducer, - dynamicPrompts: dynamicPromptsReducer, - deleteImageModal: deleteImageModalReducer, - changeBoardModal: changeBoardModalReducer, - lora: loraReducer, - modelmanager: modelmanagerReducer, - sdxl: sdxlReducer, - queue: queueReducer, - workflow: workflowReducer, - hrf: hrfReducer, + [canvasSlice.name]: canvasSlice.reducer, + [gallerySlice.name]: gallerySlice.reducer, + [generationSlice.name]: generationSlice.reducer, + [nodesSlice.name]: nodesSlice.reducer, + [nodesTemplatesSlice.name]: nodesTemplatesSlice.reducer, + [postprocessingSlice.name]: postprocessingSlice.reducer, + [systemSlice.name]: systemSlice.reducer, + [configSlice.name]: configSlice.reducer, + [uiSlice.name]: uiSlice.reducer, + [controlAdaptersSlice.name]: controlAdaptersSlice.reducer, + [dynamicPromptsSlice.name]: dynamicPromptsSlice.reducer, + [deleteImageModalSlice.name]: deleteImageModalSlice.reducer, + [changeBoardModalSlice.name]: changeBoardModalSlice.reducer, + [loraSlice.name]: loraSlice.reducer, + [modelManagerSlice.name]: modelManagerSlice.reducer, + [sdxlSlice.name]: sdxlSlice.reducer, + [queueSlice.name]: queueSlice.reducer, + [workflowSlice.name]: workflowSlice.reducer, + [hrfSlice.name]: hrfSlice.reducer, [api.reducerPath]: api.reducer, }; diff --git a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts index 1a3c6cfd73..cd734d3f00 100644 --- a/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts @@ -719,8 +719,6 @@ export const { scaledBoundingBoxDimensionsReset, } = canvasSlice.actions; -export default canvasSlice.reducer; - export const selectCanvasSlice = (state: RootState) => state.canvas; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts b/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts index b585b2b697..4b374b066a 100644 --- a/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts +++ b/invokeai/frontend/web/src/features/changeBoardModal/store/slice.ts @@ -5,7 +5,7 @@ import type { ImageDTO } from 'services/api/types'; import { initialState } from './initialState'; -const changeBoardModal = createSlice({ +export const changeBoardModalSlice = createSlice({ name: 'changeBoardModal', initialState, reducers: { @@ -22,8 +22,6 @@ const changeBoardModal = createSlice({ }, }); -export const { isModalOpenChanged, imagesToChangeSelected, changeBoardReset } = changeBoardModal.actions; - -export default changeBoardModal.reducer; +export const { isModalOpenChanged, imagesToChangeSelected, changeBoardReset } = changeBoardModalSlice.actions; export const selectChangeBoardModalSlice = (state: RootState) => state.changeBoardModal; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts index e037b871fd..49b07f16a1 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/controlAdaptersSlice.ts @@ -424,8 +424,6 @@ export const { controlAdapterModelCleared, } = controlAdaptersSlice.actions; -export default controlAdaptersSlice.reducer; - export const isAnyControlAdapterAdded = isAnyOf( controlAdapterAdded, controlAdapterAddedFromImage, diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts index 268602c350..9efb7c395f 100644 --- a/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts +++ b/invokeai/frontend/web/src/features/deleteImageModal/store/slice.ts @@ -5,7 +5,7 @@ import type { ImageDTO } from 'services/api/types'; import { initialDeleteImageState } from './initialState'; -const deleteImageModal = createSlice({ +export const deleteImageModalSlice = createSlice({ name: 'deleteImageModal', initialState: initialDeleteImageState, reducers: { @@ -22,8 +22,6 @@ const deleteImageModal = createSlice({ }, }); -export const { isModalOpenChanged, imagesToDeleteSelected, imageDeletionCanceled } = deleteImageModal.actions; - -export default deleteImageModal.reducer; +export const { isModalOpenChanged, imagesToDeleteSelected, imageDeletionCanceled } = deleteImageModalSlice.actions; export const selectDeleteImageModalSlice = (state: RootState) => state.deleteImageModal; diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts index cb4709b711..7bb0b29659 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts +++ b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts @@ -74,8 +74,6 @@ export const { seedBehaviourChanged, } = dynamicPromptsSlice.actions; -export default dynamicPromptsSlice.reducer; - export const selectDynamicPromptsSlice = (state: RootState) => state.dynamicPrompts; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts index 53b8527b34..f351d91339 100644 --- a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts @@ -109,8 +109,6 @@ export const { moreImagesLoaded, } = gallerySlice.actions; -export default gallerySlice.reducer; - const isAnyBoardDeleted = isAnyOf( imagesApi.endpoints.deleteBoard.matchFulfilled, imagesApi.endpoints.deleteBoardAndImages.matchFulfilled diff --git a/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts b/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts index 36eefe0ce6..4c5769550b 100644 --- a/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts +++ b/invokeai/frontend/web/src/features/hrf/store/hrfSlice.ts @@ -37,8 +37,6 @@ export const hrfSlice = createSlice({ export const { setHrfEnabled, setHrfStrength, setHrfMethod } = hrfSlice.actions; -export default hrfSlice.reducer; - export const selectHrfSlice = (state: RootState) => state.hrf; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/lora/store/loraSlice.ts b/invokeai/frontend/web/src/features/lora/store/loraSlice.ts index 2df882a1c5..b3c63f2e0f 100644 --- a/invokeai/frontend/web/src/features/lora/store/loraSlice.ts +++ b/invokeai/frontend/web/src/features/lora/store/loraSlice.ts @@ -81,8 +81,6 @@ export const { loraRecalled, } = loraSlice.actions; -export default loraSlice.reducer; - export const selectLoraSlice = (state: RootState) => state.lora; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts b/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts index 4f6c5840e7..c450e64b3c 100644 --- a/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts +++ b/invokeai/frontend/web/src/features/modelManager/store/modelManagerSlice.ts @@ -29,8 +29,6 @@ export const modelManagerSlice = createSlice({ export const { setSearchFolder, setAdvancedAddScanModel } = modelManagerSlice.actions; -export default modelManagerSlice.reducer; - export const selectModelManagerSlice = (state: RootState) => state.modelmanager; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/nodes/store/nodeTemplatesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodeTemplatesSlice.ts index ac67b19e43..c211131aab 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodeTemplatesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodeTemplatesSlice.ts @@ -9,7 +9,7 @@ export const initialNodeTemplatesState: NodeTemplatesState = { templates: {}, }; -const nodesTemplatesSlice = createSlice({ +export const nodesTemplatesSlice = createSlice({ name: 'nodeTemplates', initialState: initialNodeTemplatesState, reducers: { @@ -21,6 +21,4 @@ const nodesTemplatesSlice = createSlice({ export const { nodeTemplatesBuilt } = nodesTemplatesSlice.actions; -export default nodesTemplatesSlice.reducer; - export const selectNodeTemplatesSlice = (state: RootState) => state.nodeTemplates; diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts index e0291182b4..63d2d32360 100644 --- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts @@ -139,7 +139,7 @@ const fieldValueReducer = ( input.value = result.data; }; -const nodesSlice = createSlice({ +export const nodesSlice = createSlice({ name: 'nodes', initialState: initialNodesState, reducers: { @@ -852,8 +852,6 @@ export const isAnyNodeOrEdgeMutation = isAnyOf( edgeAdded ); -export default nodesSlice.reducer; - export const selectNodesSlice = (state: RootState) => state.nodes; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts b/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts index 7b33ee4d01..73802da54e 100644 --- a/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts +++ b/invokeai/frontend/web/src/features/nodes/store/workflowSlice.ts @@ -27,7 +27,7 @@ export const initialWorkflowState: WorkflowState = { ...blankWorkflow, }; -const workflowSlice = createSlice({ +export const workflowSlice = createSlice({ name: 'workflow', initialState: initialWorkflowState, reducers: { @@ -119,8 +119,6 @@ export const { workflowSaved, } = workflowSlice.actions; -export default workflowSlice.reducer; - export const selectWorkflowSlice = (state: RootState) => state.workflow; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 11bd656e6f..df98943cd3 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -299,8 +299,6 @@ export const { export const { selectOptimalDimension } = generationSlice.selectors; -export default generationSlice.reducer; - export const selectGenerationSlice = (state: RootState) => state.generation; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts b/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts index ee856bcb78..e014f60570 100644 --- a/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/postprocessingSlice.ts @@ -35,8 +35,6 @@ export const postprocessingSlice = createSlice({ export const { esrganModelNameChanged } = postprocessingSlice.actions; -export default postprocessingSlice.reducer; - export const selectPostprocessingSlice = (state: RootState) => state.postprocessing; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/queue/store/queueSlice.ts b/invokeai/frontend/web/src/features/queue/store/queueSlice.ts index 43baa57bb2..340dff5104 100644 --- a/invokeai/frontend/web/src/features/queue/store/queueSlice.ts +++ b/invokeai/frontend/web/src/features/queue/store/queueSlice.ts @@ -53,6 +53,4 @@ export const { resumeProcessorOnEnqueueChanged, } = queueSlice.actions; -export default queueSlice.reducer; - export const selectQueueSlice = (state: RootState) => state.queue; diff --git a/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts b/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts index b630bc7912..efa5f1c8bd 100644 --- a/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts +++ b/invokeai/frontend/web/src/features/sdxl/store/sdxlSlice.ts @@ -36,7 +36,7 @@ export const initialSDXLState: SDXLState = { refinerStart: 0.8, }; -const sdxlSlice = createSlice({ +export const sdxlSlice = createSlice({ name: 'sdxl', initialState: initialSDXLState, reducers: { @@ -86,8 +86,6 @@ export const { setRefinerStart, } = sdxlSlice.actions; -export default sdxlSlice.reducer; - export const selectSdxlSlice = (state: RootState) => state.sdxl; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/invokeai/frontend/web/src/features/system/store/configSlice.ts b/invokeai/frontend/web/src/features/system/store/configSlice.ts index 948634e41b..1cf62e89c8 100644 --- a/invokeai/frontend/web/src/features/system/store/configSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/configSlice.ts @@ -177,6 +177,4 @@ export const configSlice = createSlice({ export const { configChanged } = configSlice.actions; -export default configSlice.reducer; - export const selectConfigSlice = (state: RootState) => state.config; diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index edbfa60616..589397e951 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -194,8 +194,6 @@ export const { setShouldEnableInformationalPopovers, } = systemSlice.actions; -export default systemSlice.reducer; - const isAnyServerError = isAnyOf(socketInvocationError, socketSessionRetrievalError, socketInvocationRetrievalError); export const selectSystemSlice = (state: RootState) => state.system; diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index b5c748dafd..32eb26673a 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -57,8 +57,6 @@ export const { expanderStateChanged, } = uiSlice.actions; -export default uiSlice.reducer; - export const selectUiSlice = (state: RootState) => state.ui; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ From 32053716546abe36774d3cb78e3fdac6d491228e Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 3 Feb 2024 20:53:33 +1100 Subject: [PATCH 11/28] feat(ui): better error handling for persist serialize function --- invokeai/frontend/web/src/app/store/store.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts index 7a2b8673a2..e25e1351eb 100644 --- a/invokeai/frontend/web/src/app/store/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -109,12 +109,12 @@ const persistConfigs: { [key in keyof typeof allReducers]?: PersistConfig } = { const unserialize: UnserializeFunction = (data, key) => { const log = logger('system'); - const config = persistConfigs[key as keyof typeof persistConfigs]; - if (!config) { - throw new Error(`No unserialize config for slice "${key}"`); + const persistConfig = persistConfigs[key as keyof typeof persistConfigs]; + if (!persistConfig) { + throw new Error(`No persist config for slice "${key}"`); } try { - const { initialState, migrate } = config; + const { initialState, migrate } = persistConfig; const parsed = JSON.parse(data); // strip out old keys const stripped = pick(parsed, keys(initialState)); @@ -134,12 +134,16 @@ const unserialize: UnserializeFunction = (data, key) => { return transformed; } catch (err) { log.warn({ error: serializeError(err) }, `Error rehydrating slice "${key}", falling back to default initial state`); - return config.initialState; + return persistConfig.initialState; } }; export const serialize: SerializeFunction = (data, key) => { - const result = omit(data, persistConfigs[key as keyof typeof persistConfigs]?.persistDenylist ?? []); + const persistConfig = persistConfigs[key as keyof typeof persistConfigs]; + if (!persistConfig) { + throw new Error(`No persist config for slice "${key}"`); + } + const result = omit(data, persistConfig.persistDenylist); return JSON.stringify(result); }; From 8e500283b64f5cd182e53fb93404bf0c4438f2dd Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Sun, 4 Feb 2024 07:56:51 -0500 Subject: [PATCH 12/28] Fix broken import in checkpoint_convert (#5635) * Fix broken import in checkpoint_convert * simplify the fix --------- Co-authored-by: Lincoln Stein --- .../model_management/convert_ckpt_to_diffusers.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/invokeai/backend/model_management/convert_ckpt_to_diffusers.py b/invokeai/backend/model_management/convert_ckpt_to_diffusers.py index 1cecfb1a72..6878218f67 100644 --- a/invokeai/backend/model_management/convert_ckpt_to_diffusers.py +++ b/invokeai/backend/model_management/convert_ckpt_to_diffusers.py @@ -42,8 +42,7 @@ from diffusers.schedulers import ( PNDMScheduler, UnCLIPScheduler, ) -from diffusers.utils import is_accelerate_available, is_omegaconf_available -from diffusers.utils.import_utils import BACKENDS_MAPPING +from diffusers.utils import is_accelerate_available from picklescan.scanner import scan_file_path from transformers import ( AutoFeatureExtractor, @@ -1211,9 +1210,6 @@ def download_from_original_stable_diffusion_ckpt( if prediction_type == "v-prediction": prediction_type = "v_prediction" - if not is_omegaconf_available(): - raise ValueError(BACKENDS_MAPPING["omegaconf"][1]) - if from_safetensors: from safetensors.torch import load_file as safe_load @@ -1647,11 +1643,6 @@ def download_controlnet_from_original_ckpt( cross_attention_dim: Optional[bool] = None, scan_needed: bool = False, ) -> DiffusionPipeline: - if not is_omegaconf_available(): - raise ValueError(BACKENDS_MAPPING["omegaconf"][1]) - - from omegaconf import OmegaConf - if from_safetensors: from safetensors import safe_open From 4a886c0a4ab9c87dba490c1e4163c6b4daa444e4 Mon Sep 17 00:00:00 2001 From: Wubbbi Date: Sun, 4 Feb 2024 18:21:34 +0100 Subject: [PATCH 13/28] Minor dep updates --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ee55720283..b2505ffe97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ dependencies = [ "clip_anytorch==2.5.2", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip", "compel==2.0.2", "controlnet-aux==0.0.7", - "diffusers[torch]==0.26.0", + "diffusers[torch]==0.26.1", "invisible-watermark==0.2.0", # needed to install SDXL base and refiner using their repo_ids "mediapipe==0.10.7", # needed for "mediapipeface" controlnet model "numpy==1.26.3", # >1.24.0 is needed to use the 'strict' argument to np.testing.assert_array_equal() @@ -57,7 +57,7 @@ dependencies = [ # Core application dependencies, pinned for reproducible builds. "fastapi-events==0.10.0", "fastapi==0.108.0", - "huggingface-hub==0.20.2", + "huggingface-hub==0.20.3", "pydantic-settings==2.1.0", "pydantic==2.5.3", "python-socketio==5.11.0", From feb4a3f2425180efa160623936031df4ecd3af1e Mon Sep 17 00:00:00 2001 From: Mehrab Poladov Date: Sun, 4 Feb 2024 22:30:20 +0100 Subject: [PATCH 14/28] translationBot(ui): update translation (Azerbaijani) Currently translated at 0.1% (1 of 1433 strings) translationBot(ui): added translation (Azerbaijani) Co-authored-by: Mehrab Poladov Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/az/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/az.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 invokeai/frontend/web/public/locales/az.json diff --git a/invokeai/frontend/web/public/locales/az.json b/invokeai/frontend/web/public/locales/az.json new file mode 100644 index 0000000000..54c65ff291 --- /dev/null +++ b/invokeai/frontend/web/public/locales/az.json @@ -0,0 +1,5 @@ +{ + "accessibility": { + "about": "Haqqında" + } +} From 067cd4dc2e8a1b0a297f16d788da8e83337f8ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Sarp=20Sel=C3=A7ok?= Date: Sun, 4 Feb 2024 22:30:20 +0100 Subject: [PATCH 15/28] translationBot(ui): update translation (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 40.6% (582 of 1433 strings) translationBot(ui): update translation (Turkish) Currently translated at 38.8% (557 of 1433 strings) Co-authored-by: Ufuk Sarp Selçok Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/tr/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/tr.json | 110 +++++++++++++++---- 1 file changed, 90 insertions(+), 20 deletions(-) diff --git a/invokeai/frontend/web/public/locales/tr.json b/invokeai/frontend/web/public/locales/tr.json index fae92daa3a..b023bb8ab6 100644 --- a/invokeai/frontend/web/public/locales/tr.json +++ b/invokeai/frontend/web/public/locales/tr.json @@ -2,7 +2,7 @@ "accessibility": { "invokeProgressBar": "Invoke durum çubuğu", "nextImage": "Sonraki Görsel", - "useThisParameter": "Bu ayarları kullan", + "useThisParameter": "Bu seçenekleri kullan", "copyMetadataJson": "Üstveriyi kopyala (JSON)", "exitViewer": "Görüntüleyiciden Çık", "zoomIn": "Yakınlaştır", @@ -11,7 +11,7 @@ "rotateClockwise": "Saat yönüne döndür", "flipHorizontally": "Yatay Çevir", "flipVertically": "Dikey Çevir", - "modifyConfig": "Ayarları Değiştir", + "modifyConfig": "Yapılandırmayı Değiştir", "toggleAutoscroll": "Otomatik kaydırmayı Aç-Kapat", "toggleLogViewer": "Günlüğü Aç-Kapat", "showOptionsPanel": "Yan Paneli Göster", @@ -33,7 +33,7 @@ "reportBugLabel": "Sorun Bildir", "githubLabel": "Github", "discordLabel": "Discord", - "settingsLabel": "Ayarlar", + "settingsLabel": "Seçenekler", "langArabic": "Arapça", "langEnglish": "İngilizce", "langDutch": "Hollandaca", @@ -59,7 +59,7 @@ "langKorean": "Korece", "unifiedCanvas": "Tuval", "nodesDesc": "Görsel oluşturmaya yardımcı çizge tabanlı sistem şimdilik geliştirme aşamasındadır. Bu süper özellik hakkındaki gelişmeler için kulağınız bizde olsun.", - "postProcessDesc1": "Invoke AI birçok rötuş (post-process) aracı sağlar. Görsel büyütme ve yüz iyileştirme WebUI üzerinden kullanıma uygun durumdadır. Bunlara Yazıdan Görsel ve Görselden Görsel sekmelerindeki Gelişmiş Ayarlar menüsünden ulaşabilirsiniz. Ayrıca var olan görseli üzerindeki düğmeler yardımıyla düzenleyebilirsiniz.", + "postProcessDesc1": "Invoke AI birçok rötuş (post-process) aracı sağlar. Görsel büyütme ve yüz iyileştirme WebUI üzerinden kullanıma uygun durumdadır. Bunlara Yazıdan Görsel ve Görselden Görsel sekmelerindeki Gelişmiş Seçenekler menüsünden ulaşabilirsiniz. Ayrıca var olan görseli üzerindeki düğmeler yardımıyla düzenleyebilirsiniz.", "batch": "Toplu İş Yöneticisi", "accept": "Onayla", "cancel": "Vazgeç", @@ -68,7 +68,7 @@ "on": "Açık", "or": "ya da", "aboutDesc": "Invoke'u iş için mi kullanıyorsunuz? Şuna bir göz atın:", - "advancedOptions": "Gelişmiş Ayarlar", + "advancedOptions": "Gelişmiş Seçenekler", "ai": "yapay zeka", "close": "Kapat", "auto": "Otomatik", @@ -153,7 +153,11 @@ "input": "Giriş", "copy": "Kopyala", "created": "Yaratma", - "updated": "Güncelleme" + "updated": "Güncelleme", + "ipAdapter": "IP Aracı", + "t2iAdapter": "T2I Aracı", + "controlAdapter": "Yönetim Aracı", + "controlNet": "ControlNet" }, "accordions": { "generation": { @@ -173,7 +177,9 @@ "infillTab": "Doldurma" }, "control": { - "ipTab": "Görsel İstemleri" + "ipTab": "Görsel İstemleri", + "title": "Yönetim", + "controlAdaptersTab": "Yönetim Araçları" } }, "boards": { @@ -221,7 +227,7 @@ "none": "Hiçbiri", "noneDescription": "Hiçbir işlem uygulanmamış", "selectModel": "Model seçin", - "showAdvanced": "Gelişmiş Ayarları Göster", + "showAdvanced": "Gelişmiş Seçenekleri Göster", "controlNetT2IMutexDesc": "$t(common.controlNet) ve $t(common.t2iAdapter)'nün birlikte kullanımı şimdilik desteklenmiyor.", "canny": "Canny", "colorMapDescription": "Görselden renk haritası oluşturur", @@ -245,7 +251,49 @@ "importMaskFromCanvas": "Tuvalden Maskeyi İçe Aktar", "lowThreshold": "Alt Eşik", "base": "Taban", - "depthAnythingDescription": "Depth Anything yöntemi ile derinlik haritası oluşturma" + "depthAnythingDescription": "Depth Anything yöntemi ile derinlik haritası oluşturma", + "controlAdapter_one": "Yönetim Aracı", + "controlAdapter_other": "Yönetim Aracı", + "beginEndStepPercent": "Başlangıç / Bitiş Yüzdesi", + "control": "Yönetim", + "controlnet": "{{number}}. $t(controlnet.controlAdapter_one) ($t(common.controlNet))", + "amult": "a_mult", + "hideAdvanced": "Gelişmiş Seçenekleri Gizle", + "enableControlnet": "ControlNet'i Etkinleştir", + "hed": "HED", + "ip_adapter": "{{number}}. $t(controlnet.controlAdapter_one) ($t(common.ipAdapter))", + "t2i_adapter": "{{number}}. $t(controlnet.controlAdapter_one) ($t(common.t2iAdapter))", + "autoConfigure": "Aracı otomatik yapılandır", + "bgth": "bg_th", + "coarse": "İri", + "controlMode": "Yönetim Kipi", + "depthAnything": "Depth Anything", + "hedDescription": "Holistically-Nested Edge Detection (Bütünsel Yuvalanmış Kenar Tespiti)", + "lineartAnime": "Çizim (Anime)", + "lineartAnimeDescription": "Anime stili çizim işleme", + "minConfidence": "Özgüven Alt Limiti", + "pidiDescription": "PIDI görsel işleme", + "mediapipeFace": "Mediapipe Yüz", + "megaControl": "Aşırı Yönetim", + "mlsd": "M-LSD", + "openPoseDescription": "Openpose kullanarak poz belirleme", + "setControlImageDimensions": "Yönetim Görseli Boyutlarını En/Boydan Al", + "pidi": "PIDI", + "scribble": "çiziktirme", + "ipAdapterModel": "Araç Modeli", + "resetIPAdapterImage": "IP Aracı Görselini Kaldır", + "mediapipeFaceDescription": "Mediapipe kullanarak yüz algılama", + "saveControlImage": "Yönetim Görselini Kaydet", + "w": "En", + "lineartDescription": "Görseli çizime çevirir", + "maxFaces": "Yüz Üst Limiti", + "mlsdDescription": "Minimalist Line Segment Detector (Kolay Çizgi Parçası Algılama)", + "normalBae": "Normal BAE", + "normalBaeDescription": "Normal BAE işleme", + "openPose": "Openpose", + "resetControlImage": "Yönetim Görselini Kaldır", + "enableIPAdapter": "IP Aracını Etkinleştir", + "lineart": "Çizim" }, "queue": { "queuedCount": "{{pending}} Sırada", @@ -331,7 +379,7 @@ "unstarImage": "Yıldızı Kaldır", "uploads": "Yüklemeler", "problemDeletingImagesDesc": "Bir ya da daha çok görsel silinemedi", - "gallerySettings": "Galeri Ayarları", + "gallerySettings": "Galeri Düzeni", "image": "görsel", "galleryImageSize": "Görsel Boyutu", "allImagesLoaded": "Tüm Görseller Yüklendi", @@ -394,8 +442,8 @@ "title": "Çalışma Alanını Genişlet" }, "pinOptions": { - "desc": "Ayar panelini iğnele", - "title": "Ayarları İğnele" + "desc": "Seçenekler panelini iğnele", + "title": "Seçenekleri İğnele" }, "nodesHotkeys": "Çizgeler", "quickToggleMove": { @@ -500,8 +548,8 @@ "title": "Silgiyi Kullan" }, "toggleOptions": { - "desc": "Ayarlar panelini aç-kapat", - "title": "Ayarları Aç-Kapat" + "desc": "Seçenekler panelini aç-kapat", + "title": "Seçenekleri Aç-Kapat" }, "copyToClipboard": { "desc": "Tuval içeriğini kopyala", @@ -534,8 +582,8 @@ "title": "Önceki Görsel" }, "toggleOptionsAndGallery": { - "title": "Ayarları ve Galeriyi Aç-Kapat", - "desc": "Ayarlar ve galeri panellerini aç-kapat" + "title": "Seçenekleri ve Galeriyi Aç-Kapat", + "desc": "Seçenekler ve galeri panellerini aç-kapat" }, "toggleSnap": { "desc": "Kılavuza Uydur", @@ -554,8 +602,8 @@ "desc": "Tuval fırçasının/silgisinin boyutunu düşürür" }, "resetOptionsAndGallery": { - "desc": "Ayarlar ve galeri panellerini resetler", - "title": "Ayarları ve Galeriyi Resetle" + "desc": "Seçenekler ve galeri panellerini resetler", + "title": "Seçenekleri ve Galeriyi Resetle" }, "remixImage": { "desc": "Seçili görselin tohumu hariç tüm değişkenlerini kullan", @@ -606,7 +654,7 @@ "currentImageDescription": "İşlemdeki görseli Çizge Düzenleyicide gösterir", "workflowAuthor": "Yaratıcı", "workflowName": "Ad", - "workflowSettings": "İş Akışı Düzenleyici Ayarları", + "workflowSettings": "İş Akışı Düzenleyici Seçenekleri", "currentImage": "İşlemdeki Görsel", "noWorkflow": "İş Akışı Yok", "newWorkflowDesc": "Yeni iş akışı?", @@ -663,7 +711,26 @@ } }, "modelManager": { - "baseModel": "Ana Model" + "baseModel": "Ana Model", + "addManually": "Kendin Ekle", + "addNew": "Yeni Ekle", + "active": "etkin", + "addSelected": "Seçilenleri Ekle", + "addNewModel": "Yeni Model Ekle", + "configFile": "Yapılandırma Dosyası", + "deleteConfig": "Yapılandırmayı Sil", + "availableModels": "Kullanılabilir Modeller", + "customConfigFileLocation": "Özel Yapılandırma Dosyası Yeri", + "advanced": "Gelişmiş", + "allModels": "Tüm Modeller", + "alpha": "Alfa", + "configValidationMsg": "Modelin yapılandırma dosyasının yeri.", + "cannotUseSpaces": "Boşluk Kullanılamaz", + "config": "Yapılandırma", + "pathToCustomConfig": "Özel Yapılandırma Yeri", + "customConfig": "Özel Yapılandırma", + "addModel": "Model Ekle", + "useCustomConfig": "Özel Yapılandırma Kullan" }, "dynamicPrompts": { "loading": "Devimsel İstemler Oluşturuluyor...", @@ -674,5 +741,8 @@ }, "settings": { "generation": "Oluşturma" + }, + "metadata": { + "cfgScale": "" } } From 804dbeba347587c73a165cca1fba22b2cbba2b9e Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sun, 4 Feb 2024 22:30:21 +0100 Subject: [PATCH 16/28] translationBot(ui): update translation files Updated by "Remove blank strings" hook in Weblate. Co-authored-by: Hosted Weblate Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/tr.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/invokeai/frontend/web/public/locales/tr.json b/invokeai/frontend/web/public/locales/tr.json index b023bb8ab6..b4603e6f2d 100644 --- a/invokeai/frontend/web/public/locales/tr.json +++ b/invokeai/frontend/web/public/locales/tr.json @@ -741,8 +741,5 @@ }, "settings": { "generation": "Oluşturma" - }, - "metadata": { - "cfgScale": "" } } From 209bf105bcb51320d3c5ab440103f98bca2a4eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Sarp=20Sel=C3=A7ok?= Date: Sun, 4 Feb 2024 22:30:21 +0100 Subject: [PATCH 17/28] translationBot(ui): update translation (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 57.3% (822 of 1433 strings) Co-authored-by: Ufuk Sarp Selçok Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/tr/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/tr.json | 288 +++++++++++++++++-- 1 file changed, 271 insertions(+), 17 deletions(-) diff --git a/invokeai/frontend/web/public/locales/tr.json b/invokeai/frontend/web/public/locales/tr.json index b4603e6f2d..39c0313ba3 100644 --- a/invokeai/frontend/web/public/locales/tr.json +++ b/invokeai/frontend/web/public/locales/tr.json @@ -246,7 +246,7 @@ "fill": "Doldur", "highThreshold": "Üst Eşik", "imageResolution": "Görsel Çözünürlüğü", - "colorMapTileSize": "Karo Boyutu", + "colorMapTileSize": "Döşeme Boyutu", "importImageFromCanvas": "Tuvaldeki Görseli Al", "importMaskFromCanvas": "Tuvalden Maskeyi İçe Aktar", "lowThreshold": "Alt Eşik", @@ -285,7 +285,7 @@ "mediapipeFaceDescription": "Mediapipe kullanarak yüz algılama", "saveControlImage": "Yönetim Görselini Kaydet", "w": "En", - "lineartDescription": "Görseli çizime çevirir", + "lineartDescription": "Görseli çizime dönüştürür", "maxFaces": "Yüz Üst Limiti", "mlsdDescription": "Minimalist Line Segment Detector (Kolay Çizgi Parçası Algılama)", "normalBae": "Normal BAE", @@ -293,7 +293,8 @@ "openPose": "Openpose", "resetControlImage": "Yönetim Görselini Kaldır", "enableIPAdapter": "IP Aracını Etkinleştir", - "lineart": "Çizim" + "lineart": "Çizim", + "ipAdapterImageFallback": "IP Aracı Görseli Seçilmemiş" }, "queue": { "queuedCount": "{{pending}} Sırada", @@ -352,7 +353,9 @@ "batchQueued": "Toplu İş Sıraya Alındı", "notReady": "Sıraya Alınamadı", "batchFieldValues": "Toplu İş Değişkenleri", - "queueMaxExceeded": "Sıra sınırı {{max_queue_size}} aşıldı, {{skip}} atlanıyor" + "queueMaxExceeded": "Sıra sınırı {{max_queue_size}} aşıldı, {{skip}} atlanıyor", + "graphFailedToQueue": "Çizge sıraya alınamadı", + "graphQueued": "Çizge sıraya alındı" }, "invocationCache": { "cacheSize": "Önbellek Boyutu", @@ -397,13 +400,16 @@ "singleColumnLayout": "Tek Sütun Düzen", "generations": "Çıktılar", "showUploads": "Yüklenenleri Göster", - "showGenerations": "Çıktıları Göster" + "showGenerations": "Çıktıları Göster", + "dropOrUpload": "$t(gallery.drop) ya da Yükle", + "dropToUpload": "Yüklemek için $t(gallery.drop)", + "drop": "Bırak" }, "hrf": { "hrf": "Yüksek Çözünürlük Kürü", "enableHrf": "Yüksek Çözünürlük Kürünü Aç", - "hrfStrength": "Yüksek Çözünürlük Kürü Etkisi", - "strengthTooltip": "Düşük değerler daha az detaya neden olsa da olası bozuklukları önleyebilir.", + "hrfStrength": "Yüksek Çözünürlük Kürü Ölçüsü", + "strengthTooltip": "Düşük değerler daha az ayrıntıya neden olsa da olası bozuklukları önleyebilir.", "metadata": { "enabled": "Yüksek Çözünürlük Kürü Açık", "strength": "Yüksek Çözünürlük Kürü Etkisi", @@ -438,7 +444,7 @@ "desc": "Galerideki sonraki görseli göster" }, "maximizeWorkSpace": { - "desc": "Panelleri kapat ve çalışma alanını genişlet", + "desc": "Panelleri kapatıp çalışma alanını genişlet", "title": "Çalışma Alanını Genişlet" }, "pinOptions": { @@ -629,6 +635,10 @@ "selectBrush": { "desc": "Tuval fırçasını kullan", "title": "Fırçayı Kullan" + }, + "restoreFaces": { + "title": "Yüzleri Onar", + "desc": "Geçerli görseli onar" } }, "embedding": { @@ -665,7 +675,22 @@ "unableToGetWorkflowVersion": "İş akışı sürümüne ulaşılamadı", "unrecognizedWorkflowVersion": "Tanınmayan iş akışı sürümü {{version}}", "newWorkflowDesc2": "Geçerli iş akışında kaydedilmemiş değişiklikler var.", - "unableToLoadWorkflow": "İş Akışı Yüklenemedi" + "unableToLoadWorkflow": "İş Akışı Yüklenemedi", + "boardField": "Pano", + "boardFieldDescription": "Galeri panosu", + "booleanCollection": "Boole Değeri Yığını", + "booleanCollectionDescription": "Bir yığın boole değeri.", + "booleanDescription": "Boole değerleri doğru ya da yanlıştır.", + "cannotConnectInputToInput": "Giriş girişe bağlanamaz", + "zoomInNodes": "Yakınlaştır", + "boolean": "Boole Değeri", + "edge": "Uç", + "zoomOutNodes": "Uzaklaştır", + "cannotConnectOutputToOutput": "Çıkış çıkışa bağlanamaz", + "colorField": "Renk", + "colorFieldDescription": "RGBA rengi.", + "cannotConnectToSelf": "Kendisine bağlanamaz", + "cannotDuplicateConnection": "Kopya bağlantılar yaratılamaz" }, "workflows": { "searchWorkflows": "İş Akışlarında Ara", @@ -707,8 +732,115 @@ }, "parameters": { "invoke": { - "noPrompts": "İstem oluşturulmadı" - } + "noPrompts": "İstem oluşturulmadı", + "systemBusy": "Sistem kullanımda", + "noModelSelected": "Model seçilmedi", + "incompatibleBaseModelForControlAdapter": "{{number}}. yönetim aracı, ana model ile uyumlu değil.", + "systemDisconnected": "Sistem bağlantısı kesildi", + "invoke": "Invoke" + }, + "clipSkip": "CLIP Atlama", + "randomizeSeed": "Rastgele Tohum", + "cfgScale": "CFG Ölçeği", + "coherenceStrength": "Etki", + "controlNetControlMode": "Yönetim Kipi", + "general": "Genel", + "img2imgStrength": "Görselden Görsel Ölçüsü", + "seamlessYAxis": "Dikişsiz Döşeme Y Ekseni", + "seamLowThreshold": "Alt", + "isAllowedToUpscale": { + "tooLarge": "Görsel, büyütme işlemi için çok büyük, daha küçük bir boyut seçin", + "useX2Model": "Görsel 4 kat büyütme işlemi için çok geniş, 2 kat büyütmeyi kullanın" + }, + "maskAdjustmentsHeader": "Maske Düzenleme", + "maskBlur": "Bulandırma", + "aspectRatio": "En-Boy Oranı", + "images": "Görseller", + "hidePreview": "Önizlemeyi Gizle", + "info": "Bilgi", + "positivePromptPlaceholder": "Olumlu İstem", + "scaledHeight": "Ölçekli Boy", + "aspectRatioFree": "Serbest", + "lockAspectRatio": "En-Boy Oranını Koru", + "swapDimensions": "Çevir", + "setToOptimalSize": "Modele göre en uygun boyut", + "copyImage": "Görseli Kopyala", + "faceRestoration": "Yüz Onarma", + "gaussianBlur": "Çan Eğrisi Bulanıklık", + "height": "Boy", + "imageSize": "Görsel Boyutu", + "initialImage": "Öngörsel", + "otherOptions": "Diğer Seçenekler", + "manualSeed": "Özel Tohum", + "randomSeed": "Rastgele Tohum", + "seamCorrectionHeader": "Dikiş Düzeltme", + "width": "En", + "showPreview": "Önizlemeyi Göster", + "upscale": "Büyüt (Shift + U)", + "unmasked": "Maskesiz", + "useSize": "Boyutu Kullan", + "boundingBoxWidth": "Sınırlayıcı Kutu Eni", + "boundingBoxHeight": "Sınırlayıcı Kutu Boyu", + "boundingBoxHeader": "Sınırlayıcı Kutu", + "imageToImage": "Görselden Görsel", + "seamlessY": "Dikişsiz Y", + "seamlessX&Y": "Dikişsiz X & Y", + "seedWeights": "Tohum Ağırlıkları", + "symmetry": "Bakışım", + "tileSize": "Döşeme Boyutu", + "strength": "Güç", + "gpuNoise": "GPU Gürültüsü", + "useAll": "Hepsini Kullan", + "boxBlur": "Kutu Bulanıklık", + "clipSkipWithLayerCount": "CLIP Atla {{layerCount}}", + "denoisingStrength": "Arındırma Ölçüsü", + "imageFit": "Öngörseli Çıktı Boyutuna Sığdır", + "maskEdge": "Maske Kenarı", + "noiseThreshold": "Gürültü Eşiği", + "openInViewer": "Görüntüleyicide Aç", + "seed": "Tohum", + "imageActions": "Görsel İşlemleri", + "sendTo": "Şuraya Aktar", + "sendToImg2Img": "Görselden Görsele Aktar", + "sendToUnifiedCanvas": "Tuvale Aktar", + "showOptionsPanel": "Yan Paneli Göster (O ya da T)", + "shuffle": "Kar", + "usePrompt": "İstemi Kullan", + "upscaleImage": "Görseli Büyüt", + "setToOptimalSizeTooSmall": "$t(parameters.setToOptimalSize) (çok küçük olabilir)", + "setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (çok büyük olabilir)", + "cfgRescaleMultiplier": "CFG Rescale Çarpanı", + "cfgRescale": "CFG Rescale", + "coherencePassHeader": "Uyum Geçişi", + "coherenceSteps": "Adım", + "infillMethod": "Doldurma Yöntemi", + "maskBlurMethod": "Bulandırma Yöntemi", + "steps": "Adım", + "upscaling": "Büyütülüyor", + "cpuNoise": "CPU Gürültüsü", + "useSeed": "Tohumu Kullan", + "vSymmetryStep": "Dikey Bakışım Adımı", + "compositingSettingsHeader": "Birleştirme Seçenekleri", + "cancel": { + "cancel": "" + }, + "infillScalingHeader": "Doldurma ve Ölçek", + "scheduler": "Planlayıcı", + "coherenceMode": "Kip", + "closeViewer": "Görüntüleyiciyi Kapat", + "restoreFaces": "Yüzleri Onar", + "useCpuNoise": "CPU Gürültüsü Kullan", + "negativePromptPlaceholder": "Olumsuz İstem", + "patchmatchDownScaleSize": "Küçült", + "perlinNoise": "Perlin Gürültüsü", + "scaledWidth": "Ölçekli En", + "seamHighThreshold": "Üst", + "seamlessTiling": "Dikişsiz Döşeme", + "seamlessXAxis": "Dikişsiz Döşeme X Ekseni", + "downloadImage": "Görseli İndir", + "seamlessX": "Dikişsiz X", + "noiseSettings": "Gürültü", + "type": "Tür" }, "modelManager": { "baseModel": "Ana Model", @@ -720,26 +852,148 @@ "configFile": "Yapılandırma Dosyası", "deleteConfig": "Yapılandırmayı Sil", "availableModels": "Kullanılabilir Modeller", - "customConfigFileLocation": "Özel Yapılandırma Dosyası Yeri", + "customConfigFileLocation": "Özel Yapılandırma Dosyası Konumu", "advanced": "Gelişmiş", "allModels": "Tüm Modeller", "alpha": "Alfa", "configValidationMsg": "Modelin yapılandırma dosyasının yeri.", "cannotUseSpaces": "Boşluk Kullanılamaz", "config": "Yapılandırma", - "pathToCustomConfig": "Özel Yapılandırma Yeri", + "pathToCustomConfig": "Özel Yapılandırma Konumu", "customConfig": "Özel Yapılandırma", "addModel": "Model Ekle", - "useCustomConfig": "Özel Yapılandırma Kullan" + "useCustomConfig": "Özel Yapılandırma Kullan", + "height": "Boy", + "modelsMergeFailed": "Model Birleştirme Başarısız", + "mergedModelName": "Birleşmiş Model Adı", + "mergedModelSaveLocation": "Saklama Yeri", + "mergeModels": "Modelleri Birleştir", + "modelDeleted": "Model Kaldırıldı", + "notLoaded": "yüklü değil", + "selectAndAdd": "Aşağıda Gösterilen Modellerden Seçin ve Ekleyin", + "v1": "v1", + "vaePrecision": "VAE Kesinliği", + "weightedSum": "Ağırlıklı Toplam", + "convertToDiffusersHelpText6": "Bu modeli dönüştürmek istiyor musunuz?", + "modelAdded": "Model Eklendi", + "modelThree": "3. Model", + "deleteMsg1": "Bu modeli InvokeAI'dan silmek istediğinize emin misiniz?", + "customSaveLocation": "Özel Saklama Konumu", + "formMessageDiffusersModelLocationDesc": "En az bir tane girin.", + "findModels": "Model Bul", + "importModels": "Modelleri İçe Aktar", + "inpainting": "v1 İçboyama", + "invokeRoot": "InvokeAI klasörü", + "modelSyncFailed": "Modeller Senkronize Edilemedi", + "modelOne": "1. Model", + "modelsFound": "Bulunan Modeller", + "modelsMerged": "Modeller Birleştirildi", + "noModelsFound": "Model Bulunamadı", + "quickAdd": "Hızlıca Ekle", + "settings": "Seçenekler", + "syncModelsDesc": "Modelleriniz arka uçla senkronize değilse bu tuşa basarak yenileyebilirsiniz. Uygulama başladıktan sonra kendiniz models.yaml dosyasını güncellediğinizde ya da InvokeAI ana klasörüne model eklediğinizde kullanışlıdır.", + "v2_768": "v2 (768pks)", + "vae": "VAE", + "width": "En", + "delete": "Sil", + "convert": "Dönüştür", + "formMessageDiffusersVAELocation": "VAE konumu", + "deselectAll": "Seçimi Kaldır", + "syncModels": "Modelleri Senkronize Et", + "variant": "Tür", + "widthValidationMsg": "Modelinizin varsayılan eni.", + "custom": "Özel", + "closeAdvanced": "Gelişmiş Seçenekleri Kapat", + "convertingModelBegin": "Model Dönüştürülüyor. Lütfen bekleyiniz.", + "none": "hiçbiri", + "pickModelType": "Model Türü Seçin", + "search": "Ara", + "formMessageDiffusersVAELocationDesc": "VAE konumu girilmezse InvokeAI yukarıda girilen model konumunu arayacaktır.", + "heightValidationMsg": "Modelinizin varsayılan boyu.", + "interpolationType": "Aradeğerleme Türü", + "mergedModelCustomSaveLocation": "Özel Konum", + "model": "Model", + "modelEntryDeleted": "Model Girdisi Kaldırıldı", + "modelMergeHeaderHelp1": "Üç ayrı modeli birleştirip isteğinize uygun yeni bir karışım yaratabilirsiniz.", + "modelTwo": "2. Model", + "modelType": "Model Türü", + "modelUpdated": "Model Güncellendi", + "modelUpdateFailed": "Model Güncellenemedi", + "name": "Ad", + "noCustomLocationProvided": "Özel Konum Belirtilmedi", + "noModels": "Model Yok", + "sameFolder": "Aynı klasör", + "scanAgain": "Yeniden Tara", + "selectAll": "Hepsini Seç", + "selected": "Seçili", + "convertToDiffusersHelpText5": "Lütfen yeterli depolama alanınız olduğundan emin olun. Modeller çoğunlukla 2-7 GB boyutundadır.", + "modelLocation": "Model Konumu", + "modelManager": "Model Yöneticisi", + "modelMergeInterpAddDifferenceHelp": "Bu kipte ilk olarak 3. model 2. modelden çıkarılır. Bu sonuç, yukarıda belirlenen alfa değerine göre 1. model ile birleştirilir.", + "updateModel": "Modeli Güncelle", + "vaeLocation": "VAE Konumu", + "convertToDiffusersHelpText4": "Bu işlem yalnızca bir kez yapılır, bilgisayarınızın özelliklerine bağlı olarak yaklaşık 30-60 saniye sürebilir.", + "convertToDiffusersSaveLocation": "Saklama Yeri", + "deleteModel": "Modeli Sil", + "deleteMsg2": "Model InvokeAI ana klasöründeyse bilgisayarınızdan silinir, bu klasör dışındaysa bilgisayarınızdan silinmeyecektir.", + "descriptionValidationMsg": "Modeliniz için bir tanım girin", + "invokeAIFolder": "Invoke AI Klasörü", + "load": "Yükle", + "modelDeleteFailed": "Model kaldırılamadı", + "loraModels": "LoRAlar", + "modelsSynced": "Modeller Senkronize Edildi", + "noModelSelected": "Model Seçilmedi", + "predictionType": "Saptama Türü", + "selectFolder": "Klasör Seç", + "selectModel": "Model Seç", + "showExisting": "Var Olanları Göster", + "v2_base": "v2 (512pks)", + "conversionNotSupported": "Dönüşüm Desteklenmiyor", + "cached": "önbellekte", + "modelConversionFailed": "Model Dönüşümü Başarısız", + "modelConverted": "Model Dönüştürüldü", + "modelExists": "Model Var", + "modelMergeAlphaHelp": "Alfa, karışım şiddetini belirler. Düşük alfa değerleri, ikinci modelin etkisini azaltır.", + "scanForModels": "Modelleri Tara", + "ignoreMismatch": "Seçilen Modeller Arasındaki Uyumsuzluğu Yoksay", + "merge": "Birleştir", + "description": "Tanım", + "nameValidationMsg": "Modelinize bir ad verin", + "statusConverting": "Dönüştürülüyor", + "vaeLocationValidationMsg": "VAE dosyası konumu." }, "dynamicPrompts": { - "loading": "Devimsel İstemler Oluşturuluyor...", - "combinatorial": "Birleşimsel Oluşturma" + "loading": "", + "combinatorial": "Birleşimsel Oluşturma", + "promptsWithCount_one": "{{count}} İstem", + "promptsWithCount_other": "{{count}} İstem" }, "models": { - "incompatibleBaseModel": "Uyumsuz ana model" + "incompatibleBaseModel": "Uyumsuz ana model", + "selectLoRA": "LoRA Seçin", + "addLora": "LoRA Ekle", + "esrganModel": "ESRGAN Modeli", + "defaultVAE": "Varsayılan VAE", + "lora": "LoRA", + "noMainModelSelected": "Ana model seçilmedi", + "noLoRAsAvailable": "LoRA yok", + "noLoRAsLoaded": "LoRA Yok", + "noModelsAvailable": "Model yok", + "noMatchingLoRAs": "Uygun LoRA Yok", + "noMatchingModels": "Uygun Model Yok", + "allLoRAsAdded": "Tüm LoRAlar eklendi", + "loraAlreadyAdded": "LoRA yüklü", + "loading": "yükleniyor", + "selectModel": "Model Seçin", + "noLoRAsInstalled": "LoRA Yok" }, "settings": { "generation": "Oluşturma" + }, + "sdxl": { + "cfgScale": "CFG Ölçeği" + }, + "metadata": { + "cfgScale": "" } } From 87ff96553a6c00b1a54dacc5ea91942de74ef824 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sun, 4 Feb 2024 22:30:21 +0100 Subject: [PATCH 18/28] translationBot(ui): update translation files Updated by "Remove blank strings" hook in Weblate. Co-authored-by: Hosted Weblate Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/tr.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/invokeai/frontend/web/public/locales/tr.json b/invokeai/frontend/web/public/locales/tr.json index 39c0313ba3..fa52a5ccde 100644 --- a/invokeai/frontend/web/public/locales/tr.json +++ b/invokeai/frontend/web/public/locales/tr.json @@ -821,9 +821,6 @@ "useSeed": "Tohumu Kullan", "vSymmetryStep": "Dikey Bakışım Adımı", "compositingSettingsHeader": "Birleştirme Seçenekleri", - "cancel": { - "cancel": "" - }, "infillScalingHeader": "Doldurma ve Ölçek", "scheduler": "Planlayıcı", "coherenceMode": "Kip", @@ -963,7 +960,6 @@ "vaeLocationValidationMsg": "VAE dosyası konumu." }, "dynamicPrompts": { - "loading": "", "combinatorial": "Birleşimsel Oluşturma", "promptsWithCount_one": "{{count}} İstem", "promptsWithCount_other": "{{count}} İstem" @@ -992,8 +988,5 @@ }, "sdxl": { "cfgScale": "CFG Ölçeği" - }, - "metadata": { - "cfgScale": "" } } From 8a61063e8400738b18c9c1456a1b9d2bd7f1356c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Sarp=20Sel=C3=A7ok?= Date: Sun, 4 Feb 2024 22:30:21 +0100 Subject: [PATCH 19/28] translationBot(ui): update translation (Turkish) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 57.5% (825 of 1433 strings) Co-authored-by: Ufuk Sarp Selçok Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/tr/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/tr.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/public/locales/tr.json b/invokeai/frontend/web/public/locales/tr.json index fa52a5ccde..ebff991d63 100644 --- a/invokeai/frontend/web/public/locales/tr.json +++ b/invokeai/frontend/web/public/locales/tr.json @@ -987,6 +987,9 @@ "generation": "Oluşturma" }, "sdxl": { - "cfgScale": "CFG Ölçeği" + "cfgScale": "CFG Ölçeği", + "loading": "Yükleniyor...", + "denoisingStrength": "Arındırma Ölçüsü", + "concatPromptStyle": "İstem ve Stili Bitiştir" } } From ce3d37e829ace9c14545217962ebcca8321ce832 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:09:01 +1100 Subject: [PATCH 20/28] fix(ui): handle fields with single option literal Closes #5616 Turns out the OpenAPI schema definition for a pydantic field with a `Literal` type annotation is different depending on the number of options. When there is a single value (e.g. `Literal["foo"]`, this results in a `const` schema object. The schema parser didn't know how to handle this, and displayed a warning in the JS console. This situation is now handled. When a `const` schema object is encountered, we interpret that as an `EnumField` with a single option. I think this makes sense - if you had a truly constant value, you wouldn't make it a field, so a `const` must mean a dynamically generated enum that ended up with only a single option. --- .../features/nodes/util/schema/buildFieldInputTemplate.ts | 2 ++ .../web/src/features/nodes/util/schema/parseFieldType.ts | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts index b2ada08368..3e8278ea6a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/buildFieldInputTemplate.ts @@ -373,6 +373,8 @@ const buildEnumFieldInputTemplate: FieldInputTemplateBuilder Date: Sun, 4 Feb 2024 17:22:50 +1100 Subject: [PATCH 21/28] fix(ui): do not swallow errors during schema parsing Unknown errors were swallowed during schema parsing. Now they log a warning. --- .../features/nodes/util/schema/parseSchema.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts index cc7f6e040b..696e371ea6 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts @@ -124,6 +124,20 @@ export const parseSchema = ( message: e.message, }) ); + } else { + logger('nodes').warn( + { + node: type, + field: propertyName, + schema: parseify(property), + error: serializeError(e), + }, + t('nodes.inputFieldTypeParseError', { + node: type, + field: propertyName, + message: 'unknown error', + }) + ); } } @@ -203,6 +217,20 @@ export const parseSchema = ( message: e.message, }) ); + } else { + logger('nodes').warn( + { + node: type, + field: propertyName, + schema: parseify(property), + error: serializeError(e), + }, + t('nodes.outputFieldTypeParseError', { + node: type, + field: propertyName, + message: 'unknown error', + }) + ); } } return outputsAccumulator; From 6643b5cec459e93b82a70dc9bef59ce452ac48ed Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:23:29 +1100 Subject: [PATCH 22/28] feat(ui): log trace when skipping reserved input field type --- .../web/src/features/nodes/util/schema/parseSchema.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts index 696e371ea6..f9bce27372 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts @@ -12,6 +12,7 @@ import { import { t } from 'i18next'; import { reduce } from 'lodash-es'; import type { OpenAPIV3_1 } from 'openapi-types'; +import { serializeError } from 'serialize-error'; import { buildFieldInputTemplate } from './buildFieldInputTemplate'; import { buildFieldOutputTemplate } from './buildFieldOutputTemplate'; @@ -103,7 +104,10 @@ export const parseSchema = ( const fieldType = parseFieldType(property); if (isReservedFieldType(fieldType.name)) { - // Skip processing this reserved field + logger('nodes').trace( + { node: type, field: propertyName, schema: parseify(property) }, + 'Skipped reserved input field' + ); return inputsAccumulator; } From 52e07db06be59c84496ca82fc693e07e8af29856 Mon Sep 17 00:00:00 2001 From: skunkworxdark Date: Fri, 2 Feb 2024 10:45:08 +0000 Subject: [PATCH 23/28] Update communityNodes.md added Autostereogram nodes --- docs/nodes/communityNodes.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/nodes/communityNodes.md b/docs/nodes/communityNodes.md index 7dbcef3836..fa17b42411 100644 --- a/docs/nodes/communityNodes.md +++ b/docs/nodes/communityNodes.md @@ -14,6 +14,7 @@ To use a community workflow, download the the `.json` node graph file and load i - Community Nodes + [Adapters-Linked](#adapters-linked-nodes) + + [Autostereogram](#autostereogram-nodes) + [Average Images](#average-images) + [Clean Image Artifacts After Cut](#clean-image-artifacts-after-cut) + [Close Color Mask](#close-color-mask) @@ -67,6 +68,17 @@ Note: These are inherited from the core nodes so any update to the core nodes sh **Node Link:** https://github.com/skunkworxdark/adapters-linked-nodes +-------------------------------- +### Autostereogram Nodes + +**Description:** Generate autostereogram images from a depth map. This is not a very practically useful node but more a 90s nostalgic indulgence as I used to love these images as a kid. + +**Node Link:** https://github.com/skunkworxdark/autostereogram_nodes + +**Example Usage:** +
+ -> -> + -------------------------------- ### Average Images From fb50a221f8138cf049d3899783c5a9ee375a7e88 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:51:08 +1100 Subject: [PATCH 24/28] fix(ui): fix color input field alpha Closes #5647 The alpha values in the UI are `0-1` but the backend wants `0-255`. Previously, this was handled in `parseFIeldValue` when building the graph. In a recent release, field types were refactored and broke the alpha handling. The logic for handling alpha values is moved into `ColorFieldInputComponent`, and `parseFieldValue` now just does no value transformations. Though it would be a minor change, I'm leaving this function in because I don't want to change the rest of the logic except when necessary. --- .../inputs/ColorFieldInputComponent.tsx | 22 ++++++++++++++++--- .../nodes/util/graph/buildNodesGraph.ts | 19 ++-------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ColorFieldInputComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ColorFieldInputComponent.tsx index 716c922939..147289772f 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ColorFieldInputComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/ColorFieldInputComponent.tsx @@ -1,31 +1,47 @@ import { useAppDispatch } from 'app/store/storeHooks'; import { fieldColorValueChanged } from 'features/nodes/store/nodesSlice'; import type { ColorFieldInputInstance, ColorFieldInputTemplate } from 'features/nodes/types/field'; -import { memo, useCallback } from 'react'; +import { memo, useCallback, useMemo } from 'react'; import type { RgbaColor } from 'react-colorful'; import { RgbaColorPicker } from 'react-colorful'; import type { FieldComponentProps } from './types'; +const FALLBACK_COLOR: RgbaColor = { r: 0, g: 0, b: 0, a: 255 }; + const ColorFieldInputComponent = (props: FieldComponentProps) => { const { nodeId, field } = props; const dispatch = useAppDispatch(); + const color = useMemo(() => { + // For better or worse, zColorFieldValue is typed as optional. This means that `field.value` and `fieldTemplate.default` + // can be undefined. Rather than changing the schema (which could have other consequences), we can just provide a fallback. + if (!field.value) { + return FALLBACK_COLOR; + } + const { r, g, b, a } = field.value; + // We need to divide by 255 to convert from 0-255 to 0-1, which is what the UI component needs + return { r, g, b, a: a / 255 }; + }, [field.value]); + const handleValueChanged = useCallback( (value: RgbaColor) => { + // We need to multiply by 255 to convert from 0-1 to 0-255, which is what the backend needs + const { r, g, b, a: _a } = value; + const a = Math.round(_a * 255); dispatch( fieldColorValueChanged({ nodeId, fieldName: field.name, - value, + value: { r, g, b, a }, }) ); }, [dispatch, field.name, nodeId] ); - return ; + return ; }; export default memo(ColorFieldInputComponent); diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildNodesGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildNodesGraph.ts index 3dc8c8f735..582aa6b217 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildNodesGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildNodesGraph.ts @@ -1,8 +1,7 @@ import type { NodesState } from 'features/nodes/store/types'; import type { FieldInputInstance } from 'features/nodes/types/field'; -import { isColorFieldInputInstance } from 'features/nodes/types/field'; import { isInvocationNode } from 'features/nodes/types/invocation'; -import { cloneDeep, omit, reduce } from 'lodash-es'; +import { omit, reduce } from 'lodash-es'; import type { Graph } from 'services/api/types'; import type { AnyInvocation } from 'services/events/types'; import { v4 as uuidv4 } from 'uuid'; @@ -11,21 +10,7 @@ import { v4 as uuidv4 } from 'uuid'; * We need to do special handling for some fields */ export const parseFieldValue = (field: FieldInputInstance) => { - if (isColorFieldInputInstance(field)) { - if (field.value) { - const clonedValue = cloneDeep(field.value); - - const { r, g, b, a } = field.value; - - // scale alpha value to PIL's desired range 0-255 - const scaledAlpha = Math.max(0, Math.min(a * 255, 255)); - const transformedColor = { r, g, b, a: scaledAlpha }; - - Object.assign(clonedValue, transformedColor); - return clonedValue; - } - } - + // Currently, no special handling is needed. return field.value; }; From 1b4dbd283e359711d35f8ad6709bc0cdda761dcc Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 5 Feb 2024 08:51:23 +1100 Subject: [PATCH 25/28] fix(ui): hardcode language picker languages Hardcode the options in the dropdown, don't rely on translators to fill this in. Also, add a number of missing languages (Azerbaijani, Finnish, Hungarian, Swedish, Turkish). --- .../SettingsModal/SettingsLanguageSelect.tsx | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx index c43c147e6a..00af95aa4a 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx @@ -13,27 +13,30 @@ export const SettingsLanguageSelect = memo(() => { const language = useAppSelector((s) => s.system.language); const options = useMemo( () => [ - { label: t('common.langArabic', { lng: 'ar' }), value: 'ar' }, - { label: t('common.langDutch', { lng: 'nl' }), value: 'nl' }, - { label: t('common.langEnglish', { lng: 'en' }), value: 'en' }, - { label: t('common.langFrench', { lng: 'fr' }), value: 'fr' }, - { label: t('common.langGerman', { lng: 'de' }), value: 'de' }, - { label: t('common.langHebrew', { lng: 'he' }), value: 'he' }, - { label: t('common.langItalian', { lng: 'it' }), value: 'it' }, - { label: t('common.langJapanese', { lng: 'ja' }), value: 'ja' }, - { label: t('common.langKorean', { lng: 'ko' }), value: 'ko' }, - { label: t('common.langPolish', { lng: 'pl' }), value: 'pl' }, - { label: t('common.langBrPortuguese', { lng: 'pt_BR' }), value: 'pt_BR' }, - { label: t('common.langPortuguese', { lng: 'pt' }), value: 'pt' }, - { label: t('common.langRussian', { lng: 'ru' }), value: 'ru' }, - { - label: t('common.langSimplifiedChinese', { lng: 'zh_CN' }), - value: 'zh_CN', - }, - { label: t('common.langSpanish', { lng: 'es' }), value: 'es' }, - { label: t('common.langUkranian', { lng: 'ua' }), value: 'ua' }, + { label: 'العربية', value: 'ar' }, + { label: 'Azərbaycan dili', value: 'az' }, + { label: 'Deutsch', value: 'de' }, + { label: 'English', value: 'en' }, + { label: 'Español', value: 'es' }, + { label: 'Suomi', value: 'fi' }, + { label: 'Français', value: 'fr' }, + { label: 'עִבְֿרִית', value: 'he' }, + { label: 'Magyar Nyelv', value: 'hu' }, + { label: 'Italiano', value: 'it' }, + { label: '日本語', value: 'ja' }, + { label: '한국어', value: 'ko' }, + { label: 'Nederlands', value: 'nl' }, + { label: 'Polski', value: 'pl' }, + { label: 'Português', value: 'pt' }, + { label: 'Português do Brasil', value: 'pt_BR' }, + { label: 'Русский', value: 'ru' }, + { label: 'Svenska', value: 'sv' }, + { label: 'Türkçe', value: 'tr' }, + { label: 'Украї́нська', value: 'ua' }, + { label: '简体中文', value: 'zh_CN' }, + { label: '漢語', value: 'zh_Hant' }, ], - [t] + [] ); const isLocalizationEnabled = useFeatureStatus('localization').isFeatureEnabled; From c979cf5ecc5538b59265035cf0d7bacb17f14b9f Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 5 Feb 2024 08:59:34 +1100 Subject: [PATCH 26/28] tidy(ui): remove language translation strings There's no need to do things like translate Arabic into Finnish. We never use those strings. Remove these translations entirely. --- invokeai/frontend/web/public/locales/en.json | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 41d6dd3572..e204057fe5 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -118,24 +118,7 @@ "inpaint": "inpaint", "input": "Input", "installed": "Installed", - "langArabic": "العربية", - "langBrPortuguese": "Português do Brasil", - "langDutch": "Nederlands", - "langEnglish": "English", - "langFrench": "Français", - "langGerman": "German", - "langHebrew": "Hebrew", - "langItalian": "Italiano", - "langJapanese": "日本語", - "langKorean": "한국어", - "langPolish": "Polski", - "langPortuguese": "Português", - "langRussian": "Русский", - "langSimplifiedChinese": "简体中文", - "langSpanish": "Español", "languagePickerLabel": "Language", - "langUkranian": "Украї́нська", - "lightMode": "Light Mode", "linear": "Linear", "load": "Load", "loading": "Loading", From e8095b73ae147d59da15bbbbc2d60f026267e74d Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 5 Feb 2024 09:09:01 +1100 Subject: [PATCH 27/28] feat(ui): improve types for language picker Makes it impossible to miss a language or typo. --- .../SettingsModal/SettingsLanguageSelect.tsx | 58 ++++++++++--------- .../web/src/features/system/store/types.ts | 18 ++++-- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx index 00af95aa4a..eceba85b5a 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx @@ -3,44 +3,46 @@ import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { languageChanged } from 'features/system/store/systemSlice'; +import type { Language } from 'features/system/store/types'; import { isLanguage } from 'features/system/store/types'; +import { map } from 'lodash-es'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; +const optionsObject: Record = { + ar: 'العربية', + az: 'Azərbaycan dili', + de: 'Deutsch', + en: 'English', + es: 'Español', + fi: 'Suomi', + fr: 'Français', + he: 'עִבְֿרִית', + hu: 'Magyar Nyelv', + it: 'Italiano', + ja: '日本語', + ko: '한국어', + nl: 'Nederlands', + pl: 'Polski', + pt: 'Português', + pt_BR: 'Português do Brasil', + ru: 'Русский', + sv: 'Svenska', + tr: 'Türkçe', + ua: 'Украї́нська', + zh_CN: '简体中文', + zh_Hant: '漢語', +}; + +const options = map(optionsObject, (label, value) => ({ label, value })); + export const SettingsLanguageSelect = memo(() => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const language = useAppSelector((s) => s.system.language); - const options = useMemo( - () => [ - { label: 'العربية', value: 'ar' }, - { label: 'Azərbaycan dili', value: 'az' }, - { label: 'Deutsch', value: 'de' }, - { label: 'English', value: 'en' }, - { label: 'Español', value: 'es' }, - { label: 'Suomi', value: 'fi' }, - { label: 'Français', value: 'fr' }, - { label: 'עִבְֿרִית', value: 'he' }, - { label: 'Magyar Nyelv', value: 'hu' }, - { label: 'Italiano', value: 'it' }, - { label: '日本語', value: 'ja' }, - { label: '한국어', value: 'ko' }, - { label: 'Nederlands', value: 'nl' }, - { label: 'Polski', value: 'pl' }, - { label: 'Português', value: 'pt' }, - { label: 'Português do Brasil', value: 'pt_BR' }, - { label: 'Русский', value: 'ru' }, - { label: 'Svenska', value: 'sv' }, - { label: 'Türkçe', value: 'tr' }, - { label: 'Украї́нська', value: 'ua' }, - { label: '简体中文', value: 'zh_CN' }, - { label: '漢語', value: 'zh_Hant' }, - ], - [] - ); const isLocalizationEnabled = useFeatureStatus('localization').isFeatureEnabled; - const value = useMemo(() => options.find((o) => o.value === language), [language, options]); + const value = useMemo(() => options.find((o) => o.value === language), [language]); const onChange = useCallback( (v) => { diff --git a/invokeai/frontend/web/src/features/system/store/types.ts b/invokeai/frontend/web/src/features/system/store/types.ts index 09d5fdcd6f..3575501d86 100644 --- a/invokeai/frontend/web/src/features/system/store/types.ts +++ b/invokeai/frontend/web/src/features/system/store/types.ts @@ -17,21 +17,27 @@ export type DenoiseProgress = { export const zLanguage = z.enum([ 'ar', - 'nl', - 'en', - 'fr', + 'az', 'de', + 'en', + 'es', + 'fi', + 'fr', 'he', + 'hu', 'it', 'ja', 'ko', + 'nl', 'pl', - 'pt_BR', 'pt', + 'pt_BR', 'ru', + 'sv', + 'tr', + 'ua', 'zh_CN', - 'es', - 'uk', + 'zh_Hant', ]); export type Language = z.infer; export const isLanguage = (v: unknown): v is Language => zLanguage.safeParse(v).success; From 14472dc09d6ec0ce4115f927f81f6eac821cfd5e Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Mon, 5 Feb 2024 00:47:40 +0100 Subject: [PATCH 28/28] translationBot(ui): update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Hosted Weblate Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/ar.json | 1 - invokeai/frontend/web/public/locales/de.json | 17 ----------------- invokeai/frontend/web/public/locales/es.json | 17 ----------------- invokeai/frontend/web/public/locales/fi.json | 10 ---------- invokeai/frontend/web/public/locales/fr.json | 2 -- invokeai/frontend/web/public/locales/he.json | 13 ------------- invokeai/frontend/web/public/locales/hu.json | 3 +-- invokeai/frontend/web/public/locales/it.json | 17 ----------------- invokeai/frontend/web/public/locales/ja.json | 17 ----------------- invokeai/frontend/web/public/locales/ko.json | 17 ----------------- invokeai/frontend/web/public/locales/nl.json | 17 ----------------- invokeai/frontend/web/public/locales/pl.json | 4 +--- invokeai/frontend/web/public/locales/pt.json | 16 +--------------- invokeai/frontend/web/public/locales/pt_BR.json | 13 ------------- invokeai/frontend/web/public/locales/ru.json | 17 ----------------- invokeai/frontend/web/public/locales/sv.json | 16 ---------------- invokeai/frontend/web/public/locales/tr.json | 17 ----------------- invokeai/frontend/web/public/locales/uk.json | 16 ---------------- invokeai/frontend/web/public/locales/zh_CN.json | 17 ----------------- .../frontend/web/public/locales/zh_Hant.json | 15 --------------- 20 files changed, 3 insertions(+), 259 deletions(-) diff --git a/invokeai/frontend/web/public/locales/ar.json b/invokeai/frontend/web/public/locales/ar.json index 15d5c9c36d..23dc12d9fc 100644 --- a/invokeai/frontend/web/public/locales/ar.json +++ b/invokeai/frontend/web/public/locales/ar.json @@ -7,7 +7,6 @@ "img2img": "صورة إلى صورة", "unifiedCanvas": "لوحة موحدة", "nodes": "عقد", - "langArabic": "العربية", "nodesDesc": "نظام مبني على العقد لإنتاج الصور قيد التطوير حاليًا. تبقى على اتصال مع تحديثات حول هذه الميزة المذهلة.", "postProcessing": "معالجة بعد الإصدار", "postProcessDesc1": "Invoke AI توفر مجموعة واسعة من ميزات المعالجة بعد الإصدار. تحسين الصور واستعادة الوجوه متاحين بالفعل في واجهة الويب. يمكنك الوصول إليهم من الخيارات المتقدمة في قائمة الخيارات في علامة التبويب Text To Image و Image To Image. يمكن أيضًا معالجة الصور مباشرةً باستخدام أزرار الإجراء على الصورة فوق عرض الصورة الحالي أو في العارض.", diff --git a/invokeai/frontend/web/public/locales/de.json b/invokeai/frontend/web/public/locales/de.json index 1444acba3a..e1ef94f06d 100644 --- a/invokeai/frontend/web/public/locales/de.json +++ b/invokeai/frontend/web/public/locales/de.json @@ -5,7 +5,6 @@ "settingsLabel": "Einstellungen", "img2img": "Bild zu Bild", "nodes": "Knoten Editor", - "langGerman": "Deutsch", "nodesDesc": "Ein knotenbasiertes System, für die Erzeugung von Bildern, ist derzeit in der Entwicklung. Bleiben Sie gespannt auf Updates zu dieser fantastischen Funktion.", "postProcessing": "Nachbearbeitung", "postProcessDesc1": "InvokeAI bietet eine breite Palette von Nachbearbeitungsfunktionen. Bildhochskalierung und Gesichtsrekonstruktion sind bereits in der WebUI verfügbar. Sie können sie über das Menü Erweiterte Optionen der Reiter Text in Bild und Bild in Bild aufrufen. Sie können Bilder auch direkt bearbeiten, indem Sie die Schaltflächen für Bildaktionen oberhalb der aktuellen Bildanzeige oder im Viewer verwenden.", @@ -41,24 +40,11 @@ "cancel": "Abbrechen", "accept": "Annehmen", "back": "Zurück", - "langEnglish": "Englisch", - "langDutch": "Niederländisch", - "langFrench": "Französisch", - "langItalian": "Italienisch", - "langPortuguese": "Portugiesisch", - "langRussian": "Russisch", - "langUkranian": "Ukrainisch", "hotkeysLabel": "Tastenkombinationen", "githubLabel": "Github", "discordLabel": "Discord", "txt2img": "Text zu Bild", "postprocessing": "Nachbearbeitung", - "langPolish": "Polnisch", - "langJapanese": "Japanisch", - "langArabic": "Arabisch", - "langKorean": "Koreanisch", - "langHebrew": "Hebräisch", - "langSpanish": "Spanisch", "t2iAdapter": "T2I Adapter", "communityLabel": "Gemeinschaft", "dontAskMeAgain": "Frag mich nicht nochmal", @@ -69,7 +55,6 @@ "on": "An", "nodeEditor": "Knoten Editor", "statusMergingModels": "Modelle zusammenführen", - "langSimplifiedChinese": "Vereinfachtes Chinesisch", "ipAdapter": "IP Adapter", "controlAdapter": "Control Adapter", "auto": "Automatisch", @@ -77,7 +62,6 @@ "imageFailedToLoad": "Kann Bild nicht laden", "statusModelConverted": "Model konvertiert", "modelManager": "Model Manager", - "lightMode": "Heller Modus", "generate": "Erstellen", "learnMore": "Mehr lernen", "darkMode": "Dunkler Modus", @@ -85,7 +69,6 @@ "random": "Zufall", "batch": "Stapel-Manager", "advanced": "Erweitert", - "langBrPortuguese": "Portugiesisch (Brasilien)", "unifiedCanvas": "Einheitliche Leinwand", "openInNewTab": "In einem neuem Tab öffnen", "statusProcessing": "wird bearbeitet", diff --git a/invokeai/frontend/web/public/locales/es.json b/invokeai/frontend/web/public/locales/es.json index 9f2fda6089..f85cd89721 100644 --- a/invokeai/frontend/web/public/locales/es.json +++ b/invokeai/frontend/web/public/locales/es.json @@ -7,7 +7,6 @@ "img2img": "Imagen a Imagen", "unifiedCanvas": "Lienzo Unificado", "nodes": "Editor del flujo de trabajo", - "langSpanish": "Español", "nodesDesc": "Un sistema de generación de imágenes basado en nodos, actualmente se encuentra en desarrollo. Mantente pendiente a nuestras actualizaciones acerca de esta fabulosa funcionalidad.", "postProcessing": "Post-procesamiento", "postProcessDesc1": "Invoke AI ofrece una gran variedad de funciones de post-procesamiento, El aumento de tamaño y Restauración de Rostros ya se encuentran disponibles en la interfaz web, puedes acceder desde el menú de Opciones Avanzadas en las pestañas de Texto a Imagen y de Imagen a Imagen. También puedes acceder a estas funciones directamente mediante el botón de acciones en el menú superior de la imagen actual o en el visualizador.", @@ -43,25 +42,10 @@ "statusMergedModels": "Modelos combinados", "githubLabel": "Github", "discordLabel": "Discord", - "langEnglish": "Inglés", - "langDutch": "Holandés", - "langFrench": "Francés", - "langGerman": "Alemán", - "langItalian": "Italiano", - "langArabic": "Árabe", - "langJapanese": "Japones", - "langPolish": "Polaco", - "langBrPortuguese": "Portugués brasileño", - "langRussian": "Ruso", - "langSimplifiedChinese": "Chino simplificado", - "langUkranian": "Ucraniano", "back": "Atrás", "statusConvertingModel": "Convertir el modelo", "statusModelConverted": "Modelo adaptado", "statusMergingModels": "Fusionar modelos", - "langPortuguese": "Portugués", - "langKorean": "Coreano", - "langHebrew": "Hebreo", "loading": "Cargando", "loadingInvokeAI": "Cargando invocar a la IA", "postprocessing": "Tratamiento posterior", @@ -77,7 +61,6 @@ "imagePrompt": "Indicación de imagen", "batch": "Administrador de lotes", "darkMode": "Modo oscuro", - "lightMode": "Modo claro", "modelManager": "Administrador de modelos", "communityLabel": "Comunidad" }, diff --git a/invokeai/frontend/web/public/locales/fi.json b/invokeai/frontend/web/public/locales/fi.json index cf7fc6701b..10bbddd72f 100644 --- a/invokeai/frontend/web/public/locales/fi.json +++ b/invokeai/frontend/web/public/locales/fi.json @@ -27,22 +27,12 @@ "statusModelChanged": "Malli vaihdettu", "statusConvertingModel": "Muunnetaan mallia", "statusModelConverted": "Malli muunnettu", - "langFrench": "Ranska", - "langItalian": "Italia", "languagePickerLabel": "Kielen valinta", "hotkeysLabel": "Pikanäppäimet", "reportBugLabel": "Raportoi Bugista", - "langPolish": "Puola", - "langDutch": "Hollanti", "settingsLabel": "Asetukset", "githubLabel": "Github", - "langGerman": "Saksa", - "langPortuguese": "Portugali", "discordLabel": "Discord", - "langEnglish": "Englanti", - "langRussian": "Venäjä", - "langUkranian": "Ukraina", - "langSpanish": "Espanja", "upload": "Lataa", "statusMergedModels": "Mallit yhdistelty", "img2img": "Kuva kuvaksi", diff --git a/invokeai/frontend/web/public/locales/fr.json b/invokeai/frontend/web/public/locales/fr.json index adbfbcfc30..dce2574c38 100644 --- a/invokeai/frontend/web/public/locales/fr.json +++ b/invokeai/frontend/web/public/locales/fr.json @@ -7,7 +7,6 @@ "img2img": "Image en image", "unifiedCanvas": "Canvas unifié", "nodes": "Nœuds", - "langFrench": "Français", "nodesDesc": "Un système basé sur les nœuds pour la génération d'images est actuellement en développement. Restez à l'écoute pour des mises à jour à ce sujet.", "postProcessing": "Post-traitement", "postProcessDesc1": "Invoke AI offre une grande variété de fonctionnalités de post-traitement. Le redimensionnement d'images et la restauration de visages sont déjà disponibles dans la WebUI. Vous pouvez y accéder à partir du menu 'Options avancées' des onglets 'Texte vers image' et 'Image vers image'. Vous pouvez également traiter les images directement en utilisant les boutons d'action d'image au-dessus de l'affichage d'image actuel ou dans le visualiseur.", @@ -47,7 +46,6 @@ "statusMergingModels": "Mélange des modèles", "loadingInvokeAI": "Chargement de Invoke AI", "cancel": "Annuler", - "langEnglish": "Anglais", "statusConvertingModel": "Conversion du modèle", "statusModelConverted": "Modèle converti", "loading": "Chargement", diff --git a/invokeai/frontend/web/public/locales/he.json b/invokeai/frontend/web/public/locales/he.json index aee10f839b..9920053fe8 100644 --- a/invokeai/frontend/web/public/locales/he.json +++ b/invokeai/frontend/web/public/locales/he.json @@ -111,17 +111,6 @@ "githubLabel": "גיטהאב", "discordLabel": "דיסקורד", "settingsLabel": "הגדרות", - "langEnglish": "אנגלית", - "langDutch": "הולנדית", - "langArabic": "ערבית", - "langFrench": "צרפתית", - "langGerman": "גרמנית", - "langJapanese": "יפנית", - "langBrPortuguese": "פורטוגזית", - "langRussian": "רוסית", - "langSimplifiedChinese": "סינית", - "langUkranian": "אוקראינית", - "langSpanish": "ספרדית", "img2img": "תמונה לתמונה", "unifiedCanvas": "קנבס מאוחד", "nodes": "צמתים", @@ -152,9 +141,7 @@ "statusMergedModels": "מודלים מוזגו", "hotkeysLabel": "מקשים חמים", "reportBugLabel": "דווח באג", - "langItalian": "איטלקית", "upload": "העלאה", - "langPolish": "פולנית", "training": "אימון", "load": "טעינה", "back": "אחורה", diff --git a/invokeai/frontend/web/public/locales/hu.json b/invokeai/frontend/web/public/locales/hu.json index aa959bc890..7c19af599e 100644 --- a/invokeai/frontend/web/public/locales/hu.json +++ b/invokeai/frontend/web/public/locales/hu.json @@ -34,7 +34,6 @@ "delete": "Törlés", "data": "Adat", "discordLabel": "Discord", - "folder": "Mappa", - "langEnglish": "Angol" + "folder": "Mappa" } } diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json index c363ba1faf..fe5667cfef 100644 --- a/invokeai/frontend/web/public/locales/it.json +++ b/invokeai/frontend/web/public/locales/it.json @@ -7,7 +7,6 @@ "img2img": "Immagine a Immagine", "unifiedCanvas": "Tela unificata", "nodes": "Editor del flusso di lavoro", - "langItalian": "Italiano", "nodesDesc": "Attualmente è in fase di sviluppo un sistema basato su nodi per la generazione di immagini. Resta sintonizzato per gli aggiornamenti su questa fantastica funzionalità.", "postProcessing": "Post-elaborazione", "postProcessDesc1": "Invoke AI offre un'ampia varietà di funzionalità di post-elaborazione. Ampliamento Immagine e Restaura Volti sono già disponibili nell'interfaccia Web. È possibile accedervi dal menu 'Opzioni avanzate' delle schede 'Testo a Immagine' e 'Immagine a Immagine'. È inoltre possibile elaborare le immagini direttamente, utilizzando i pulsanti di azione dell'immagine sopra la visualizzazione dell'immagine corrente o nel visualizzatore.", @@ -43,26 +42,11 @@ "statusModelChanged": "Modello cambiato", "githubLabel": "GitHub", "discordLabel": "Discord", - "langArabic": "Arabo", - "langEnglish": "Inglese", - "langFrench": "Francese", - "langGerman": "Tedesco", - "langJapanese": "Giapponese", - "langPolish": "Polacco", - "langBrPortuguese": "Portoghese Basiliano", - "langRussian": "Russo", - "langUkranian": "Ucraino", - "langSpanish": "Spagnolo", "statusMergingModels": "Fusione Modelli", "statusMergedModels": "Modelli fusi", - "langSimplifiedChinese": "Cinese semplificato", - "langDutch": "Olandese", "statusModelConverted": "Modello Convertito", "statusConvertingModel": "Conversione Modello", - "langKorean": "Coreano", - "langPortuguese": "Portoghese", "loading": "Caricamento in corso", - "langHebrew": "Ebraico", "loadingInvokeAI": "Caricamento Invoke AI", "postprocessing": "Post Elaborazione", "txt2img": "Testo a Immagine", @@ -76,7 +60,6 @@ "dontAskMeAgain": "Non chiedermelo più", "imagePrompt": "Prompt Immagine", "darkMode": "Modalità scura", - "lightMode": "Modalità chiara", "batch": "Gestione Lotto", "modelManager": "Gestore modello", "communityLabel": "Comunità", diff --git a/invokeai/frontend/web/public/locales/ja.json b/invokeai/frontend/web/public/locales/ja.json index 0fee501e11..e92b5320f3 100644 --- a/invokeai/frontend/web/public/locales/ja.json +++ b/invokeai/frontend/web/public/locales/ja.json @@ -3,7 +3,6 @@ "languagePickerLabel": "言語", "reportBugLabel": "バグ報告", "settingsLabel": "設定", - "langJapanese": "日本語", "nodesDesc": "現在、画像生成のためのノードベースシステムを開発中です。機能についてのアップデートにご期待ください。", "postProcessing": "後処理", "postProcessDesc1": "Invoke AIは、多彩な後処理の機能を備えています。アップスケーリングと顔修復は、すでにWebUI上で利用可能です。これらは、[Text To Image]および[Image To Image]タブの[詳細オプション]メニューからアクセスできます。また、現在の画像表示の上やビューア内の画像アクションボタンを使って、画像を直接処理することもできます。", @@ -36,11 +35,6 @@ "statusModelChanged": "モデルを変更", "cancel": "キャンセル", "accept": "同意", - "langBrPortuguese": "Português do Brasil", - "langRussian": "Русский", - "langSimplifiedChinese": "简体中文", - "langUkranian": "Украї́нська", - "langSpanish": "Español", "img2img": "img2img", "unifiedCanvas": "Unified Canvas", "statusMergingModels": "モデルのマージ", @@ -54,18 +48,8 @@ "statusMergedModels": "マージ済モデル", "githubLabel": "Github", "hotkeysLabel": "ホットキー", - "langHebrew": "עברית", "discordLabel": "Discord", - "langItalian": "Italiano", - "langEnglish": "English", - "langArabic": "アラビア語", - "langDutch": "Nederlands", - "langFrench": "Français", - "langGerman": "Deutsch", - "langPortuguese": "Português", "nodes": "ワークフローエディター", - "langKorean": "한국어", - "langPolish": "Polski", "txt2img": "txt2img", "postprocessing": "Post Processing", "t2iAdapter": "T2I アダプター", @@ -84,7 +68,6 @@ "imageFailedToLoad": "画像が読み込めません", "imagePrompt": "画像プロンプト", "modelManager": "モデルマネージャー", - "lightMode": "ライトモード", "generate": "生成", "learnMore": "もっと学ぶ", "darkMode": "ダークモード", diff --git a/invokeai/frontend/web/public/locales/ko.json b/invokeai/frontend/web/public/locales/ko.json index 476c421fa3..cf37e24d7b 100644 --- a/invokeai/frontend/web/public/locales/ko.json +++ b/invokeai/frontend/web/public/locales/ko.json @@ -4,17 +4,7 @@ "reportBugLabel": "버그 리포트", "githubLabel": "Github", "settingsLabel": "설정", - "langArabic": "العربية", - "langEnglish": "English", - "langDutch": "Nederlands", "unifiedCanvas": "통합 캔버스", - "langFrench": "Français", - "langGerman": "Deutsch", - "langItalian": "Italiano", - "langJapanese": "日本語", - "langBrPortuguese": "Português do Brasil", - "langRussian": "Русский", - "langSpanish": "Español", "nodes": "Workflow Editor", "nodesDesc": "이미지 생성을 위한 노드 기반 시스템은 현재 개발 중입니다. 이 놀라운 기능에 대한 업데이트를 계속 지켜봐 주세요.", "postProcessing": "후처리", @@ -31,7 +21,6 @@ "statusDisconnected": "연결 끊김", "statusError": "에러", "statusPreparing": "준비 중", - "langSimplifiedChinese": "简体中文", "statusGenerating": "생성 중", "statusGeneratingTextToImage": "텍스트->이미지 생성", "statusGeneratingInpainting": "인페인팅 생성", @@ -51,9 +40,7 @@ "hotkeysLabel": "단축키 설정", "img2img": "이미지->이미지", "discordLabel": "Discord", - "langPolish": "Polski", "postProcessDesc1": "Invoke AI는 다양한 후처리 기능을 제공합니다. 이미지 업스케일링 및 얼굴 복원은 이미 Web UI에서 사용할 수 있습니다. 텍스트->이미지 또는 이미지->이미지 탭의 고급 옵션 메뉴에서 사용할 수 있습니다. 또한 현재 이미지 표시 위, 또는 뷰어에서 액션 버튼을 사용하여 이미지를 직접 처리할 수도 있습니다.", - "langUkranian": "Украї́нська", "statusProcessingCanceled": "처리 취소됨", "statusGeneratingImageToImage": "이미지->이미지 생성", "statusProcessingComplete": "처리 완료", @@ -73,7 +60,6 @@ "updated": "업데이트 됨", "on": "켜기", "save": "저장", - "langPortuguese": "Português", "created": "생성됨", "nodeEditor": "Node Editor", "error": "에러", @@ -100,10 +86,8 @@ "somethingWentWrong": "뭔가 잘못됐어요", "imagePrompt": "이미지 프롬프트", "modelManager": "Model Manager", - "lightMode": "라이트 모드", "safetensors": "Safetensors", "outpaint": "outpaint", - "langKorean": "한국어", "orderBy": "정렬 기준", "generate": "생성", "copyError": "$t(gallery.copy) 에러", @@ -113,7 +97,6 @@ "darkMode": "다크 모드", "loading": "불러오는 중", "random": "랜덤", - "langHebrew": "Hebrew", "batch": "Batch 매니저", "postprocessing": "후처리", "advanced": "고급", diff --git a/invokeai/frontend/web/public/locales/nl.json b/invokeai/frontend/web/public/locales/nl.json index 195fe4dc06..8290c8904f 100644 --- a/invokeai/frontend/web/public/locales/nl.json +++ b/invokeai/frontend/web/public/locales/nl.json @@ -7,7 +7,6 @@ "img2img": "Afbeelding naar afbeelding", "unifiedCanvas": "Centraal canvas", "nodes": "Werkstroom-editor", - "langDutch": "Nederlands", "nodesDesc": "Een op knooppunten gebaseerd systeem voor het genereren van afbeeldingen is momenteel in ontwikkeling. Blijf op de hoogte voor nieuws over deze verbluffende functie.", "postProcessing": "Naverwerking", "postProcessDesc1": "Invoke AI biedt een breed scala aan naverwerkingsfuncties. Afbeeldingsopschaling en Gezichtsherstel zijn al beschikbaar in de web-UI. Je kunt ze openen via het menu Uitgebreide opties in de tabbladen Tekst naar afbeelding en Afbeelding naar afbeelding. Je kunt een afbeelding ook direct verwerken via de afbeeldingsactieknoppen boven de weergave van de huidigde afbeelding of in de Viewer.", @@ -41,18 +40,6 @@ "statusModelChanged": "Model gewijzigd", "githubLabel": "Github", "discordLabel": "Discord", - "langArabic": "Arabisch", - "langEnglish": "Engels", - "langFrench": "Frans", - "langGerman": "Duits", - "langItalian": "Italiaans", - "langJapanese": "Japans", - "langPolish": "Pools", - "langBrPortuguese": "Portugees (Brazilië)", - "langRussian": "Russisch", - "langSimplifiedChinese": "Chinees (vereenvoudigd)", - "langUkranian": "Oekraïens", - "langSpanish": "Spaans", "training": "Training", "back": "Terug", "statusConvertingModel": "Omzetten van model", @@ -61,11 +48,8 @@ "statusMergedModels": "Modellen samengevoegd", "cancel": "Annuleer", "accept": "Akkoord", - "langPortuguese": "Portugees", "loading": "Bezig met laden", "loadingInvokeAI": "Bezig met laden van Invoke AI", - "langHebrew": "עברית", - "langKorean": "한국어", "txt2img": "Tekst naar afbeelding", "postprocessing": "Naverwerking", "dontAskMeAgain": "Vraag niet opnieuw", @@ -78,7 +62,6 @@ "batch": "Seriebeheer", "modelManager": "Modelbeheer", "darkMode": "Donkere modus", - "lightMode": "Lichte modus", "communityLabel": "Gemeenschap", "t2iAdapter": "T2I-adapter", "on": "Aan", diff --git a/invokeai/frontend/web/public/locales/pl.json b/invokeai/frontend/web/public/locales/pl.json index 35300596f4..7178bd1487 100644 --- a/invokeai/frontend/web/public/locales/pl.json +++ b/invokeai/frontend/web/public/locales/pl.json @@ -7,7 +7,6 @@ "img2img": "Obraz na obraz", "unifiedCanvas": "Tryb uniwersalny", "nodes": "Węzły", - "langPolish": "Polski", "nodesDesc": "W tym miejscu powstanie graficzny system generowania obrazów oparty na węzłach. Jest na co czekać!", "postProcessing": "Przetwarzanie końcowe", "postProcessDesc1": "Invoke AI oferuje wiele opcji przetwarzania końcowego. Z poziomu przeglądarki dostępne jest już zwiększanie rozdzielczości oraz poprawianie twarzy. Znajdziesz je wśród ustawień w trybach \"Tekst na obraz\" oraz \"Obraz na obraz\". Są również obecne w pasku menu wyświetlanym nad podglądem wygenerowanego obrazu.", @@ -42,8 +41,7 @@ "statusModelChanged": "Zmieniono model", "githubLabel": "GitHub", "discordLabel": "Discord", - "darkMode": "Tryb ciemny", - "lightMode": "Tryb jasny" + "darkMode": "Tryb ciemny" }, "gallery": { "generations": "Wygenerowane", diff --git a/invokeai/frontend/web/public/locales/pt.json b/invokeai/frontend/web/public/locales/pt.json index 9dd020f7e2..b44db81b49 100644 --- a/invokeai/frontend/web/public/locales/pt.json +++ b/invokeai/frontend/web/public/locales/pt.json @@ -1,22 +1,9 @@ { "common": { - "langArabic": "العربية", "reportBugLabel": "Reportar Bug", "settingsLabel": "Configurações", - "langBrPortuguese": "Português do Brasil", "languagePickerLabel": "Seletor de Idioma", - "langDutch": "Nederlands", - "langEnglish": "English", "hotkeysLabel": "Hotkeys", - "langPolish": "Polski", - "langFrench": "Français", - "langGerman": "Deutsch", - "langItalian": "Italiano", - "langJapanese": "日本語", - "langSimplifiedChinese": "简体中文", - "langSpanish": "Espanhol", - "langRussian": "Русский", - "langUkranian": "Украї́нська", "img2img": "Imagem para Imagem", "unifiedCanvas": "Tela Unificada", "nodes": "Nós", @@ -60,8 +47,7 @@ "statusMergingModels": "Mesclando Modelos", "statusMergedModels": "Modelos Mesclados", "loading": "A carregar", - "loadingInvokeAI": "A carregar Invoke AI", - "langPortuguese": "Português" + "loadingInvokeAI": "A carregar Invoke AI" }, "gallery": { "galleryImageResetSize": "Resetar Imagem", diff --git a/invokeai/frontend/web/public/locales/pt_BR.json b/invokeai/frontend/web/public/locales/pt_BR.json index ac2d36839b..6d0f12f660 100644 --- a/invokeai/frontend/web/public/locales/pt_BR.json +++ b/invokeai/frontend/web/public/locales/pt_BR.json @@ -7,7 +7,6 @@ "img2img": "Imagem Para Imagem", "unifiedCanvas": "Tela Unificada", "nodes": "Nódulos", - "langBrPortuguese": "Português do Brasil", "nodesDesc": "Um sistema baseado em nódulos para geração de imagens está em contrução. Fique ligado para atualizações sobre essa funcionalidade incrível.", "postProcessing": "Pós-processamento", "postProcessDesc1": "Invoke AI oferece uma variedade e funcionalidades de pós-processamento. Redimensionador de Imagem e Restauração Facial já estão disponíveis na interface. Você pode acessar elas no menu de Opções Avançadas na aba de Texto para Imagem e Imagem para Imagem. Você também pode processar imagens diretamente, usando os botões de ação de imagem acima da atual tela de imagens ou visualizador.", @@ -42,23 +41,11 @@ "statusModelChanged": "Modelo Alterado", "githubLabel": "Github", "discordLabel": "Discord", - "langArabic": "Árabe", - "langEnglish": "Inglês", - "langDutch": "Holandês", - "langFrench": "Francês", - "langGerman": "Alemão", - "langItalian": "Italiano", - "langJapanese": "Japonês", - "langPolish": "Polonês", - "langSimplifiedChinese": "Chinês", - "langUkranian": "Ucraniano", "back": "Voltar", "statusConvertingModel": "Convertendo Modelo", "statusModelConverted": "Modelo Convertido", "statusMergingModels": "Mesclando Modelos", "statusMergedModels": "Modelos Mesclados", - "langRussian": "Russo", - "langSpanish": "Espanhol", "loadingInvokeAI": "Carregando Invoke AI", "loading": "Carregando" }, diff --git a/invokeai/frontend/web/public/locales/ru.json b/invokeai/frontend/web/public/locales/ru.json index db4f7552cb..9643699333 100644 --- a/invokeai/frontend/web/public/locales/ru.json +++ b/invokeai/frontend/web/public/locales/ru.json @@ -7,7 +7,6 @@ "img2img": "Изображение в изображение (img2img)", "unifiedCanvas": "Единый холст", "nodes": "Редактор рабочего процесса", - "langRussian": "Русский", "nodesDesc": "Cистема генерации изображений на основе нодов (узлов) уже разрабатывается. Следите за новостями об этой замечательной функции.", "postProcessing": "Постобработка", "postProcessDesc1": "Invoke AI предлагает широкий спектр функций постобработки. Увеличение изображения (upscale) и восстановление лиц уже доступны в интерфейсе. Получите доступ к ним из меню 'Дополнительные параметры' на вкладках 'Текст в изображение' и 'Изображение в изображение'. Обрабатывайте изображения напрямую, используя кнопки действий с изображениями над текущим изображением или в режиме просмотра.", @@ -51,23 +50,8 @@ "statusConvertingModel": "Конвертация модели", "cancel": "Отменить", "accept": "Принять", - "langUkranian": "Украї́нська", - "langEnglish": "English", "postprocessing": "Постобработка", - "langArabic": "العربية", - "langSpanish": "Español", - "langSimplifiedChinese": "简体中文", - "langDutch": "Nederlands", - "langFrench": "Français", - "langGerman": "German", - "langHebrew": "Hebrew", - "langItalian": "Italiano", - "langJapanese": "日本語", - "langKorean": "한국어", - "langPolish": "Polski", - "langPortuguese": "Português", "txt2img": "Текст в изображение (txt2img)", - "langBrPortuguese": "Português do Brasil", "linear": "Линейная обработка", "dontAskMeAgain": "Больше не спрашивать", "areYouSure": "Вы уверены?", @@ -76,7 +60,6 @@ "openInNewTab": "Открыть в новой вкладке", "imagePrompt": "Запрос", "communityLabel": "Сообщество", - "lightMode": "Светлая тема", "batch": "Пакетный менеджер", "modelManager": "Менеджер моделей", "darkMode": "Темная тема", diff --git a/invokeai/frontend/web/public/locales/sv.json b/invokeai/frontend/web/public/locales/sv.json index ac2c3661e6..b292b08753 100644 --- a/invokeai/frontend/web/public/locales/sv.json +++ b/invokeai/frontend/web/public/locales/sv.json @@ -26,24 +26,8 @@ "githubLabel": "Github", "discordLabel": "Discord", "settingsLabel": "Inställningar", - "langEnglish": "Engelska", - "langDutch": "Nederländska", - "langFrench": "Franska", - "langGerman": "Tyska", - "langItalian": "Italienska", - "langArabic": "العربية", - "langHebrew": "עברית", - "langPolish": "Polski", - "langPortuguese": "Português", - "langBrPortuguese": "Português do Brasil", - "langSimplifiedChinese": "简体中文", - "langJapanese": "日本語", - "langKorean": "한국어", - "langRussian": "Русский", "unifiedCanvas": "Förenad kanvas", "nodesDesc": "Ett nodbaserat system för bildgenerering är under utveckling. Håll utkik för uppdateringar om denna fantastiska funktion.", - "langUkranian": "Украї́нська", - "langSpanish": "Español", "postProcessDesc2": "Ett dedikerat användargränssnitt kommer snart att släppas för att underlätta mer avancerade arbetsflöden av efterbehandling.", "trainingDesc1": "Ett dedikerat arbetsflöde för träning av dina egna inbäddningar och kontrollpunkter genom Textual Inversion eller Dreambooth från webbgränssnittet.", "trainingDesc2": "InvokeAI stöder redan träning av anpassade inbäddningar med hjälp av Textual Inversion genom huvudscriptet.", diff --git a/invokeai/frontend/web/public/locales/tr.json b/invokeai/frontend/web/public/locales/tr.json index ebff991d63..a7b7d998ef 100644 --- a/invokeai/frontend/web/public/locales/tr.json +++ b/invokeai/frontend/web/public/locales/tr.json @@ -34,20 +34,6 @@ "githubLabel": "Github", "discordLabel": "Discord", "settingsLabel": "Seçenekler", - "langArabic": "Arapça", - "langEnglish": "İngilizce", - "langDutch": "Hollandaca", - "langFrench": "Fransızca", - "langGerman": "Almanca", - "langItalian": "İtalyanca", - "langJapanese": "Japonca", - "langPolish": "Lehçe", - "langPortuguese": "Portekizce", - "langBrPortuguese": "Portekizce (Brezilya)", - "langRussian": "Rusça", - "langSimplifiedChinese": "Çince (Basit)", - "langUkranian": "Ukraynaca", - "langSpanish": "İspanyolca", "txt2img": "Yazıdan Görsel", "img2img": "Görselden Görsel", "linear": "Doğrusal", @@ -56,7 +42,6 @@ "postProcessing": "Rötuş", "postProcessDesc2": "Daha gelişmiş iş akışlarına olanak sağlayacak özel bir arayüz yakında yayınlanacaktır.", "postProcessDesc3": "Invoke AI Komut Satırı Arayüzü, içlerinde Embiggen da bulunan birçok özellik sunmaktadır.", - "langKorean": "Korece", "unifiedCanvas": "Tuval", "nodesDesc": "Görsel oluşturmaya yardımcı çizge tabanlı sistem şimdilik geliştirme aşamasındadır. Bu süper özellik hakkındaki gelişmeler için kulağınız bizde olsun.", "postProcessDesc1": "Invoke AI birçok rötuş (post-process) aracı sağlar. Görsel büyütme ve yüz iyileştirme WebUI üzerinden kullanıma uygun durumdadır. Bunlara Yazıdan Görsel ve Görselden Görsel sekmelerindeki Gelişmiş Seçenekler menüsünden ulaşabilirsiniz. Ayrıca var olan görseli üzerindeki düğmeler yardımıyla düzenleyebilirsiniz.", @@ -78,7 +63,6 @@ "notInstalled": "$t(common.installed) Değil", "openInNewTab": "Yeni Sekmede Aç", "aboutHeading": "Yaratıcı Gücünüzün Sahibi Olun", - "lightMode": "Açık Tema", "load": "Yükle", "loading": "Yükleniyor", "loadingInvokeAI": "Invoke AI Yükleniyor", @@ -88,7 +72,6 @@ "orderBy": "Sırala", "outpaint": "dışboyama", "outputs": "Çıktılar", - "langHebrew": "İbranice", "learnMore": "Bilgi Edin", "nodeEditor": "Çizge Düzenleyici", "save": "Kaydet", diff --git a/invokeai/frontend/web/public/locales/uk.json b/invokeai/frontend/web/public/locales/uk.json index 92f6a88282..bbf2daf099 100644 --- a/invokeai/frontend/web/public/locales/uk.json +++ b/invokeai/frontend/web/public/locales/uk.json @@ -7,7 +7,6 @@ "img2img": "Зображення із зображення (img2img)", "unifiedCanvas": "Універсальне полотно", "nodes": "Вузли", - "langUkranian": "Украї́нська", "nodesDesc": "Система генерації зображень на основі нодів (вузлів) вже розробляється. Слідкуйте за новинами про цю чудову функцію.", "postProcessing": "Постобробка", "postProcessDesc1": "Invoke AI пропонує широкий спектр функцій постобробки. Збільшення зображення (upscale) та відновлення облич вже доступні в інтерфейсі. Отримайте доступ до них з меню 'Додаткові параметри' на вкладках 'Зображення із тексту' та 'Зображення із зображення'. Обробляйте зображення безпосередньо, використовуючи кнопки дій із зображеннями над поточним зображенням або в режимі перегляду.", @@ -48,24 +47,9 @@ "statusMergingModels": "Злиття моделей", "loading": "Завантаження", "loadingInvokeAI": "Завантаження Invoke AI", - "langHebrew": "Іврит", - "langKorean": "Корейська", - "langPortuguese": "Португальська", - "langArabic": "Арабська", - "langSimplifiedChinese": "Китайська (спрощена)", - "langSpanish": "Іспанська", - "langEnglish": "Англійська", - "langGerman": "Німецька", - "langItalian": "Італійська", - "langJapanese": "Японська", - "langPolish": "Польська", - "langBrPortuguese": "Португальська (Бразилія)", - "langRussian": "Російська", "githubLabel": "Github", "txt2img": "Текст в зображення (txt2img)", "discordLabel": "Discord", - "langDutch": "Голландська", - "langFrench": "Французька", "statusMergedModels": "Моделі об'єднані", "statusConvertingModel": "Конвертація моделі", "linear": "Лінійна обробка" diff --git a/invokeai/frontend/web/public/locales/zh_CN.json b/invokeai/frontend/web/public/locales/zh_CN.json index 746f859668..24bda1efa7 100644 --- a/invokeai/frontend/web/public/locales/zh_CN.json +++ b/invokeai/frontend/web/public/locales/zh_CN.json @@ -7,7 +7,6 @@ "img2img": "图生图", "unifiedCanvas": "统一画布", "nodes": "工作流编辑器", - "langSimplifiedChinese": "简体中文", "nodesDesc": "一个基于节点的图像生成系统目前正在开发中。请持续关注关于这一功能的更新。", "postProcessing": "后期处理", "postProcessDesc1": "Invoke AI 提供各种各样的后期处理功能。图像放大和面部修复在网页界面中已经可用。你可以从文生图和图生图页面的高级选项菜单中访问它们。你也可以直接使用图像显示上方或查看器中的图像操作按钮处理图像。", @@ -45,12 +44,9 @@ "dontAskMeAgain": "不要再次询问", "areYouSure": "你确认吗?", "imagePrompt": "图片提示词", - "langKorean": "朝鲜语", - "langPortuguese": "葡萄牙语", "random": "随机", "generate": "生成", "openInNewTab": "在新的标签页打开", - "langUkranian": "乌克兰语", "back": "返回", "statusMergedModels": "模型已合并", "statusConvertingModel": "转换模型中", @@ -58,18 +54,6 @@ "statusMergingModels": "合并模型", "githubLabel": "GitHub", "discordLabel": "Discord", - "langPolish": "波兰语", - "langBrPortuguese": "葡萄牙语(巴西)", - "langDutch": "荷兰语", - "langFrench": "法语", - "langRussian": "俄语", - "langGerman": "德语", - "langHebrew": "希伯来语", - "langItalian": "意大利语", - "langJapanese": "日语", - "langSpanish": "西班牙语", - "langEnglish": "英语", - "langArabic": "阿拉伯语", "txt2img": "文生图", "postprocessing": "后期处理", "loading": "加载中", @@ -81,7 +65,6 @@ "nodeEditor": "节点编辑器", "statusProcessing": "处理中", "imageFailedToLoad": "无法加载图像", - "lightMode": "浅色模式", "learnMore": "了解更多", "darkMode": "深色模式", "advanced": "高级", diff --git a/invokeai/frontend/web/public/locales/zh_Hant.json b/invokeai/frontend/web/public/locales/zh_Hant.json index fe51856117..b15333edf6 100644 --- a/invokeai/frontend/web/public/locales/zh_Hant.json +++ b/invokeai/frontend/web/public/locales/zh_Hant.json @@ -2,37 +2,22 @@ "common": { "nodes": "節點", "img2img": "圖片轉圖片", - "langSimplifiedChinese": "簡體中文", "statusError": "錯誤", "statusDisconnected": "已中斷連線", "statusConnected": "已連線", "back": "返回", "load": "載入", "close": "關閉", - "langEnglish": "英語", "settingsLabel": "設定", "upload": "上傳", - "langArabic": "阿拉伯語", "discordLabel": "Discord", "nodesDesc": "使用Node生成圖像的系統正在開發中。敬請期待有關於這項功能的更新。", "reportBugLabel": "回報錯誤", "githubLabel": "GitHub", - "langKorean": "韓語", - "langPortuguese": "葡萄牙語", "hotkeysLabel": "快捷鍵", "languagePickerLabel": "切換語言", - "langDutch": "荷蘭語", - "langFrench": "法語", - "langGerman": "德語", - "langItalian": "義大利語", - "langJapanese": "日語", - "langPolish": "波蘭語", - "langBrPortuguese": "巴西葡萄牙語", - "langRussian": "俄語", - "langSpanish": "西班牙語", "unifiedCanvas": "統一畫布", "cancel": "取消", - "langHebrew": "希伯來語", "txt2img": "文字轉圖片" }, "accessibility": {