mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into refactor/model-manager2/loader
This commit is contained in:
@ -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:**
|
||||
</br>
|
||||
<img src="https://github.com/skunkworxdark/autostereogram_nodes/blob/main/images/spider.png" width="200" /> -> <img src="https://github.com/skunkworxdark/autostereogram_nodes/blob/main/images/spider-depth.png" width="200" /> -> <img src="https://github.com/skunkworxdark/autostereogram_nodes/raw/main/images/spider-dots.png" width="200" /> <img src="https://github.com/skunkworxdark/autostereogram_nodes/raw/main/images/spider-pattern.png" width="200" />
|
||||
|
||||
--------------------------------
|
||||
### Average Images
|
||||
|
||||
|
@ -173,10 +173,10 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, ClassVar, Dict, List, Literal, Optional, get_type_hints
|
||||
from typing import Any, ClassVar, Dict, List, Literal, Optional, Union
|
||||
|
||||
from omegaconf import DictConfig, OmegaConf
|
||||
from pydantic import Field, TypeAdapter
|
||||
from pydantic import Field
|
||||
from pydantic.config import JsonDict
|
||||
from pydantic_settings import SettingsConfigDict
|
||||
|
||||
@ -339,13 +339,9 @@ 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]),
|
||||
)
|
||||
# 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)
|
||||
|
||||
@classmethod
|
||||
def get_config(cls, **kwargs: Any) -> InvokeAIAppConfig:
|
||||
|
@ -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
|
||||
@ -63,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,
|
||||
@ -78,11 +79,11 @@ 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)
|
||||
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
|
||||
|
@ -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:
|
||||
|
@ -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")
|
@ -1,15 +1,16 @@
|
||||
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)
|
||||
|
||||
|
||||
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.
|
||||
@ -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:
|
||||
if item is None:
|
||||
raise ItemNotFoundError(item_id)
|
||||
self._items[item_id] = item
|
||||
return self._items.get(item_id)
|
||||
return item
|
||||
|
||||
def set(self, item: T) -> None:
|
||||
item_id = getattr(item, self._id_field)
|
||||
|
@ -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
|
||||
|
||||
|
@ -424,6 +424,7 @@ class ONNXModelPatcher:
|
||||
blended_loras = {}
|
||||
|
||||
for lora, lora_weight in loras:
|
||||
print(f'DEBUG: lora type = {type(lora)}')
|
||||
for layer_key, layer in lora.layers.items():
|
||||
if not layer_key.startswith(prefix):
|
||||
continue
|
||||
|
@ -7,7 +7,6 @@
|
||||
"img2img": "صورة إلى صورة",
|
||||
"unifiedCanvas": "لوحة موحدة",
|
||||
"nodes": "عقد",
|
||||
"langArabic": "العربية",
|
||||
"nodesDesc": "نظام مبني على العقد لإنتاج الصور قيد التطوير حاليًا. تبقى على اتصال مع تحديثات حول هذه الميزة المذهلة.",
|
||||
"postProcessing": "معالجة بعد الإصدار",
|
||||
"postProcessDesc1": "Invoke AI توفر مجموعة واسعة من ميزات المعالجة بعد الإصدار. تحسين الصور واستعادة الوجوه متاحين بالفعل في واجهة الويب. يمكنك الوصول إليهم من الخيارات المتقدمة في قائمة الخيارات في علامة التبويب Text To Image و Image To Image. يمكن أيضًا معالجة الصور مباشرةً باستخدام أزرار الإجراء على الصورة فوق عرض الصورة الحالي أو في العارض.",
|
||||
|
5
invokeai/frontend/web/public/locales/az.json
Normal file
5
invokeai/frontend/web/public/locales/az.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"accessibility": {
|
||||
"about": "Haqqında"
|
||||
}
|
||||
}
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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": "אחורה",
|
||||
|
@ -34,7 +34,6 @@
|
||||
"delete": "Törlés",
|
||||
"data": "Adat",
|
||||
"discordLabel": "Discord",
|
||||
"folder": "Mappa",
|
||||
"langEnglish": "Angol"
|
||||
"folder": "Mappa"
|
||||
}
|
||||
}
|
||||
|
@ -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à",
|
||||
|
@ -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": "ダークモード",
|
||||
|
@ -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": "고급",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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": "Темная тема",
|
||||
|
@ -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.",
|
||||
|
@ -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,21 +33,7 @@
|
||||
"reportBugLabel": "Sorun Bildir",
|
||||
"githubLabel": "Github",
|
||||
"discordLabel": "Discord",
|
||||
"settingsLabel": "Ayarlar",
|
||||
"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",
|
||||
"settingsLabel": "Seçenekler",
|
||||
"txt2img": "Yazıdan Görsel",
|
||||
"img2img": "Görselden Görsel",
|
||||
"linear": "Doğrusal",
|
||||
@ -56,10 +42,9 @@
|
||||
"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ş 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 +53,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",
|
||||
@ -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",
|
||||
@ -153,7 +136,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 +160,9 @@
|
||||
"infillTab": "Doldurma"
|
||||
},
|
||||
"control": {
|
||||
"ipTab": "Görsel İstemleri"
|
||||
"ipTab": "Görsel İstemleri",
|
||||
"title": "Yönetim",
|
||||
"controlAdaptersTab": "Yönetim Araçları"
|
||||
}
|
||||
},
|
||||
"boards": {
|
||||
@ -221,7 +210,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",
|
||||
@ -240,12 +229,55 @@
|
||||
"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",
|
||||
"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 dönüştürür",
|
||||
"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",
|
||||
"ipAdapterImageFallback": "IP Aracı Görseli Seçilmemiş"
|
||||
},
|
||||
"queue": {
|
||||
"queuedCount": "{{pending}} Sırada",
|
||||
@ -304,7 +336,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",
|
||||
@ -331,7 +365,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",
|
||||
@ -349,13 +383,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",
|
||||
@ -390,12 +427,12 @@
|
||||
"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": {
|
||||
"desc": "Ayar panelini iğnele",
|
||||
"title": "Ayarları İğnele"
|
||||
"desc": "Seçenekler panelini iğnele",
|
||||
"title": "Seçenekleri İğnele"
|
||||
},
|
||||
"nodesHotkeys": "Çizgeler",
|
||||
"quickToggleMove": {
|
||||
@ -500,8 +537,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 +571,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 +591,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",
|
||||
@ -581,6 +618,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": {
|
||||
@ -606,7 +647,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ışı?",
|
||||
@ -617,7 +658,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",
|
||||
@ -659,20 +715,264 @@
|
||||
},
|
||||
"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",
|
||||
"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"
|
||||
"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ı 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 Konumu",
|
||||
"customConfig": "Özel Yapılandırma",
|
||||
"addModel": "Model Ekle",
|
||||
"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"
|
||||
"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",
|
||||
"loading": "Yükleniyor...",
|
||||
"denoisingStrength": "Arındırma Ölçüsü",
|
||||
"concatPromptStyle": "İstem ve Stili Bitiştir"
|
||||
}
|
||||
}
|
||||
|
@ -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": "Лінійна обробка"
|
||||
|
@ -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": "高级",
|
||||
|
@ -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": {
|
||||
|
@ -3,49 +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 { canvasPersistDenylist } from 'features/canvas/store/canvasPersistDenylist';
|
||||
import canvasReducer, { initialCanvasState, migrateCanvasState } from 'features/canvas/store/canvasSlice';
|
||||
import changeBoardModalReducer from 'features/changeBoardModal/store/slice';
|
||||
import { controlAdaptersPersistDenylist } from 'features/controlAdapters/store/controlAdaptersPersistDenylist';
|
||||
import controlAdaptersReducer, {
|
||||
initialControlAdaptersState,
|
||||
migrateControlAdaptersState,
|
||||
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 { 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 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 queueReducer from 'features/queue/store/queueSlice';
|
||||
import sdxlReducer, { initialSDXLState, migrateSDXLState } 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 { 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';
|
||||
@ -61,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,
|
||||
};
|
||||
|
||||
@ -88,75 +68,53 @@ 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<T = any> = {
|
||||
/**
|
||||
* 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];
|
||||
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));
|
||||
@ -176,26 +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;
|
||||
}
|
||||
};
|
||||
|
||||
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 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);
|
||||
};
|
||||
|
||||
@ -215,7 +163,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,
|
||||
|
@ -1,6 +0,0 @@
|
||||
import type { CanvasState } from './canvasTypes';
|
||||
|
||||
/**
|
||||
* Canvas slice persist denylist
|
||||
*/
|
||||
export const canvasPersistDenylist: (keyof CanvasState)[] = [];
|
@ -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';
|
||||
@ -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 */
|
||||
@ -731,3 +729,10 @@ export const migrateCanvasState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const canvasPersistConfig: PersistConfig<CanvasState> = {
|
||||
name: canvasSlice.name,
|
||||
initialState: initialCanvasState,
|
||||
migrate: migrateCanvasState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -1,6 +0,0 @@
|
||||
import type { ControlAdaptersState } from './types';
|
||||
|
||||
/**
|
||||
* ControlNet slice persist denylist
|
||||
*/
|
||||
export const controlAdaptersPersistDenylist: (keyof ControlAdaptersState)[] = ['pendingControlImages'];
|
@ -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,
|
||||
@ -424,8 +424,6 @@ export const {
|
||||
controlAdapterModelCleared,
|
||||
} = controlAdaptersSlice.actions;
|
||||
|
||||
export default controlAdaptersSlice.reducer;
|
||||
|
||||
export const isAnyControlAdapterAdded = isAnyOf(
|
||||
controlAdapterAdded,
|
||||
controlAdapterAddedFromImage,
|
||||
@ -441,3 +439,10 @@ export const migrateControlAdaptersState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const controlAdaptersPersistConfig: PersistConfig<ControlAdaptersState> = {
|
||||
name: controlAdaptersSlice.name,
|
||||
initialState: initialControlAdaptersState,
|
||||
migrate: migrateControlAdaptersState,
|
||||
persistDenylist: ['pendingControlImages'],
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -1,3 +0,0 @@
|
||||
import type { initialDynamicPromptsState } from './dynamicPromptsSlice';
|
||||
|
||||
export const dynamicPromptsPersistDenylist: (keyof typeof initialDynamicPromptsState)[] = ['prompts'];
|
@ -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']);
|
||||
@ -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 */
|
||||
@ -85,3 +83,10 @@ export const migrateDynamicPromptsState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const dynamicPromptsPersistConfig: PersistConfig<DynamicPromptsState> = {
|
||||
name: dynamicPromptsSlice.name,
|
||||
initialState: initialDynamicPromptsState,
|
||||
migrate: migrateDynamicPromptsState,
|
||||
persistDenylist: ['prompts'],
|
||||
};
|
||||
|
@ -1,12 +0,0 @@
|
||||
import type { initialGalleryState } from './gallerySlice';
|
||||
|
||||
/**
|
||||
* Gallery slice persist denylist
|
||||
*/
|
||||
export const galleryPersistDenylist: (keyof typeof initialGalleryState)[] = [
|
||||
'selection',
|
||||
'selectedBoardId',
|
||||
'galleryView',
|
||||
'offset',
|
||||
'limit',
|
||||
];
|
@ -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';
|
||||
@ -109,8 +109,6 @@ export const {
|
||||
moreImagesLoaded,
|
||||
} = gallerySlice.actions;
|
||||
|
||||
export default gallerySlice.reducer;
|
||||
|
||||
const isAnyBoardDeleted = isAnyOf(
|
||||
imagesApi.endpoints.deleteBoard.matchFulfilled,
|
||||
imagesApi.endpoints.deleteBoardAndImages.matchFulfilled
|
||||
@ -125,3 +123,10 @@ export const migrateGalleryState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const galleryPersistConfig: PersistConfig<GalleryState> = {
|
||||
name: gallerySlice.name,
|
||||
initialState: initialGalleryState,
|
||||
migrate: migrateGalleryState,
|
||||
persistDenylist: ['selection', 'selectedBoardId', 'galleryView', 'offset', 'limit'],
|
||||
};
|
||||
|
@ -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 {
|
||||
@ -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 */
|
||||
@ -48,3 +46,10 @@ export const migrateHRFState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const hrfPersistConfig: PersistConfig<HRFState> = {
|
||||
name: hrfSlice.name,
|
||||
initialState: initialHRFState,
|
||||
migrate: migrateHRFState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -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';
|
||||
|
||||
@ -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 */
|
||||
@ -92,3 +90,10 @@ export const migrateLoRAState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const loraPersistConfig: PersistConfig<LoraState> = {
|
||||
name: loraSlice.name,
|
||||
initialState: initialLoraState,
|
||||
migrate: migrateLoRAState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -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;
|
||||
@ -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 */
|
||||
@ -40,3 +38,10 @@ export const migrateModelManagerState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const modelManagerPersistConfig: PersistConfig<ModelManagerState> = {
|
||||
name: modelManagerSlice.name,
|
||||
initialState: initialModelManagerState,
|
||||
migrate: migrateModelManagerState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -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<ColorFieldInputInstance, ColorFieldInputTemplate>) => {
|
||||
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 <RgbaColorPicker className="nodrag" color={field.value} onChange={handleValueChanged} />;
|
||||
return <RgbaColorPicker className="nodrag" color={color} onChange={handleValueChanged} />;
|
||||
};
|
||||
|
||||
export default memo(ColorFieldInputComponent);
|
||||
|
@ -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;
|
||||
|
@ -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',
|
||||
];
|
@ -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';
|
||||
@ -139,7 +139,7 @@ const fieldValueReducer = <T extends FieldValue>(
|
||||
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 */
|
||||
@ -863,3 +861,21 @@ export const migrateNodesState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const nodesPersistConfig: PersistConfig<NodesState> = {
|
||||
name: nodesSlice.name,
|
||||
initialState: initialNodesState,
|
||||
migrate: migrateNodesState,
|
||||
persistDenylist: [
|
||||
'connectionStartParams',
|
||||
'connectionStartFieldType',
|
||||
'selectedNodes',
|
||||
'selectedEdges',
|
||||
'isReady',
|
||||
'nodesToCopy',
|
||||
'edgesToCopy',
|
||||
'connectionMade',
|
||||
'modifyingEdge',
|
||||
'addNewNodePosition',
|
||||
],
|
||||
};
|
||||
|
@ -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';
|
||||
@ -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 */
|
||||
@ -130,3 +128,10 @@ export const migrateWorkflowState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const workflowPersistConfig: PersistConfig<WorkflowState> = {
|
||||
name: workflowSlice.name,
|
||||
initialState: initialWorkflowState,
|
||||
migrate: migrateWorkflowState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -373,6 +373,8 @@ const buildEnumFieldInputTemplate: FieldInputTemplateBuilder<EnumFieldInputTempl
|
||||
} else {
|
||||
options = firstAnyOf.enum ?? [];
|
||||
}
|
||||
} else if (schemaObject.const) {
|
||||
options = [schemaObject.const];
|
||||
} else {
|
||||
options = schemaObject.enum ?? [];
|
||||
}
|
||||
|
@ -55,6 +55,14 @@ export const parseFieldType = (schemaObject: OpenAPIV3_1SchemaOrRef): FieldType
|
||||
}
|
||||
}
|
||||
if (isSchemaObject(schemaObject)) {
|
||||
if (schemaObject.const) {
|
||||
// Fields with a single const value are defined as `Literal["value"]` in the pydantic schema - it's actually an enum
|
||||
return {
|
||||
name: 'EnumField',
|
||||
isCollection: false,
|
||||
isCollectionOrScalar: false,
|
||||
};
|
||||
}
|
||||
if (!schemaObject.type) {
|
||||
// if schemaObject has no type, then it should have one of allOf, anyOf, oneOf
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -124,6 +128,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 +221,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;
|
||||
|
@ -1,6 +0,0 @@
|
||||
import type { GenerationState } from './types';
|
||||
|
||||
/**
|
||||
* Generation slice persist denylist
|
||||
*/
|
||||
export const generationPersistDenylist: (keyof GenerationState)[] = [];
|
@ -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';
|
||||
@ -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 */
|
||||
@ -311,3 +309,10 @@ export const migrateGenerationState = (state: any): GenerationState => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const generationPersistConfig: PersistConfig<GenerationState> = {
|
||||
name: generationSlice.name,
|
||||
initialState: initialGenerationState,
|
||||
migrate: migrateGenerationState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -1,6 +0,0 @@
|
||||
import type { PostprocessingState } from './postprocessingSlice';
|
||||
|
||||
/**
|
||||
* Postprocessing slice persist denylist
|
||||
*/
|
||||
export const postprocessingPersistDenylist: (keyof PostprocessingState)[] = [];
|
@ -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([
|
||||
@ -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 */
|
||||
@ -46,3 +44,10 @@ export const migratePostprocessingState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const postprocessingPersistConfig: PersistConfig<PostprocessingState> = {
|
||||
name: postprocessingSlice.name,
|
||||
initialState: initialPostprocessingState,
|
||||
migrate: migratePostprocessingState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -53,6 +53,4 @@ export const {
|
||||
resumeProcessorOnEnqueueChanged,
|
||||
} = queueSlice.actions;
|
||||
|
||||
export default queueSlice.reducer;
|
||||
|
||||
export const selectQueueSlice = (state: RootState) => state.queue;
|
||||
|
@ -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,
|
||||
@ -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 */
|
||||
@ -97,3 +95,10 @@ export const migrateSDXLState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const sdxlPersistConfig: PersistConfig<SDXLState> = {
|
||||
name: sdxlSlice.name,
|
||||
initialState: initialSDXLState,
|
||||
migrate: migrateSDXLState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
@ -3,41 +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<Language, string> = {
|
||||
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: 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' },
|
||||
],
|
||||
[t]
|
||||
);
|
||||
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<ComboboxOnChange>(
|
||||
(v) => {
|
||||
|
@ -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,
|
||||
})}
|
||||
|
||||
<Modal isOpen={isSettingsModalOpen} onClose={onSettingsModalClose} size="2xl" isCentered>
|
||||
|
@ -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 };
|
||||
};
|
||||
|
@ -177,6 +177,4 @@ export const configSlice = createSlice({
|
||||
|
||||
export const { configChanged } = configSlice.actions;
|
||||
|
||||
export default configSlice.reducer;
|
||||
|
||||
export const selectConfigSlice = (state: RootState) => state.config;
|
||||
|
@ -1,3 +0,0 @@
|
||||
import type { SystemState } from './types';
|
||||
|
||||
export const systemPersistDenylist: (keyof SystemState)[] = ['isConnected', 'denoiseProgress', 'status'];
|
@ -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';
|
||||
@ -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;
|
||||
@ -207,3 +205,10 @@ export const migrateSystemState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const systemPersistConfig: PersistConfig<SystemState> = {
|
||||
name: systemSlice.name,
|
||||
initialState: initialSystemState,
|
||||
migrate: migrateSystemState,
|
||||
persistDenylist: ['isConnected', 'denoiseProgress', 'status'],
|
||||
};
|
||||
|
@ -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<typeof zLanguage>;
|
||||
export const isLanguage = (v: unknown): v is Language => zLanguage.safeParse(v).success;
|
||||
|
@ -1,6 +0,0 @@
|
||||
import type { UIState } from './uiTypes';
|
||||
|
||||
/**
|
||||
* UI slice persist denylist
|
||||
*/
|
||||
export const uiPersistDenylist: (keyof UIState)[] = ['shouldShowImageDetails'];
|
@ -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';
|
||||
@ -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 */
|
||||
@ -68,3 +66,10 @@ export const migrateUIState = (state: any): any => {
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const uiPersistConfig: PersistConfig<UIState> = {
|
||||
name: uiSlice.name,
|
||||
initialState: initialUIState,
|
||||
migrate: migrateUIState,
|
||||
persistDenylist: ['shouldShowImageDetails'],
|
||||
};
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
||||
|
||||
@ -17,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]):
|
||||
@ -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]):
|
||||
@ -73,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 == {
|
||||
|
Reference in New Issue
Block a user