chore: import upstream snapshot with attribution
docs / deploy (push) Has been cancelled
docs / changes (push) Has been cancelled
docs / check-and-build (push) Has been cancelled
build container image / cpu (push) Has been cancelled
build container image / cuda (push) Has been cancelled
build container image / rocm (push) Has been cancelled
frontend checks / frontend-checks (push) Has been cancelled
frontend tests / frontend-tests (push) Has been cancelled
lfs checks / lfs-check (push) Has been cancelled
python checks / python-checks (push) Has been cancelled
python tests / py3.12: macos-default (push) Has been cancelled
python tests / py3.11: windows-cpu (push) Has been cancelled
python tests / py3.12: windows-cpu (push) Has been cancelled
python tests / py3.11: linux-cpu (push) Has been cancelled
typegen checks / typegen-checks (push) Has been cancelled
uv lock checks / uv-lock-checks (push) Has been cancelled
openapi checks / openapi-checks (push) Has been cancelled
python tests / py3.11: macos-default (push) Has been cancelled
python tests / py3.12: linux-cpu (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:22:06 +08:00
commit cddb07a176
3370 changed files with 685519 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
"""
Initialization file for invokeai.frontend
"""
View File
+46
View File
@@ -0,0 +1,46 @@
from argparse import ArgumentParser, Namespace, RawTextHelpFormatter
from typing import Optional
from invokeai.version import __version__
_root_help = r"""Path to the runtime root directory. If omitted, the app will search for the root directory in the following order:
- The `$INVOKEAI_ROOT` environment variable
- The currently active virtual environment's parent directory
- `$HOME/invokeai`"""
_config_file_help = r"""Path to the invokeai.yaml configuration file. If omitted, the app will search for the file in the root directory."""
_parser = ArgumentParser(description="Invoke Studio", formatter_class=RawTextHelpFormatter)
_parser.add_argument("--root", type=str, help=_root_help)
_parser.add_argument("--config", dest="config_file", type=str, help=_config_file_help)
_parser.add_argument("--version", action="version", version=__version__, help="Displays the version and exits.")
class InvokeAIArgs:
"""Helper class for parsing CLI args.
Args should never be parsed within the application code, only in the CLI entrypoints. Parsing args within the
application creates conflicts when running tests or when using application modules directly.
If the args are needed within the application, the consumer should access them from this class.
Example:
```
# In a CLI wrapper
from invokeai.frontend.cli.arg_parser import InvokeAIArgs
InvokeAIArgs.parse_args()
# In the application
from invokeai.frontend.cli.arg_parser import InvokeAIArgs
args = InvokeAIArgs.args
"""
args: Optional[Namespace] = None
did_parse: bool = False
@staticmethod
def parse_args() -> Optional[Namespace]:
"""Parse CLI args and store the result."""
InvokeAIArgs.args = _parser.parse_args()
InvokeAIArgs.did_parse = True
return InvokeAIArgs.args
+3
View File
@@ -0,0 +1,3 @@
"""
Initialization file for invokeai.frontend.config
"""
+786
View File
@@ -0,0 +1,786 @@
# Copyright (c) 2023 - The InvokeAI Team
# Primary Author: David Lovell (github @f412design, discord @techjedi)
# co-author, minor tweaks - Lincoln Stein
# pylint: disable=line-too-long
# pylint: disable=broad-exception-caught
"""Script to import images into the new database system for 3.0.0"""
import datetime
import glob
import json
import locale
import os
import re
import shutil
import sqlite3
from pathlib import Path
import PIL
import PIL.ImageOps
import PIL.PngImagePlugin
import yaml
from prompt_toolkit import prompt
from prompt_toolkit.completion import PathCompleter
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.shortcuts import message_dialog
from invokeai.app.services.config.config_default import get_config
from invokeai.app.util.misc import uuid_string
app_config = get_config()
bindings = KeyBindings()
@bindings.add("c-c")
def _(event):
raise KeyboardInterrupt
# release notes
# "Use All" with size dimensions not selectable in the UI will not load dimensions
class Config:
"""Configuration loader."""
def __init__(self):
pass
TIMESTAMP_STRING = datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
INVOKE_DIRNAME = "invokeai"
YAML_FILENAME = "invokeai.yaml"
DATABASE_FILENAME = "invokeai.db"
database_path = None
database_backup_dir = None
outputs_path = None
thumbnail_path = None
def find_and_load(self):
"""Find the yaml config file and load"""
root = app_config.root_path
if not self.confirm_and_load(os.path.abspath(root)):
print("\r\nSpecify custom database and outputs paths:")
self.confirm_and_load_from_user()
self.database_backup_dir = os.path.join(os.path.dirname(self.database_path), "backup")
self.thumbnail_path = os.path.join(self.outputs_path, "thumbnails")
def confirm_and_load(self, invoke_root):
"""Validate a yaml path exists, confirms the user wants to use it and loads config."""
yaml_path = os.path.join(invoke_root, self.YAML_FILENAME)
if os.path.exists(yaml_path):
db_dir, outdir = self.load_paths_from_yaml(yaml_path)
if os.path.isabs(db_dir):
database_path = os.path.join(db_dir, self.DATABASE_FILENAME)
else:
database_path = os.path.join(invoke_root, db_dir, self.DATABASE_FILENAME)
if os.path.isabs(outdir):
outputs_path = os.path.join(outdir, "images")
else:
outputs_path = os.path.join(invoke_root, outdir, "images")
db_exists = os.path.exists(database_path)
outdir_exists = os.path.exists(outputs_path)
text = f"Found {self.YAML_FILENAME} file at {yaml_path}:"
text += f"\n Database : {database_path}"
text += f"\n Outputs : {outputs_path}"
text += "\n\nUse these paths for import (yes) or choose different ones (no) [Yn]: "
if db_exists and outdir_exists:
if (prompt(text).strip() or "Y").upper().startswith("Y"):
self.database_path = database_path
self.outputs_path = outputs_path
return True
else:
return False
else:
print(" Invalid: One or more paths in this config did not exist and cannot be used.")
else:
message_dialog(
title="Path not found",
text=f"Auto-discovery of configuration failed! Could not find ({yaml_path}), Custom paths can be specified.",
).run()
return False
def confirm_and_load_from_user(self):
default = ""
while True:
database_path = os.path.expanduser(
prompt(
"Database: Specify absolute path to the database to import into: ",
completer=PathCompleter(
expanduser=True, file_filter=lambda x: Path(x).is_dir() or x.endswith((".db"))
),
default=default,
)
)
if database_path.endswith(".db") and os.path.isabs(database_path) and os.path.exists(database_path):
break
default = database_path + "/" if Path(database_path).is_dir() else database_path
default = ""
while True:
outputs_path = os.path.expanduser(
prompt(
"Outputs: Specify absolute path to outputs/images directory to import into: ",
completer=PathCompleter(expanduser=True, only_directories=True),
default=default,
)
)
if outputs_path.endswith("images") and os.path.isabs(outputs_path) and os.path.exists(outputs_path):
break
default = outputs_path + "/" if Path(outputs_path).is_dir() else outputs_path
self.database_path = database_path
self.outputs_path = outputs_path
return
def load_paths_from_yaml(self, yaml_path):
"""Load an Invoke AI yaml file and get the database and outputs paths."""
try:
with open(yaml_path, "rt", encoding=locale.getpreferredencoding()) as file:
yamlinfo = yaml.safe_load(file)
db_dir = yamlinfo.get("InvokeAI", {}).get("Paths", {}).get("db_dir", None)
outdir = yamlinfo.get("InvokeAI", {}).get("Paths", {}).get("outdir", None)
return db_dir, outdir
except Exception:
print(f"Failed to load paths from yaml file! {yaml_path}!")
return None, None
class ImportStats:
"""DTO for tracking work progress."""
def __init__(self):
pass
time_start = datetime.datetime.utcnow()
count_source_files = 0
count_skipped_file_exists = 0
count_skipped_db_exists = 0
count_imported = 0
count_imported_by_version = {}
count_file_errors = 0
@staticmethod
def get_elapsed_time_string():
"""Get a friendly time string for the time elapsed since processing start."""
time_now = datetime.datetime.utcnow()
total_seconds = (time_now - ImportStats.time_start).total_seconds()
hours = int((total_seconds) / 3600)
minutes = int(((total_seconds) % 3600) / 60)
seconds = total_seconds % 60
out_str = f"{hours} hour(s) -" if hours > 0 else ""
out_str += f"{minutes} minute(s) -" if minutes > 0 else ""
out_str += f"{seconds:.2f} second(s)"
return out_str
class InvokeAIMetadata:
"""DTO for core Invoke AI generation properties parsed from metadata."""
def __init__(self):
pass
def __str__(self):
formatted_str = f"{self.generation_mode}~{self.steps}~{self.cfg_scale}~{self.model_name}~{self.scheduler}~{self.seed}~{self.width}~{self.height}~{self.rand_device}~{self.strength}~{self.init_image}"
formatted_str += f"\r\npositive_prompt: {self.positive_prompt}"
formatted_str += f"\r\nnegative_prompt: {self.negative_prompt}"
return formatted_str
generation_mode = None
steps = None
cfg_scale = None
model_name = None
scheduler = None
seed = None
width = None
height = None
rand_device = None
strength = None
init_image = None
positive_prompt = None
negative_prompt = None
imported_app_version = None
def to_json(self):
"""Convert the active instance to json format."""
prop_dict = {}
prop_dict["generation_mode"] = self.generation_mode
# dont render prompt nodes if neither are set to avoid the ui thinking it can set them
# if at least one exists, render them both, but use empty string instead of None if one of them is empty
# this allows the field that is empty to actually be cleared byt he UI instead of leaving the previous value
if self.positive_prompt or self.negative_prompt:
prop_dict["positive_prompt"] = "" if self.positive_prompt is None else self.positive_prompt
prop_dict["negative_prompt"] = "" if self.negative_prompt is None else self.negative_prompt
prop_dict["width"] = self.width
prop_dict["height"] = self.height
# only render seed if it has a value to avoid ui thinking it can set this and then error
if self.seed:
prop_dict["seed"] = self.seed
prop_dict["rand_device"] = self.rand_device
prop_dict["cfg_scale"] = self.cfg_scale
prop_dict["steps"] = self.steps
prop_dict["scheduler"] = self.scheduler
prop_dict["clip_skip"] = 0
prop_dict["model"] = {}
prop_dict["model"]["model_name"] = self.model_name
prop_dict["model"]["base_model"] = None
prop_dict["controlnets"] = []
prop_dict["loras"] = []
prop_dict["vae"] = None
prop_dict["strength"] = self.strength
prop_dict["init_image"] = self.init_image
prop_dict["positive_style_prompt"] = None
prop_dict["negative_style_prompt"] = None
prop_dict["refiner_model"] = None
prop_dict["refiner_cfg_scale"] = None
prop_dict["refiner_steps"] = None
prop_dict["refiner_scheduler"] = None
prop_dict["refiner_aesthetic_store"] = None
prop_dict["refiner_start"] = None
prop_dict["imported_app_version"] = self.imported_app_version
return json.dumps(prop_dict)
class InvokeAIMetadataParser:
"""Parses strings with json data to find Invoke AI core metadata properties."""
def __init__(self):
pass
def parse_meta_tag_dream(self, dream_string):
"""Take as input an png metadata json node for the 'dream' field variant from prior to 1.15"""
props = InvokeAIMetadata()
props.imported_app_version = "pre1.15"
seed_match = re.search("-S\\s*(\\d+)", dream_string)
if seed_match is not None:
try:
props.seed = int(seed_match[1])
except ValueError:
props.seed = None
raw_prompt = re.sub("(-S\\s*\\d+)", "", dream_string)
else:
raw_prompt = dream_string
pos_prompt, neg_prompt = self.split_prompt(raw_prompt)
props.positive_prompt = pos_prompt
props.negative_prompt = neg_prompt
return props
def parse_meta_tag_sd_metadata(self, tag_value):
"""Take as input an png metadata json node for the 'sd-metadata' field variant from 1.15 through 2.3.5 post 2"""
props = InvokeAIMetadata()
props.imported_app_version = tag_value.get("app_version")
props.model_name = tag_value.get("model_weights")
img_node = tag_value.get("image")
if img_node is not None:
props.generation_mode = img_node.get("type")
props.width = img_node.get("width")
props.height = img_node.get("height")
props.seed = img_node.get("seed")
props.rand_device = "cuda" # hardcoded since all generations pre 3.0 used cuda random noise instead of cpu
props.cfg_scale = img_node.get("cfg_scale")
props.steps = img_node.get("steps")
props.scheduler = self.map_scheduler(img_node.get("sampler"))
props.strength = img_node.get("strength")
if props.strength is None:
props.strength = img_node.get("strength_steps") # try second name for this property
props.init_image = img_node.get("init_image_path")
if props.init_image is None: # try second name for this property
props.init_image = img_node.get("init_img")
# remove the path info from init_image so if we move the init image, it will be correctly relative in the new location
if props.init_image is not None:
props.init_image = os.path.basename(props.init_image)
raw_prompt = img_node.get("prompt")
if isinstance(raw_prompt, list):
raw_prompt = raw_prompt[0].get("prompt")
props.positive_prompt, props.negative_prompt = self.split_prompt(raw_prompt)
return props
def parse_meta_tag_invokeai(self, tag_value):
"""Take as input an png metadata json node for the 'invokeai' field variant from 3.0.0 beta 1 through 5"""
props = InvokeAIMetadata()
props.imported_app_version = "3.0.0 or later"
props.generation_mode = tag_value.get("type")
if props.generation_mode is not None:
props.generation_mode = props.generation_mode.replace("t2l", "txt2img").replace("l2l", "img2img")
props.width = tag_value.get("width")
props.height = tag_value.get("height")
props.seed = tag_value.get("seed")
props.cfg_scale = tag_value.get("cfg_scale")
props.steps = tag_value.get("steps")
props.scheduler = tag_value.get("scheduler")
props.strength = tag_value.get("strength")
props.positive_prompt = tag_value.get("positive_conditioning")
props.negative_prompt = tag_value.get("negative_conditioning")
return props
def map_scheduler(self, old_scheduler):
"""Convert the legacy sampler names to matching 3.0 schedulers"""
# this was more elegant as a case statement, but that's not available in python 3.9
if old_scheduler is None:
return None
scheduler_map = {
"ddim": "ddim",
"plms": "pnmd",
"k_lms": "lms",
"k_dpm_2": "kdpm_2",
"k_dpm_2_a": "kdpm_2_a",
"dpmpp_2": "dpmpp_2s",
"k_dpmpp_2": "dpmpp_2m",
"k_dpmpp_2_a": None, # invalid, in 2.3.x, selecting this sample would just fallback to last run or plms if new session
"k_euler": "euler",
"k_euler_a": "euler_a",
"k_heun": "heun",
}
return scheduler_map.get(old_scheduler)
def split_prompt(self, raw_prompt: str):
"""Split the unified prompt strings by extracting all negative prompt blocks out into the negative prompt."""
if raw_prompt is None:
return "", ""
raw_prompt_search = raw_prompt.replace("\r", "").replace("\n", "")
matches = re.findall(r"\[(.+?)\]", raw_prompt_search)
if len(matches) > 0:
negative_prompt = ""
if len(matches) == 1:
negative_prompt = matches[0].strip().strip(",")
else:
for match in matches:
negative_prompt += f"({match.strip().strip(',')})"
positive_prompt = re.sub(r"(\[.+?\])", "", raw_prompt_search).strip()
else:
positive_prompt = raw_prompt_search.strip()
negative_prompt = ""
return positive_prompt, negative_prompt
class DatabaseMapper:
"""Class to abstract database functionality."""
def __init__(self, database_path, database_backup_dir):
self.database_path = database_path
self.database_backup_dir = database_backup_dir
self.connection = None
self.cursor = None
def connect(self):
"""Open connection to the database."""
self.connection = sqlite3.connect(self.database_path)
self.cursor = self.connection.cursor()
def get_board_names(self):
"""Get a list of the current board names from the database."""
sql_get_board_name = "SELECT board_name FROM boards"
self.cursor.execute(sql_get_board_name)
rows = self.cursor.fetchall()
return [row[0] for row in rows]
def does_image_exist(self, image_name):
"""Check database if a image name already exists and return a boolean."""
sql_get_image_by_name = f"SELECT image_name FROM images WHERE image_name='{image_name}'"
self.cursor.execute(sql_get_image_by_name)
rows = self.cursor.fetchall()
return True if len(rows) > 0 else False
def add_new_image_to_database(self, filename, width, height, metadata, modified_date_string):
"""Add an image to the database."""
sql_add_image = f"""INSERT INTO images (image_name, image_origin, image_category, width, height, session_id, node_id, metadata, is_intermediate, created_at, updated_at)
VALUES ('{filename}', 'internal', 'general', {width}, {height}, null, null, '{metadata}', 0, '{modified_date_string}', '{modified_date_string}')"""
self.cursor.execute(sql_add_image)
self.connection.commit()
def get_board_id_with_create(self, board_name):
"""Get the board id for supplied name, and create the board if one does not exist."""
sql_find_board = f"SELECT board_id FROM boards WHERE board_name='{board_name}' COLLATE NOCASE"
self.cursor.execute(sql_find_board)
rows = self.cursor.fetchall()
if len(rows) > 0:
return rows[0][0]
else:
board_date_string = datetime.datetime.utcnow().date().isoformat()
new_board_id = uuid_string()
sql_insert_board = f"INSERT INTO boards (board_id, board_name, created_at, updated_at) VALUES ('{new_board_id}', '{board_name}', '{board_date_string}', '{board_date_string}')"
self.cursor.execute(sql_insert_board)
self.connection.commit()
return new_board_id
def add_image_to_board(self, filename, board_id):
"""Add an image mapping to a board."""
add_datetime_str = datetime.datetime.utcnow().isoformat()
sql_add_image_to_board = f"""INSERT INTO board_images (board_id, image_name, created_at, updated_at)
VALUES ('{board_id}', '{filename}', '{add_datetime_str}', '{add_datetime_str}')"""
self.cursor.execute(sql_add_image_to_board)
self.connection.commit()
def disconnect(self):
"""Disconnect from the db, cleaning up connections and cursors."""
if self.cursor is not None:
self.cursor.close()
if self.connection is not None:
self.connection.close()
def backup(self, timestamp_string):
"""Take a backup of the database."""
if not os.path.exists(self.database_backup_dir):
print(f"Database backup directory {self.database_backup_dir} does not exist -> creating...", end="")
os.makedirs(self.database_backup_dir)
print("Done!")
database_backup_path = os.path.join(self.database_backup_dir, f"backup-{timestamp_string}-invokeai.db")
print(f"Making DB Backup at {database_backup_path}...", end="")
shutil.copy2(self.database_path, database_backup_path)
print("Done!")
class MediaImportProcessor:
"""Containing class for script functionality."""
def __init__(self):
pass
board_name_id_map = {}
def get_import_file_list(self):
"""Ask the user for the import folder and scan for the list of files to return."""
while True:
default = ""
while True:
import_dir = os.path.expanduser(
prompt(
"Inputs: Specify absolute path containing InvokeAI .png images to import: ",
completer=PathCompleter(expanduser=True, only_directories=True),
default=default,
)
)
if len(import_dir) > 0 and Path(import_dir).is_dir():
break
default = import_dir
recurse_directories = (
(prompt("Include files from subfolders recursively [yN]? ").strip() or "N").upper().startswith("N")
)
if recurse_directories:
is_recurse = False
matching_file_list = glob.glob(import_dir + "/*.png", recursive=False)
else:
is_recurse = True
matching_file_list = glob.glob(import_dir + "/**/*.png", recursive=True)
if len(matching_file_list) > 0:
return import_dir, is_recurse, matching_file_list
else:
print(f"The specific path {import_dir} exists, but does not contain .png files!")
def get_file_details(self, filepath):
"""Retrieve the embedded metedata fields and dimensions from an image file."""
with PIL.Image.open(filepath) as img:
img.load()
png_width, png_height = img.size
img_info = img.info
return img_info, png_width, png_height
def select_board_option(self, board_names, timestamp_string):
"""Allow the user to choose how a board is selected for imported files."""
while True:
print("\r\nOptions for board selection for imported images:")
print(f"1) Select an existing board name. (found {len(board_names)})")
print("2) Specify a board name to create/add to.")
print("3) Create/add to board named 'IMPORT'.")
print(
f"4) Create/add to board named 'IMPORT' with the current datetime string appended (.e.g IMPORT_{timestamp_string})."
)
print(
"5) Create/add to board named 'IMPORT' with a the original file app_version appended (.e.g IMPORT_2.2.5)."
)
input_option = input("Specify desired board option: ")
# This was more elegant as a case statement, but not supported in python 3.9
if input_option == "1":
if len(board_names) < 1:
print("\r\nThere are no existing board names to choose from. Select another option!")
continue
board_name = self.select_item_from_list(
board_names, "board name", True, "Cancel, go back and choose a different board option."
)
if board_name is not None:
return board_name
elif input_option == "2":
while True:
board_name = input("Specify new/existing board name: ")
if board_name:
return board_name
elif input_option == "3":
return "IMPORT"
elif input_option == "4":
return f"IMPORT_{timestamp_string}"
elif input_option == "5":
return "IMPORT_APPVERSION"
def select_item_from_list(self, items, entity_name, allow_cancel, cancel_string):
"""A general function to render a list of items to select in the console, prompt the user for a selection and ensure a valid entry is selected."""
print(f"Select a {entity_name.lower()} from the following list:")
index = 1
for item in items:
print(f"{index}) {item}")
index += 1
if allow_cancel:
print(f"{index}) {cancel_string}")
while True:
try:
option_number = int(input("Specify number of selection: "))
except ValueError:
continue
if allow_cancel and option_number == index:
return None
if option_number >= 1 and option_number <= len(items):
return items[option_number - 1]
def import_image(self, filepath: str, board_name_option: str, db_mapper: DatabaseMapper, config: Config):
"""Import a single file by its path"""
parser = InvokeAIMetadataParser()
file_name = os.path.basename(filepath)
file_destination_path = os.path.join(config.outputs_path, file_name)
print("===============================================================================")
print(f"Importing {filepath}")
# check destination to see if the file was previously imported
if os.path.exists(file_destination_path):
print("File already exists in the destination, skipping!")
ImportStats.count_skipped_file_exists += 1
return
# check if file name is already referenced in the database
if db_mapper.does_image_exist(file_name):
print("A reference to a file with this name already exists in the database, skipping!")
ImportStats.count_skipped_db_exists += 1
return
# load image info and dimensions
img_info, png_width, png_height = self.get_file_details(filepath)
# parse metadata
destination_needs_meta_update = True
log_version_note = "(Unknown)"
if "invokeai_metadata" in img_info:
# for the latest, we will just re-emit the same json, no need to parse/modify
converted_field = None
latest_json_string = img_info.get("invokeai_metadata")
log_version_note = "3.0.0+"
destination_needs_meta_update = False
else:
if "sd-metadata" in img_info:
converted_field = parser.parse_meta_tag_sd_metadata(json.loads(img_info.get("sd-metadata")))
elif "invokeai" in img_info:
converted_field = parser.parse_meta_tag_invokeai(json.loads(img_info.get("invokeai")))
elif "dream" in img_info:
converted_field = parser.parse_meta_tag_dream(img_info.get("dream"))
elif "Dream" in img_info:
converted_field = parser.parse_meta_tag_dream(img_info.get("Dream"))
else:
converted_field = InvokeAIMetadata()
destination_needs_meta_update = False
print("File does not have metadata from known Invoke AI versions, add only, no update!")
# use the loaded img dimensions if the metadata didnt have them
if converted_field.width is None:
converted_field.width = png_width
if converted_field.height is None:
converted_field.height = png_height
log_version_note = converted_field.imported_app_version if converted_field else "NoVersion"
log_version_note = log_version_note or "NoVersion"
latest_json_string = converted_field.to_json()
print(f"From Invoke AI Version {log_version_note} with dimensions {png_width} x {png_height}.")
# if metadata needs update, then update metdata and copy in one shot
if destination_needs_meta_update:
print("Updating metadata while copying...", end="")
self.update_file_metadata_while_copying(
filepath, file_destination_path, "invokeai_metadata", latest_json_string
)
print("Done!")
else:
print("No metadata update necessary, copying only...", end="")
shutil.copy2(filepath, file_destination_path)
print("Done!")
# create thumbnail
print("Creating thumbnail...", end="")
thumbnail_path = os.path.join(config.thumbnail_path, os.path.splitext(file_name)[0]) + ".webp"
thumbnail_size = 256, 256
with PIL.Image.open(filepath) as source_image:
source_image.thumbnail(thumbnail_size)
source_image.save(thumbnail_path, "webp")
print("Done!")
# finalize the dynamic board name if there is an APPVERSION token in it.
if converted_field is not None:
board_name = board_name_option.replace("APPVERSION", converted_field.imported_app_version or "NoVersion")
else:
board_name = board_name_option.replace("APPVERSION", "Latest")
# maintain a map of alrady created/looked up ids to avoid DB queries
print("Finding/Creating board...", end="")
if board_name in self.board_name_id_map:
board_id = self.board_name_id_map[board_name]
else:
board_id = db_mapper.get_board_id_with_create(board_name)
self.board_name_id_map[board_name] = board_id
print("Done!")
# add image to db
print("Adding image to database......", end="")
modified_time = datetime.datetime.utcfromtimestamp(os.path.getmtime(filepath))
db_mapper.add_new_image_to_database(file_name, png_width, png_height, latest_json_string, modified_time)
print("Done!")
# add image to board
print("Adding image to board......", end="")
db_mapper.add_image_to_board(file_name, board_id)
print("Done!")
ImportStats.count_imported += 1
if log_version_note in ImportStats.count_imported_by_version:
ImportStats.count_imported_by_version[log_version_note] += 1
else:
ImportStats.count_imported_by_version[log_version_note] = 1
def update_file_metadata_while_copying(self, filepath, file_destination_path, tag_name, tag_value):
"""Perform a metadata update with save to a new destination which accomplishes a copy while updating metadata."""
with PIL.Image.open(filepath) as target_image:
existing_img_info = target_image.info
metadata = PIL.PngImagePlugin.PngInfo()
# re-add any existing invoke ai tags unless they are the one we are trying to add
for key in existing_img_info:
if key != tag_name and key in ("dream", "Dream", "sd-metadata", "invokeai", "invokeai_metadata"):
metadata.add_text(key, existing_img_info[key])
metadata.add_text(tag_name, tag_value)
target_image.save(file_destination_path, pnginfo=metadata)
def process(self):
"""Begin main processing."""
print("===============================================================================")
print("This script will import images generated by earlier versions of")
print("InvokeAI into the currently installed root directory:")
print(f" {app_config.root_path}")
print("If this is not what you want to do, type ctrl-C now to cancel.")
# load config
print("===============================================================================")
print("= Configuration & Settings")
config = Config()
config.find_and_load()
db_mapper = DatabaseMapper(config.database_path, config.database_backup_dir)
db_mapper.connect()
import_dir, is_recurse, import_file_list = self.get_import_file_list()
ImportStats.count_source_files = len(import_file_list)
board_names = db_mapper.get_board_names()
board_name_option = self.select_board_option(board_names, config.TIMESTAMP_STRING)
print("\r\n===============================================================================")
print("= Import Settings Confirmation")
print()
print(f"Database File Path : {config.database_path}")
print(f"Outputs/Images Directory : {config.outputs_path}")
print(f"Import Image Source Directory : {import_dir}")
print(f" Recurse Source SubDirectories : {'Yes' if is_recurse else 'No'}")
print(f"Count of .png file(s) found : {len(import_file_list)}")
print(f"Board name option specified : {board_name_option}")
print(f"Database backup will be taken at : {config.database_backup_dir}")
print("\r\nNotes about the import process:")
print("- Source image files will not be modified, only copied to the outputs directory.")
print("- If the same file name already exists in the destination, the file will be skipped.")
print("- If the same file name already has a record in the database, the file will be skipped.")
print("- Invoke AI metadata tags will be updated/written into the imported copy only.")
print(
"- On the imported copy, only Invoke AI known tags (latest and legacy) will be retained (dream, sd-metadata, invokeai, invokeai_metadata)"
)
print(
"- A property 'imported_app_version' will be added to metadata that can be viewed in the UI's metadata viewer."
)
print(
"- The new 3.x InvokeAI outputs folder structure is flat so recursively found source imges will all be placed into the single outputs/images folder."
)
while True:
should_continue = prompt("\nDo you wish to continue with the import [Yn] ? ").lower() or "y"
if should_continue == "n":
print("\r\nCancelling Import")
return
elif should_continue == "y":
print()
break
db_mapper.backup(config.TIMESTAMP_STRING)
print()
ImportStats.time_start = datetime.datetime.utcnow()
for filepath in import_file_list:
try:
self.import_image(filepath, board_name_option, db_mapper, config)
except sqlite3.Error as sql_ex:
print(f"A database related exception was found processing {filepath}, will continue to next file. ")
print("Exception detail:")
print(sql_ex)
ImportStats.count_file_errors += 1
except Exception as ex:
print(f"Exception processing {filepath}, will continue to next file. ")
print("Exception detail:")
print(ex)
ImportStats.count_file_errors += 1
print("\r\n===============================================================================")
print(f"= Import Complete - Elpased Time: {ImportStats.get_elapsed_time_string()}")
print()
print(f"Source File(s) : {ImportStats.count_source_files}")
print(f"Total Imported : {ImportStats.count_imported}")
print(f"Skipped b/c file already exists on disk : {ImportStats.count_skipped_file_exists}")
print(f"Skipped b/c file already exists in db : {ImportStats.count_skipped_db_exists}")
print(f"Errors during import : {ImportStats.count_file_errors}")
if ImportStats.count_imported > 0:
print("\r\nBreakdown of imported files by version:")
for key, version in ImportStats.count_imported_by_version.items():
print(f" {key:20} : {version}")
def main():
try:
processor = MediaImportProcessor()
processor.process()
except KeyboardInterrupt:
print("\r\n\r\nUser cancelled execution.")
if __name__ == "__main__":
main()
+48
View File
@@ -0,0 +1,48 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.pnpm-store
# We want to distribute the repo
dist
dist/**
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# build stats
stats.html
# Yarn - https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Yalc
.yalc
yalc.lock
# vitest
tsconfig.vitest-temp.json
coverage/
*.tgz
+17
View File
@@ -0,0 +1,17 @@
dist/
public/locales/*.json
!public/locales/en.json
.husky/
node_modules/
patches/
stats.html
index.html
.yarn/
.yalc/
*.scss
src/services/api/schema.ts
static/
src/theme/css/overlayscrollbars.css
src/theme_/css/overlayscrollbars.css
pnpm-lock.yaml
.claude
+17
View File
@@ -0,0 +1,17 @@
{
"$schema": "http://json.schemastore.org/prettierrc",
"trailingComma": "es5",
"printWidth": 120,
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"endOfLine": "auto",
"overrides": [
{
"files": ["public/locales/*.json"],
"options": {
"tabWidth": 4
}
}
]
}
@@ -0,0 +1,23 @@
import { useGlobalModifiersInit } from '@invoke-ai/ui-library';
import type { PropsWithChildren } from 'react';
import { memo, useEffect } from 'react';
import { useAppDispatch } from '../src/app/store/storeHooks';
import { modelChanged } from '../src/features/controlLayers/store/paramsSlice';
/**
* Initializes some state for storybook. Must be in a different component
* so that it is run inside the redux context.
*/
export const ReduxInit = memo(({ children }: PropsWithChildren) => {
const dispatch = useAppDispatch();
useGlobalModifiersInit();
useEffect(() => {
dispatch(
modelChanged({ model: { key: 'test_model', hash: 'some_hash', name: 'some name', base: 'sd-1', type: 'main' } })
);
}, [dispatch]);
return children;
});
ReduxInit.displayName = 'ReduxInit';
+16
View File
@@ -0,0 +1,16 @@
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-docs'],
framework: {
name: '@storybook/react-vite',
options: {},
},
core: {
disableTelemetry: true,
},
};
export default config;
@@ -0,0 +1,6 @@
import { addons } from 'storybook/manager-api';
import { themes } from 'storybook/theming';
addons.setConfig({
theme: themes.dark,
});
@@ -0,0 +1,53 @@
import type { Preview } from '@storybook/react-vite';
import { themes } from 'storybook/theming';
import { $store } from 'app/store/nanostores/store';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { Provider } from 'react-redux';
// TODO: Disabled for IDE performance issues with our translation JSON
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import translationEN from '../public/locales/en.json';
import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider';
import { createStore } from '../src/app/store/store';
import { ReduxInit } from './ReduxInit';
i18n.use(initReactI18next).init({
lng: 'en',
resources: {
en: { translation: translationEN },
},
debug: true,
interpolation: {
escapeValue: false,
},
returnNull: false,
});
const store = createStore();
$store.set(store);
const preview: Preview = {
decorators: [
(Story) => {
return (
<Provider store={store}>
<ThemeLocaleProvider>
<ReduxInit>
<Story />
</ReduxInit>
</ThemeLocaleProvider>
</Provider>
);
},
],
parameters: {
docs: {
theme: themes.dark,
codePanel: true,
},
},
};
export default preview;
+39
View File
@@ -0,0 +1,39 @@
# Bash commands
All commands should be run from `<REPO_ROOT>/invokeai/frontend/web/`.
- `pnpm lint:prettier`: check formatting
- `pnpm lint:eslint`: check for linting issues
- `pnpm lint:knip`: check for unused dependencies
- `pnpm lint:dpdm`: check for dependency cycles
- `pnpm lint:tsc`: check for TypeScript issues
- `pnpm lint`: run all checks
- `pnpm fix`: automatically fix issues where possible
- `pnpm test:no-watch`: run the test suite
# Writing Tests
This repo uses `vitest` for unit tests.
Tests should be colocated with the code they test, and should use the `.test.ts` suffix.
Tests do not need to be written for code that is trivial or has no logic (e.g. simple type definitions, re-exports, etc.). We currently do not do UI tests.
# Agents
- Use @agent-javascript-pro and @agent-typescript-pro for JavaScript and TypeScript code generation and assistance.
- Use @frontend-developer for general frontend development tasks.
## Workflow
Split up tasks into smaller subtasks and handle them one at a time using an agent. Ensure each subtask is completed before moving on to the next.
Each agent should maintain a work log in a markdown file.
When an agent completes a task, it should:
1. Summarize the changes made.
2. List any files that were added, modified, or deleted.
3. Commit the changes with a descriptive commit message.
DO NOT PUSH ANY CHANGES TO THE REMOTE REPOSITORY.
+3
View File
@@ -0,0 +1,3 @@
# Invoke UI
<https://invoke.ai/development/front-end/>
+3
View File
@@ -0,0 +1,3 @@
"""
Initialization file for invokeai.frontend.web
"""
+247
View File
@@ -0,0 +1,247 @@
import js from '@eslint/js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
import pluginI18Next from 'eslint-plugin-i18next';
import pluginImport from 'eslint-plugin-import';
import pluginPath from 'eslint-plugin-path';
import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from 'eslint-plugin-react-hooks';
import pluginReactRefresh from 'eslint-plugin-react-refresh';
import pluginSimpleImportSort from 'eslint-plugin-simple-import-sort';
import pluginStorybook from 'eslint-plugin-storybook';
import pluginUnusedImports from 'eslint-plugin-unused-imports';
import globals from 'globals';
export default [
js.configs.recommended,
{
languageOptions: {
parser: typescriptParser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
...globals.node,
GlobalCompositeOperation: 'readonly',
RequestInit: 'readonly',
},
},
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
plugins: {
react: pluginReact,
'@typescript-eslint': typescriptEslint,
'react-hooks': pluginReactHooks,
import: pluginImport,
'unused-imports': pluginUnusedImports,
'simple-import-sort': pluginSimpleImportSort,
'react-refresh': pluginReactRefresh.configs.vite,
path: pluginPath,
i18next: pluginI18Next,
storybook: pluginStorybook,
},
rules: {
...typescriptEslint.configs.recommended.rules,
...pluginReact.configs.recommended.rules,
...pluginReact.configs['jsx-runtime'].rules,
...pluginReactHooks.configs['recommended-latest'].rules,
...pluginStorybook.configs.recommended.rules,
'react/jsx-no-bind': [
'error',
{
allowBind: true,
allowArrowFunctions: true,
},
],
'react/jsx-curly-brace-presence': [
'error',
{
props: 'never',
children: 'never',
},
],
'react-hooks/exhaustive-deps': 'error',
curly: 'error',
'no-var': 'error',
'brace-style': 'error',
'prefer-template': 'error',
radix: 'error',
'space-before-blocks': 'error',
eqeqeq: 'error',
'one-var': ['error', 'never'],
'no-eval': 'error',
'no-extend-native': 'error',
'no-implied-eval': 'error',
'no-label-var': 'error',
'no-return-assign': 'error',
'no-sequences': 'error',
'no-template-curly-in-string': 'error',
'no-throw-literal': 'error',
'no-unmodified-loop-condition': 'error',
'import/no-duplicates': 'error',
'import/prefer-default-export': 'off',
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': [
'error',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-expect-error': 'allow-with-description',
'ts-ignore': true,
'ts-nocheck': true,
'ts-check': false,
minimumDescriptionLength: 10,
},
],
'@typescript-eslint/no-empty-interface': [
'error',
{
allowSingleExtends: true,
},
],
'@typescript-eslint/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
fixStyle: 'separate-type-imports',
disallowTypeAnnotations: true,
},
],
'@typescript-eslint/no-import-type-side-effects': 'error',
'@typescript-eslint/consistent-type-assertions': [
'error',
{
assertionStyle: 'as',
},
],
'path/no-relative-imports': [
'error',
{
maxDepth: 0,
},
],
'no-console': 'warn',
'no-promise-executor-return': 'error',
'require-await': 'error',
'no-restricted-syntax': [
'error',
{
selector: 'CallExpression[callee.name="setActiveTab"]',
message:
'setActiveTab() can only be called from use-navigation-api.tsx. Use navigationApi.switchToTab() instead.',
},
],
'no-restricted-properties': [
'error',
{
object: 'crypto',
property: 'randomUUID',
message: 'Use of crypto.randomUUID is not allowed as it is not available in all browsers.',
},
{
object: 'navigator',
property: 'clipboard',
message:
'The Clipboard API is not available by default in Firefox. Use the `useClipboard` hook instead, which wraps clipboard access to prevent errors.',
},
],
// Typescript handles this for us: https://eslint.org/docs/latest/rules/no-redeclare#handled_by_typescript
'no-redeclare': 'off',
'no-restricted-imports': [
'error',
{
paths: [
{
name: 'lodash-es',
importNames: ['isEqual'],
message: 'Please use objectEquals from @observ33r/object-equals instead.',
},
{
name: 'lodash-es',
message: 'Please use es-toolkit instead.',
},
{
name: 'es-toolkit',
importNames: ['isEqual'],
message: 'Please use objectEquals from @observ33r/object-equals instead.',
},
{
name: 'zod/v3',
message: 'Import from zod instead.',
},
],
},
],
},
settings: {
react: {
version: 'detect',
},
},
},
{
files: ['**/use-navigation-api.tsx'],
rules: {
'no-restricted-syntax': 'off',
},
},
{
files: ['**/*.stories.tsx'],
rules: {
'i18next/no-literal-string': 'off',
},
},
{
ignores: [
'**/dist/',
'**/static/',
'**/.husky/',
'**/node_modules/',
'**/patches/',
'**/stats.html',
'**/index.html',
'**/.yarn/',
'**/*.scss',
'src/services/api/schema.ts',
'.prettierrc.js',
'.storybook',
],
},
];
+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Invoke - Community Edition</title>
<link id="invoke-favicon" rel="icon" type="icon" href="assets/images/invoke-favicon.svg" />
<style>
html,
body,
#root {
padding: 0;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body dir="ltr">
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
import type { KnipConfig } from 'knip';
const config: KnipConfig = {
project: ['src/**/*.{ts,tsx}!'],
ignore: [
// This file is only used during debugging
'src/app/store/middleware/debugLoggerMiddleware.ts',
// Autogenerated types - shouldn't ever touch these
'src/services/api/schema.ts',
'src/features/nodes/types/v1/**',
'src/features/nodes/types/v2/**',
'src/features/parameters/types/parameterSchemas.ts',
// TODO(psyche): maybe we can clean up these utils after canvas v2 release
'src/features/controlLayers/konva/util.ts',
// Will be using this
'src/common/hooks/useAsyncState.ts',
'src/app/store/use-debounced-app-selector.ts',
// Auth features - exports will be used in follow-up phases
'src/features/auth/**',
'src/services/api/endpoints/auth.ts',
],
ignoreBinaries: ['only-allow'],
ignoreDependencies: ['magic-string', '@babel/preset-typescript', 'babel-plugin-react-compiler'],
paths: {
'public/*': ['public/*'],
},
};
export default config;
File diff suppressed because one or more lines are too long
+173
View File
@@ -0,0 +1,173 @@
{
"name": "@invoke-ai/invoke-ai-ui",
"private": true,
"version": "0.0.1",
"publishConfig": {
"access": "restricted",
"registry": "https://npm.pkg.github.com"
},
"main": "./dist/invoke-ai-ui.umd.js",
"module": "./dist/invoke-ai-ui.es.js",
"exports": {
".": {
"import": "./dist/invoke-ai-ui.es.js",
"require": "./dist/invoke-ai-ui.umd.js"
}
},
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"dev": "vite dev",
"dev:host": "vite dev --host",
"build": "pnpm run lint && vitest run && vite build",
"typegen": "node scripts/typegen.js",
"preview": "vite preview",
"lint:knip": "knip --tags=-knipignore",
"lint:dpdm": "dpdm --no-warning --no-tree --transform --exit-code circular:1 src/main.tsx",
"lint:eslint": "eslint --max-warnings=0 .",
"lint:prettier": "prettier --check .",
"lint:tsc": "tsc --noEmit",
"lint": "concurrently -g -c red,green,yellow,blue,magenta pnpm:lint:*",
"fix": "eslint --fix . && prettier --log-level warn --write .",
"preinstall": "npx only-allow pnpm",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"test": "vitest",
"test:run": "vitest run",
"test:ui": "vitest --coverage --ui",
"test:no-watch": "vitest --no-watch"
},
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.2",
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
"@dagrejs/dagre": "^1.1.8",
"@dagrejs/graphlib": "^2.2.4",
"@fontsource-variable/inter": "^5.2.8",
"@invoke-ai/ui-library": "github:invoke-ai/ui-library#v0.0.48",
"@nanostores/react": "^1.1.0",
"@observ33r/object-equals": "^1.1.6",
"@reduxjs/toolkit": "2.8.2",
"@roarr/browser-log-writer": "^1.3.0",
"@xyflow/react": "^12.10.0",
"ag-psd": "^28.5.1",
"async-mutex": "^0.5.0",
"chakra-react-select": "^4.10.1",
"cmdk": "^1.1.1",
"compare-versions": "^6.1.1",
"dockview": "^4.12.0",
"es-toolkit": "^1.46.1",
"filesize": "^10.1.6",
"fracturedjsonjs": "^4.1.1",
"framer-motion": "^11.18.2",
"i18next": "^25.7.3",
"i18next-http-backend": "^3.0.2",
"idb-keyval": "6.2.1",
"jsondiffpatch": "^0.7.3",
"jszip": "^3.10.1",
"konva": "^9.3.22",
"linkify-react": "^4.3.2",
"linkifyjs": "^4.3.2",
"lru-cache": "^11.2.4",
"mtwist": "^1.0.2",
"nanoid": "^5.1.6",
"nanostores": "^1.3.0",
"new-github-issue-url": "^1.1.0",
"overlayscrollbars": "^2.13.0",
"overlayscrollbars-react": "^0.5.6",
"perfect-freehand": "^1.2.2",
"query-string": "^9.3.1",
"raf-throttle": "^2.0.6",
"react": "^19.2.6",
"react-colorful": "^5.7.0",
"react-dom": "^19.2.6",
"react-dropzone": "^14.3.8",
"react-error-boundary": "^6.0.0",
"react-hook-form": "^7.69.0",
"react-hotkeys-hook": "4.5.0",
"react-i18next": "^16.5.0",
"react-icons": "^5.5.0",
"react-redux": "9.2.0",
"react-resizable-panels": "^3.0.6",
"react-router-dom": "^7.12.0",
"react-textarea-autosize": "^8.5.9",
"react-use": "^17.6.0",
"react-virtuoso": "^4.18.6",
"redux-remember": "^5.3.0",
"redux-undo": "^1.1.0",
"rfdc": "^1.4.1",
"roarr": "^7.21.2",
"serialize-error": "^12.0.0",
"socket.io-client": "^4.8.3",
"stable-hash": "^0.0.6",
"use-debounce": "^10.0.6",
"use-device-pixel-ratio": "^1.1.2",
"uuid": "^11.1.0",
"zod": "^4.2.1",
"zod-validation-error": "^4.0.2"
},
"peerDependencies": {
"react": "^18.2.0 || ^19.1.4",
"react-dom": "^18.2.0 || ^19.1.4"
},
"devDependencies": {
"@babel/preset-typescript": "^7.29.7",
"@eslint/js": "^9.39.2",
"@storybook/addon-docs": "^10.3.6",
"@storybook/addon-links": "^10.3.6",
"@storybook/react-vite": "^10.3.6",
"@types/node": "^22.19.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^8.59.2",
"@typescript-eslint/parser": "^8.59.2",
"@vitejs/plugin-react-swc": "^4.3.0",
"@vitest/coverage-v8": "^4.1.5",
"@vitest/ui": "^4.1.5",
"babel-plugin-react-compiler": "^1.0.0",
"concurrently": "^9.2.1",
"csstype": "^3.2.3",
"dpdm": "^3.14.0",
"eslint": "^9.39.2",
"eslint-plugin-i18next": "^6.1.3",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-path": "^2.1.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.2",
"eslint-plugin-simple-import-sort": "^13.0.0",
"eslint-plugin-storybook": "^10.3.6",
"eslint-plugin-unused-imports": "^4.4.1",
"globals": "^16.5.0",
"knip": "^5.77.4",
"magic-string": "^0.30.21",
"openapi-types": "^12.1.3",
"openapi-typescript": "^7.10.1",
"prettier": "^3.8.3",
"rollup-plugin-visualizer": "^6.0.5",
"storybook": "^10.3.6",
"tsafe": "^1.8.12",
"type-fest": "^4.41.0",
"typescript": "^5.9.3",
"vite": "^8.0.11",
"vite-plugin-babel": "^1.6.0",
"vite-plugin-eslint": "^1.8.1",
"vitest": "^4.1.5"
},
"pnpm": {
"peerDependencyRules": {
"allowedVersions": {
"react": "19",
"react-dom": "19",
"zod": "4"
}
}
},
"engines": {
"pnpm": "10"
},
"packageManager": "pnpm@10.12.4"
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,3 @@
onlyBuiltDependencies:
- '@swc/core'
- esbuild
Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

@@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" rx="2" fill="#E6FD13"/>
<path d="M9.61889 5.45H12.5V3.5H3.5V5.45H6.38111L9.61889 10.55H12.5V12.5H3.5V10.55H6.38111" stroke="black"/>
<circle cx="12" cy="4" r="3" fill="#f5480c" stroke="#0d1117" stroke-width="1"/>
</svg>

After

Width:  |  Height:  |  Size: 345 B

@@ -0,0 +1,4 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" rx="50" fill="#E6FD13"/>
<path d="M55.8887 40.7241H66.369V33.6309H33.6309V40.7241H44.1111L55.8887 59.2757H66.369V66.369H33.6309V59.2757H44.1111" stroke="#181818" stroke-width="2.5"/>
</svg>

After

Width:  |  Height:  |  Size: 321 B

@@ -0,0 +1,4 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="#E6FD13"/>
<path d="M55.8887 40.7241H66.369V33.6309H33.6309V40.7241H44.1111L55.8887 59.2757H66.369V66.369H33.6309V59.2757H44.1111" stroke="#181818" stroke-width="2.5"/>
</svg>

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" rx="2" fill="#E6FD13"/>
<path d="M9.61889 5.45H12.5V3.5H3.5V5.45H6.38111L9.61889 10.55H12.5V12.5H3.5V10.55H6.38111" stroke="black"/>
</svg>

After

Width:  |  Height:  |  Size: 265 B

@@ -0,0 +1,4 @@
<svg width="106" height="106" viewBox="0 0 106 106" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="3" width="100" height="100" rx="6.66667" stroke="#181818" stroke-width="5"/>
<path d="M63.9137 36H83.1211V23H23.1211V36H42.3285L63.9137 70H83.1211V83H23.1211V70H42.3285" stroke="#181818" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 328 B

@@ -0,0 +1,4 @@
<svg width="42" height="42" viewBox="0 0 42 42" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="40" height="40" rx="4" stroke="#181818" stroke-width="2"/>
<path d="M25.3659 14.2H33.0488V9H9.04883V14.2H16.7318L25.3659 27.8H33.0488V33H9.04883V27.8H16.7318" stroke="#181818" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 323 B

@@ -0,0 +1,4 @@
<svg width="106" height="106" viewBox="0 0 106 106" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="3" width="100" height="100" rx="6.66667" stroke="white" stroke-width="5"/>
<path d="M63.9137 36H83.1211V23H23.1211V36H42.3285L63.9137 70H83.1211V83H23.1211V70H42.3285" stroke="white" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 324 B

@@ -0,0 +1,4 @@
<svg width="42" height="42" viewBox="0 0 42 42" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="40" height="40" rx="4" stroke="white" stroke-width="2"/>
<path d="M25.3659 14.2H33.0488V9H9.04883V14.2H16.7318L25.3659 27.8H33.0488V33H9.04883V27.8H16.7318" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 319 B

@@ -0,0 +1,3 @@
<svg width="66" height="66" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M43.9137 16H63.1211V3H3.12109V16H22.3285L43.9137 50H63.1211V63H3.12109V50H22.3285" stroke="#181818" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 231 B

@@ -0,0 +1,3 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5975 5.33333H21V1H1V5.33333H7.40246L14.5975 16.6667H21V21H1V16.6667H7.40246" stroke="#181818" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 229 B

@@ -0,0 +1,3 @@
<svg width="66" height="66" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M43.9137 16H63.1211V3H3.12109V16H22.3285L43.9137 50H63.1211V63H3.12109V50H22.3285" stroke="white" stroke-width="5"/>
</svg>

After

Width:  |  Height:  |  Size: 229 B

@@ -0,0 +1,3 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5975 5.33333H21V1H1V5.33333H7.40246L14.5975 16.6667H21V21H1V16.6667H7.40246" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 227 B

@@ -0,0 +1,3 @@
<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M29.1951 10.6667H42V2H2V10.6667H14.8049L29.1951 33.3333H42V42H2V33.3333H14.8049" stroke="#E6FD13" stroke-width="2.8"/>
</svg>

After

Width:  |  Height:  |  Size: 231 B

@@ -0,0 +1,13 @@
<svg width="231" height="100" viewBox="0 0 231 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_659_3591)">
<rect width="100" height="100" fill="#181818"/>
<path d="M57.1951 38.6667H70V30H30V38.6667H42.8049L57.1951 61.3333H70V70H30V61.3333H42.8049" stroke="white" stroke-width="2.8"/>
<rect width="131" height="100" transform="translate(100)" fill="#181818"/>
<path d="M111.37 43.34H107.89V39.65H111.37V43.34ZM116.38 60.5H102.76V58.16H108.22V47.84H103.36V45.5H111.07V58.16H116.38V60.5ZM120.538 60.5V45.5H123.388V47.6C124.288 46.25 125.788 45.2 128.188 45.2C131.638 45.2 133.588 47.3 133.588 50.45V60.5H130.738V51.05C130.738 48.95 129.838 47.6 127.708 47.6H127.468C125.338 47.6 123.388 49.25 123.388 52.1V60.5H120.538ZM141.786 60.5L136.236 45.5H139.176L143.526 57.71L147.876 45.5H150.786L145.236 60.5H141.786ZM159.723 60.8C155.673 60.8 152.523 57.65 152.523 53C152.523 48.35 155.673 45.2 159.723 45.2C163.773 45.2 166.923 48.35 166.923 53C166.923 57.65 163.773 60.8 159.723 60.8ZM155.373 53C155.373 56.45 157.173 58.4 159.603 58.4H159.843C162.273 58.4 164.073 56.45 164.073 53C164.073 49.55 162.273 47.6 159.843 47.6H159.603C157.173 47.6 155.373 49.55 155.373 53ZM170.804 60.5V39.5H173.654V51.98L180.254 45.5H184.004L177.764 51.47L184.304 60.5H180.794L175.724 53.42L173.654 55.43V60.5H170.804ZM192.459 60.8C188.739 60.8 185.379 58.22 185.379 52.97C185.379 47.78 188.829 45.2 192.369 45.2C196.269 45.2 198.729 47.9 198.729 51.8V53.45H188.229C188.409 56.87 190.599 58.4 192.429 58.4H192.669C194.139 58.4 195.549 57.65 195.849 56.06H198.699C198.159 59.09 195.549 60.8 192.459 60.8ZM188.409 51.2H195.879C195.759 48.59 194.199 47.6 192.489 47.6H192.249C190.689 47.6 188.949 48.53 188.409 51.2Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_659_3591">
<rect width="231" height="100" rx="5" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,13 @@
<svg width="116" height="50" viewBox="0 0 116 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_659_3586)">
<rect width="50" height="50" fill="#181818"/>
<path d="M28.5975 19.3333H35V15H15V19.3333H21.4025L28.5975 30.6667H35V35H15V30.6667H21.4025" stroke="white" stroke-width="1.2"/>
<rect width="66" height="50" transform="translate(50)" fill="#181818"/>
<path d="M55.685 21.92H53.945V20.075H55.685V21.92ZM58.19 30.5H51.38V29.33H54.11V24.17H51.68V23H55.535V29.33H58.19V30.5ZM60.2691 30.5V23H61.6941V24.05C62.1441 23.375 62.8941 22.85 64.0941 22.85C65.8191 22.85 66.7941 23.9 66.7941 25.475V30.5H65.3691V25.775C65.3691 24.725 64.9191 24.05 63.8541 24.05H63.7341C62.6691 24.05 61.6941 24.875 61.6941 26.3V30.5H60.2691ZM70.8931 30.5L68.1181 23H69.5881L71.7631 29.105L73.9381 23H75.3931L72.6181 30.5H70.8931ZM79.8614 30.65C77.8364 30.65 76.2614 29.075 76.2614 26.75C76.2614 24.425 77.8364 22.85 79.8614 22.85C81.8864 22.85 83.4614 24.425 83.4614 26.75C83.4614 29.075 81.8864 30.65 79.8614 30.65ZM77.6864 26.75C77.6864 28.475 78.5864 29.45 79.8014 29.45H79.9214C81.1364 29.45 82.0364 28.475 82.0364 26.75C82.0364 25.025 81.1364 24.05 79.9214 24.05H79.8014C78.5864 24.05 77.6864 25.025 77.6864 26.75ZM85.4018 30.5V20H86.8268V26.24L90.1268 23H92.0018L88.8818 25.985L92.1518 30.5H90.3968L87.8618 26.96L86.8268 27.965V30.5H85.4018ZM96.2296 30.65C94.3696 30.65 92.6896 29.36 92.6896 26.735C92.6896 24.14 94.4146 22.85 96.1846 22.85C98.1346 22.85 99.3646 24.2 99.3646 26.15V26.975H94.1146C94.2046 28.685 95.2996 29.45 96.2146 29.45H96.3346C97.0696 29.45 97.7746 29.075 97.9246 28.28H99.3496C99.0796 29.795 97.7746 30.65 96.2296 30.65ZM94.2046 25.85H97.9396C97.8796 24.545 97.0996 24.05 96.2446 24.05H96.1246C95.3446 24.05 94.4746 24.515 94.2046 25.85Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_659_3586">
<rect width="116" height="50" rx="4" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,13 @@
<svg width="231" height="100" viewBox="0 0 231 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_659_3578)">
<rect width="100" height="100" fill="#E6FD13"/>
<path d="M57.1951 38.6667H70V30H30V38.6667H42.8049L57.1951 61.3333H70V70H30V61.3333H42.8049" stroke="#181818" stroke-width="2.8"/>
<rect width="131" height="100" transform="translate(100)" fill="#E6FD13"/>
<path d="M111.37 43.34H107.89V39.65H111.37V43.34ZM116.38 60.5H102.76V58.16H108.22V47.84H103.36V45.5H111.07V58.16H116.38V60.5ZM120.538 60.5V45.5H123.388V47.6C124.288 46.25 125.788 45.2 128.188 45.2C131.638 45.2 133.588 47.3 133.588 50.45V60.5H130.738V51.05C130.738 48.95 129.838 47.6 127.708 47.6H127.468C125.338 47.6 123.388 49.25 123.388 52.1V60.5H120.538ZM141.786 60.5L136.236 45.5H139.176L143.526 57.71L147.876 45.5H150.786L145.236 60.5H141.786ZM159.723 60.8C155.673 60.8 152.523 57.65 152.523 53C152.523 48.35 155.673 45.2 159.723 45.2C163.773 45.2 166.923 48.35 166.923 53C166.923 57.65 163.773 60.8 159.723 60.8ZM155.373 53C155.373 56.45 157.173 58.4 159.603 58.4H159.843C162.273 58.4 164.073 56.45 164.073 53C164.073 49.55 162.273 47.6 159.843 47.6H159.603C157.173 47.6 155.373 49.55 155.373 53ZM170.804 60.5V39.5H173.654V51.98L180.254 45.5H184.004L177.764 51.47L184.304 60.5H180.794L175.724 53.42L173.654 55.43V60.5H170.804ZM192.459 60.8C188.739 60.8 185.379 58.22 185.379 52.97C185.379 47.78 188.829 45.2 192.369 45.2C196.269 45.2 198.729 47.9 198.729 51.8V53.45H188.229C188.409 56.87 190.599 58.4 192.429 58.4H192.669C194.139 58.4 195.549 57.65 195.849 56.06H198.699C198.159 59.09 195.549 60.8 192.459 60.8ZM188.409 51.2H195.879C195.759 48.59 194.199 47.6 192.489 47.6H192.249C190.689 47.6 188.949 48.53 188.409 51.2Z" fill="#181818"/>
</g>
<defs>
<clipPath id="clip0_659_3578">
<rect width="231" height="100" rx="5" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,13 @@
<svg width="116" height="50" viewBox="0 0 116 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_659_3573)">
<rect width="50" height="50" fill="#E6FD13"/>
<path d="M28.5975 19.3333H35V15H15V19.3333H21.4025L28.5975 30.6667H35V35H15V30.6667H21.4025" stroke="#181818" stroke-width="1.2"/>
<rect width="66" height="50" transform="translate(50)" fill="#E6FD13"/>
<path d="M55.685 21.92H53.945V20.075H55.685V21.92ZM58.19 30.5H51.38V29.33H54.11V24.17H51.68V23H55.535V29.33H58.19V30.5ZM60.2691 30.5V23H61.6941V24.05C62.1441 23.375 62.8941 22.85 64.0941 22.85C65.8191 22.85 66.7941 23.9 66.7941 25.475V30.5H65.3691V25.775C65.3691 24.725 64.9191 24.05 63.8541 24.05H63.7341C62.6691 24.05 61.6941 24.875 61.6941 26.3V30.5H60.2691ZM70.8931 30.5L68.1181 23H69.5881L71.7631 29.105L73.9381 23H75.3931L72.6181 30.5H70.8931ZM79.8614 30.65C77.8364 30.65 76.2614 29.075 76.2614 26.75C76.2614 24.425 77.8364 22.85 79.8614 22.85C81.8864 22.85 83.4614 24.425 83.4614 26.75C83.4614 29.075 81.8864 30.65 79.8614 30.65ZM77.6864 26.75C77.6864 28.475 78.5864 29.45 79.8014 29.45H79.9214C81.1364 29.45 82.0364 28.475 82.0364 26.75C82.0364 25.025 81.1364 24.05 79.9214 24.05H79.8014C78.5864 24.05 77.6864 25.025 77.6864 26.75ZM85.4018 30.5V20H86.8268V26.24L90.1268 23H92.0018L88.8818 25.985L92.1518 30.5H90.3968L87.8618 26.96L86.8268 27.965V30.5H85.4018ZM96.2296 30.65C94.3696 30.65 92.6896 29.36 92.6896 26.735C92.6896 24.14 94.4146 22.85 96.1846 22.85C98.1346 22.85 99.3646 24.2 99.3646 26.15V26.975H94.1146C94.2046 28.685 95.2996 29.45 96.2146 29.45H96.3346C97.0696 29.45 97.7746 29.075 97.9246 28.28H99.3496C99.0796 29.795 97.7746 30.65 96.2296 30.65ZM94.2046 25.85H97.9396C97.8796 24.545 97.0996 24.05 96.2446 24.05H96.1246C95.3446 24.05 94.4746 24.515 94.2046 25.85Z" fill="#181818"/>
</g>
<defs>
<clipPath id="clip0_659_3573">
<rect width="116" height="50" rx="4" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,8 @@
<svg width="293" height="65" viewBox="0 0 293 65" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M273.51 65.0002C269.604 65.0002 266.003 64.1152 262.707 62.3453C259.472 60.5143 256.848 57.7983 254.834 54.1974C252.881 50.5964 251.904 46.2326 251.904 41.1058C251.904 36.0401 252.881 31.7373 254.834 28.1974C256.848 24.5964 259.472 21.911 262.707 20.141C266.003 18.31 269.512 17.3945 273.235 17.3945C277.142 17.3945 280.559 18.249 283.489 19.9579C286.419 21.6058 288.677 23.9556 290.264 27.0072C291.851 30.0589 292.644 33.5683 292.644 37.5354V42.5706H260.602C260.785 45.8664 261.517 48.6434 262.799 50.9016C264.08 53.1598 265.667 54.8688 267.559 56.0284C269.512 57.127 271.465 57.6763 273.419 57.6763H274.151C276.531 57.6763 278.637 57.0659 280.468 55.8453C282.299 54.6246 283.428 52.8547 283.855 50.5354H292.553C291.759 55.0518 289.592 58.5918 286.052 61.1551C282.513 63.7185 278.332 65.0002 273.51 65.0002ZM283.947 35.7044C283.764 31.9814 282.696 29.2349 280.743 27.465C278.851 25.634 276.47 24.7185 273.602 24.7185H272.869C270.184 24.7185 267.742 25.6035 265.545 27.3734C263.409 29.1434 261.944 31.9204 261.151 35.7044H283.947Z" fill="#181818"/>
<path d="M205.254 0H213.951V38.0846L234.092 18.3099H245.536L226.494 36.5282L246.451 64.0846H235.74L220.268 42.4789L213.951 48.6127V64.0846H205.254V0Z" fill="#181818"/>
<path d="M173.507 65.0002C169.418 65.0002 165.695 63.9932 162.338 61.9791C158.981 59.965 156.326 57.1575 154.373 53.5565C152.481 49.9556 151.535 45.8359 151.535 41.1974C151.535 36.5589 152.481 32.4391 154.373 28.8382C156.326 25.2373 158.981 22.4297 162.338 20.4157C165.695 18.4016 169.418 17.3945 173.507 17.3945C177.596 17.3945 181.319 18.4016 184.676 20.4157C188.033 22.4297 190.658 25.2373 192.55 28.8382C194.503 32.4391 195.479 36.5589 195.479 41.1974C195.479 45.8359 194.503 49.9556 192.55 53.5565C190.658 57.1575 188.033 59.965 184.676 61.9791C181.319 63.9932 177.596 65.0002 173.507 65.0002ZM173.873 57.6763C177.657 57.6763 180.74 56.2115 183.12 53.2819C185.561 50.3523 186.782 46.3241 186.782 41.1974C186.782 36.0706 185.561 32.0424 183.12 29.1129C180.74 26.1833 177.657 24.7185 173.873 24.7185H173.141C169.357 24.7185 166.244 26.1833 163.803 29.1129C161.423 32.0424 160.232 36.0706 160.232 41.1974C160.232 46.3241 161.423 50.3523 163.803 53.2819C166.244 56.2115 169.357 57.6763 173.141 57.6763H173.873Z" fill="#181818"/>
<path d="M146.078 18.3096L129.141 64.0843H118.613L101.676 18.3096H110.648L123.922 55.5702L137.197 18.3096H146.078Z" fill="#181818"/>
<path d="M53.9727 18.31H62.6699V24.7185C65.9047 19.8358 70.7873 17.3945 77.3179 17.3945C82.5057 17.3945 86.5339 18.8593 89.4025 21.7889C92.3321 24.6575 93.7969 28.533 93.7969 33.4157V64.0847H85.0997V35.2467C85.0997 31.8899 84.3368 29.296 82.8109 27.465C81.3461 25.634 79.0268 24.7185 75.8531 24.7185H75.1207C72.9235 24.7185 70.8789 25.2678 68.9869 26.3664C67.0948 27.465 65.569 29.0518 64.4094 31.1269C63.2497 33.2021 62.6699 35.6434 62.6699 38.4509V64.0847H53.9727V18.31Z" fill="#181818"/>
<path d="M15.732 0.144531H26.4041V11.4605H15.732V0.144531ZM0 56.9086H16.744V25.2606H1.84V18.0846H25.4841V56.9086H41.7681V64.0846H0V56.9086Z" fill="#181818"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -0,0 +1,8 @@
<svg width="293" height="65" viewBox="0 0 293 65" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M273.51 65.0002C269.604 65.0002 266.003 64.1152 262.707 62.3453C259.472 60.5143 256.848 57.7983 254.834 54.1974C252.881 50.5964 251.904 46.2326 251.904 41.1058C251.904 36.0401 252.881 31.7373 254.834 28.1974C256.848 24.5964 259.472 21.911 262.707 20.141C266.003 18.31 269.512 17.3945 273.235 17.3945C277.142 17.3945 280.559 18.249 283.489 19.9579C286.419 21.6058 288.677 23.9556 290.264 27.0072C291.851 30.0589 292.644 33.5683 292.644 37.5354V42.5706H260.602C260.785 45.8664 261.517 48.6434 262.799 50.9016C264.08 53.1598 265.667 54.8688 267.559 56.0284C269.512 57.127 271.465 57.6763 273.419 57.6763H274.151C276.531 57.6763 278.637 57.0659 280.468 55.8453C282.299 54.6246 283.428 52.8547 283.855 50.5354H292.553C291.759 55.0518 289.592 58.5918 286.052 61.1551C282.513 63.7185 278.332 65.0002 273.51 65.0002ZM283.947 35.7044C283.764 31.9814 282.696 29.2349 280.743 27.465C278.851 25.634 276.47 24.7185 273.602 24.7185H272.869C270.184 24.7185 267.742 25.6035 265.545 27.3734C263.409 29.1434 261.944 31.9204 261.151 35.7044H283.947Z" fill="white"/>
<path d="M205.254 0H213.951V38.0846L234.092 18.3099H245.536L226.494 36.5282L246.451 64.0846H235.74L220.268 42.4789L213.951 48.6127V64.0846H205.254V0Z" fill="white"/>
<path d="M173.507 65.0002C169.418 65.0002 165.695 63.9932 162.338 61.9791C158.981 59.965 156.326 57.1575 154.373 53.5565C152.481 49.9556 151.535 45.8359 151.535 41.1974C151.535 36.5589 152.481 32.4391 154.373 28.8382C156.326 25.2373 158.981 22.4297 162.338 20.4157C165.695 18.4016 169.418 17.3945 173.507 17.3945C177.596 17.3945 181.319 18.4016 184.676 20.4157C188.033 22.4297 190.658 25.2373 192.55 28.8382C194.503 32.4391 195.479 36.5589 195.479 41.1974C195.479 45.8359 194.503 49.9556 192.55 53.5565C190.658 57.1575 188.033 59.965 184.676 61.9791C181.319 63.9932 177.596 65.0002 173.507 65.0002ZM173.873 57.6763C177.657 57.6763 180.74 56.2115 183.12 53.2819C185.561 50.3523 186.782 46.3241 186.782 41.1974C186.782 36.0706 185.561 32.0424 183.12 29.1129C180.74 26.1833 177.657 24.7185 173.873 24.7185H173.141C169.357 24.7185 166.244 26.1833 163.803 29.1129C161.423 32.0424 160.232 36.0706 160.232 41.1974C160.232 46.3241 161.423 50.3523 163.803 53.2819C166.244 56.2115 169.357 57.6763 173.141 57.6763H173.873Z" fill="white"/>
<path d="M146.078 18.3096L129.141 64.0843H118.613L101.676 18.3096H110.648L123.922 55.5702L137.197 18.3096H146.078Z" fill="white"/>
<path d="M53.9727 18.31H62.6699V24.7185C65.9047 19.8358 70.7873 17.3945 77.3179 17.3945C82.5057 17.3945 86.5339 18.8593 89.4025 21.7889C92.3321 24.6575 93.7969 28.533 93.7969 33.4157V64.0847H85.0997V35.2467C85.0997 31.8899 84.3368 29.296 82.8109 27.465C81.3461 25.634 79.0268 24.7185 75.8531 24.7185H75.1207C72.9235 24.7185 70.8789 25.2678 68.9869 26.3664C67.0948 27.465 65.569 29.0518 64.4094 31.1269C63.2497 33.2021 62.6699 35.6434 62.6699 38.4509V64.0847H53.9727V18.31Z" fill="white"/>
<path d="M15.732 0.144531H26.4041V11.4605H15.732V0.144531ZM0 56.9086H16.744V25.2606H1.84V18.0846H25.4841V56.9086H41.7681V64.0846H0V56.9086Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 60 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
<g transform="matrix(1,0,0,1,0,5)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,10)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,15)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,20)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,25)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,30)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,35)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,40)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,45)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,50)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,55)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,60)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-5)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-10)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-15)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-20)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-25)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-30)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-35)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-40)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-45)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-50)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-55)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
<g transform="matrix(1,0,0,1,0,-60)">
<path d="M-3.5,63.5L64,-4" style="fill:none;stroke:black;stroke-width:1px;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

@@ -0,0 +1,83 @@
{
"common": {
"hotkeysLabel": "مفاتيح الأختصار",
"languagePickerLabel": "منتقي اللغة",
"reportBugLabel": "بلغ عن خطأ",
"settingsLabel": "إعدادات",
"img2img": "صورة إلى صورة",
"nodes": "عقد",
"upload": "رفع",
"load": "تحميل",
"back": "الى الخلف",
"statusDisconnected": "غير متصل"
},
"gallery": {
"galleryImageSize": "حجم الصورة",
"gallerySettings": "إعدادات المعرض",
"autoSwitchNewImages": "التبديل التلقائي إلى الصور الجديدة"
},
"modelManager": {
"modelManager": "مدير النموذج",
"model": "نموذج",
"allModels": "جميع النماذج",
"modelUpdated": "تم تحديث النموذج",
"manual": "يدوي",
"name": "الاسم",
"description": "الوصف",
"config": "تكوين",
"repo_id": "معرف المستودع",
"width": "عرض",
"height": "ارتفاع",
"addModel": "أضف نموذج",
"availableModels": "النماذج المتاحة",
"search": "بحث",
"load": "تحميل",
"active": "نشط",
"selected": "تم التحديد",
"delete": "حذف",
"deleteModel": "حذف النموذج",
"deleteConfig": "حذف التكوين",
"deleteMsg1": "هل أنت متأكد من رغبتك في حذف إدخال النموذج هذا من استحضر الذكاء الصناعي",
"deleteMsg2": "هذا لن يحذف ملف نقطة التحكم للنموذج من القرص الخاص بك. يمكنك إعادة إضافتهم إذا كنت ترغب في ذلك."
},
"parameters": {
"images": "الصور",
"steps": "الخطوات",
"cfgScale": "مقياس الإعداد الذاتي للجملة",
"width": "عرض",
"height": "ارتفاع",
"seed": "بذرة",
"shuffle": "تشغيل",
"noiseThreshold": "عتبة الضوضاء",
"perlinNoise": "ضجيج برلين",
"type": "نوع",
"strength": "قوة",
"upscaling": "تصغير",
"scale": "مقياس",
"imageFit": "ملائمة الصورة الأولية لحجم الخرج",
"scaleBeforeProcessing": "تحجيم قبل المعالجة",
"scaledWidth": "العرض المحجوب",
"scaledHeight": "الارتفاع المحجوب",
"infillMethod": "طريقة التعبئة",
"tileSize": "حجم البلاطة",
"copyImage": "نسخ الصورة",
"usePrompt": "استخدم المحث",
"useSeed": "استخدام البذور",
"useAll": "استخدام الكل",
"info": "معلومات"
},
"settings": {
"models": "موديلات",
"displayInProgress": "عرض الصور المؤرشفة",
"confirmOnDelete": "تأكيد عند الحذف",
"resetWebUI": "إعادة تعيين واجهة الويب",
"resetWebUIDesc1": "إعادة تعيين واجهة الويب يعيد فقط ذاكرة التخزين المؤقت للمتصفح لصورك وإعداداتك المذكورة. لا يحذف أي صور من القرص.",
"resetWebUIDesc2": "إذا لم تظهر الصور في الصالة أو إذا كان شيء آخر غير ناجح، يرجى المحاولة إعادة تعيين قبل تقديم مشكلة على جيت هب.",
"resetComplete": "تم إعادة تعيين واجهة الويب. تحديث الصفحة لإعادة التحميل."
},
"toast": {
"uploadFailed": "فشل التحميل",
"imageCopied": "تم نسخ الصورة",
"parametersNotSet": "لم يتم تعيين المعلمات"
}
}
@@ -0,0 +1,5 @@
{
"accessibility": {
"about": "Haqqında"
}
}
@@ -0,0 +1,60 @@
{
"accessibility": {
"menu": "Меню",
"nextImage": "Следваща снимка",
"previousImage": "Предишно изображение",
"uploadImage": "Качете изображение",
"invokeProgressBar": "Invoke лента за напредък",
"mode": "Режим"
},
"boards": {
"addBoard": "Добавете табло",
"cancel": "Отказ",
"autoAddBoard": "Авто-добавяне на табло",
"changeBoard": "Смяна на табло",
"deleteBoard": "Изтриване на табло",
"deleteBoardAndImages": "Изтриване на табло и изображения",
"deleteBoardOnly": "Изтриване само на таблото",
"loading": "Зареждане...",
"movingImagesToBoard_one": "Преместване на {{count}} снимка към табло:",
"movingImagesToBoard_other": "Преместване на {{count}} снимки към табло:",
"selectBoard": "Изберете табло",
"uncategorized": "Некатегоризирани",
"downloadBoard": "Изтегляне на табло",
"bottomMessage": "Изтриването на това табло и изображенията в него ще нулира всички функции, които ги използват в момента.",
"deletedBoardsCannotbeRestored": "Изтритите табла не могат да бъдат възстановени",
"myBoard": "Моето табло"
},
"accordions": {
"image": {
"title": "Изображение"
},
"control": {
"title": "Контрол"
}
},
"common": {
"aboutDesc": "Използвате Invoke за работа? Разгледайте:",
"ai": "ии",
"areYouSure": "Сигурен ли сте?",
"back": "Назад",
"cancel": "Отказ",
"or": "или",
"controlNet": "ControlNet",
"details": "Детайли",
"dontAskMeAgain": "Не питай повече",
"folder": "Папка",
"githubLabel": "Github",
"img2img": "Снимка към снимка",
"languagePickerLabel": "Език",
"loading": "Зареждане",
"learnMore": "Научете повече",
"modelManager": "Мениджър на модели",
"openInNewTab": "Отворете в нов таб",
"orderBy": "Подреждане по",
"communityLabel": "Общност",
"discordLabel": "Дискорд",
"error": "Грешка",
"file": "Файл"
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
{
"accessibility": {
"about": "About",
"createIssue": "Create Issue",
"submitSupportTicket": "Submit Support Ticket"
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,980 @@
{
"common": {
"hotkeysLabel": "Atajos de teclado",
"languagePickerLabel": "Selector de idioma",
"reportBugLabel": "Reportar errores",
"settingsLabel": "Ajustes",
"img2img": "Imagen a Imagen",
"nodes": "Flujos de trabajo",
"upload": "Subir imagen",
"load": "Cargar",
"statusDisconnected": "Desconectado",
"githubLabel": "Github",
"discordLabel": "Discord",
"back": "Atrás",
"loading": "Cargando",
"postprocessing": "Postprocesamiento",
"txt2img": "De texto a imagen",
"accept": "Aceptar",
"cancel": "Cancelar",
"linear": "Lineal",
"random": "Aleatorio",
"openInNewTab": "Abrir en una nueva pestaña",
"dontAskMeAgain": "No me preguntes de nuevo",
"areYouSure": "¿Estas seguro?",
"batch": "Administrador de lotes",
"modelManager": "Administrador de modelos",
"communityLabel": "Comunidad",
"direction": "Dirección",
"ai": "Ia",
"add": "Añadir",
"auto": "Automático",
"copyError": "Error $t(gallery.copy)",
"details": "Detalles",
"or": "o",
"checkpoint": "Punto de control",
"controlNet": "ControlNet",
"aboutHeading": "Sea dueño de su poder creativo",
"advanced": "Avanzado",
"data": "Fecha",
"delete": "Borrar",
"copy": "Copiar",
"beta": "Beta",
"on": "En",
"aboutDesc": "¿Utilizas Invoke para trabajar? Mira aquí:",
"installed": "Instalado",
"green": "Verde",
"editor": "Editor",
"orderBy": "Ordenar por",
"file": "Archivo",
"saveAs": "Guardar Como",
"somethingWentWrong": "Algo salió mal",
"selected": "Seleccionado",
"tab": "Tabulador",
"positivePrompt": "Prompt Positivo",
"negativePrompt": "Prompt Negativo",
"error": "Error",
"format": "formato",
"unknown": "Desconocido",
"input": "Entrada",
"template": "Plantilla",
"red": "Rojo",
"alpha": "Transparencia",
"outputs": "Resultados",
"learnMore": "Aprende más",
"enabled": "Activado",
"disabled": "Desactivado",
"folder": "Carpeta",
"updated": "Actualizado",
"created": "Creado",
"save": "Guardar",
"unknownError": "Error Desconocido",
"blue": "Azul",
"clipboard": "Portapapeles",
"loadingImage": "Cargando la imagen",
"inpaint": "inpaint",
"ipAdapter": "Adaptador IP",
"t2iAdapter": "Adaptador T2I",
"apply": "Aplicar",
"openInViewer": "Abrir en el visor",
"off": "Apagar",
"generating": "Generando",
"ok": "De acuerdo",
"placeholderSelectAModel": "Seleccionar un modelo",
"reset": "Restablecer",
"none": "Ninguno",
"new": "Nuevo",
"dontShowMeThese": "No mostrar estos",
"loadingModel": "Cargando el modelo",
"view": "Ver",
"edit": "Editar",
"safetensors": "Safetensors",
"toResolve": "Para resolver",
"outpaint": "outpaint",
"simple": "Sencillo",
"close": "Cerrar",
"board": "Tablero",
"crop": "Cortar"
},
"gallery": {
"galleryImageSize": "Tamaño de la imagen",
"gallerySettings": "Ajustes de la galería",
"autoSwitchNewImages": "Auto seleccionar Imágenes nuevas",
"deleteImage_one": "Eliminar Imagen",
"deleteImage_many": "Eliminar {{count}} Imágenes",
"deleteImage_other": "Eliminar {{count}} Imágenes",
"deleteImagePermanent": "Las imágenes eliminadas no se pueden restaurar.",
"autoAssignBoardOnClick": "Asignar automática tableros al hacer clic",
"gallery": "Galería",
"noImageSelected": "Sin imágenes seleccionadas",
"bulkDownloadRequestFailed": "Error al preparar la descarga",
"oldestFirst": "La más antigua primero",
"sideBySide": "conjuntamente",
"selectForCompare": "Seleccionar para comparar",
"alwaysShowImageSizeBadge": "Mostrar siempre las dimensiones de la imagen",
"currentlyInUse": "Esta imagen se utiliza actualmente con las siguientes funciones:",
"selectAllOnPage": "Seleccionar todo en la página",
"bulkDownloadFailed": "Error en la descarga",
"compareHelp2": "Presione <Kbd> M </Kbd> para recorrer los modos de comparación.",
"move": "Mover",
"copy": "Copiar",
"drop": "Gota",
"displayBoardSearch": "Tablero de búsqueda",
"deleteSelection": "Borrar selección",
"downloadSelection": "Descargar selección",
"openInViewer": "Abrir en el visor",
"searchImages": "Búsqueda por metadatos",
"swapImages": "Intercambiar imágenes",
"sortDirection": "Orden de clasificación",
"showStarredImagesFirst": "Mostrar imágenes destacadas primero",
"go": "Ir",
"bulkDownloadRequested": "Preparando la descarga",
"image": "imagen",
"compareHelp4": "Presione <Kbd> Z </Kbd> o <Kbd> Esc </Kbd> para salir.",
"viewerImage": "Ver imagen",
"dropOrUpload": "$t(gallery.drop) o cargar",
"displaySearch": "Buscar imagen",
"download": "Descargar",
"exitBoardSearch": "Finalizar búsqueda",
"exitSearch": "Salir de la búsqueda de imágenes",
"featuresWillReset": "Si elimina esta imagen, dichas funciones se restablecerán inmediatamente.",
"loading": "Cargando",
"newestFirst": "La más nueva primero",
"unstarImage": "Dejar de ser favorita",
"bulkDownloadRequestedDesc": "Su solicitud de descarga se está preparando. Esto puede tardar unos minutos.",
"hover": "Desplazar",
"compareHelp1": "Mantenga presionada la tecla <Kbd> Alt </Kbd> mientras hace clic en una imagen de la galería o utiliza las teclas de flecha para cambiar la imagen de comparación.",
"stretchToFit": "Estirar para encajar",
"exitCompare": "Salir de la comparación",
"starImage": "Imágenes favoritas",
"dropToUpload": "$t(gallery.drop) para cargar",
"slider": "Deslizador",
"assetsTab": "Archivos que has cargado para utilizarlos en tus proyectos.",
"imagesTab": "Imágenes que ha creado y guardado en Invoke.",
"compareImage": "Comparar imagen",
"boardsSettings": "Ajustes de los tableros",
"imagesSettings": "Configuración de imágenes de la galería",
"compareHelp3": "Presione <Kbd> C </Kbd> para intercambiar las imágenes comparadas.",
"showArchivedBoards": "Mostrar paneles archivados"
},
"modelManager": {
"modelManager": "Gestor de Modelos",
"model": "Modelo",
"modelUpdated": "Modelo actualizado",
"manual": "Manual",
"name": "Nombre",
"description": "Descripción",
"config": "Configurar",
"width": "Ancho",
"height": "Alto",
"addModel": "Añadir Modelo",
"availableModels": "Modelos disponibles",
"search": "Búsqueda",
"load": "Cargar",
"active": "activo",
"selected": "Seleccionado",
"delete": "Eliminar",
"deleteModel": "Eliminar Modelo",
"deleteConfig": "Eliminar Configuración",
"deleteMsg1": "¿Estás seguro de que deseas eliminar este modelo de InvokeAI?",
"deleteMsg2": "Esto eliminará el modelo del disco si está en la carpeta raíz de InvokeAI. Si está utilizando una ubicación personalizada, el modelo NO se eliminará del disco.",
"convertToDiffusersHelpText4": "Este proceso se realiza una sola vez. Puede tardar entre 30 y 60 segundos dependiendo de las especificaciones de tu ordenador.",
"convert": "Convertir",
"convertToDiffusers": "Convertir en difusores",
"convertToDiffusersHelpText1": "Este modelo se convertirá al formato 🧨 Difusores.",
"convertToDiffusersHelpText2": "Este proceso sustituirá su entrada del Gestor de Modelos por la versión de Difusores del mismo modelo.",
"convertToDiffusersHelpText3": "Tu archivo del punto de control en el disco se eliminará si está en la carpeta raíz de InvokeAI. Si está en una ubicación personalizada, NO se eliminará.",
"convertToDiffusersHelpText5": "Por favor, asegúrate de tener suficiente espacio en el disco. Los modelos generalmente varían entre 2 GB y 7 GB de tamaño.",
"convertToDiffusersHelpText6": "¿Desea transformar este modelo?",
"modelConverted": "Modelo adaptado",
"alpha": "Alfa",
"allModels": "Todos los modelos",
"repo_id": "Identificador del repositorio",
"none": "ninguno",
"vae": "VAE",
"variant": "Variante",
"baseModel": "Modelo básico",
"modelConversionFailed": "Conversión al modelo fallida",
"selectModel": "Seleccionar un modelo",
"modelUpdateFailed": "Error al actualizar el modelo",
"convertingModelBegin": "Convirtiendo el modelo. Por favor, espere.",
"modelDeleted": "Modelo eliminado",
"modelDeleteFailed": "Error al borrar el modelo",
"settings": "Ajustes",
"syncModels": "Sincronizar las plantillas",
"clipEmbed": "Incrustar CLIP",
"addModels": "Añadir modelos",
"advanced": "Avanzado",
"clipGEmbed": "Incrustar CLIP-G",
"cancel": "Cancelar",
"clipLEmbed": "Incrustar CLIP-L"
},
"parameters": {
"images": "Imágenes",
"steps": "Pasos",
"cfgScale": "Escala CFG",
"width": "Ancho",
"height": "Alto",
"seed": "Semilla",
"shuffle": "Semilla aleatoria",
"noiseThreshold": "Umbral de Ruido",
"perlinNoise": "Ruido Perlin",
"type": "Tipo",
"strength": "Fuerza",
"upscaling": "Aumento de resolución",
"scale": "Escala",
"imageFit": "Ajuste tamaño de imagen inicial al tamaño objetivo",
"scaleBeforeProcessing": "Redimensionar antes de procesar",
"scaledWidth": "Ancho escalado",
"scaledHeight": "Alto escalado",
"infillMethod": "Método de relleno",
"tileSize": "Tamaño del mosaico",
"usePrompt": "Usar Entrada",
"useSeed": "Usar Semilla",
"useAll": "Usar Todo",
"info": "Información",
"symmetry": "Simetría",
"copyImage": "Copiar la imagen",
"general": "General",
"denoisingStrength": "Intensidad de la eliminación del ruido",
"seamlessXAxis": "Eje X sin juntas",
"seamlessYAxis": "Eje Y sin juntas",
"scheduler": "Programador",
"positivePromptPlaceholder": "Prompt Positivo",
"negativePromptPlaceholder": "Prompt Negativo",
"controlNetControlMode": "Modo de control",
"clipSkip": "Omitir el CLIP",
"maskBlur": "Desenfoque de máscara",
"patchmatchDownScaleSize": "Reducir a escala",
"coherenceMode": "Modo"
},
"settings": {
"models": "Modelos",
"displayInProgress": "Mostrar las imágenes del progreso",
"confirmOnDelete": "Confirmar antes de eliminar",
"resetWebUI": "Restablecer interfaz web",
"resetWebUIDesc1": "Al restablecer la interfaz web, solo se restablece la caché local del navegador de sus imágenes y la configuración guardada. No se elimina ninguna imagen de su disco duro.",
"resetWebUIDesc2": "Si las imágenes no se muestran en la galería o algo más no funciona, intente restablecer antes de reportar un incidente en GitHub.",
"resetComplete": "Se ha restablecido la interfaz web.",
"general": "General",
"developer": "Desarrollador",
"antialiasProgressImages": "Imágenes del progreso de Antialias",
"showProgressInViewer": "Mostrar las imágenes del progreso en el visor",
"ui": "Interfaz del usuario",
"generation": "Generación",
"beta": "Beta",
"reloadingIn": "Recargando en",
"intermediatesClearedFailed": "Error limpiando los intermediarios",
"intermediatesCleared_one": "Borrado {{count}} intermediario",
"intermediatesCleared_many": "Borrados {{count}} intermediarios",
"intermediatesCleared_other": "Borrados {{count}} intermediarios"
},
"toast": {
"uploadFailed": "Error al subir archivo",
"imageCopied": "Imágen copiada",
"parametersNotSet": "Parámetros no recuperados",
"serverError": "Error en el servidor",
"canceled": "Procesando la cancelación",
"connected": "Conectado al servidor",
"uploadFailedInvalidUploadDesc": "Deben ser imágenes PNG o JPEG.",
"parameterSet": "Parámetro recuperado",
"parameterNotSet": "Parámetro no recuperado",
"problemCopyingImage": "No se puede copiar la imagen",
"errorCopied": "Error al copiar",
"baseModelChanged": "Modelo base cambiado",
"addedToBoard": "Se agregó a los activos del panel {{name}}",
"baseModelChangedCleared_one": "Borrado o desactivado {{count}} submodelo incompatible",
"baseModelChangedCleared_many": "Borrados o desactivados {{count}} submodelos incompatibles",
"baseModelChangedCleared_other": "Borrados o desactivados {{count}} submodelos incompatibles",
"addedToUncategorized": "Añadido a los activos del tablero $t(boards.uncategorized)",
"imagesWillBeAddedTo": "Las imágenes subidas se añadirán a los activos del panel {{boardName}}.",
"layerCopiedToClipboard": "Capa copiada en el portapapeles"
},
"accessibility": {
"invokeProgressBar": "Activar la barra de progreso",
"reset": "Reiniciar",
"uploadImage": "Cargar imagen",
"previousImage": "Imagen anterior",
"nextImage": "Siguiente imagen",
"menu": "Menú",
"about": "Acerca de",
"createIssue": "Crear un problema",
"resetUI": "Interfaz de usuario $t(accessibility.reset)",
"mode": "Modo",
"submitSupportTicket": "Enviar Ticket de Soporte",
"toggleRightPanel": "Activar o desactivar el panel derecho (G)",
"toggleLeftPanel": "Activar o desactivar el panel izquierdo (T)",
"uploadImages": "Cargar imagen(es)"
},
"nodes": {
"zoomInNodes": "Acercar",
"hideMinimapnodes": "Ocultar el minimapa",
"fitViewportNodes": "Ajustar la vista",
"zoomOutNodes": "Alejar",
"showMinimapnodes": "Mostrar el minimapa",
"reloadNodeTemplates": "Recargar las plantillas de nodos",
"loadWorkflow": "Cargar el flujo de trabajo",
"downloadWorkflow": "Descargar el flujo de trabajo en un archivo JSON",
"boardAccessError": "No se puede encontrar el panel {{board_id}}, se está restableciendo al valor predeterminado"
},
"boards": {
"autoAddBoard": "Agregar panel automáticamente",
"changeBoard": "Cambiar el panel",
"clearSearch": "Borrar la búsqueda",
"deleteBoard": "Borrar el panel",
"selectBoard": "Seleccionar un panel",
"uncategorized": "Sin categoría",
"cancel": "Cancelar",
"addBoard": "Agregar un panel",
"movingImagesToBoard_one": "Moviendo {{count}} imagen al panel:",
"movingImagesToBoard_many": "Moviendo {{count}} imágenes al panel:",
"movingImagesToBoard_other": "Moviendo {{count}} imágenes al panel:",
"bottomMessage": "Al eliminarlas imágenes, se restablecerán las funcionalidades que actualmente las estén utilizando.",
"deleteBoardAndImages": "Borrar el panel y las imágenes",
"loading": "Cargando...",
"deletedBoardsCannotbeRestored": "Los paneles eliminados no se pueden restaurar. Al Seleccionar 'Borrar solo el panel' transferirá las imágenes a un estado sin categorizar.",
"move": "Mover",
"menuItemAutoAdd": "Agregar automáticamente a este panel",
"searchBoard": "Buscando paneles…",
"topMessage": "Este panel contiene imágenes utilizadas en las siguientes funciones:",
"downloadBoard": "Descargar panel",
"deleteBoardOnly": "Borrar solo el panel",
"myBoard": "Mi panel",
"noMatching": "Sin paneles coincidentes",
"imagesWithCount_one": "{{count}} imagen",
"imagesWithCount_many": "{{count}} imágenes",
"imagesWithCount_other": "{{count}} imágenes",
"assetsWithCount_one": "{{count}} activo",
"assetsWithCount_many": "{{count}} activos",
"assetsWithCount_other": "{{count}} activos",
"addPrivateBoard": "Agregar un panel privado",
"addSharedBoard": "Añadir panel compartido",
"boards": "Paneles",
"archiveBoard": "Archivar panel",
"archived": "Archivado",
"selectedForAutoAdd": "Seleccionado para agregar automáticamente",
"unarchiveBoard": "Desarchivar el panel",
"noBoards": "No hay paneles {{boardType}}",
"shared": "Paneles compartidos",
"deletedPrivateBoardsCannotbeRestored": "Los paneles eliminados no se pueden restaurar. Al elegir \"Eliminar solo el panel\", las imágenes se colocarán en un estado privado y sin categoría para el creador de la imagen.",
"private": "Paneles privados",
"updateBoardError": "No se pudo actualizar el panel",
"pause": "Pausa",
"resume": "Reanudar",
"restartFailed": "Reinicio fallido",
"restartFile": "Reiniciar archivo",
"restartRequired": "Reinicio requerido",
"resumeRefused": "Reanudación rechazada por el servidor. Reinicio requerido.",
"uncategorizedImages": "Imágenes sin categoría",
"deleteAllUncategorizedImages": "Eliminar todas las imágenes sin categoría",
"deletedImagesCannotBeRestored": "Las imágenes eliminadas no pueden ser restauradas.",
"hideBoards": "Ocultar tableros",
"locateInGalery": "Ubicar en galeria",
"viewBoards": "Ver paneles"
},
"accordions": {
"compositing": {
"title": "Composición",
"infillTab": "Relleno",
"coherenceTab": "Parámetros de la coherencia"
},
"generation": {
"title": "Generación"
},
"image": {
"title": "Imagen"
},
"control": {
"title": "Control"
},
"advanced": {
"options": "$t(accordions.advanced.title) opciones",
"title": "Avanzado"
}
},
"ui": {
"tabs": {
"canvas": "Lienzo",
"queue": "Cola",
"workflows": "Flujos de trabajo",
"models": "Modelos",
"modelsTab": "$t(ui.tabs.models) $t(common.tab)",
"workflowsTab": "$t(ui.tabs.workflows) $t(common.tab)",
"upscaling": "Upscaling",
"gallery": "Galería",
"upscalingTab": "$t(ui.tabs.upscaling) $t(common.tab)"
}
},
"queue": {
"back": "Atrás",
"front": "Delante",
"batchQueuedDesc_one": "Se agregó {{count}} sesión a {{direction}} la cola",
"batchQueuedDesc_many": "Se agregaron {{count}} sesiones a {{direction}} la cola",
"batchQueuedDesc_other": "Se agregaron {{count}} sesiones a {{direction}} la cola",
"clearQueueAlertDialog": "Al vaciar la cola se cancela inmediatamente cualquier elemento de procesamiento y se vaciará la cola por completo. Los filtros pendientes se cancelarán.",
"time": "Tiempo",
"clearFailed": "Error al vaciar la cola",
"cancelFailed": "Error al cancelar el elemento",
"resumeFailed": "Error al reanudar el proceso",
"pause": "Pausar",
"pauseTooltip": "Pausar el proceso",
"cancelBatchSucceeded": "Lote cancelado",
"pruneSucceeded": "Se purgaron {{item_count}} elementos completados de la cola",
"pruneFailed": "Error al purgar la cola",
"cancelBatchFailed": "Error al cancelar los lotes",
"pauseFailed": "Error al pausar el proceso",
"status": "Estado",
"origin": "Origen",
"destination": "Destino",
"generations_one": "Generación",
"generations_many": "Generaciones",
"generations_other": "Generaciones",
"resume": "Reanudar",
"queueEmpty": "Cola vacía",
"cancelItem": "Cancelar elemento",
"cancelBatch": "Cancelar lote",
"openQueue": "Abrir la cola",
"completed": "Completado",
"enqueueing": "Añadir lotes a la cola",
"clear": "Limpiar",
"pauseSucceeded": "Proceso pausado",
"resumeSucceeded": "Proceso reanudado",
"resumeTooltip": "Reanudar proceso",
"cancel": "Cancelar",
"cancelTooltip": "Cancelar artículo actual",
"pruneTooltip": "Purgar {{item_count}} elementos completados",
"batchQueued": "Lote en cola",
"pending": "Pendiente",
"item": "Elemento",
"total": "Total",
"in_progress": "En proceso",
"failed": "Fallido",
"completedIn": "Completado en",
"upscaling": "Upscaling",
"canvas": "Lienzo",
"generation": "Generación",
"workflows": "Flujo de trabajo",
"other": "Otro",
"queueFront": "Añadir al principio de la cola",
"gallery": "Galería",
"session": "Sesión",
"notReady": "La cola aún no está lista",
"graphQueued": "Gráfico en cola",
"clearQueueAlertDialog2": "¿Estás seguro que deseas vaciar la cola?",
"next": "Siguiente",
"iterations_one": "Interacción",
"iterations_many": "Interacciones",
"iterations_other": "Interacciones",
"current": "Actual",
"queue": "Cola",
"queueBack": "Añadir a la cola",
"cancelSucceeded": "Elemento cancelado",
"clearTooltip": "Cancelar y limpiar todos los elementos",
"clearSucceeded": "Cola vaciada",
"canceled": "Cancelado",
"batch": "Lote",
"graphFailedToQueue": "Error al poner el gráfico en cola",
"batchFailedToQueue": "Error al poner en cola el lote",
"prompts_one": "Prompt",
"prompts_many": "Prompts",
"prompts_other": "Prompts",
"prune": "Eliminar"
},
"controlLayers": {
"layer_one": "Capa",
"layer_many": "Capas",
"layer_other": "Capas",
"copyToClipboard": "Copiar al portapapeles"
},
"whatsNew": {
"readReleaseNotes": "Leer las notas de la versión",
"watchRecentReleaseVideos": "Ver videos de versiones recientes",
"whatsNewInInvoke": "Novedades en Invoke",
"items": [
"<StrongComponent>SD 3.5</StrongComponent>: compatibilidad con SD 3.5 Medium y Large."
]
},
"invocationCache": {
"enableFailed": "Error al activar la cache",
"cacheSize": "Tamaño de la caché",
"hits": "Accesos a la caché",
"invocationCache": "Caché",
"misses": "Errores de la caché",
"clear": "Limpiar",
"maxCacheSize": "Tamaño máximo de la caché",
"enableSucceeded": "Cache activada",
"clearFailed": "Error al borrar la cache",
"enable": "Activar",
"useCache": "Uso de la caché",
"disableSucceeded": "Caché desactivada",
"clearSucceeded": "Caché borrada",
"disable": "Desactivar",
"disableFailed": "Error al desactivar la caché"
},
"hrf": {
"hrf": "Solución de alta resolución",
"metadata": {
"enabled": "Corrección de alta resolución activada",
"strength": "Forzar la corrección de alta resolución",
"method": "Método de corrección de alta resolución"
}
},
"prompt": {
"addPromptTrigger": "Añadir activador de los avisos",
"compatibleEmbeddings": "Incrustaciones compatibles",
"noMatchingTriggers": "No hay activadores coincidentes"
},
"hotkeys": {
"hotkeys": "Atajo del teclado",
"canvas": {
"selectViewTool": {
"desc": "Selecciona la herramienta de Visualización.",
"title": "Visualización"
},
"cancelFilter": {
"title": "Cancelar el filtro",
"desc": "Cancelar el filtro pendiente."
},
"applyTransform": {
"title": "Aplicar la transformación",
"desc": "Aplicar la transformación pendiente a la capa seleccionada."
},
"applyFilter": {
"desc": "Aplicar el filtro pendiente a la capa seleccionada.",
"title": "Aplicar filtro"
},
"selectBrushTool": {
"title": "Pincel",
"desc": "Selecciona la herramienta pincel."
},
"selectBboxTool": {
"desc": "Seleccionar la herramienta de selección del marco.",
"title": "Selección del marco"
},
"selectMoveTool": {
"desc": "Selecciona la herramienta Mover.",
"title": "Mover"
},
"selectRectTool": {
"title": "Rectángulo",
"desc": "Selecciona la herramienta Rectángulo."
},
"decrementToolWidth": {
"title": "Reducir el ancho de la herramienta",
"desc": "Disminuye la anchura de la herramienta pincel o goma de borrar, según la que esté seleccionada."
},
"incrementToolWidth": {
"title": "Incrementar la anchura de la herramienta",
"desc": "Aumenta la anchura de la herramienta pincel o goma de borrar, según la que esté seleccionada."
},
"fitBboxToCanvas": {
"title": "Ajustar bordes al lienzo",
"desc": "Escala y posiciona la vista para ajustarla a los bodes."
},
"fitLayersToCanvas": {
"title": "Ajustar capas al lienzo",
"desc": "Escala y posiciona la vista para que se ajuste a todas las capas visibles."
},
"resetSelected": {
"title": "Restablecer capa",
"desc": "Restablecer la capa seleccionada. Solo se aplica a Máscara de retoque y Guía regional."
},
"setZoomTo400Percent": {
"desc": "Ajuste la aplicación del lienzo al 400%.",
"title": "Ampliar al 400%"
},
"transformSelected": {
"desc": "Transformar la capa seleccionada.",
"title": "Transformar"
},
"selectColorPickerTool": {
"title": "Selector de color",
"desc": "Seleccione la herramienta de selección de color."
},
"selectEraserTool": {
"title": "Borrador",
"desc": "Selecciona la herramienta Borrador."
},
"setZoomTo100Percent": {
"title": "Ampliar al 100%",
"desc": "Ajuste ampliar el lienzo al 100%."
},
"undo": {
"title": "Deshacer",
"desc": "Deshacer la última acción en el lienzo."
},
"nextEntity": {
"desc": "Seleccione la siguiente capa de la lista.",
"title": "Capa siguiente"
},
"redo": {
"title": "Rehacer",
"desc": "Rehacer la última acción en el lienzo."
},
"prevEntity": {
"title": "Capa anterior",
"desc": "Seleccione la capa anterior de la lista."
},
"title": "Lienzo",
"setZoomTo200Percent": {
"title": "Ampliar al 200%",
"desc": "Ajuste la ampliación del lienzo al 200%."
},
"setZoomTo800Percent": {
"title": "Ampliar al 800%",
"desc": "Ajuste la ampliación del lienzo al 800%."
},
"filterSelected": {
"desc": "Filtra la capa seleccionada. Solo se aplica a las capas Ráster y Control.",
"title": "Filtrar"
},
"cancelTransform": {
"title": "Cancelar transformación",
"desc": "Cancelar la transformación pendiente."
},
"deleteSelected": {
"title": "Borrar la capa",
"desc": "Borrar la capa seleccionada."
},
"quickSwitch": {
"desc": "Cambiar entre las dos últimas capas seleccionadas. Si una capa está seleccionada, cambia siempre entre ella y la última capa no seleccionada.",
"title": "Cambio rápido de capa"
}
},
"app": {
"selectModelsTab": {
"title": "Seleccione la pestaña Modelos",
"desc": "Selecciona la pestaña Modelos."
},
"focusPrompt": {
"desc": "Mueve el foco del cursor a la indicación positiva.",
"title": "Enfoque"
},
"toggleLeftPanel": {
"title": "Alternar panel izquierdo",
"desc": "Mostrar u ocultar el panel izquierdo."
},
"selectQueueTab": {
"title": "Seleccione la pestaña Cola",
"desc": "Seleccione la pestaña Cola."
},
"selectCanvasTab": {
"title": "Seleccione la pestaña Lienzo",
"desc": "Selecciona la pestaña Lienzo."
},
"clearQueue": {
"title": "Vaciar cola",
"desc": "Cancelar y variar todos los elementos de la cola."
},
"selectUpscalingTab": {
"title": "Selecciona la pestaña Ampliar",
"desc": "Selecciona la pestaña Aumento de escala."
},
"togglePanels": {
"desc": "Muestra u oculta los paneles izquierdo y derecho a la vez.",
"title": "Alternar paneles"
},
"toggleRightPanel": {
"title": "Alternar panel derecho",
"desc": "Mostrar u ocultar el panel derecho."
},
"invokeFront": {
"desc": "Pone en cola la solicitud de compilación y la agrega al principio de la cola.",
"title": "Invocar (frente)"
},
"cancelQueueItem": {
"title": "Cancelar",
"desc": "Cancelar el elemento de la cola que se está procesando."
},
"invoke": {
"desc": "Pone en cola la solicitud de compilación y la agrega al final de la cola.",
"title": "Invocar"
},
"title": "Aplicación",
"selectWorkflowsTab": {
"title": "Seleccione la pestaña Flujos de trabajo",
"desc": "Selecciona la pestaña Flujos de trabajo."
},
"resetPanelLayout": {
"title": "Reiniciar la posición del panel",
"desc": "Restablece los paneles izquierdo y derecho a su tamaño y disposición por defecto."
}
},
"workflows": {
"addNode": {
"title": "Añadir nodo",
"desc": "Abrir añadir nodo."
},
"selectAll": {
"title": "Seleccionar todo",
"desc": "Seleccione todos los nodos y enlaces."
},
"deleteSelection": {
"desc": "Borrar todos los nodos y enlaces seleccionados.",
"title": "Borrar"
},
"undo": {
"desc": "Deshaga la última acción.",
"title": "Deshacer"
},
"redo": {
"desc": "Rehacer la última acción.",
"title": "Rehacer"
},
"pasteSelection": {
"desc": "Pegar nodos y bordes copiados.",
"title": "Pegar"
},
"title": "Flujos de trabajo",
"copySelection": {
"desc": "Copiar nodos y bordes seleccionados.",
"title": "Copiar"
},
"pasteSelectionWithEdges": {
"desc": "Pega los nodos copiados, los enlaces y todos los enlaces conectados a los nodos copiados.",
"title": "Pegar con enlaces"
}
},
"viewer": {
"useSize": {
"title": "Usar dimensiones",
"desc": "Utiliza las dimensiones de la imagen actual como el tamaño del borde."
},
"remix": {
"title": "Remezcla",
"desc": "Recupera todos los metadatos excepto la semilla de la imagen actual."
},
"loadWorkflow": {
"desc": "Carga el flujo de trabajo guardado de la imagen actual (si tiene uno).",
"title": "Cargar flujo de trabajo"
},
"recallAll": {
"desc": "Recupera todos los metadatos de la imagen actual.",
"title": "Recuperar todos los metadatos"
},
"recallPrompts": {
"desc": "Recuerde las indicaciones positivas y negativas de la imagen actual.",
"title": "Recordatorios"
},
"recallSeed": {
"title": "Recuperar semilla",
"desc": "Recupera la semilla de la imagen actual."
},
"runPostprocessing": {
"title": "Ejecutar posprocesamiento",
"desc": "Ejecutar el posprocesamiento seleccionado en la imagen actual."
},
"toggleMetadata": {
"title": "Mostrar/ocultar los metadatos",
"desc": "Mostrar u ocultar la superposición de metadatos de la imagen actual."
},
"nextComparisonMode": {
"desc": "Desplácese por los modos de comparación.",
"title": "Siguiente comparación"
},
"title": "Visor de imágenes",
"toggleViewer": {
"title": "Mostrar/Ocultar el visor de imágenes",
"desc": "Mostrar u ocultar el visor de imágenes. Solo disponible en la pestaña Lienzo."
},
"swapImages": {
"title": "Intercambiar imágenes en la comparación",
"desc": "Intercambia las imágenes que se están comparando."
}
},
"gallery": {
"clearSelection": {
"title": "Limpiar selección",
"desc": "Borrar la selección actual, si hay alguna."
},
"galleryNavUp": {
"title": "Subir",
"desc": "Navega hacia arriba en la cuadrícula de la galería y selecciona esa imagen. Si estás en la parte superior de la página, ve a la página anterior."
},
"galleryNavLeft": {
"title": "Izquierda",
"desc": "Navegue hacia la izquierda en la rejilla de la galería, seleccionando esa imagen. Si está en la primera imagen de la fila, vaya a la fila anterior. Si está en la primera imagen de la página, vaya a la página anterior."
},
"galleryNavDown": {
"title": "Bajar",
"desc": "Navegue hacia abajo en la parrilla de la galería, seleccionando esa imagen. Si se encuentra al final de la página, vaya a la página siguiente."
},
"galleryNavRight": {
"title": "A la derecha",
"desc": "Navegue hacia la derecha en la rejilla de la galería, seleccionando esa imagen. Si está en la última imagen de la fila, vaya a la fila siguiente. Si está en la última imagen de la página, vaya a la página siguiente."
},
"galleryNavUpAlt": {
"desc": "Igual que arriba, pero selecciona la imagen de comparación, abriendo el modo de comparación si no está ya abierto.",
"title": "Arriba (Comparar imagen)"
},
"deleteSelection": {
"desc": "Borrar todas las imágenes seleccionadas. Por defecto, se le pedirá que confirme la eliminación. Si las imágenes están actualmente en uso en la aplicación, se te avisará.",
"title": "Borrar"
},
"title": "Galería",
"selectAllOnPage": {
"title": "Seleccionar todo en la página",
"desc": "Seleccionar todas las imágenes en la página actual."
}
},
"searchHotkeys": "Buscar teclas de acceso rápido",
"noHotkeysFound": "Sin teclas de acceso rápido",
"clearSearch": "Limpiar la búsqueda"
},
"metadata": {
"guidance": "Orientación",
"createdBy": "Creado por",
"noImageDetails": "Sin detalles en la imagen",
"cfgRescaleMultiplier": "$t(parameters.cfgRescaleMultiplier)",
"height": "Altura",
"imageDimensions": "Dimensiones de la imagen",
"seamlessXAxis": "Eje X sin juntas",
"seamlessYAxis": "Eje Y sin juntas",
"generationMode": "Modo de generación",
"scheduler": "Programador",
"width": "Ancho",
"Threshold": "Umbral de ruido",
"canvasV2Metadata": "Lienzo",
"metadata": "Metadatos",
"model": "Modelo",
"allPrompts": "Todas las indicaciones",
"cfgScale": "Escala CFG",
"imageDetails": "Detalles de la imagen",
"negativePrompt": "Indicación negativa",
"noMetaData": "Sin metadatos",
"parameterSet": "Parámetro {{parameter}} establecido",
"vae": "Autocodificador",
"workflow": "Flujo de trabajo",
"seed": "Semilla",
"strength": "Forzar imagen a imagen",
"recallParameters": "Parámetros de recuperación",
"steps": "Pasos",
"noRecallParameters": "Sin parámetros para recuperar"
},
"system": {
"logLevel": {
"debug": "Depurar",
"info": "Información",
"warn": "Advertir",
"fatal": "Grave",
"error": "Error",
"trace": "Rastro",
"logLevel": "Nivel del registro"
},
"enableLogging": "Activar registro",
"logNamespaces": {
"workflows": "Flujos de trabajo",
"system": "Sistema",
"metadata": "Metadatos",
"gallery": "Galería",
"logNamespaces": "Espacios para los nombres de registro",
"generation": "Generación",
"events": "Eventos",
"canvas": "Lienzo",
"config": "Ajustes",
"models": "Modelos",
"queue": "Cola"
}
},
"newUserExperience": {
"toGetStarted": "Para empezar, introduzca un mensaje en el cuadro y haga clic en <StrongComponent>Invocar</StrongComponent> para generar su primera imagen. Seleccione una plantilla para mejorar los resultados. Puede elegir guardar sus imágenes directamente en <StrongComponent>Galería</StrongComponent> o editarlas en <StrongComponent>Lienzo</StrongComponent>.",
"noModelsInstalled": "Parece que no tienes ningún modelo instalado",
"gettingStartedSeries": "¿Desea más orientación? Consulte nuestra <LinkComponent>Serie de introducción</LinkComponent> para obtener consejos sobre cómo aprovechar todo el potencial de Invoke Studio.",
"toGetStartedLocal": "Para empezar, asegúrate de descargar o importar los modelos necesarios para ejecutar Invoke. A continuación, introduzca un mensaje en el cuadro y haga clic en <StrongComponent>Invocar</StrongComponent> para generar su primera imagen. Seleccione una plantilla para mejorar los resultados. Puede elegir guardar sus imágenes directamente en <StrongComponent>Galería</StrongComponent> o editarlas en el <StrongComponent>Lienzo</StrongComponent>."
},
"auth": {
"login": {
"title": "Iniciar sesión en InvokeAI",
"email": "Email",
"emailPlaceholder": "Email",
"password": "Contraseña",
"passwordPlaceholder": "Contraseña",
"rememberMe": "Recordarme por 7 días",
"signIn": "Iniciar sesión",
"signingIn": "Iniciando sesión...",
"loginFailed": "Inicio de sesión fallido. Por favor revise sus credenciales."
},
"setup": {
"title": "Bienvenido a InvokeAI",
"subtitle": "Configure su cuenta de administrador para empezar",
"email": "Email",
"emailPlaceholder": "admin@example.com",
"emailHelper": "Este será su nombre de usuario para iniciar sesión",
"displayName": "Nombre para mostrar",
"displayNamePlaceholder": "Administrador",
"displayNameHelper": "Su nombre como se mostrará en la aplicación",
"password": "Contraseña",
"passwordPlaceholder": "Contraseña",
"passwordHelper": "Debe tener al menos 8 caracteres con mayúsculas, minúsculas y números",
"passwordTooShort": "La contraseña debe tener al menos 8 caracteres",
"passwordMissingRequirements": "La contraseña debe contener mayúsculas, minúsculas y numeros",
"confirmPassword": "Confirmar contraseña",
"confirmPasswordPlaceholder": "Confirmar contraseña",
"passwordsDoNotMatch": "Las contraseñas no coinciden",
"createAccount": "Crear cuenta de administrador",
"creatingAccount": "Configurando...",
"setupFailed": "Configuración fallida. Por favor intente nuevamente.",
"passwordHelperRelaxed": "Ingrese una contraseña (se mostrará la fortaleza)"
},
"userMenu": "Menu de usuario",
"admin": "Administrador",
"logout": "Cerrar Sesión",
"adminOnlyFeature": "Esta funcionalidad solo esta disponible para administradores.",
"profile": {
"menuItem": "Mi perfil",
"title": "Mi perfil",
"email": "Email",
"emailReadOnly": "La dirección de email no puede ser cambiada",
"displayName": "Nombre para mostrar",
"displayNamePlaceholder": "Su nombre",
"changePassword": "Cambiar contraseña",
"currentPassword": "Contraseña Actual",
"currentPasswordPlaceholder": "Contraseña Actual",
"newPassword": "Nueva contraseña",
"newPasswordPlaceholder": "Nueva contraseña",
"confirmPassword": "Confirmar nueva contraseña",
"confirmPasswordPlaceholder": "Confirmar nueva contraseña",
"passwordsDoNotMatch": "Las contraseñas no coinciden",
"saveSuccess": "Perfil actualizado correctamente",
"saveFailed": "Falló el guardado del perfil. Por favor intente nuevamente."
},
"userManagement": {
"menuItem": "Administración de usuario",
"title": "Administración de usuario",
"email": "Email",
"emailPlaceholder": "user@example.com",
"displayName": "Nombre para mostrar",
"displayNamePlaceholder": "Nombre para mostrar",
"password": "Contraseña",
"passwordPlaceholder": "Contraseña",
"newPassword": "Nueva contraseña",
"newPasswordPlaceholder": "Deje en blanco para conservar la contraseña actual",
"role": "Rol",
"status": "Estado",
"actions": "Acciones",
"isAdmin": "Administrador",
"user": "Usuario",
"you": "Tu",
"createUser": "Crear usuario",
"editUser": "Editar usuario",
"deleteUser": "Eliminar usuario",
"deleteConfirm": "Esta seguro que desea eliminar {{name}}? Esta accion no se podrá revertir.",
"generatePassword": "Generar contraseña robusta",
"showPassword": "Mostrar contraseña",
"hidePassword": "Ocultar contraseña",
"activate": "Activar",
"deactivate": "Desactivar",
"saveFailed": "Fallo al guardar usuario. Por favor intente nuevamente.",
"deleteFailed": "Fallo al borrar usuario. Por favor intente nuevamente.",
"loadFailed": "Fallo al cargar usuarios.",
"back": "Atras",
"cannotDeleteSelf": "Usted no puede eliminar su propia cuenta",
"cannotDeactivateSelf": "Usted no puede desactivar su propia cuenta"
},
"passwordStrength": {
"weak": "Contraseña debil",
"moderate": "Contraseña moderada",
"strong": "Contraseña fuerte"
}
}
}
@@ -0,0 +1,57 @@
{
"accessibility": {
"reset": "Resetoi",
"uploadImage": "Lataa kuva",
"invokeProgressBar": "Invoken edistymispalkki",
"nextImage": "Seuraava kuva",
"previousImage": "Edellinen kuva",
"uploadImages": "Lähetä Kuva(t)"
},
"common": {
"languagePickerLabel": "Kielen valinta",
"hotkeysLabel": "Pikanäppäimet",
"reportBugLabel": "Raportoi Bugista",
"settingsLabel": "Asetukset",
"githubLabel": "Github",
"discordLabel": "Discord",
"upload": "Lataa",
"img2img": "Kuva kuvaksi",
"nodes": "Solmut",
"postprocessing": "Jälkikäsitellään",
"cancel": "Peruuta",
"accept": "Hyväksy",
"load": "Lataa",
"back": "Takaisin",
"statusDisconnected": "Yhteys katkaistu",
"loading": "Ladataan",
"txt2img": "Teksti kuvaksi"
},
"gallery": {
"galleryImageSize": "Kuvan koko",
"gallerySettings": "Gallerian asetukset",
"autoSwitchNewImages": "Vaihda uusiin kuviin automaattisesti"
},
"modelManager": {
"t5Encoder": "T5-kooderi",
"qwen3Encoder": "Qwen3-kooderi",
"zImageVae": "VAE (valinnainen)",
"zImageQwen3Encoder": "Qwen3-kooderi (valinnainen)",
"zImageQwen3SourcePlaceholder": "Pakollinen, jos VAE/Enkooderi on tyhjä",
"flux2KleinVae": "VAE (valinnainen)",
"flux2KleinQwen3Encoder": "Qwen3-kooderi (valinnainen)"
},
"auth": {
"login": {
"title": "Kirjaudu sisään InvokeAI:hin",
"password": "Salasana",
"passwordPlaceholder": "Salasana",
"signIn": "Kirjaudu sisään",
"signingIn": "Kirjaudutaan sisään...",
"loginFailed": "Kirjautuminen epäonnistui. Tarkista käyttäjätunnuksesi tiedot."
},
"setup": {
"title": "Tervetuloa InvokeAI:hin",
"subtitle": "Määritä ensimmäiseksi järjestelmänvalvojan tili"
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,98 @@
{
"modelManager": {
"height": "גובה",
"load": "טען",
"search": "חיפוש",
"allModels": "כל המודלים",
"modelUpdated": "מודל עודכן",
"manual": "ידני",
"name": "שם",
"description": "תיאור",
"config": "תצורה",
"repo_id": "מזהה מאגר",
"width": "רוחב",
"addModel": "הוסף מודל",
"active": "פעיל",
"selected": "נבחר",
"deleteModel": "מחיקת מודל",
"deleteConfig": "מחיקת תצורה",
"convertToDiffusersHelpText5": "אנא ודא/י שיש לך מספיק מקום בדיסק. גדלי מודלים בדרך כלל הינם בין 4GB-7GB.",
"convertToDiffusersHelpText1": "מודל זה יומר לפורמט 🧨 המפזרים.",
"convertToDiffusersHelpText2": "תהליך זה יחליף את הרשומה של מנהל המודלים שלך בגרסת המפזרים של אותו המודל.",
"convertToDiffusersHelpText6": "האם ברצונך להמיר מודל זה?",
"modelConverted": "מודל הומר",
"alpha": "אלפא",
"modelManager": "מנהל המודלים",
"model": "מודל",
"availableModels": "מודלים זמינים",
"delete": "מחיקה",
"deleteMsg1": "האם אתה בטוח שברצונך למחוק רשומת מודל זו מ- InvokeAI?",
"deleteMsg2": "פעולה זו לא תמחק את קובץ נקודת הביקורת מהדיסק שלך. ניתן לקרוא אותם מחדש במידת הצורך.",
"convertToDiffusers": "המרה למפזרים",
"convert": "המרה",
"convertToDiffusersHelpText3": "קובץ נקודת הביקורת שלך בדיסק לא יימחק או ישונה בכל מקרה. אתה יכול להוסיף את נקודת הביקורת שלך למנהל המודלים שוב אם תרצה בכך.",
"convertToDiffusersHelpText4": "זהו תהליך חד פעמי בלבד. התהליך עשוי לקחת בסביבות 30-60 שניות, תלוי במפרט המחשב שלך."
},
"common": {
"languagePickerLabel": "בחירת שפה",
"githubLabel": "גיטהאב",
"discordLabel": "דיסקורד",
"settingsLabel": "הגדרות",
"img2img": "תמונה לתמונה",
"nodes": "צמתים",
"statusDisconnected": "מנותק",
"hotkeysLabel": "מקשים חמים",
"reportBugLabel": "דווח באג",
"upload": "העלאה",
"load": "טעינה",
"back": "אחורה"
},
"gallery": {
"galleryImageSize": "גודל תמונה",
"gallerySettings": "הגדרות גלריה",
"autoSwitchNewImages": "החלף אוטומטית לתמונות חדשות"
},
"parameters": {
"images": "תמונות",
"steps": "צעדים",
"cfgScale": "סולם CFG",
"width": "רוחב",
"height": "גובה",
"seed": "זרע",
"type": "סוג",
"strength": "חוזק",
"denoisingStrength": "חוזק מנטרל הרעש",
"scaleBeforeProcessing": "שנה קנה מידה לפני עיבוד",
"scaledWidth": "קנה מידה לאחר שינוי W",
"scaledHeight": "קנה מידה לאחר שינוי H",
"infillMethod": "שיטת מילוי",
"tileSize": "גודל אריח",
"symmetry": "סימטריה",
"copyImage": "העתקת תמונה",
"usePrompt": "שימוש בבקשה",
"useSeed": "שימוש בזרע",
"useAll": "שימוש בהכל",
"info": "פרטים",
"shuffle": "ערבוב",
"noiseThreshold": "סף רעש",
"perlinNoise": "רעש פרלין",
"imageFit": "התאמת תמונה ראשונית לגודל הפלט",
"general": "כללי",
"upscaling": "מגדיל את קנה מידה",
"scale": "סולם"
},
"settings": {
"models": "מודלים",
"displayInProgress": "הצגת תמונות בתהליך",
"confirmOnDelete": "אישור בעת המחיקה",
"resetWebUI": "איפוס ממשק משתמש",
"resetWebUIDesc1": "איפוס ממשק המשתמש האינטרנטי מאפס רק את המטמון המקומי של הדפדפן של התמונות וההגדרות שנשמרו. זה לא מוחק תמונות מהדיסק.",
"resetComplete": "ממשק המשתמש אופס. יש לבצע רענון דף בכדי לטעון אותו מחדש.",
"resetWebUIDesc2": "אם תמונות לא מופיעות בגלריה או שמשהו אחר לא עובד, נא לנסות איפוס /או אתחול לפני שליחת תקלה ב-GitHub."
},
"toast": {
"uploadFailed": "העלאה נכשלה",
"imageCopied": "התמונה הועתקה",
"parametersNotSet": "פרמטרים לא הוגדרו"
}
}
@@ -0,0 +1,34 @@
{
"accessibility": {
"mode": "Mód",
"uploadImage": "Fénykép feltöltése",
"nextImage": "Következő kép",
"previousImage": "Előző kép",
"menu": "Menü"
},
"boards": {
"cancel": "Mégsem",
"loading": "Betöltés..."
},
"accordions": {
"image": {
"title": "Kép"
}
},
"common": {
"accept": "Elfogad",
"ai": "ai",
"back": "Vissza",
"cancel": "Mégsem",
"or": "vagy",
"details": "Részletek",
"error": "Hiba",
"file": "Fájl",
"githubLabel": "Github",
"hotkeysLabel": "Gyorsbillentyűk",
"delete": "Törlés",
"data": "Adat",
"discordLabel": "Discord",
"folder": "Mappa"
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,326 @@
{
"common": {
"languagePickerLabel": "언어 설정",
"reportBugLabel": "버그 리포트",
"githubLabel": "Github",
"settingsLabel": "설정",
"nodes": "Workflow Editor",
"upload": "업로드",
"load": "불러오기",
"back": "뒤로 가기",
"statusDisconnected": "연결 끊김",
"hotkeysLabel": "단축키 설정",
"img2img": "이미지->이미지",
"discordLabel": "Discord",
"t2iAdapter": "T2I 어댑터",
"communityLabel": "커뮤니티",
"txt2img": "텍스트->이미지",
"dontAskMeAgain": "다시 묻지 마세요",
"checkpoint": "체크포인트",
"format": "형식",
"unknown": "알려지지 않음",
"areYouSure": "확실하나요?",
"folder": "폴더",
"inpaint": "inpaint",
"updated": "업데이트 됨",
"on": "켜기",
"save": "저장",
"created": "생성됨",
"error": "에러",
"ipAdapter": "IP 어댑터",
"installed": "설치됨",
"accept": "수락",
"ai": "인공지능",
"auto": "자동",
"file": "파일",
"openInNewTab": "새 탭에서 열기",
"delete": "삭제",
"template": "템플릿",
"cancel": "취소",
"controlNet": "컨트롤넷",
"outputs": "결과물",
"unknownError": "알려지지 않은 에러",
"linear": "선형",
"direction": "방향",
"data": "데이터",
"somethingWentWrong": "뭔가 잘못됐어요",
"modelManager": "Model Manager",
"safetensors": "Safetensors",
"outpaint": "outpaint",
"orderBy": "정렬 기준",
"copyError": "$t(gallery.copy) 에러",
"learnMore": "더 알아보기",
"saveAs": "다른 이름으로 저장",
"loading": "불러오는 중",
"random": "랜덤",
"batch": "Batch 매니저",
"postprocessing": "후처리",
"advanced": "고급",
"input": "입력",
"details": "세부사항"
},
"gallery": {
"galleryImageSize": "이미지 크기",
"gallerySettings": "갤러리 설정",
"deleteSelection": "선택 항목 삭제",
"featuresWillReset": "이 이미지를 삭제하면 해당 기능이 즉시 재설정됩니다.",
"autoSwitchNewImages": "새로운 이미지로 자동 전환",
"loading": "불러오는 중",
"image": "이미지",
"drop": "드랍",
"downloadSelection": "선택 항목 다운로드",
"deleteImage_other": "이미지 삭제",
"currentlyInUse": "이 이미지는 현재 다음 기능에서 사용되고 있습니다:",
"dropOrUpload": "$t(gallery.drop) 또는 업로드",
"copy": "복사",
"download": "다운로드",
"deleteImagePermanent": "삭제된 이미지는 복원할 수 없습니다.",
"noImageSelected": "선택된 이미지 없음",
"autoAssignBoardOnClick": "클릭 시 Board로 자동 할당",
"dropToUpload": "업로드를 위해 $t(gallery.drop)"
},
"accessibility": {
"previousImage": "이전 이미지",
"nextImage": "다음 이미지",
"mode": "모드",
"menu": "메뉴",
"uploadImage": "이미지 업로드",
"reset": "리셋"
},
"modelManager": {
"availableModels": "사용 가능한 모델",
"addModel": "모델 추가",
"none": "없음",
"modelConverted": "변환된 모델",
"width": "너비",
"convert": "변환",
"vae": "VAE",
"deleteModel": "모델 삭제",
"description": "Description",
"search": "검색",
"predictionType": "예측 유형(안정 확산 2.x 모델 및 간혹 안정 확산 1.x 모델의 경우)",
"selectModel": "모델 선택",
"repo_id": "Repo ID",
"convertToDiffusersHelpText6": "이 모델을 변환하시겠습니까?",
"config": "구성",
"selected": "선택된",
"advanced": "고급",
"load": "불러오기",
"height": "높이",
"modelDeleted": "삭제된 모델",
"convertToDiffusersHelpText2": "이 프로세스는 모델 관리자 항목을 동일한 모델의 Diffusers 버전으로 대체합니다.",
"modelUpdateFailed": "모델 업데이트 실패",
"modelUpdated": "업데이트된 모델",
"settings": "설정",
"convertToDiffusersHelpText5": "디스크 공간이 충분한지 확인해 주세요. 모델은 일반적으로 2GB에서 7GB 사이로 다양합니다.",
"deleteConfig": "구성 삭제",
"modelConversionFailed": "모델 변환 실패",
"deleteMsg1": "InvokeAI에서 이 모델을 삭제하시겠습니까?",
"syncModels": "동기화 모델",
"modelType": "모델 유형",
"convertingModelBegin": "모델 변환 중입니다. 잠시만 기다려 주십시오.",
"name": "이름",
"convertToDiffusersHelpText1": "이 모델은 🧨 Diffusers 형식으로 변환됩니다.",
"vaePrecision": "VAE 정밀도",
"deleteMsg2": "모델이 InvokeAI root 폴더에 있으면 디스크에서 모델이 삭제됩니다. 사용자 지정 위치를 사용하는 경우 모델이 디스크에서 삭제되지 않습니다.",
"baseModel": "기본 모델",
"manual": "매뉴얼",
"convertToDiffusersHelpText3": "디스크의 체크포인트 파일이 InvokeAI root 폴더에 있으면 삭제됩니다. 사용자 지정 위치에 있으면 삭제되지 않습니다.",
"modelManager": "모델 매니저",
"variant": "Variant",
"modelDeleteFailed": "모델을 삭제하지 못했습니다",
"convertToDiffusers": "Diffusers로 변환",
"allModels": "모든 모델",
"alpha": "Alpha",
"noModelSelected": "선택한 모델 없음",
"convertToDiffusersHelpText4": "이것은 한 번의 과정일 뿐입니다. 컴퓨터 사양에 따라 30-60초 정도 소요될 수 있습니다.",
"model": "모델",
"delete": "삭제"
},
"nodes": {
"missingTemplate": "잘못된 노드: {{type}} 유형의 {{node}} 템플릿 누락(설치되지 않으셨나요?)",
"noNodeSelected": "선택한 노드 없음",
"addNode": "노드 추가",
"enum": "Enum",
"loadWorkflow": "Workflow 불러오기",
"noOutputRecorded": "기록된 출력 없음",
"colorCodeEdgesHelp": "연결된 필드에 따른 색상 코드 선",
"float": "실수",
"targetNodeFieldDoesNotExist": "잘못된 모서리: 대상/입력 필드 {{node}}. {{field}}이(가) 없습니다",
"animatedEdges": "애니메이션 모서리",
"integer": "정수",
"nodeTemplate": "노드 템플릿",
"nodeOpacity": "노드 불투명도",
"sourceNodeDoesNotExist": "잘못된 모서리: 소스/출력 노드 {{node}}이(가) 없습니다",
"nodeSearch": "노드 검색",
"inputMayOnlyHaveOneConnection": "입력에 하나의 연결만 있을 수 있습니다",
"notes": "메모",
"nodeOutputs": "노드 결과물",
"currentImageDescription": "Node Editor에 현재 이미지를 표시합니다",
"downloadWorkflow": "Workflow JSON 다운로드",
"ipAdapter": "IP-Adapter",
"noConnectionInProgress": "진행중인 연결이 없습니다",
"fieldTypesMustMatch": "필드 유형은 일치해야 합니다",
"edge": "Edge",
"sourceNodeFieldDoesNotExist": "잘못된 모서리: 소스/출력 필드 {{node}}. {{field}}이(가) 없습니다",
"animatedEdgesHelp": "선택한 노드에 연결된 선택한 가장자리 및 가장자리를 애니메이션화합니다",
"cannotDuplicateConnection": "중복 연결을 만들 수 없습니다",
"noWorkflow": "Workflow 없음",
"fullyContainNodesHelp": "선택하려면 노드가 선택 상자 안에 완전히 있어야 합니다",
"nodePack": "Node pack",
"nodeType": "노드 유형",
"fullyContainNodes": "선택할 노드 전체 포함",
"executionStateInProgress": "진행중",
"executionStateError": "에러",
"boolean": "Booleans",
"hideMinimapnodes": "미니맵 숨기기",
"executionStateCompleted": "완료된",
"node": "노드",
"currentImage": "현재 이미지",
"collection": "컬렉션",
"cannotConnectInputToInput": "입력을 입력에 연결할 수 없습니다",
"collectionFieldType": "{{name}} 컬렉션",
"cannotConnectOutputToOutput": "출력을 출력에 연결할 수 없습니다",
"connectionWouldCreateCycle": "연결하면 주기가 생성됩니다",
"cannotConnectToSelf": "자체에 연결할 수 없습니다",
"notesDescription": "Workflow에 대한 메모 추가",
"colorCodeEdges": "색상-코드 선",
"targetNodeDoesNotExist": "잘못된 모서리: 대상/입력 노드 {{node}}이(가) 없습니다",
"addNodeToolTip": "노드 추가(Shift+A, Space)",
"collectionOrScalarFieldType": "{{name}} 컬렉션|Scalar",
"nodeVersion": "노드 버전",
"loadingNodes": "노드 로딩중...",
"deletedInvalidEdge": "잘못된 모서리 {{source}} -> {{target}} 삭제"
},
"queue": {
"status": "상태",
"pruneSucceeded": "Queue로부터 {{item_count}} 완성된 항목 잘라내기",
"cancelTooltip": "현재 항목 취소",
"queueEmpty": "비어있는 Queue",
"pauseSucceeded": "중지된 프로세서",
"in_progress": "진행 중",
"queueFront": "Front of Queue에 추가",
"notReady": "Queue를 생성할 수 없음",
"batchFailedToQueue": "Queue Batch에 실패",
"completed": "완성된",
"queueBack": "Queue에 추가",
"cancelFailed": "항목 취소 중 발생한 문제",
"batchQueued": "Batch Queued",
"pauseFailed": "프로세서 중지 중 발생한 문제",
"clearFailed": "Queue 제거 중 발생한 문제",
"front": "front",
"clearSucceeded": "제거된 Queue",
"pause": "중지",
"pruneTooltip": "{{item_count}} 완성된 항목 잘라내기",
"cancelSucceeded": "취소된 항목",
"batchQueuedDesc_other": "queue의 {{direction}}에 추가된 {{count}}세션",
"queue": "Queue",
"batch": "Batch",
"clearQueueAlertDialog": "Queue를 지우면 처리 항목이 즉시 취소되고 Queue가 완전히 지워집니다.",
"resumeFailed": "프로세서 재개 중 발생한 문제",
"clear": "제거하다",
"prune": "잘라내다",
"total": "총 개수",
"canceled": "취소된",
"pruneFailed": "Queue 잘라내는 중 발생한 문제",
"cancelBatchSucceeded": "취소된 Batch",
"clearTooltip": "모든 항목을 취소하고 제거",
"current": "최근",
"pauseTooltip": "프로세서 중지",
"failed": "실패한",
"cancelItem": "항목 취소",
"next": "다음",
"cancelBatch": "Batch 취소",
"back": "back",
"cancel": "취소",
"session": "세션",
"time": "시간",
"resumeSucceeded": "재개된 프로세서",
"enqueueing": "Queueing Batch",
"resumeTooltip": "프로세서 재개",
"resume": "재개",
"cancelBatchFailed": "Batch 취소 중 발생한 문제",
"clearQueueAlertDialog2": "Queue를 지우시겠습니까?",
"item": "항목",
"graphFailedToQueue": "queue graph에 실패"
},
"metadata": {
"positivePrompt": "긍정적 프롬프트",
"negativePrompt": "부정적인 프롬프트",
"generationMode": "Generation Mode",
"Threshold": "Noise Threshold",
"metadata": "Metadata",
"seed": "시드",
"imageDetails": "이미지 세부 정보",
"model": "모델",
"noImageDetails": "이미지 세부 정보를 찾을 수 없습니다",
"cfgScale": "CFG scale",
"recallParameters": "매개변수 호출",
"height": "Height",
"noMetaData": "metadata를 찾을 수 없습니다",
"cfgRescaleMultiplier": "$t(parameters.cfgRescaleMultiplier)",
"width": "너비",
"vae": "VAE",
"createdBy": "~에 의해 생성된",
"workflow": "작업의 흐름",
"steps": "단계",
"scheduler": "스케줄러",
"noRecallParameters": "호출할 매개 변수가 없습니다"
},
"invocationCache": {
"useCache": "캐시 사용",
"disable": "이용 불가능한",
"misses": "캐시 미스",
"enableFailed": "Invocation 캐시를 사용하도록 설정하는 중 발생한 문제",
"invocationCache": "Invocation 캐시",
"clearSucceeded": "제거된 Invocation 캐시",
"enableSucceeded": "이용 가능한 Invocation 캐시",
"clearFailed": "Invocation 캐시 제거 중 발생한 문제",
"hits": "캐시 적중",
"disableSucceeded": "이용 불가능한 Invocation 캐시",
"disableFailed": "Invocation 캐시를 이용하지 못하게 설정 중 발생한 문제",
"enable": "이용 가능한",
"clear": "제거",
"maxCacheSize": "최대 캐시 크기",
"cacheSize": "캐시 크기"
},
"hrf": {
"metadata": {
"strength": "고해상도 고정 강도",
"enabled": "고해상도 고정 사용",
"method": "고해상도 고정 방법"
},
"hrf": "고해상도 고정"
},
"models": {
"noMatchingModels": "일치하는 모델 없음",
"loading": "로딩중",
"noModelsAvailable": "사용 가능한 모델이 없음",
"addLora": "LoRA 추가",
"selectModel": "모델 선택",
"noRefinerModelsInstalled": "SDXL Refiner 모델이 설치되지 않음"
},
"boards": {
"autoAddBoard": "자동 추가 Board",
"topMessage": "이 보드에는 다음 기능에 사용되는 이미지가 포함되어 있습니다:",
"move": "이동",
"menuItemAutoAdd": "해당 Board에 자동 추가",
"myBoard": "나의 Board",
"searchBoard": "Board 찾는 중...",
"deleteBoardOnly": "Board만 삭제",
"noMatching": "일치하는 Board들이 없음",
"movingImagesToBoard_other": "{{count}}이미지를 Board로 이동시키기",
"selectBoard": "Board 선택",
"cancel": "취소",
"addBoard": "Board 추가",
"bottomMessage": "이 보드와 이미지를 삭제하면 현재 사용 중인 모든 기능이 재설정됩니다.",
"uncategorized": "미분류",
"downloadBoard": "Board 다운로드",
"changeBoard": "Board 바꾸기",
"loading": "불러오는 중...",
"clearSearch": "검색 지우기",
"deleteBoard": "Board 삭제",
"deleteBoardAndImages": "Board와 이미지 삭제",
"deletedBoardsCannotbeRestored": "삭제된 Board는 복원할 수 없습니다"
}
}
@@ -0,0 +1 @@
{}
@@ -0,0 +1,806 @@
{
"common": {
"hotkeysLabel": "Sneltoetsen",
"languagePickerLabel": "Taal",
"reportBugLabel": "Meld bug",
"settingsLabel": "Instellingen",
"img2img": "Afbeelding naar afbeelding",
"nodes": "Werkstromen",
"upload": "Upload",
"load": "Laad",
"statusDisconnected": "Niet verbonden",
"githubLabel": "Github",
"discordLabel": "Discord",
"back": "Terug",
"cancel": "Annuleer",
"accept": "Akkoord",
"loading": "Bezig met laden",
"txt2img": "Tekst naar afbeelding",
"postprocessing": "Naverwerking",
"dontAskMeAgain": "Vraag niet opnieuw",
"random": "Willekeurig",
"openInNewTab": "Open in nieuw tabblad",
"areYouSure": "Weet je het zeker?",
"linear": "Lineair",
"batch": "Seriebeheer",
"modelManager": "Modelbeheer",
"communityLabel": "Gemeenschap",
"t2iAdapter": "T2I-adapter",
"on": "Aan",
"ipAdapter": "IP-adapter",
"auto": "Autom.",
"controlNet": "ControlNet",
"learnMore": "Meer informatie",
"advanced": "Uitgebreid",
"file": "Bestand",
"installed": "Geïnstalleerd",
"simple": "Eenvoudig",
"somethingWentWrong": "Er ging iets mis",
"add": "Voeg toe",
"checkpoint": "Checkpoint",
"details": "Details",
"outputs": "Uitvoeren",
"save": "Bewaar",
"blue": "Blauw",
"alpha": "Alfa",
"red": "Rood",
"editor": "Editor",
"folder": "Map",
"format": "structuur",
"template": "Sjabloon",
"input": "Invoer",
"safetensors": "Safetensors",
"saveAs": "Bewaar als",
"created": "Gemaakt",
"green": "Groen",
"tab": "Tab",
"positivePrompt": "Positieve prompt",
"negativePrompt": "Negatieve prompt",
"selected": "Geselecteerd",
"orderBy": "Sorteer op",
"beta": "Bèta",
"copyError": "$t(gallery.copy) Fout",
"toResolve": "Op te lossen",
"aboutDesc": "Gebruik je Invoke voor het werk? Kijk dan naar:",
"aboutHeading": "Creatieve macht voor jou",
"copy": "Kopieer",
"data": "Gegevens",
"or": "of",
"updated": "Bijgewerkt",
"outpaint": "outpainten",
"ai": "ai",
"inpaint": "inpainten",
"unknown": "Onbekend",
"delete": "Verwijder",
"direction": "Richting",
"error": "Fout",
"unknownError": "Onbekende fout"
},
"gallery": {
"galleryImageSize": "Afbeeldingsgrootte",
"gallerySettings": "Instellingen galerij",
"autoSwitchNewImages": "Wissel autom. naar nieuwe afbeeldingen",
"deleteImage_one": "Verwijder afbeelding",
"deleteImage_other": "",
"deleteImagePermanent": "Verwijderde afbeeldingen kunnen niet worden hersteld.",
"autoAssignBoardOnClick": "Ken automatisch bord toe bij klikken",
"featuresWillReset": "Als je deze afbeelding verwijdert, dan worden deze functies onmiddellijk teruggezet.",
"loading": "Bezig met laden",
"downloadSelection": "Download selectie",
"currentlyInUse": "Deze afbeelding is momenteel in gebruik door de volgende functies:",
"copy": "Kopieer",
"download": "Download"
},
"modelManager": {
"modelManager": "Modelonderhoud",
"model": "Model",
"modelUpdated": "Model bijgewerkt",
"manual": "Handmatig",
"name": "Naam",
"description": "Beschrijving",
"config": "Configuratie",
"width": "Breedte",
"height": "Hoogte",
"addModel": "Voeg model toe",
"availableModels": "Beschikbare modellen",
"search": "Zoek",
"load": "Laad",
"active": "actief",
"selected": "Gekozen",
"delete": "Verwijder",
"deleteModel": "Verwijder model",
"deleteConfig": "Verwijder configuratie",
"deleteMsg1": "Weet je zeker dat je dit model wilt verwijderen uit InvokeAI?",
"deleteMsg2": "Hiermee ZAL het model van schijf worden verwijderd als het zich bevindt in de beginmap van InvokeAI. Als je het model vanaf een eigen locatie gebruikt, dan ZAL het model NIET van schijf worden verwijderd.",
"convertToDiffusersHelpText3": "Je checkpoint-bestand op de schijf ZAL worden verwijderd als het zich in de beginmap van InvokeAI bevindt. Het ZAL NIET worden verwijderd als het zich in een andere locatie bevindt.",
"convertToDiffusersHelpText6": "Wil je dit model omzetten?",
"allModels": "Alle modellen",
"repo_id": "Repo-id",
"convert": "Omzetten",
"convertToDiffusers": "Omzetten naar Diffusers",
"convertToDiffusersHelpText1": "Dit model wordt omgezet naar de🧨 Diffusers-indeling.",
"convertToDiffusersHelpText2": "Dit proces vervangt het onderdeel in Modelonderhoud met de Diffusers-versie van hetzelfde model.",
"convertToDiffusersHelpText4": "Dit is een eenmalig proces. Dit neemt ongeveer 30 tot 60 sec. in beslag, afhankelijk van de specificaties van je computer.",
"convertToDiffusersHelpText5": "Zorg ervoor dat je genoeg schijfruimte hebt. Modellen nemen gewoonlijk ongeveer 2 tot 7 GB ruimte in beslag.",
"modelConverted": "Model omgezet",
"alpha": "Alfa",
"none": "geen",
"baseModel": "Basismodel",
"vae": "VAE",
"variant": "Variant",
"modelConversionFailed": "Omzetten model mislukt",
"modelUpdateFailed": "Bijwerken model mislukt",
"selectModel": "Kies model",
"settings": "Instellingen",
"modelDeleted": "Model verwijderd",
"syncModels": "Synchroniseer Modellen",
"modelDeleteFailed": "Model kon niet verwijderd worden",
"convertingModelBegin": "Model aan het converteren. Even geduld.",
"predictionType": "Soort voorspelling",
"advanced": "Uitgebreid",
"modelType": "Soort model",
"vaePrecision": "Nauwkeurigheid VAE",
"loraTriggerPhrases": "LoRA-triggerzinnen",
"urlOrLocalPathHelper": "URL's zouden moeten wijzen naar een los bestand. Lokale paden kunnen wijzen naar een los bestand of map voor een individueel Diffusers-model.",
"modelName": "Modelnaam",
"path": "Pad",
"triggerPhrases": "Triggerzinnen",
"typePhraseHere": "Typ zin hier in",
"modelImageDeleteFailed": "Fout bij verwijderen modelafbeelding",
"modelImageUpdated": "Modelafbeelding bijgewerkt",
"modelImageUpdateFailed": "Fout bij bijwerken modelafbeelding",
"noMatchingModels": "Geen overeenkomende modellen",
"scanPlaceholder": "Pad naar een lokale map",
"noModelsInstalled": "Geen modellen geïnstalleerd",
"noModelsInstalledDesc1": "Installeer modellen met de",
"noModelSelected": "Geen model geselecteerd",
"starterModels": "Beginnermodellen",
"textualInversions": "Tekstuele omkeringen",
"upcastAttention": "Upcast-aandacht",
"uploadImage": "Upload afbeelding",
"mainModelTriggerPhrases": "Triggerzinnen hoofdmodel",
"urlOrLocalPath": "URL of lokaal pad",
"scanFolderHelper": "De map zal recursief worden ingelezen voor modellen. Dit kan enige tijd in beslag nemen voor erg grote mappen.",
"simpleModelPlaceholder": "URL of pad naar een lokaal pad of Diffusers-map",
"modelSettings": "Modelinstellingen",
"pathToConfig": "Pad naar configuratie",
"prune": "Snoei",
"pruneTooltip": "Snoei voltooide importeringen uit wachtrij",
"repoVariant": "Repovariant",
"scanFolder": "Lees map in",
"scanResults": "Resultaten inlezen",
"source": "Bron"
},
"parameters": {
"images": "Afbeeldingen",
"steps": "Stappen",
"cfgScale": "CFG-schaal",
"width": "Breedte",
"height": "Hoogte",
"seed": "Seed",
"shuffle": "Mengseed",
"noiseThreshold": "Drempelwaarde ruis",
"perlinNoise": "Perlinruis",
"type": "Soort",
"strength": "Sterkte",
"upscaling": "Opschalen",
"scale": "Schaal",
"imageFit": "Pas initiële afbeelding in uitvoergrootte",
"scaleBeforeProcessing": "Schalen voor verwerking",
"scaledWidth": "Geschaalde B",
"scaledHeight": "Geschaalde H",
"infillMethod": "Infill-methode",
"tileSize": "Grootte tegel",
"usePrompt": "Hergebruik invoertekst",
"useSeed": "Hergebruik seed",
"useAll": "Hergebruik alles",
"info": "Info",
"symmetry": "Symmetrie",
"cancel": {
"cancel": "Annuleer"
},
"general": "Algemeen",
"copyImage": "Kopieer afbeelding",
"denoisingStrength": "Sterkte ontruisen",
"scheduler": "Planner",
"seamlessXAxis": "Naadloze tegels in x-as",
"seamlessYAxis": "Naadloze tegels in y-as",
"clipSkip": "Overslaan CLIP",
"negativePromptPlaceholder": "Negatieve prompt",
"controlNetControlMode": "Aansturingsmodus",
"positivePromptPlaceholder": "Positieve prompt",
"maskBlur": "Vervaging van masker",
"invoke": {
"noNodesInGraph": "Geen knooppunten in graaf",
"noModelSelected": "Geen model ingesteld",
"invoke": "Start",
"noPrompts": "Geen prompts gegenereerd",
"missingInputForField": "{{nodeLabel}} -> {{fieldLabel}} invoer ontbreekt",
"systemDisconnected": "Systeem is niet verbonden",
"missingNodeTemplate": "Knooppuntsjabloon ontbreekt",
"missingFieldTemplate": "Veldsjabloon ontbreekt",
"addingImagesTo": "Bezig met toevoegen van afbeeldingen aan"
},
"patchmatchDownScaleSize": "Verklein",
"useCpuNoise": "Gebruik CPU-ruis",
"imageActions": "Afbeeldingshandeling",
"iterations": "Iteraties",
"coherenceMode": "Modus",
"infillColorValue": "Vulkleur",
"remixImage": "Meng afbeelding opnieuw",
"setToOptimalSize": "Optimaliseer grootte voor het model",
"setToOptimalSizeTooSmall": "$t(parameters.setToOptimalSize) (is mogelijk te klein)",
"aspect": "Beeldverhouding",
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (is mogelijk te groot)",
"lockAspectRatio": "Zet beeldverhouding vast",
"useSize": "Gebruik grootte",
"swapDimensions": "Wissel afmetingen om",
"coherenceEdgeSize": "Randgrootte",
"coherenceMinDenoise": "Min. ontruising",
"cfgRescaleMultiplier": "Vermenigvuldiger voor CFG-herschaling"
},
"settings": {
"models": "Modellen",
"displayInProgress": "Toon voortgangsafbeeldingen",
"confirmOnDelete": "Bevestig bij verwijderen",
"resetWebUI": "Herstel web-UI",
"resetWebUIDesc1": "Herstel web-UI herstelt alleen de lokale afbeeldingscache en de onthouden instellingen van je browser. Het verwijdert geen afbeeldingen van schijf.",
"resetWebUIDesc2": "Als afbeeldingen niet getoond worden in de galerij of iets anders werkt niet, probeer dan eerst deze herstelfunctie voordat je een fout aanmeldt op GitHub.",
"resetComplete": "Webinterface is hersteld.",
"developer": "Ontwikkelaar",
"general": "Algemeen",
"showProgressInViewer": "Toon voortgangsafbeeldingen in viewer",
"generation": "Genereren",
"ui": "Gebruikersinterface",
"antialiasProgressImages": "Voer anti-aliasing uit op voortgangsafbeeldingen",
"beta": "Bèta",
"clearIntermediates": "Wis tussentijdse afbeeldingen",
"clearIntermediatesDesc3": "Je galerijafbeeldingen zullen niet worden verwijderd.",
"clearIntermediatesWithCount_one": "Wis {{count}} tussentijdse afbeelding",
"clearIntermediatesWithCount_other": "Wis {{count}} tussentijdse afbeeldingen",
"clearIntermediatesDesc2": "Tussentijdse afbeeldingen zijn nevenproducten bij het genereren. Deze wijken af van de uitvoerafbeeldingen in de galerij. Als je tussentijdse afbeeldingen wist, wordt schijfruimte vrijgemaakt.",
"intermediatesCleared_one": "{{count}} tussentijdse afbeelding gewist",
"intermediatesCleared_other": "{{count}} tussentijdse afbeeldingen gewist",
"clearIntermediatesDesc1": "Als je tussentijdse afbeeldingen wist, dan wordt de staat hersteld van je canvas en van ControlNet.",
"intermediatesClearedFailed": "Fout bij wissen van tussentijdse afbeeldingen",
"clearIntermediatesDisabled": "Wachtrij moet leeg zijn om tussentijdse afbeeldingen te kunnen leegmaken",
"enableInformationalPopovers": "Schakel informatieve hulpballonnen in",
"enableInvisibleWatermark": "Schakel onzichtbaar watermerk in",
"enableNSFWChecker": "Schakel NSFW-controle in",
"reloadingIn": "Opnieuw laden na"
},
"toast": {
"uploadFailed": "Upload mislukt",
"imageCopied": "Afbeelding gekopieerd",
"parametersNotSet": "Parameters niet ingesteld",
"serverError": "Serverfout",
"connected": "Verbonden met server",
"canceled": "Verwerking geannuleerd",
"uploadFailedInvalidUploadDesc": "Moet een enkele PNG- of JPEG-afbeelding zijn",
"parameterNotSet": "{{parameter}} niet ingesteld",
"parameterSet": "{{parameter}} ingesteld",
"problemCopyingImage": "Kan Afbeelding Niet Kopiëren",
"baseModelChangedCleared_one": "Basismodel is gewijzigd: {{count}} niet-compatibel submodel weggehaald of uitgeschakeld",
"baseModelChangedCleared_other": "Basismodel is gewijzigd: {{count}} niet-compatibele submodellen weggehaald of uitgeschakeld",
"loadedWithWarnings": "Werkstroom geladen met waarschuwingen",
"imageUploaded": "Afbeelding geüpload",
"addedToBoard": "Toegevoegd aan bord",
"workflowLoaded": "Werkstroom geladen",
"modelAddedSimple": "Model toegevoegd aan wachtrij",
"imageUploadFailed": "Fout bij uploaden afbeelding",
"workflowDeleted": "Werkstroom verwijderd",
"problemRetrievingWorkflow": "Fout bij ophalen van werkstroom",
"parameters": "Parameters",
"modelImportCanceled": "Importeren model geannuleerd",
"problemDeletingWorkflow": "Fout bij verwijderen van werkstroom",
"prunedQueue": "Wachtrij gesnoeid",
"problemDownloadingImage": "Fout bij downloaden afbeelding"
},
"accessibility": {
"invokeProgressBar": "Voortgangsbalk Invoke",
"reset": "Herstel",
"uploadImage": "Upload afbeelding",
"previousImage": "Vorige afbeelding",
"nextImage": "Volgende afbeelding",
"menu": "Menu",
"about": "Over",
"mode": "Modus",
"resetUI": "$t(accessibility.reset) UI",
"createIssue": "Maak probleem aan"
},
"nodes": {
"zoomOutNodes": "Uitzoomen",
"fitViewportNodes": "Aanpassen aan beeld",
"hideMinimapnodes": "Minimap verbergen",
"zoomInNodes": "Inzoomen",
"showMinimapnodes": "Minimap tonen",
"reloadNodeTemplates": "Herlaad knooppuntsjablonen",
"loadWorkflow": "Laad werkstroom",
"downloadWorkflow": "Download JSON van werkstroom",
"scheduler": "Planner",
"missingTemplate": "Ongeldig knooppunt: knooppunt {{node}} van het soort {{type}} heeft een ontbrekend sjabloon (niet geïnstalleerd?)",
"workflowDescription": "Korte beschrijving",
"noNodeSelected": "Geen knooppunt gekozen",
"addNode": "Voeg knooppunt toe",
"unableToValidateWorkflow": "Kan werkstroom niet valideren",
"enum": "Enumeratie",
"noOutputRecorded": "Geen uitvoer opgenomen",
"updateApp": "Werk app bij",
"colorCodeEdgesHelp": "Kleurgecodeerde randen op basis van hun verbonden velden",
"float": "Zwevende-kommagetal",
"workflowContact": "Contactpersoon",
"animatedEdges": "Geanimeerde randen",
"integer": "Geheel getal",
"nodeTemplate": "Sjabloon knooppunt",
"nodeOpacity": "Dekking knooppunt",
"snapToGrid": "Lijn uit op raster",
"nodeSearch": "Zoek naar knooppunten",
"updateNode": "Werk knooppunt bij",
"version": "Versie",
"validateConnections": "Valideer verbindingen en graaf",
"inputMayOnlyHaveOneConnection": "Invoer mag slechts een enkele verbinding hebben",
"notes": "Opmerkingen",
"nodeOutputs": "Uitvoer knooppunt",
"currentImageDescription": "Toont de huidige afbeelding in de knooppunteditor",
"validateConnectionsHelp": "Voorkom dat er ongeldige verbindingen worden gelegd en dat er ongeldige grafen worden aangeroepen",
"problemSettingTitle": "Fout bij instellen titel",
"ipAdapter": "IP-adapter",
"noConnectionInProgress": "Geen verbinding bezig te maken",
"workflowVersion": "Versie",
"fieldTypesMustMatch": "Veldsoorten moeten overeenkomen",
"workflow": "Werkstroom",
"edge": "Rand",
"animatedEdgesHelp": "Animeer gekozen randen en randen verbonden met de gekozen knooppunten",
"cannotDuplicateConnection": "Kan geen dubbele verbindingen maken",
"noWorkflow": "Geen werkstroom",
"workflowTags": "Labels",
"fullyContainNodesHelp": "Knooppunten moeten zich volledig binnen het keuzevak bevinden om te worden gekozen",
"workflowValidation": "Validatiefout werkstroom",
"nodeType": "Soort knooppunt",
"fullyContainNodes": "Omvat knooppunten volledig om ze te kiezen",
"executionStateInProgress": "Bezig",
"executionStateError": "Fout",
"boolean": "Booleaanse waarden",
"executionStateCompleted": "Voltooid",
"node": "Knooppunt",
"workflowAuthor": "Auteur",
"currentImage": "Huidige afbeelding",
"workflowName": "Naam",
"collection": "Verzameling",
"cannotConnectInputToInput": "Kan invoer niet aan invoer verbinden",
"workflowNotes": "Opmerkingen",
"string": "Tekenreeks",
"cannotConnectOutputToOutput": "Kan uitvoer niet aan uitvoer verbinden",
"connectionWouldCreateCycle": "Verbinding zou cyclisch worden",
"cannotConnectToSelf": "Kan niet aan zichzelf verbinden",
"notesDescription": "Voeg opmerkingen toe aan je werkstroom",
"unknownField": "Onbekend veld",
"colorCodeEdges": "Kleurgecodeerde randen",
"unknownNode": "Onbekend knooppunt",
"addNodeToolTip": "Voeg knooppunt toe (Shift+A, spatie)",
"loadingNodes": "Bezig met laden van knooppunten...",
"snapToGridHelp": "Lijn knooppunten uit op raster bij verplaatsing",
"workflowSettings": "Instellingen werkstroomeditor",
"nodePack": "Knooppuntpakket",
"sourceNodeFieldDoesNotExist": "Ongeldige rand: bron-/uitvoerveld {{node}}.{{field}} bestaat niet",
"collectionFieldType": "Verzameling {{name}}",
"deletedInvalidEdge": "Ongeldige hoek {{source}} -> {{target}} verwijderd",
"graph": "Grafiek",
"targetNodeDoesNotExist": "Ongeldige rand: doel-/invoerknooppunt {{node}} bestaat niet",
"resetToDefaultValue": "Herstel naar standaardwaarden",
"editMode": "Bewerk in Werkstroom-editor",
"showEdgeLabels": "Toon randlabels",
"showEdgeLabelsHelp": "Toon labels aan randen, waarmee de verbonden knooppunten mee worden aangegeven",
"clearWorkflowDesc2": "Je huidige werkstroom heeft niet-bewaarde wijzigingen.",
"unableToParseFieldType": "fout bij bepalen soort veld",
"sourceNodeDoesNotExist": "Ongeldige rand: bron-/uitvoerknooppunt {{node}} bestaat niet",
"unsupportedArrayItemType": "niet-ondersteunde soort van het array-onderdeel \"{{type}}\"",
"targetNodeFieldDoesNotExist": "Ongeldige rand: doel-/invoerveld {{node}}.{{field}} bestaat niet",
"newWorkflowDesc": "Een nieuwe werkstroom aanmaken?",
"collectionOrScalarFieldType": "Verzameling|scalair {{name}}",
"newWorkflow": "Nieuwe werkstroom",
"unknownErrorValidatingWorkflow": "Onbekende fout bij valideren werkstroom",
"unsupportedAnyOfLength": "te veel union-leden ({{count}})",
"viewMode": "Gebruik in lineaire weergave",
"unableToExtractSchemaNameFromRef": "fout bij het extraheren van de schemanaam via de ref",
"unsupportedMismatchedUnion": "niet-overeenkomende soort CollectionOrScalar met basissoorten {{firstType}} en {{secondType}}",
"unknownNodeType": "Onbekend soort knooppunt",
"edit": "Bewerk",
"updateAllNodes": "Werk knooppunten bij",
"allNodesUpdated": "Alle knooppunten bijgewerkt",
"nodeVersion": "Knooppuntversie",
"newWorkflowDesc2": "Je huidige werkstroom heeft niet-bewaarde wijzigingen.",
"clearWorkflow": "Maak werkstroom leeg",
"clearWorkflowDesc": "Deze werkstroom leegmaken en met een nieuwe beginnen?",
"inputFieldTypeParseError": "Fout bij bepalen van het soort invoerveld {{node}}.{{field}} ({{message}})",
"outputFieldTypeParseError": "Fout bij het bepalen van het soort uitvoerveld {{node}}.{{field}} ({{message}})",
"unableToExtractEnumOptions": "fout bij extraheren enumeratie-opties",
"unknownFieldType": "Soort $t(nodes.unknownField): {{type}}",
"unableToGetWorkflowVersion": "Fout bij ophalen schemaversie van werkstroom",
"betaDesc": "Deze uitvoering is in bèta. Totdat deze stabiel is kunnen er wijzigingen voorkomen gedurende app-updates die zaken kapotmaken. We zijn van plan om deze uitvoering op lange termijn te gaan ondersteunen.",
"prototypeDesc": "Deze uitvoering is een prototype. Er kunnen wijzigingen voorkomen gedurende app-updates die zaken kapotmaken. Deze kunnen op een willekeurig moment verwijderd worden.",
"noFieldsViewMode": "Deze werkstroom heeft geen geselecteerde velden om te tonen. Bekijk de volledige werkstroom om de waarden te configureren.",
"unableToUpdateNodes_one": "Fout bij bijwerken van {{count}} knooppunt",
"unableToUpdateNodes_other": "Fout bij bijwerken van {{count}} knooppunten"
},
"dynamicPrompts": {
"seedBehaviour": {
"perPromptDesc": "Gebruik een verschillende seedwaarde per afbeelding",
"perIterationLabel": "Seedwaarde per iteratie",
"perIterationDesc": "Gebruik een verschillende seedwaarde per iteratie",
"perPromptLabel": "Seedwaarde per afbeelding",
"label": "Gedrag seedwaarde"
},
"maxPrompts": "Max. prompts",
"dynamicPrompts": "Dynamische prompts",
"showDynamicPrompts": "Toon dynamische prompts",
"loading": "Genereren van dynamische prompts...",
"promptsPreview": "Voorvertoning prompts"
},
"popovers": {
"noiseUseCPU": {
"paragraphs": [
"Bepaalt of ruis wordt gegenereerd op de CPU of de GPU.",
"Met CPU-ruis ingeschakeld zal een bepaalde seedwaarde dezelfde afbeelding opleveren op welke machine dan ook.",
"Er is geen prestatieverschil bij het inschakelen van CPU-ruis."
],
"heading": "Gebruik CPU-ruis"
},
"paramScheduler": {
"paragraphs": [
"De planner gebruikt gedurende het genereringsproces."
],
"heading": "Planner"
},
"scaleBeforeProcessing": {
"paragraphs": [
"Schaalt het gekozen gebied naar de grootte die het meest geschikt is voor het model, vooraf aan het proces van het afbeeldingen genereren."
],
"heading": "Schaal vooraf aan verwerking"
},
"compositingMaskAdjustments": {
"heading": "Aanpassingen masker",
"paragraphs": [
"Pas het masker aan."
]
},
"paramRatio": {
"heading": "Beeldverhouding",
"paragraphs": [
"De beeldverhouding van de afmetingen van de afbeelding die wordt gegenereerd.",
"Een afbeeldingsgrootte (in aantal pixels) equivalent aan 512x512 wordt aanbevolen voor SD1.5-modellen. Een grootte-equivalent van 1024x1024 wordt aanbevolen voor SDXL-modellen."
]
},
"dynamicPrompts": {
"paragraphs": [
"Dynamische prompts vormt een enkele prompt om in vele.",
"De basissyntax is \"a {red|green|blue} ball\". Dit zal de volgende drie prompts geven: \"a red ball\", \"a green ball\" en \"a blue ball\".",
"Gebruik de syntax zo vaak als je wilt in een enkele prompt, maar zorg ervoor dat het aantal gegenereerde prompts in lijn ligt met de instelling Max. prompts."
],
"heading": "Dynamische prompts"
},
"paramVAE": {
"paragraphs": [
"Het model gebruikt voor het vertalen van AI-uitvoer naar de uiteindelijke afbeelding."
],
"heading": "VAE"
},
"paramIterations": {
"paragraphs": [
"Het aantal te genereren afbeeldingen.",
"Als dynamische prompts is ingeschakeld, dan zal elke prompt dit aantal keer gegenereerd worden."
],
"heading": "Iteraties"
},
"paramVAEPrecision": {
"heading": "Nauwkeurigheid VAE",
"paragraphs": [
"De nauwkeurigheid gebruikt tijdens de VAE-codering en -decodering. FP16/halve nauwkeurig is efficiënter, ten koste van kleine afbeeldingsvariaties."
]
},
"compositingCoherenceMode": {
"heading": "Modus",
"paragraphs": [
"De modus van de coherentiefase."
]
},
"paramSeed": {
"paragraphs": [
"Bepaalt de startruis die gebruikt wordt bij het genereren.",
"Schakel \"Willekeurige seedwaarde\" uit om identieke resultaten te krijgen met dezelfde genereer-instellingen."
],
"heading": "Seedwaarde"
},
"controlNetResizeMode": {
"heading": "Schaalmodus",
"paragraphs": [
"Hoe de ControlNet-afbeelding zal worden geschaald aan de uitvoergrootte van de afbeelding."
]
},
"controlNetBeginEnd": {
"paragraphs": [
"Op welke stappen van het ontruisingsproces ControlNet worden toegepast.",
"ControlNets die worden toegepast aan het begin begeleiden het compositieproces. ControlNets die worden toegepast aan het eind zorgen voor details."
],
"heading": "Percentage begin- / eindstap"
},
"dynamicPromptsSeedBehaviour": {
"paragraphs": [
"Bepaalt hoe de seedwaarde wordt gebruikt bij het genereren van prompts.",
"Per iteratie zal een unieke seedwaarde worden gebruikt voor elke iteratie. Gebruik dit om de promptvariaties binnen een enkele seedwaarde te verkennen.",
"Bijvoorbeeld: als je vijf prompts heb, dan zal voor elke afbeelding dezelfde seedwaarde gebruikt worden.",
"De optie Per afbeelding zal een unieke seedwaarde voor elke afbeelding gebruiken. Dit biedt meer variatie."
],
"heading": "Gedrag seedwaarde"
},
"clipSkip": {
"paragraphs": [
"Aantal over te slaan CLIP-modellagen.",
"Bepaalde modellen zijn beter geschikt met bepaalde Overslaan CLIP-instellingen."
],
"heading": "Overslaan CLIP"
},
"paramModel": {
"heading": "Model",
"paragraphs": [
"Model gebruikt voor de ontruisingsstappen."
]
},
"compositingCoherencePass": {
"heading": "Coherentiefase",
"paragraphs": [
"Een tweede ronde ontruising helpt bij het samenstellen van de erin- of eruitgetekende afbeelding."
]
},
"paramDenoisingStrength": {
"paragraphs": [
"Hoeveel ruis wordt toegevoegd aan de invoerafbeelding.",
"0 levert een identieke afbeelding op, waarbij 1 een volledig nieuwe afbeelding oplevert."
],
"heading": "Ontruisingssterkte"
},
"paramNegativeConditioning": {
"paragraphs": [
"Het genereerproces voorkomt de gegeven begrippen in de negatieve prompt. Gebruik dit om bepaalde zaken of voorwerpen uit te sluiten van de uitvoerafbeelding.",
"Ondersteunt Compel-syntax en -embeddingen."
],
"heading": "Negatieve prompt"
},
"compositingBlurMethod": {
"heading": "Vervagingsmethode",
"paragraphs": [
"De methode van de vervaging die wordt toegepast op het gemaskeerd gebied."
]
},
"dynamicPromptsMaxPrompts": {
"heading": "Max. prompts",
"paragraphs": [
"Beperkt het aantal prompts die kunnen worden gegenereerd door dynamische prompts."
]
},
"infillMethod": {
"paragraphs": [
"Methode om een gekozen gebied in te vullen."
],
"heading": "Invulmethode"
},
"controlNetWeight": {
"heading": "Gewicht",
"paragraphs": [
"Hoe sterk ControlNet effect heeft op de gegeneerde afbeelding."
]
},
"controlNet": {
"heading": "ControlNet",
"paragraphs": [
"ControlNets begeleidt het genereerproces, waarbij geholpen wordt bij het maken van afbeeldingen met aangestuurde compositie, structuur of stijl, afhankelijk van het gekozen model."
]
},
"paramCFGScale": {
"heading": "CFG-schaal",
"paragraphs": [
"Bepaalt hoeveel je prompt invloed heeft op het genereerproces."
]
},
"controlNetControlMode": {
"paragraphs": [
"Geeft meer gewicht aan ofwel de prompt danwel ControlNet."
],
"heading": "Controlemodus"
},
"paramSteps": {
"heading": "Stappen",
"paragraphs": [
"Het aantal uit te voeren stappen tijdens elke generatie.",
"Een hoger aantal stappen geven meestal betere afbeeldingen, ten koste van een hogere benodigde tijd om te genereren."
]
},
"paramPositiveConditioning": {
"heading": "Positieve prompt",
"paragraphs": [
"Begeleidt het generartieproces. Gebruik een woord of frase naar keuze.",
"Syntaxes en embeddings voor Compel en dynamische prompts."
]
},
"lora": {
"heading": "Gewicht LoRA",
"paragraphs": [
"Een hogere LoRA-gewicht zal leiden tot een groter effect op de uiteindelijke afbeelding."
]
}
},
"metadata": {
"positivePrompt": "Positieve prompt",
"negativePrompt": "Negatieve prompt",
"generationMode": "Genereermodus",
"Threshold": "Drempelwaarde ruis",
"metadata": "Metagegevens",
"strength": "Sterkte Afbeelding naar afbeelding",
"seed": "Seedwaarde",
"imageDetails": "Afbeeldingsdetails",
"model": "Model",
"noImageDetails": "Geen afbeeldingsdetails gevonden",
"cfgScale": "CFG-schaal",
"recallParameters": "Opnieuw aan te roepen parameters",
"height": "Hoogte",
"noMetaData": "Geen metagegevens gevonden",
"width": "Breedte",
"createdBy": "Gemaakt door",
"workflow": "Werkstroom",
"steps": "Stappen",
"scheduler": "Planner",
"noRecallParameters": "Geen opnieuw uit te voeren parameters gevonden"
},
"queue": {
"status": "Status",
"pruneSucceeded": "{{item_count}} voltooide onderdelen uit wachtrij opgeruimd",
"cancelTooltip": "Annuleer huidig onderdeel",
"queueEmpty": "Wachtrij leeg",
"pauseSucceeded": "Verwerker onderbroken",
"in_progress": "Bezig",
"queueFront": "Voeg vooraan toe in wachtrij",
"notReady": "Fout bij plaatsen in wachtrij",
"batchFailedToQueue": "Fout bij reeks in wachtrij plaatsen",
"completed": "Voltooid",
"queueBack": "Voeg toe aan wachtrij",
"cancelFailed": "Fout bij annuleren onderdeel",
"batchQueued": "Reeks in wachtrij geplaatst",
"pauseFailed": "Fout bij onderbreken verwerker",
"clearFailed": "Fout bij wissen van wachtrij",
"front": "begin",
"clearSucceeded": "Wachtrij gewist",
"pause": "Onderbreek",
"pruneTooltip": "Ruim {{item_count}} voltooide onderdelen op",
"cancelSucceeded": "Onderdeel geannuleerd",
"batchQueuedDesc_one": "Voeg {{count}} sessie toe aan het {{direction}} van de wachtrij",
"batchQueuedDesc_other": "Voeg {{count}} sessies toe aan het {{direction}} van de wachtrij",
"graphQueued": "Graaf in wachtrij geplaatst",
"queue": "Wachtrij",
"batch": "Reeks",
"clearQueueAlertDialog": "Als je de wachtrij onmiddellijk wist, dan worden alle onderdelen die bezig zijn geannuleerd en wordt de wachtrij volledig gewist.",
"pending": "Wachtend",
"completedIn": "Voltooid na",
"resumeFailed": "Fout bij hervatten verwerker",
"clear": "Wis",
"prune": "Ruim op",
"total": "Totaal",
"canceled": "Geannuleerd",
"pruneFailed": "Fout bij opruimen van wachtrij",
"cancelBatchSucceeded": "Reeks geannuleerd",
"clearTooltip": "Annuleer en wis alle onderdelen",
"current": "Huidig",
"pauseTooltip": "Onderbreek verwerker",
"failed": "Mislukt",
"cancelItem": "Annuleer onderdeel",
"next": "Volgende",
"cancelBatch": "Annuleer reeks",
"back": "eind",
"cancel": "Annuleer",
"session": "Sessie",
"resumeSucceeded": "Verwerker hervat",
"enqueueing": "Bezig met toevoegen van reeks aan wachtrij",
"resumeTooltip": "Hervat verwerker",
"resume": "Hervat",
"cancelBatchFailed": "Fout bij annuleren van reeks",
"clearQueueAlertDialog2": "Weet je zeker dat je de wachtrij wilt wissen?",
"item": "Onderdeel",
"graphFailedToQueue": "Fout bij toevoegen graaf aan wachtrij"
},
"sdxl": {
"refinerStart": "Startwaarde verfijning",
"scheduler": "Planner",
"cfgScale": "CFG-schaal",
"noModelsAvailable": "Geen modellen beschikbaar",
"refiner": "Verfijning",
"negAestheticScore": "Negatieve esthetische score",
"denoisingStrength": "Sterkte ontruising",
"refinermodel": "Verfijningsmodel",
"posAestheticScore": "Positieve esthetische score",
"loading": "Bezig met laden...",
"steps": "Stappen",
"refinerSteps": "Aantal stappen verfijner"
},
"models": {
"noMatchingModels": "Geen overeenkomend modellen",
"loading": "bezig met laden",
"noModelsAvailable": "Geen modellen beschikbaar",
"selectModel": "Kies een model",
"noRefinerModelsInstalled": "Geen SDXL-verfijningsmodellen geïnstalleerd",
"defaultVAE": "Standaard-VAE",
"lora": "LoRA",
"addLora": "Voeg LoRA toe",
"concepts": "Concepten"
},
"boards": {
"autoAddBoard": "Voeg automatisch bord toe",
"topMessage": "Dit bord bevat afbeeldingen die in gebruik zijn door de volgende functies:",
"move": "Verplaats",
"menuItemAutoAdd": "Voeg dit automatisch toe aan bord",
"myBoard": "Mijn bord",
"searchBoard": "Zoek borden...",
"noMatching": "Geen overeenkomende borden",
"selectBoard": "Kies een bord",
"cancel": "Annuleer",
"addBoard": "Voeg bord toe",
"bottomMessage": "Als je dit bord en alle afbeeldingen erop verwijdert, dan worden alle functies teruggezet die ervan gebruik maken.",
"uncategorized": "Zonder categorie",
"downloadBoard": "Download bord",
"changeBoard": "Wijzig bord",
"loading": "Bezig met laden...",
"clearSearch": "Maak zoekopdracht leeg",
"deleteBoard": "Verwijder bord",
"deleteBoardAndImages": "Verwijder bord en afbeeldingen",
"deleteBoardOnly": "Verwijder alleen bord",
"deletedBoardsCannotbeRestored": "Verwijderde borden kunnen niet worden hersteld",
"movingImagesToBoard_one": "Verplaatsen van {{count}} afbeelding naar bord:",
"movingImagesToBoard_other": "Verplaatsen van {{count}} afbeeldingen naar bord:"
},
"invocationCache": {
"disable": "Schakel uit",
"misses": "Mislukt cacheverzoek",
"enableFailed": "Fout bij inschakelen aanroepcache",
"invocationCache": "Aanroepcache",
"clearSucceeded": "Aanroepcache gewist",
"enableSucceeded": "Aanroepcache ingeschakeld",
"clearFailed": "Fout bij wissen aanroepcache",
"hits": "Gelukt cacheverzoek",
"disableSucceeded": "Aanroepcache uitgeschakeld",
"disableFailed": "Fout bij uitschakelen aanroepcache",
"enable": "Schakel in",
"clear": "Wis",
"maxCacheSize": "Max. grootte cache",
"cacheSize": "Grootte cache"
},
"accordions": {
"generation": {
"title": "Genereren"
},
"image": {
"title": "Afbeelding"
},
"advanced": {
"title": "Geavanceerd",
"options": "$t(accordions.advanced.title) Opties"
},
"control": {
"title": "Besturing"
},
"compositing": {
"title": "Samenstellen",
"coherenceTab": "Coherentiefase",
"infillTab": "Invullen"
}
},
"hrf": {
"metadata": {
"strength": "Sterkte oplossing voor hoge resolutie",
"method": "Methode oplossing voor hoge resolutie",
"enabled": "Oplossing voor hoge resolutie ingeschakeld"
},
"hrf": "Oplossing voor hoge resolutie"
},
"prompt": {
"addPromptTrigger": "Voeg prompttrigger toe",
"compatibleEmbeddings": "Compatibele embeddings"
}
}
@@ -0,0 +1,315 @@
{
"common": {
"hotkeysLabel": "Skróty klawiszowe",
"languagePickerLabel": "Język",
"reportBugLabel": "Zgłoś błąd",
"settingsLabel": "Ustawienia",
"img2img": "Obraz na obraz",
"nodes": "Węzły",
"upload": "Prześlij",
"load": "Załaduj",
"statusDisconnected": "Odłączono",
"githubLabel": "GitHub",
"discordLabel": "Discord",
"clipboard": "Schowek",
"aboutDesc": "Wykorzystujesz Invoke do pracy? Sprawdź:",
"ai": "SI",
"areYouSure": "Czy jesteś pewien?",
"copyError": "$t(gallery.copy) Błąd",
"apply": "Zastosuj",
"copy": "Kopiuj",
"or": "albo",
"add": "Dodaj",
"off": "Wyłączony",
"accept": "Zaakceptuj",
"cancel": "Anuluj",
"advanced": "Zawansowane",
"back": "Do tyłu",
"auto": "Automatyczny",
"beta": "Beta",
"close": "Wyjdź",
"checkpoint": "Punkt kontrolny",
"controlNet": "ControlNet",
"details": "Detale",
"direction": "Kierunek",
"ipAdapter": "Adapter IP",
"dontAskMeAgain": "Nie pytaj ponownie",
"modelManager": "Menedżer modeli",
"blue": "Niebieski",
"orderBy": "Sortuj według",
"openInNewTab": "Otwórz w nowym oknie",
"somethingWentWrong": "Coś poszło nie tak",
"green": "Zielony",
"red": "Czerwony",
"saveAs": "Zapisz jako",
"outputs": "Wyjścia",
"data": "Dane",
"t2iAdapter": "Adapter T2I",
"selected": "Zaznaczone",
"warnings": "Ostrzeżenia",
"save": "Zapisz",
"created": "Stworzono",
"alpha": "Alfa",
"error": "Bład",
"editor": "Edytor",
"loading": "Ładuję",
"edit": "Edytuj",
"enabled": "Aktywny",
"communityLabel": "Społeczeństwo",
"linear": "Liniowy",
"installed": "Zainstalowany",
"dontShowMeThese": "Nie pokazuj mi tego",
"openInViewer": "Otwórz podgląd",
"safetensors": "Bezpieczniki",
"ok": "Ok",
"loadingImage": "wczytywanie zdjęcia",
"input": "Wejście",
"view": "Podgląd",
"learnMore": "Dowiedz się więcej",
"loadingModel": "Wczytywanie modelu",
"postprocessing": "Przetwarzanie końcowe",
"random": "Losowo",
"disabled": "Wyłączony",
"generating": "Generowanie",
"simple": "Prosty",
"folder": "Katalog",
"format": "Format",
"updated": "Zaktualizowano",
"unknown": "nieznany",
"delete": "Usuń",
"template": "Szablon",
"txt2img": "Tekst na obraz",
"file": "Plik",
"toResolve": "Do rozwiązania",
"unknownError": "Nieznany błąd",
"placeholderSelectAModel": "Wybierz model",
"new": "Nowy",
"none": "Żadne",
"reset": "Reset",
"on": "Włączony",
"aboutHeading": "Posiadaj swoją kreatywną moc"
},
"gallery": {
"galleryImageSize": "Rozmiar obrazów",
"gallerySettings": "Ustawienia galerii",
"autoSwitchNewImages": "Przełączaj na nowe obrazy",
"gallery": "Galeria",
"alwaysShowImageSizeBadge": "Zawsze pokazuj odznakę wielkości obrazu",
"assetsTab": "Pliki, które wrzuciłeś do użytku w twoich projektach.",
"currentlyInUse": "Ten obraz jest obecnie w użyciu przez następujące funkcje:",
"boardsSettings": "Ustawienia tablic",
"autoAssignBoardOnClick": "Automatycznie przypisz tablicę po kliknięciu",
"copy": "Kopiuj"
},
"parameters": {
"images": "L. obrazów",
"steps": "L. kroków",
"cfgScale": "Skala CFG",
"width": "Szerokość",
"height": "Wysokość",
"seed": "Inicjator",
"shuffle": "Losuj",
"noiseThreshold": "Poziom szumu",
"perlinNoise": "Szum Perlina",
"type": "Metoda",
"strength": "Siła",
"upscaling": "Powiększanie",
"scale": "Skala",
"imageFit": "Przeskaluj oryginalny obraz",
"scaleBeforeProcessing": "Tryb skalowania",
"scaledWidth": "Sk. do szer.",
"scaledHeight": "Sk. do wys.",
"infillMethod": "Metoda wypełniania",
"tileSize": "Rozmiar kafelka",
"usePrompt": "Skopiuj sugestie",
"useSeed": "Skopiuj inicjator",
"useAll": "Skopiuj wszystko",
"info": "Informacje"
},
"settings": {
"models": "Modele",
"displayInProgress": "Podgląd generowanego obrazu",
"confirmOnDelete": "Potwierdzaj usuwanie",
"resetWebUI": "Zresetuj interfejs",
"resetWebUIDesc1": "Resetowanie interfejsu wyczyści jedynie dane i ustawienia zapisane w pamięci przeglądarki. Nie usunie żadnych obrazów z dysku.",
"resetWebUIDesc2": "Jeśli obrazy nie są poprawnie wyświetlane w galerii lub doświadczasz innych problemów, przed zgłoszeniem błędu spróbuj zresetować interfejs.",
"resetComplete": "Interfejs został zresetowany. Odśwież stronę, aby załadować ponownie."
},
"toast": {
"uploadFailed": "Błąd przesyłania obrazu",
"imageCopied": "Skopiowano obraz",
"parametersNotSet": "Nie ustawiono parametrów"
},
"accessibility": {
"invokeProgressBar": "Pasek postępu",
"reset": "Zerowanie",
"uploadImage": "Wgrywanie obrazu",
"previousImage": "Poprzedni obraz",
"nextImage": "Następny obraz",
"menu": "Menu",
"mode": "Tryb",
"resetUI": "$t(accessibility.reset) UI",
"uploadImages": "Wgrywaj obrazy",
"about": "Informacje",
"toggleRightPanel": "Przełącz prawy panel (G)",
"toggleLeftPanel": "Przełącz lewy panel (G)",
"createIssue": "Stwórz problem",
"submitSupportTicket": "Wyślij bilet pomocy"
},
"boards": {
"cancel": "Anuluj",
"noBoards": "Brak tablic typu {{boardType}}",
"imagesWithCount_one": "{{count}} zdjęcie",
"imagesWithCount_few": "{{count}} zdjęcia",
"imagesWithCount_many": "{{count}} zdjęcia",
"private": "Prywatne tablice",
"updateBoardError": "Błąd aktualizacji tablicy",
"uncategorized": "Nieskategoryzowane",
"selectBoard": "Wybierz tablicę",
"downloadBoard": "Pobierz tablice",
"loading": "Ładowanie...",
"move": "Przenieś",
"noMatching": "Brak pasujących tablic",
"addBoard": "Dodaj tablicę",
"autoAddBoard": "Automatycznie dodaj tablicę",
"searchBoard": "Szukaj tablic.",
"unarchiveBoard": "Odarchiwizuj tablicę",
"selectedForAutoAdd": "Wybrany do automatycznego dodania",
"deleteBoard": "Usuń tablicę",
"clearSearch": "Usuń historię",
"addSharedBoard": "Dodaj udostępnioną tablicę",
"boards": "Tablice",
"addPrivateBoard": "Dodaj prywatną tablicę",
"movingImagesToBoard_one": "Przenoszenie {{count}} zdjęcia do tablicy:",
"movingImagesToBoard_few": "Przenoszenie {{count}} zdjęć do tablicy:",
"movingImagesToBoard_many": "Przenoszenie {{count}} zdjęć do tablicy:",
"shared": "Udostępnione tablice",
"topMessage": "Ta tablica zawiera obrazy wykorzystywane w następujących funkcjach:",
"deletedPrivateBoardsCannotbeRestored": "Usunięte tablice nie mogą być odzyskane. Wybierając \"Usuń tylko tablicę\" spowoduje że obrazy zostaną przeniesione do prywatnego nieskategoryzowanego stanu autora obrazu.",
"changeBoard": "Zmień tablicę",
"bottomMessage": "Usuwając tę tablicę oraz jej obrazów zresetują wszystkie funkcje które obecnie ich używają.",
"deleteBoardAndImages": "Usuń tablicę i zdjęcia",
"deleteBoardOnly": "Usuń tylko tablicę",
"deletedBoardsCannotbeRestored": "Usunięte tablice nie mogą być odzyskane. Wybierając \"Usuń tylko tablicę\" spowoduje że obrazy zostaną przeniesione do nieskategoryzowanego stanu.",
"archiveBoard": "Zarchiwizuj tablicę",
"archived": "Zarchiwizowano",
"myBoard": "Moja tablica",
"menuItemAutoAdd": "Automatycznie dodaj do tej tablicy"
},
"accordions": {
"compositing": {
"title": "Kompozycja",
"infillTab": "Inskrypcja",
"coherenceTab": "Przebieg Koherencji"
},
"generation": {
"title": "Generowanie"
},
"image": {
"title": "Zdjęcie"
},
"advanced": {
"options": "$t(accordions.advanced.title) Opcje",
"title": "Zaawansowane"
},
"control": {
"title": "Kontrola"
}
},
"hrf": {
"metadata": {
"enabled": "Włączono poprawkę wysokiej rozdzielczości",
"strength": "Moc poprawki wysokiej rozdzielczości",
"method": "Metoda High Resolution Fix"
},
"hrf": "Poprawka \"Wysoka rozdzielczość\""
},
"queue": {
"cancelTooltip": "Anuluj aktualną pozycję",
"resumeFailed": "Błąd z kontynuowaniem procesora",
"current": "Obecne",
"cancelBatchFailed": "Problem z anulacją masy",
"queueFront": "Dodaj do przodu kolejki",
"cancelBatch": "Anuluj serię",
"cancelFailed": "Problem z anulowaniem pozycji",
"pruneTooltip": "Wyczyść {{item_count}} skończonych pozycji",
"pruneSucceeded": "Wyczyszczono {{item_count}} zakończonych pozycji z kolejki",
"cancelBatchSucceeded": "Partia anulowana",
"clear": "Wyczyść",
"clearTooltip": "Anuluj i usuń wszystkie pozycje",
"clearSucceeded": "Kolejka wyczyszczona",
"cancelItem": "Anuluj pozycję",
"clearQueueAlertDialog2": "Czy na pewno chcesz wyczyścić kolejkę?",
"pauseFailed": "Problem z zapauzowaniem processora",
"clearFailed": "Problem z czyszczeniem kolejki",
"queueBack": "Dodaj do kolejki",
"queueEmpty": "Kolejka pusta",
"enqueueing": "Kolejkowanie partii",
"resumeTooltip": "Kontynuuj processor",
"resumeSucceeded": "Processor kontynuowany",
"pause": "Zapauzuj",
"pauseTooltip": "Zapauzuj processor",
"queue": "Kolejka",
"resume": "Kontynuuj",
"cancel": "Anuluj",
"cancelSucceeded": "Pozycja anulowana",
"prune": "Wyczyść",
"pauseSucceeded": "Processor zapauzowany",
"clearQueueAlertDialog": "Czyszczenie kolejki od razu anuluje wszystkie przetwarzane elementy and całkowicie czyści kolejkę. Oczekujące filtry zostaną anulowane.",
"pruneFailed": "Problem z wyczyszczeniem kolejki",
"batchQueued": "Masa w kolejce",
"openQueue": "Otwórz kolejkę",
"iterations_one": "Iteracja",
"iterations_few": "Iteracje",
"iterations_many": "Iteracje",
"graphQueued": "Wykres w kolejce",
"canvas": "Płótno",
"generation": "Generacja",
"status": "Status",
"total": "Suma",
"time": "Czas",
"front": "Przód",
"back": "tył",
"batchFailedToQueue": "Nie można zkolejkować masy",
"completedIn": "Ukończony w całości",
"other": "Inne",
"origin": "Pochodzenie",
"destination": "Miejsce docelowe",
"notReady": "Nie można zkolejkować",
"canceled": "Anulowano",
"in_progress": "W trakcie",
"gallery": "Galeria",
"session": "Sesja",
"pending": "W toku",
"completed": "Zakończono",
"item": "Pozycja",
"failed": "Niepowodzenie",
"graphFailedToQueue": "NIe udało się dodać tabeli do kolejki",
"workflows": "Przepływy pracy",
"next": "Następny",
"batchQueuedDesc_one": "Dodano {{count}} sesję do {{direction}} kolejki",
"batchQueuedDesc_few": "Dodano {{count}} sesje do {{direction}} kolejki",
"batchQueuedDesc_many": "Dodano {{count}} sesje do {{direction}} kolejki",
"batch": "Masa",
"upscaling": "Skalowanie w górę",
"generations_one": "Generacja",
"generations_few": "Generacje",
"generations_many": "Generacje",
"prompts_one": "Monit",
"prompts_few": "Monity",
"prompts_many": "Monity",
"batchSize": "Rozmiar masy"
},
"prompt": {
"compatibleEmbeddings": "Kompatybilne osadzenia",
"noMatchingTriggers": "Nie dopasowywanie spustów"
},
"invocationCache": {
"hits": "Uderzenia cache",
"enable": "Włącz",
"clear": "Wyczyść",
"disable": "Wyłącz",
"maxCacheSize": "Maksymalny rozmiar cache",
"cacheSize": "Rozmiar Cache"
}
}
@@ -0,0 +1,99 @@
{
"common": {
"hotkeysLabel": "Teclas de atalho",
"languagePickerLabel": "Seletor de Idioma",
"reportBugLabel": "Relatar Bug",
"settingsLabel": "Configurações",
"img2img": "Imagem Para Imagem",
"nodes": "Nódulos",
"upload": "Enviar",
"load": "Carregar",
"statusDisconnected": "Disconectado",
"githubLabel": "Github",
"discordLabel": "Discord",
"back": "Voltar",
"loading": "Carregando"
},
"gallery": {
"galleryImageSize": "Tamanho da Imagem",
"gallerySettings": "Configurações de Galeria",
"autoSwitchNewImages": "Trocar para Novas Imagens Automaticamente"
},
"modelManager": {
"modelManager": "Gerente de Modelo",
"model": "Modelo",
"modelUpdated": "Modelo Atualizado",
"manual": "Manual",
"name": "Nome",
"description": "Descrição",
"config": "Configuração",
"width": "Largura",
"height": "Altura",
"addModel": "Adicionar Modelo",
"availableModels": "Modelos Disponíveis",
"search": "Procurar",
"load": "Carregar",
"active": "Ativado",
"selected": "Selecionada",
"delete": "Excluir",
"deleteModel": "Excluir modelo",
"deleteConfig": "Excluir Config",
"deleteMsg1": "Tem certeza de que deseja excluir esta entrada do modelo de InvokeAI?",
"deleteMsg2": "Isso não vai excluir o arquivo de modelo checkpoint do seu disco. Você pode lê-los, se desejar.",
"repo_id": "Repo ID",
"convertToDiffusers": "Converter para Diffusers",
"convertToDiffusersHelpText1": "Este modelo será convertido para o formato 🧨 Diffusers.",
"convertToDiffusersHelpText5": "Por favor, certifique-se de que você tenha espaço suficiente em disco. Os modelos geralmente variam entre 4GB e 7GB de tamanho.",
"convertToDiffusersHelpText6": "Você deseja converter este modelo?",
"convertToDiffusersHelpText3": "Seu arquivo de ponto de verificação no disco NÃO será excluído ou modificado de forma alguma. Você pode adicionar seu ponto de verificação ao Gerenciador de modelos novamente, se desejar.",
"convertToDiffusersHelpText4": "Este é um processo único. Pode levar cerca de 30 a 60s, dependendo das especificações do seu computador.",
"modelConverted": "Modelo Convertido",
"alpha": "Alpha",
"allModels": "Todos os Modelos",
"convert": "Converter",
"convertToDiffusersHelpText2": "Este processo irá substituir sua entrada de Gerenciador de Modelos por uma versão Diffusers do mesmo modelo."
},
"parameters": {
"images": "Imagems",
"steps": "Passos",
"cfgScale": "Escala CFG",
"width": "Largura",
"height": "Altura",
"seed": "Seed",
"shuffle": "Embaralhar",
"noiseThreshold": "Limite de Ruído",
"perlinNoise": "Ruído de Perlin",
"type": "Tipo",
"strength": "Força",
"upscaling": "Redimensionando",
"scale": "Escala",
"imageFit": "Caber Imagem Inicial No Tamanho de Saída",
"scaleBeforeProcessing": "Escala Antes do Processamento",
"scaledWidth": "L Escalada",
"scaledHeight": "A Escalada",
"infillMethod": "Método de Preenchimento",
"tileSize": "Tamanho do Ladrilho",
"usePrompt": "Usar Prompt",
"useSeed": "Usar Seed",
"useAll": "Usar Todos",
"info": "Informações",
"symmetry": "Simetria",
"copyImage": "Copiar imagem",
"denoisingStrength": "A força de remoção de ruído",
"general": "Geral"
},
"settings": {
"models": "Modelos",
"displayInProgress": "Mostrar Progresso de Imagens Em Andamento",
"confirmOnDelete": "Confirmar Antes de Apagar",
"resetWebUI": "Reiniciar Interface",
"resetWebUIDesc1": "Reiniciar a interface apenas reinicia o cache local do broswer para imagens e configurações lembradas. Não apaga nenhuma imagem do disco.",
"resetWebUIDesc2": "Se as imagens não estão aparecendo na galeria ou algo mais não está funcionando, favor tentar reiniciar antes de postar um problema no GitHub.",
"resetComplete": "A interface foi reiniciada. Atualize a página para carregar."
},
"toast": {
"uploadFailed": "Envio Falhou",
"imageCopied": "Imagem Copiada",
"parametersNotSet": "Parâmetros Não Definidos"
}
}
@@ -0,0 +1,123 @@
{
"common": {
"reportBugLabel": "Reportar Bug",
"settingsLabel": "Configurações",
"languagePickerLabel": "Seletor de Idioma",
"hotkeysLabel": "Hotkeys",
"img2img": "Imagem para Imagem",
"nodes": "Nós",
"upload": "Upload",
"load": "Abrir",
"back": "Voltar",
"statusDisconnected": "Desconectado",
"githubLabel": "Github",
"discordLabel": "Discord",
"loading": "A carregar"
},
"gallery": {
"gallerySettings": "Configurações de Galeria",
"autoSwitchNewImages": "Trocar para Novas Imagens Automaticamente",
"galleryImageSize": "Tamanho da Imagem"
},
"modelManager": {
"modelUpdated": "Modelo Atualizado",
"description": "Descrição",
"repo_id": "Repo ID",
"width": "Largura",
"height": "Altura",
"deleteConfig": "Apagar Config",
"convertToDiffusersHelpText6": "Deseja converter este modelo?",
"alpha": "Alpha",
"config": "Configuração",
"modelConverted": "Modelo Convertido",
"manual": "Manual",
"name": "Nome",
"availableModels": "Modelos Disponíveis",
"load": "Carregar",
"active": "Ativado",
"deleteModel": "Apagar modelo",
"deleteMsg1": "Tem certeza de que deseja apagar esta entrada do modelo de InvokeAI?",
"deleteMsg2": "Isso não vai apagar o ficheiro de modelo checkpoint do seu disco. Pode lê-los, se desejar.",
"convertToDiffusers": "Converter para Diffusers",
"convertToDiffusersHelpText1": "Este modelo será convertido ao formato 🧨 Diffusers.",
"convertToDiffusersHelpText2": "Este processo irá substituir a sua entrada de Gestor de Modelos por uma versão Diffusers do mesmo modelo.",
"convertToDiffusersHelpText3": "O seu ficheiro de ponto de verificação no disco NÃO será excluído ou modificado de forma alguma. Pode adicionar o seu ponto de verificação ao Gestor de modelos novamente, se desejar.",
"none": "nenhum",
"modelManager": "Gerente de Modelo",
"model": "Modelo",
"allModels": "Todos os Modelos",
"addModel": "Adicionar Modelo",
"search": "Procurar",
"selected": "Selecionada",
"delete": "Apagar",
"convert": "Converter",
"convertToDiffusersHelpText4": "Este é um processo único. Pode levar cerca de 30 a 60s, a depender das especificações do seu computador.",
"convertToDiffusersHelpText5": "Por favor, certifique-se de que tenha espaço suficiente no disco. Os modelos geralmente variam entre 4GB e 7GB de tamanho."
},
"parameters": {
"width": "Largura",
"seed": "Seed",
"general": "Geral",
"shuffle": "Embaralhar",
"noiseThreshold": "Limite de Ruído",
"perlinNoise": "Ruído de Perlin",
"type": "Tipo",
"denoisingStrength": "A força de remoção de ruído",
"scale": "Escala",
"imageFit": "Caber Imagem Inicial No Tamanho de Saída",
"tileSize": "Tamanho do Ladrilho",
"symmetry": "Simetria",
"usePrompt": "Usar Prompt",
"strength": "Força",
"upscaling": "Redimensionando",
"scaleBeforeProcessing": "Escala Antes do Processamento",
"images": "Imagems",
"steps": "Passos",
"cfgScale": "Escala CFG",
"height": "Altura",
"scaledWidth": "L Escalada",
"scaledHeight": "A Escalada",
"infillMethod": "Método de Preenchimento",
"copyImage": "Copiar imagem",
"useSeed": "Usar Seed",
"useAll": "Usar Todos",
"info": "Informações"
},
"settings": {
"confirmOnDelete": "Confirmar Antes de Apagar",
"resetWebUIDesc1": "Reiniciar a interface apenas reinicia o cache local do broswer para imagens e configurações lembradas. Não apaga nenhuma imagem do disco.",
"models": "Modelos",
"displayInProgress": "Mostrar Progresso de Imagens Em Andamento",
"resetWebUI": "Reiniciar Interface",
"resetWebUIDesc2": "Se as imagens não estão a aparecer na galeria ou algo mais não está a funcionar, favor tentar reiniciar antes de postar um problema no GitHub.",
"resetComplete": "A interface foi reiniciada. Atualize a página para carregar."
},
"toast": {
"uploadFailed": "Envio Falhou",
"imageCopied": "Imagem Copiada",
"parametersNotSet": "Parâmetros Não Definidos"
},
"accessibility": {
"invokeProgressBar": "Invocar barra de progresso",
"reset": "Reiniciar",
"nextImage": "Próxima imagem",
"uploadImage": "Enviar imagem",
"previousImage": "Imagem Anterior",
"menu": "Menu",
"about": "Sobre",
"resetUI": "$t(accessibility.reset)UI",
"createIssue": "Reportar Problema",
"submitSupportTicket": "Submeter um ticket de Suporte",
"mode": "Modo"
},
"boards": {
"selectedForAutoAdd": "Selecionado para Auto-Adicionar",
"addBoard": "Adicionar Quadro",
"addPrivateBoard": "Adicionar Quadro privado",
"addSharedBoard": "Adicionar quadro Compartilhado",
"boards": "Quadros",
"autoAddBoard": "Auto-adicao de Quadro",
"archiveBoard": "Arquivar Quadro",
"archived": "Arquivado"
}
}
@@ -0,0 +1,457 @@
{
"accessibility": {
"about": "Despre",
"reset": "Resetează",
"menu": "Meniu",
"mode": "Mod"
},
"common": {
"hotkeysLabel": "Scurtături",
"languagePickerLabel": "Limbă",
"githubLabel": "Github",
"discordLabel": "Discord",
"settingsLabel": "Setări",
"nodes": "Workflow-uri",
"upload": "Încarcă",
"load": "Încarcă",
"back": "Înapoi",
"statusDisconnected": "Deconectat",
"loading": "Se încarcă",
"cancel": "Anulează",
"accept": "Acceptă",
"linear": "Linear",
"random": "Random",
"communityLabel": "Comunitate",
"advanced": "Avansat",
"controlNet": "ControlNet",
"auto": "Auto",
"on": "Pornit",
"checkpoint": "Checkpoint",
"data": "Date",
"details": "Detalii",
"inpaint": "inpaint",
"outpaint": "outpaint",
"outputs": "Outputs",
"safetensors": "Safetensors",
"simple": "Simplu",
"template": "Șablon",
"ai": "ai",
"error": "Eroare",
"file": "Fișier",
"folder": "Folder",
"format": "format",
"input": "Input",
"installed": "Instalat",
"unknown": "Necunoscut",
"delete": "Șterge",
"direction": "Direcție",
"save": "Salvează",
"updated": "Actualizat",
"created": "Creat",
"or": "sau",
"red": "Roșu",
"green": "Verde",
"blue": "Albastru",
"alpha": "Alpha",
"copy": "Copiază",
"add": "Adaugă",
"beta": "Beta",
"selected": "Selectat",
"editor": "Editor",
"tab": "Filă",
"enabled": "Activat",
"disabled": "Dezactivat",
"apply": "Aplică",
"view": "Vizualizează",
"edit": "Editează",
"off": "Oprit",
"reset": "Resetează",
"none": "Niciunul",
"new": "Nou"
},
"modelManager": {
"model": "Model",
"manual": "Manual",
"name": "Nume",
"description": "Descriere",
"config": "Configurare",
"width": "Lățime",
"height": "Înălțime",
"search": "Caută",
"load": "Încarcă",
"active": "activ",
"selected": "Selectat",
"delete": "Șterge",
"convert": "Convertește",
"alpha": "Alpha",
"none": "niciunul",
"vae": "VAE",
"variant": "Variantă",
"settings": "Setări",
"advanced": "Avansat",
"cancel": "Anulează",
"edit": "Editează",
"path": "Path",
"prune": "Taie",
"source": "Sursă",
"metadata": "Metadata",
"huggingFace": "HuggingFace",
"huggingFacePlaceholder": "autor/nume-model",
"install": "Instalează",
"loraModels": "LoRAs",
"main": "Main"
},
"parameters": {
"general": "General",
"images": "Imagini",
"steps": "Pași",
"width": "Lățime",
"height": "Înălțime",
"seed": "Seed",
"type": "Tip",
"strength": "Putere",
"upscaling": "Upscaling",
"scale": "Scale",
"symmetry": "Simetrie",
"info": "Informații",
"scheduler": "Planificator",
"coherenceMode": "Mod",
"patchmatchDownScaleSize": "Downscale",
"cancel": {
"cancel": "Anulează"
},
"invoke": {
"invoke": "Invocă"
},
"iterations": "Iterații",
"aspect": "Aspect"
},
"settings": {
"models": "Modele",
"developer": "Developer",
"general": "General",
"generation": "Generare",
"beta": "Beta"
},
"boards": {
"cancel": "Anulează",
"loading": "Se încarcă...",
"move": "Mută",
"uncategorized": "Necategorizat",
"archived": "Arhivat",
"boards": "Boards"
},
"gallery": {
"copy": "Copiază",
"download": "Descarcă",
"loading": "Se încarcă",
"drop": "Lasă",
"image": "imagine",
"starImage": "Adaugă la favorite",
"unstarImage": "Elimină de la favorite",
"slider": "Slider",
"sideBySide": "Side-by-Side",
"hover": "Hover",
"go": "Du-te",
"gallery": "Galerie"
},
"metadata": {
"height": "Înălțime",
"metadata": "Metadata",
"model": "Model",
"scheduler": "Planificator",
"seed": "Seed",
"steps": "Pași",
"width": "Lățime",
"workflow": "Workflow",
"vae": "VAE",
"cfgRescaleMultiplier": "$t(parameters.cfgRescaleMultiplier)"
},
"models": {
"loading": "se încarcă",
"lora": "LoRA",
"concepts": "Concepte"
},
"nodes": {
"notes": "Note",
"workflow": "Workflow",
"workflowAuthor": "Autor",
"workflowContact": "Contact",
"workflowName": "Nume",
"workflowNotes": "Note",
"workflowTags": "Etichete",
"workflowVersion": "Versiune",
"executionStateError": "Eroare",
"executionStateCompleted": "Completat",
"version": "Versiune",
"boolean": "Booleani",
"collection": "Colecție",
"edge": "Muchie",
"enum": "Enum",
"float": "Float",
"integer": "Integer",
"node": "Nod",
"scheduler": "Planificator",
"string": "String",
"ipAdapter": "IP-Adapter",
"edit": "Editează",
"graph": "Graf"
},
"sdxl": {
"loading": "Se încarcă...",
"refiner": "Refiner",
"scheduler": "Planificator",
"steps": "Pași"
},
"queue": {
"queue": "Coadă",
"resume": "Reia",
"pause": "Întrerupe",
"cancel": "Anulează",
"prune": "Taie",
"clear": "Golește",
"current": "Curent",
"next": "Următorul",
"status": "Status",
"total": "Total",
"pending": "În așteptare",
"completed": "Completat",
"failed": "Eșuat",
"canceled": "Anulat",
"batch": "Lot",
"item": "Item",
"session": "Sesiune",
"front": "față",
"back": "spate",
"time": "Timp",
"origin": "Origine",
"destination": "Destinație",
"upscaling": "Upscaling",
"canvas": "Canvas",
"generation": "Generare",
"workflows": "Workflows",
"other": "Altele",
"gallery": "Galerie"
},
"popovers": {
"compositingCoherenceMode": {
"heading": "Mod"
},
"controlNetWeight": {
"heading": "Weight"
},
"lora": {
"heading": "LoRA"
},
"paramModel": {
"heading": "Model"
},
"paramScheduler": {
"heading": "Planificator"
},
"paramSeed": {
"heading": "Seed"
},
"paramSteps": {
"heading": "Pași"
},
"paramVAE": {
"heading": "VAE"
},
"paramIterations": {
"heading": "Iterații"
},
"controlNet": {
"heading": "ControlNet"
},
"controlNetProcessor": {
"heading": "Procesator"
},
"loraWeight": {
"heading": "Weight"
},
"paramAspect": {
"heading": "Aspect"
},
"paramHeight": {
"heading": "Înălțime"
},
"paramWidth": {
"heading": "Lățime"
},
"patchmatchDownScaleSize": {
"heading": "Downscale"
},
"refinerScheduler": {
"heading": "Planificator"
},
"refinerSteps": {
"heading": "Pași"
},
"ipAdapterMethod": {
"heading": "Mod"
},
"scale": {
"heading": "Scale"
},
"creativity": {
"heading": "Creativitate"
},
"structure": {
"heading": "Structură"
}
},
"invocationCache": {
"clear": "Golește",
"enable": "Activează",
"disable": "Dezactivează"
},
"workflows": {
"workflows": "Workflows",
"ascending": "În ordine crescătoare",
"created": "Creat",
"descending": "În ordine descrescătoare",
"opened": "Deschis",
"updated": "Actualizat",
"name": "Nume"
},
"accordions": {
"generation": {
"title": "Generare"
},
"image": {
"title": "Imagine"
},
"advanced": {
"title": "Avansat"
},
"control": {
"title": "Control"
},
"compositing": {
"title": "Se compune",
"infillTab": "Infill"
}
},
"toast": {
"parameters": "Parametri"
},
"controlLayers": {
"rectangle": "Dreptunghi",
"opacity": "Opacitate",
"duplicate": "Duplică",
"width": "Lățime",
"transparency": "Transparență",
"locked": "Blocat",
"unlocked": "Deblocat",
"fill": {
"solid": "Solid",
"grid": "Grid",
"crosshatch": "Crosshatch",
"vertical": "Vertical",
"horizontal": "Orizontal",
"diagonal": "Diagonal"
},
"tool": {
"brush": "Pensulă",
"eraser": "Radieră",
"rectangle": "Dreptunghi",
"bbox": "Bbox",
"move": "Mută",
"view": "Vizualizează"
},
"filter": {
"filter": "Filtrează",
"filters": "Filtre",
"apply": "Aplică",
"cancel": "Anulează",
"reset": "Resetare",
"process": "Procesează",
"spandrel_filter": {
"model": "Model"
},
"depth_anything_depth_estimation": {
"model_size_small": "Mică",
"model_size_base": "Bază",
"model_size_large": "Mare"
},
"hed_edge_detection": {
"scribble": "Scribble"
},
"lineart_edge_detection": {
"coarse": "Coarse"
},
"pidi_edge_detection": {
"scribble": "Scribble"
}
},
"transform": {
"transform": "Transformă",
"reset": "Resetează",
"apply": "Aplică",
"cancel": "Anulează"
},
"settings": {
"snapToGrid": {
"off": "Oprit",
"on": "Pornit"
}
},
"HUD": {
"bbox": "Bbox"
},
"canvas": "Canvas",
"regional": "Regional",
"global": "Global",
"prompt": "Prompt",
"weight": "Weight"
},
"ui": {
"tabs": {
"canvas": "Canvas",
"workflows": "Workflows",
"models": "Modele",
"queue": "Coadă",
"upscaling": "Upscaling",
"gallery": "Galerie"
}
},
"upscaling": {
"creativity": "Creativitate",
"structure": "Structură",
"scale": "Scale",
"upscale": "Upscale"
},
"stylePresets": {
"active": "Activ",
"name": "Nume",
"preview": "Previzualizare",
"private": "Privat",
"shared": "Partajat",
"type": "Tip",
"nameColumn": "'nume'",
"negativePromptColumn": "'negative_prompt'"
},
"system": {
"logLevel": {
"trace": "Trace",
"debug": "Debug",
"info": "Informații",
"warn": "Avertizează",
"error": "Eroare",
"fatal": "Fatal"
},
"logNamespaces": {
"gallery": "Galerie",
"models": "Modele",
"config": "Configurare",
"canvas": "Canvas",
"generation": "Generare",
"workflows": "Workflows",
"system": "Sistem",
"events": "Evenimente",
"queue": "Coadă",
"metadata": "Metadata"
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
{
"accessibility": {
"uploadImage": "Ladda upp bild",
"invokeProgressBar": "Invoke förloppsmätare",
"nextImage": "Nästa bild",
"reset": "Starta om",
"previousImage": "Föregående bild"
},
"common": {
"hotkeysLabel": "Snabbtangenter",
"reportBugLabel": "Rapportera bugg",
"githubLabel": "Github",
"discordLabel": "Discord",
"settingsLabel": "Inställningar",
"upload": "Ladda upp",
"cancel": "Avbryt",
"accept": "Acceptera",
"statusDisconnected": "Frånkopplad",
"loading": "Laddar",
"languagePickerLabel": "Språkväljare",
"txt2img": "Text till bild",
"nodes": "Noder",
"img2img": "Bild till bild",
"postprocessing": "Efterbehandling",
"load": "Ladda",
"back": "Bakåt"
},
"gallery": {
"galleryImageSize": "Bildstorlek",
"gallerySettings": "Galleriinställningar",
"autoSwitchNewImages": "Ändra automatiskt till nya bilder"
}
}
@@ -0,0 +1,397 @@
{
"accessibility": {
"invokeProgressBar": "Invoke durum çubuğu",
"nextImage": "Sonraki Görsel",
"reset": "Resetle",
"uploadImage": "Görsel Yükle",
"previousImage": "Önceki Görsel",
"menu": "Menü",
"about": "Hakkında",
"mode": "Kip",
"resetUI": "$t(accessibility.reset)Arayüz",
"createIssue": "Sorun Bildir"
},
"common": {
"hotkeysLabel": "Kısayol Tuşları",
"languagePickerLabel": "Dil",
"reportBugLabel": "Sorun Bildir",
"githubLabel": "Github",
"discordLabel": "Discord",
"settingsLabel": "Seçenekler",
"txt2img": "Yazıdan Görsel",
"img2img": "Görselden Görsel",
"linear": "Doğrusal",
"nodes": "İş Akışı Düzenleyici",
"postprocessing": "Rötuş",
"batch": "Toplu İş Yöneticisi",
"accept": "Onayla",
"cancel": "Vazgeç",
"advanced": "Gelişmiş",
"copyError": "$t(gallery.copy) Hata",
"on": "Açık",
"or": "ya da",
"aboutDesc": "Invoke'u iş için mi kullanıyorsunuz? Şuna bir göz atın:",
"ai": "yapay zeka",
"auto": "Otomatik",
"communityLabel": "Topluluk",
"back": "Geri",
"areYouSure": "Emin misiniz?",
"openInNewTab": "Yeni Sekmede Aç",
"aboutHeading": "Yaratıcı Gücünüzün Sahibi Olun",
"load": "Yükle",
"loading": "Yükleniyor",
"inpaint": "içboyama",
"modelManager": "Model Yöneticisi",
"orderBy": "Sırala",
"outpaint": "dışboyama",
"outputs": "Çıktılar",
"learnMore": "Bilgi Edin",
"save": "Kaydet",
"random": "Rastgele",
"simple": "Basit",
"template": "Şablon",
"saveAs": "Farklı Kaydet",
"somethingWentWrong": "Bir sorun oluştu",
"statusDisconnected": "Bağlantı Kesildi",
"unknown": "Bilinmeyen",
"green": "Yeşil",
"red": "Kırmızı",
"blue": "Mavi",
"alpha": "Alfa",
"file": "Dosya",
"folder": "Klasör",
"format": "biçim",
"details": "Ayrıntılar",
"error": "Hata",
"safetensors": "Safetensors",
"upload": "Yükle",
"dontAskMeAgain": "Bir daha sorma",
"delete": "Kaldır",
"direction": "Yön",
"unknownError": "Bilinmeyen Hata",
"installed": "Yüklü",
"data": "Veri",
"input": "Giriş",
"copy": "Kopyala",
"created": "Yaratma",
"updated": "Güncelleme",
"ipAdapter": "IP Aracı",
"t2iAdapter": "T2I Aracı",
"controlNet": "ControlNet"
},
"accordions": {
"generation": {
"title": "Oluşturma"
},
"image": {
"title": "Görsel"
},
"advanced": {
"title": "Gelişmiş"
},
"compositing": {
"title": "Birleştirme",
"coherenceTab": "Uyum Geçişi",
"infillTab": "Doldurma"
},
"control": {
"title": "Yönetim"
}
},
"boards": {
"autoAddBoard": "Panoya Otomatik Ekleme",
"cancel": "Vazgeç",
"clearSearch": "Aramayı Sil",
"deleteBoard": "Panoyu Sil",
"loading": "Yükleniyor...",
"myBoard": "Panom",
"selectBoard": "Bir Pano Seç",
"addBoard": "Pano Ekle",
"deleteBoardAndImages": "Panoyu ve Görselleri Sil",
"deleteBoardOnly": "Sadece Panoyu Sil",
"deletedBoardsCannotbeRestored": "Silinen panolar geri getirilemez",
"menuItemAutoAdd": "Bu panoya otomatik olarak ekle",
"move": "Taşı",
"movingImagesToBoard_one": "{{count}} görseli şu panoya taşı:",
"movingImagesToBoard_other": "{{count}} görseli şu panoya taşı:",
"noMatching": "Eşleşen pano yok",
"searchBoard": "Pano Ara...",
"topMessage": "Bu pano, şuralarda kullanılan görseller içeriyor:",
"downloadBoard": "Panoyu İndir",
"uncategorized": "Kategorisiz",
"changeBoard": "Panoyu Değiştir",
"bottomMessage": "Bu panoyu ve görselleri silmek, bunları kullanan özelliklerin resetlemesine neden olacaktır."
},
"queue": {
"resumeSucceeded": "İşlem Sürdürüldü",
"openQueue": "Sırayı Göster",
"cancelSucceeded": "İş Geri Çekildi",
"cancelFailed": "İşi Geri Çekmede Sorun",
"prune": "Arındır",
"pruneTooltip": "{{item_count}} Bitmiş İşi Sil",
"resumeFailed": "İşlemi Sürdürmede Sorun",
"pauseFailed": "İşlemi Duraklatmada Sorun",
"cancelBatchSucceeded": "Toplu İşten Vazgeçildi",
"pruneSucceeded": "{{item_count}} Bitmiş İş Sıradan Silindi",
"in_progress": "İşleniyor",
"completed": "Bitti",
"canceled": "Vazgeçildi",
"back": "arka",
"queueFront": "Sıranın Başına Ekle",
"queueBack": "Sıraya Ekle",
"resumeTooltip": "İşlemi Sürdür",
"clearQueueAlertDialog2": "Sırayı boşaltmak istediğinizden emin misiniz?",
"batchQueuedDesc_one": "{{count}} iş sıranın {{direction}} eklendi",
"batchQueuedDesc_other": "{{count}} iş sıranın {{direction}} eklendi",
"batchFailedToQueue": "Toplu İş Sıraya Alınamadı",
"front": "ön",
"queue": "Sıra",
"resume": "Sürdür",
"queueEmpty": "Sıra Boş",
"clearQueueAlertDialog": "Sırayı boşaltma düğmesi geçerli işlemi durdurur ve sırayı boşaltır.",
"current": "Şimdiki",
"time": "Süre",
"pause": "Duraklat",
"pauseTooltip": "İşlemi Duraklat",
"pruneFailed": "Sırayı Arındırmada Sorun",
"clearTooltip": "Vazgeç ve Tüm İşleri Sil",
"clear": "Boşalt",
"cancelBatchFailed": "Toplu İşten Vazgeçmede Sorun",
"next": "Sonraki",
"status": "Durum",
"failed": "Başarısız",
"item": "İş",
"enqueueing": "Toplu İş Sıraya Alınıyor",
"pauseSucceeded": "İşlem Duraklatıldı",
"cancel": "Vazgeç",
"cancelTooltip": "Bu İşi Geri Çek",
"clearSucceeded": "Sıra Boşaltıldı",
"clearFailed": "Sırayı Boşaltmada Sorun",
"cancelBatch": "Toplu İşten Vazgeç",
"cancelItem": "İşi Geri Çek",
"total": "Toplam",
"pending": "Sırada",
"completedIn": "'de bitirildi",
"batch": "Toplu İş",
"session": "Oturum",
"batchQueued": "Toplu İş Sıraya Alındı",
"notReady": "Sıraya Alınamadı",
"graphFailedToQueue": "Çizge sıraya alınamadı",
"graphQueued": "Çizge sıraya alındı"
},
"invocationCache": {
"cacheSize": "Önbellek Boyutu",
"disable": "Kapat",
"clear": "Boşalt",
"maxCacheSize": "Maksimum Önbellek Boyutu",
"useCache": "Önbellek Kullan",
"enable": "Aç"
},
"gallery": {
"deleteImagePermanent": "Silinen görseller geri getirilemez.",
"autoAssignBoardOnClick": "Tıklanan Panoya Otomatik Atama",
"loading": "Yükleniyor",
"starImage": "Yıldız Koy",
"download": "İndir",
"deleteSelection": "Seçileni Sil",
"featuresWillReset": "Bu görseli silerseniz, o özellikler resetlenecektir.",
"noImageSelected": "Görsel Seçilmedi",
"unstarImage": "Yıldızı Kaldır",
"gallerySettings": "Galeri Düzeni",
"image": "görsel",
"galleryImageSize": "Görsel Boyutu",
"copy": "Kopyala",
"autoSwitchNewImages": "Yeni Görseli Biter Bitmez Gör",
"currentlyInUse": "Bu görsel şurada kullanımda:",
"deleteImage_one": "Görseli Sil",
"deleteImage_other": "",
"downloadSelection": "Seçileni İndir",
"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ü",
"metadata": {
"enabled": "Yüksek Çözünürlük Kürü Açık",
"strength": "Yüksek Çözünürlük Kürü Etkisi",
"method": "Yüksek Çözünürlük Kürü Yöntemi"
}
},
"hotkeys": {
"noHotkeysFound": "Kısayol Tuşu Bulanamadı",
"searchHotkeys": "Kısayol Tuşlarında Ara",
"clearSearch": "Aramayı Sil"
},
"nodes": {
"unableToValidateWorkflow": "İş Akışı Doğrulanamadı",
"workflowContact": "İletişim",
"loadWorkflow": "İş Akışı Yükle",
"workflowNotes": "Notlar",
"workflow": "İş Akışı",
"notesDescription": "İş akışınız hakkında not düşün",
"workflowTags": "Etiketler",
"workflowDescription": "Kısa Tanım",
"workflowValidation": "İş Akışı Doğrulama Sorunu",
"workflowVersion": "Sürüm",
"newWorkflow": "Yeni İş Akışı",
"currentImageDescription": "İşlemdeki görseli Çizge Düzenleyicide gösterir",
"workflowAuthor": "Yaratıcı",
"workflowName": "Ad",
"workflowSettings": "İş Akışı Düzenleyici Seçenekleri",
"currentImage": "İşlemdeki Görsel",
"noWorkflow": "İş Akışı Yok",
"newWorkflowDesc": "Yeni iş akışı?",
"downloadWorkflow": "İş Akışını İndir (JSON)",
"unknownErrorValidatingWorkflow": "İş akışını doğrulamada bilinmeyen bir sorun",
"unableToGetWorkflowVersion": "İş akışı sürümüne ulaşılamadı",
"newWorkflowDesc2": "Geçerli iş akışında kaydedilmemiş değişiklikler var.",
"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",
"cannotConnectToSelf": "Kendisine bağlanamaz",
"cannotDuplicateConnection": "Kopya bağlantılar yaratılamaz"
},
"workflows": {
"workflowName": "İş Akışı Adı",
"problemSavingWorkflow": "İş Akışını Kaydetmede Sorun",
"saveWorkflow": "İş Akışını Kaydet",
"uploadWorkflow": "Dosyadan Yükle",
"newWorkflowCreated": "Yeni İş Akışı Yaratıldı",
"loading": "İş Akışları Yükleniyor",
"workflowEditorMenu": "İş Akışı Düzenleyici Menüsü",
"downloadWorkflow": "İndir",
"saveWorkflowAs": "İş Akışını Farklı Kaydet",
"savingWorkflow": "İş Akışı Kaydediliyor...",
"workflows": "İş Akışları",
"workflowLibrary": "Depo",
"deleteWorkflow": "İş Akışını Sil",
"unnamedWorkflow": "Adsız İş Akışı",
"noWorkflows": "İş Akışı Yok",
"workflowSaved": "İş Akışı Kaydedildi"
},
"toast": {
"problemRetrievingWorkflow": "İş Akışını Getirmede Sorun",
"workflowDeleted": "İş Akışı Silindi",
"loadedWithWarnings": "İş Akışı Yüklendi Ancak Uyarılar Var",
"workflowLoaded": "İş Akışı Yüklendi",
"problemDeletingWorkflow": "İş Akışını Silmede Sorun"
},
"parameters": {
"invoke": {
"noPrompts": "İstem oluşturulmadı",
"noModelSelected": "Model seçilmedi",
"systemDisconnected": "Sistem bağlantısı kesildi",
"invoke": "Invoke"
},
"clipSkip": "CLIP Atlama",
"cfgScale": "CFG Ölçeği",
"controlNetControlMode": "Yönetim Kipi",
"general": "Genel",
"seamlessYAxis": "Dikişsiz Döşeme Y Ekseni",
"maskBlur": "Bulandırma",
"images": "Görseller",
"info": "Bilgi",
"positivePromptPlaceholder": "Olumlu İstem",
"scaledHeight": "Ölçekli Boy",
"lockAspectRatio": "En-Boy Oranını Koru",
"swapDimensions": "Çevir",
"setToOptimalSize": "Modele göre en uygun boyut",
"copyImage": "Görseli Kopyala",
"height": "Boy",
"width": "En",
"useSize": "Boyutu Kullan",
"symmetry": "Bakışım",
"tileSize": "Döşeme Boyutu",
"strength": "Güç",
"useAll": "Hepsini Kullan",
"denoisingStrength": "Arındırma Ölçüsü",
"imageFit": "Öngörseli Çıktı Boyutuna Sığdır",
"noiseThreshold": "Gürültü Eşiği",
"seed": "Tohum",
"imageActions": "Görsel İşlemleri",
"shuffle": "Kar",
"usePrompt": "İstemi Kullan",
"setToOptimalSizeTooSmall": "$t(parameters.setToOptimalSize) (çok küçük olabilir)",
"setToOptimalSizeTooLarge": "$t(parameters.setToOptimalSize) (çok büyük olabilir)",
"cfgRescaleMultiplier": "CFG Rescale Çarpanı",
"infillMethod": "Doldurma Yöntemi",
"steps": "Adım",
"upscaling": "Büyütülüyor",
"useSeed": "Tohumu Kullan",
"scheduler": "Planlayıcı",
"coherenceMode": "Kip",
"useCpuNoise": "CPU Gürültüsü Kullan",
"negativePromptPlaceholder": "Olumsuz İstem",
"patchmatchDownScaleSize": "Küçült",
"perlinNoise": "Perlin Gürültüsü",
"scaledWidth": "Ölçekli En",
"seamlessXAxis": "Dikişsiz Döşeme X Ekseni",
"type": "Tür"
},
"modelManager": {
"baseModel": "Ana Model",
"active": "etkin",
"deleteConfig": "Yapılandırmayı Sil",
"availableModels": "Kullanılabilir Modeller",
"advanced": "Gelişmiş",
"allModels": "Tüm Modeller",
"alpha": "Alfa",
"config": "Yapılandırma",
"addModel": "Model Ekle",
"height": "Boy",
"modelDeleted": "Model Kaldırıldı",
"vaePrecision": "VAE Kesinliği",
"convertToDiffusersHelpText6": "Bu modeli dönüştürmek istiyor musunuz?",
"deleteMsg1": "Bu modeli InvokeAI'dan silmek istediğinize emin misiniz?",
"settings": "Seçenekler",
"vae": "VAE",
"width": "En",
"delete": "Sil",
"convert": "Dönüştür",
"syncModels": "Modelleri Senkronize Et",
"variant": "Tür",
"convertingModelBegin": "Model Dönüştürülüyor. Lütfen bekleyiniz.",
"none": "hiçbiri",
"search": "Ara",
"model": "Model",
"modelType": "Model Türü",
"modelUpdated": "Model Güncellendi",
"modelUpdateFailed": "Model Güncellenemedi",
"name": "Ad",
"selected": "Seçili",
"convertToDiffusersHelpText5": "Lütfen yeterli depolama alanınız olduğundan emin olun. Modeller çoğunlukla 2-7 GB boyutundadır.",
"modelManager": "Model Yöneticisi",
"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.",
"deleteModel": "Modeli Sil",
"deleteMsg2": "Model InvokeAI ana klasöründeyse bilgisayarınızdan silinir, bu klasör dışındaysa bilgisayarınızdan silinmeyecektir.",
"load": "Yükle",
"modelDeleteFailed": "Model kaldırılamadı",
"noModelSelected": "Model Seçilmedi",
"predictionType": "Saptama Türü",
"selectModel": "Model Seç",
"modelConversionFailed": "Model Dönüşümü Başarısız",
"modelConverted": "Model Dönüştürüldü",
"description": "Tanım"
},
"models": {
"addLora": "LoRA Ekle",
"defaultVAE": "Varsayılan VAE",
"lora": "LoRA",
"noModelsAvailable": "Model yok",
"noMatchingModels": "Uygun Model Yok",
"loading": "yükleniyor",
"selectModel": "Model Seçin"
},
"settings": {
"generation": "Oluşturma"
},
"sdxl": {
"cfgScale": "CFG Ölçeği",
"loading": "Yükleniyor...",
"denoisingStrength": "Arındırma Ölçüsü"
}
}
@@ -0,0 +1,116 @@
{
"common": {
"hotkeysLabel": "Гарячi клавіші",
"languagePickerLabel": "Мова",
"reportBugLabel": "Повідомити про помилку",
"settingsLabel": "Налаштування",
"img2img": "Зображення із зображення (img2img)",
"nodes": "Вузли",
"upload": "Завантажити",
"load": "Завантажити",
"statusDisconnected": "Відключено",
"cancel": "Скасувати",
"accept": "Підтвердити",
"back": "Назад",
"postprocessing": "Постобробка",
"loading": "Завантаження",
"githubLabel": "Github",
"txt2img": "Текст в зображення (txt2img)",
"discordLabel": "Discord",
"linear": "Лінійна обробка"
},
"gallery": {
"galleryImageSize": "Розмір зображень",
"gallerySettings": "Налаштування галереї",
"autoSwitchNewImages": "Автоматично вибирати нові"
},
"modelManager": {
"modelManager": "Менеджер моделей",
"model": "Модель",
"modelUpdated": "Модель оновлена",
"manual": "Ручне",
"name": "Назва",
"description": "Опис",
"config": "Файл конфігурації",
"width": "Ширина",
"height": "Висота",
"addModel": "Додати модель",
"availableModels": "Доступні моделі",
"search": "Шукати",
"load": "Завантажити",
"active": "активна",
"selected": "Обрані",
"delete": "Видалити",
"deleteModel": "Видалити модель",
"deleteConfig": "Видалити конфігурацію",
"deleteMsg1": "Ви точно хочете видалити модель із InvokeAI?",
"deleteMsg2": "Це не призведе до видалення файлу моделі з диску. Позніше ви можете додати його знову.",
"allModels": "Усі моделі",
"convert": "Конвертувати",
"convertToDiffusers": "Конвертувати в Diffusers",
"convertToDiffusersHelpText3": "Файл моделі на диску НЕ буде видалено або змінено. Ви можете знову додати його в Model Manager, якщо потрібно.",
"alpha": "Альфа",
"repo_id": "ID репозиторію",
"convertToDiffusersHelpText5": "Переконайтеся, що у вас достатньо місця на диску. Моделі зазвичай займають від 4 до 7 Гб.",
"convertToDiffusersHelpText6": "Ви хочете перетворити цю модель?",
"modelConverted": "Модель перетворено",
"none": "пусто",
"convertToDiffusersHelpText4": "Це одноразова дія. Вона може зайняти від 30 до 60 секунд в залежності від характеристик вашого комп'ютера.",
"convertToDiffusersHelpText1": "Ця модель буде конвертована в формат 🧨 Diffusers.",
"convertToDiffusersHelpText2": "Цей процес замінить ваш запис в Model Manager на версію тієї ж моделі в Diffusers."
},
"parameters": {
"images": "Зображення",
"steps": "Кроки",
"cfgScale": "Рівень CFG",
"width": "Ширина",
"height": "Висота",
"seed": "Сід",
"shuffle": "Оновити",
"noiseThreshold": "Поріг шуму",
"perlinNoise": "Шум Перліна",
"type": "Тип",
"strength": "Сила",
"upscaling": "Збільшення",
"scale": "Масштаб",
"imageFit": "Вмістити зображення",
"scaleBeforeProcessing": "Масштабувати",
"scaledWidth": "Масштаб Ш",
"scaledHeight": "Масштаб В",
"infillMethod": "Засіб заповнення",
"tileSize": "Розмір області",
"usePrompt": "Використати запит",
"useSeed": "Використати сід",
"useAll": "Використати все",
"info": "Метадані",
"general": "Основне",
"denoisingStrength": "Сила шумоподавлення",
"copyImage": "Копіювати зображення",
"symmetry": "Симетрія"
},
"settings": {
"models": "Моделі",
"displayInProgress": "Показувати процес генерації",
"confirmOnDelete": "Підтверджувати видалення",
"resetWebUI": "Повернути початкові",
"resetWebUIDesc1": "Скидання настройок веб-інтерфейсу видаляє лише локальний кеш браузера з вашими зображеннями та налаштуваннями. Це не призводить до видалення зображень з диску.",
"resetWebUIDesc2": "Якщо зображення не відображаються в галереї або не працює ще щось, спробуйте скинути налаштування, перш ніж повідомляти про проблему на GitHub.",
"resetComplete": "Інтерфейс скинуто. Оновіть цю сторінку."
},
"toast": {
"uploadFailed": "Не вдалося завантажити",
"imageCopied": "Зображення скопійоване",
"parametersNotSet": "Параметри не задані",
"serverError": "Помилка сервера",
"connected": "Підключено до сервера",
"canceled": "Обробку скасовано"
},
"accessibility": {
"nextImage": "Наступне зображення",
"invokeProgressBar": "Індикатор виконання",
"reset": "Скинути",
"uploadImage": "Завантажити зображення",
"previousImage": "Попереднє зображення",
"menu": "Меню"
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,204 @@
{
"common": {
"nodes": "工作流程",
"img2img": "圖片轉圖片",
"statusDisconnected": "已中斷連線",
"back": "返回",
"load": "載入",
"settingsLabel": "設定",
"upload": "上傳",
"discordLabel": "Discord",
"reportBugLabel": "回報錯誤",
"githubLabel": "GitHub",
"hotkeysLabel": "快捷鍵",
"languagePickerLabel": "語言",
"cancel": "取消",
"txt2img": "文字轉圖片",
"controlNet": "ControlNet",
"advanced": "進階",
"folder": "資料夾",
"installed": "已安裝",
"accept": "接受",
"input": "輸入",
"random": "隨機",
"selected": "已選擇",
"communityLabel": "社群",
"loading": "載入中",
"delete": "刪除",
"copy": "複製",
"error": "錯誤",
"file": "檔案",
"format": "格式"
},
"accessibility": {
"invokeProgressBar": "Invoke 進度條",
"uploadImage": "上傳圖片",
"reset": "重置",
"nextImage": "下一張圖片",
"previousImage": "上一張圖片",
"menu": "選單",
"about": "關於",
"createIssue": "建立問題",
"resetUI": "$t(accessibility.reset) 介面",
"submitSupportTicket": "提交支援工單",
"mode": "模式"
},
"boards": {
"loading": "載入中…",
"movingImagesToBoard_other": "正在移動 {{count}} 張圖片至板上:",
"move": "移動",
"uncategorized": "未分類",
"cancel": "取消"
},
"metadata": {
"workflow": "工作流程",
"steps": "步數",
"model": "模型",
"seed": "種子",
"vae": "VAE",
"metadata": "元數據",
"width": "寬度",
"height": "高度"
},
"accordions": {
"control": {
"title": "控制"
},
"compositing": {
"title": "合成"
},
"advanced": {
"title": "進階",
"options": "$t(accordions.advanced.title) 選項"
}
},
"modelManager": {
"advanced": "進階",
"allModels": "全部模型",
"variant": "變體",
"config": "配置",
"model": "模型",
"selected": "已選擇",
"huggingFace": "HuggingFace",
"install": "安裝",
"metadata": "元數據",
"delete": "刪除",
"description": "描述",
"cancel": "取消",
"convert": "轉換",
"manual": "手動",
"none": "無",
"name": "名稱",
"load": "載入",
"height": "高度",
"width": "寬度",
"search": "搜尋",
"vae": "VAE",
"settings": "設定"
},
"queue": {
"queue": "佇列",
"canceled": "已取消",
"failed": "已失敗",
"completed": "已完成",
"cancel": "取消",
"session": "工作階段",
"batch": "批量",
"item": "項目",
"completedIn": "完成於",
"notReady": "無法排隊"
},
"parameters": {
"cancel": {
"cancel": "取消"
},
"height": "高度",
"type": "類型",
"symmetry": "對稱性",
"images": "圖片",
"width": "寬度",
"coherenceMode": "模式",
"seed": "種子",
"general": "一般",
"strength": "強度",
"steps": "步數",
"info": "資訊"
},
"settings": {
"beta": "Beta",
"developer": "開發者",
"general": "一般",
"models": "模型"
},
"popovers": {
"paramModel": {
"heading": "模型"
},
"compositingCoherenceMode": {
"heading": "模式"
},
"paramSteps": {
"heading": "步數"
},
"controlNetProcessor": {
"heading": "處理器"
},
"paramVAE": {
"heading": "VAE"
},
"paramHeight": {
"heading": "高度"
},
"paramSeed": {
"heading": "種子"
},
"paramWidth": {
"heading": "寬度"
},
"refinerSteps": {
"heading": "步數"
}
},
"nodes": {
"workflowName": "名稱",
"notes": "註釋",
"workflowVersion": "版本",
"workflowNotes": "註釋",
"executionStateError": "錯誤",
"unableToUpdateNodes_other": "無法更新 {{count}} 個節點",
"integer": "整數",
"workflow": "工作流程",
"enum": "枚舉",
"edit": "編輯",
"string": "字串",
"workflowTags": "標籤",
"node": "節點",
"boolean": "布林值",
"workflowAuthor": "作者",
"version": "版本",
"executionStateCompleted": "已完成",
"edge": "邊緣"
},
"sdxl": {
"steps": "步數",
"loading": "載入中…",
"refiner": "精煉器"
},
"gallery": {
"copy": "複製",
"download": "下載",
"loading": "載入中"
},
"ui": {
"tabs": {
"models": "模型",
"queue": "佇列"
}
},
"models": {
"loading": "載入中"
},
"workflows": {
"name": "名稱"
}
}
@@ -0,0 +1,89 @@
# Cleans translations by removing unused keys
# Usage: python clean_translations.py
# Note: Must be run from invokeai/frontend/web/scripts directory
#
# After running the script, open `en.json` and check for empty objects (`{}`) and remove them manually.
# Also, the script does not handle keys with underscores. They need to be checked manually.
import json
import os
import re
from typing import TypeAlias, Union
from tqdm import tqdm
RecursiveDict: TypeAlias = dict[str, Union["RecursiveDict", str]]
class TranslationCleaner:
file_cache: dict[str, str] = {}
def _get_keys(self, obj: RecursiveDict, current_path: str = "", keys: list[str] | None = None):
if keys is None:
keys = []
for key in obj:
new_path = f"{current_path}.{key}" if current_path else key
next_ = obj[key]
if isinstance(next_, dict):
self._get_keys(next_, new_path, keys)
elif "_" in key:
# This typically means its a pluralized key
continue
else:
keys.append(new_path)
return keys
def _search_codebase(self, key: str):
for root, _dirs, files in os.walk("../src"):
for file in files:
if file.endswith(".ts") or file.endswith(".tsx"):
full_path = os.path.join(root, file)
if full_path in self.file_cache:
content = self.file_cache[full_path]
else:
with open(full_path, "r") as f:
content = f.read()
self.file_cache[full_path] = content
# match the whole key, surrounding by quotes
if re.search(r"['\"`]" + re.escape(key) + r"['\"`]", self.file_cache[full_path]):
return True
# math the stem of the key, with quotes at the end
if re.search(re.escape(key.split(".")[-1]) + r"['\"`]", self.file_cache[full_path]):
return True
return False
def _remove_key(self, obj: RecursiveDict, key: str):
path = key.split(".")
last_key = path[-1]
for k in path[:-1]:
obj = obj[k]
del obj[last_key]
def clean(self, obj: RecursiveDict) -> RecursiveDict:
keys = self._get_keys(obj)
pbar = tqdm(keys, desc="Checking keys")
for key in pbar:
if not self._search_codebase(key):
self._remove_key(obj, key)
return obj
def main():
try:
with open("../public/locales/en.json", "r") as f:
data = json.load(f)
except FileNotFoundError as e:
raise FileNotFoundError(
"Unable to find en.json file - must be run from invokeai/frontend/web/scripts directory"
) from e
cleaner = TranslationCleaner()
cleaned_data = cleaner.clean(data)
with open("../public/locales/en.json", "w") as f:
json.dump(cleaned_data, f, indent=4)
if __name__ == "__main__":
main()
@@ -0,0 +1,4 @@
{
"type": "module",
"packageManager": "pnpm@10.12.4"
}
+104
View File
@@ -0,0 +1,104 @@
/* eslint-disable no-console */
import fs from 'node:fs';
import openapiTS, { astToString } from 'openapi-typescript';
import ts from 'typescript';
const OPENAPI_URL = 'http://127.0.0.1:9090/openapi.json';
const OUTPUT_FILE = 'src/services/api/schema.ts';
async function generateTypes(schema) {
process.stdout.write(`Generating types ${OUTPUT_FILE}...`);
// Use https://ts-ast-viewer.com to figure out how to create these AST nodes - define a type and use the bottom-left pane's output
// `Blob` type
const BLOB = ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Blob'));
// `null` type
const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull());
// `Record<string, unknown>` type
const RECORD_STRING_UNKNOWN = ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Record'), [
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
]);
const types = await openapiTS(schema, {
exportType: true,
transform: (schemaObject) => {
if ('format' in schemaObject && schemaObject.format === 'binary') {
return schemaObject.nullable ? ts.factory.createUnionTypeNode([BLOB, NULL]) : BLOB;
}
if (schemaObject.title === 'MetadataField') {
// This is `Record<string, never>` by default, but it actually accepts any a dict of any valid JSON value.
return RECORD_STRING_UNKNOWN;
}
},
defaultNonNullable: false,
});
let output = astToString(types);
// Post-process: openapi-typescript sometimes computes enum types from `const`
// usage in discriminated unions rather than from the enum definition itself,
// dropping values that only appear in some union members. Patch the generated
// output to match the OpenAPI schema's actual enum definitions.
//
// The `schema` parameter is a parsed JSON object when piped from stdin, or
// a URL/Buffer when passed as an argument. We only patch in the JSON case.
if (schema && typeof schema === 'object' && !Buffer.isBuffer(schema)) {
const schemas = schema.components?.schemas;
if (schemas) {
// Collect all string enum types and their expected values from the OpenAPI schema
for (const [typeName, typeDef] of Object.entries(schemas)) {
if (typeDef && typeDef.type === 'string' && Array.isArray(typeDef.enum)) {
const expectedUnion = typeDef.enum.map((v) => `"${v}"`).join(' | ');
// Match the type definition line. These appear as:
// `TypeName: "val1" | "val2" | ...;`
// Use word boundary to avoid matching types that contain this
// type name as a substring (e.g. ModelType vs BaseModelType).
const regex = new RegExp(`(\\b${typeName}: )"[^;]+(;)`);
const match = output.match(regex);
if (match) {
output = output.replace(regex, `$1${expectedUnion}$2`);
}
}
}
}
}
fs.writeFileSync(OUTPUT_FILE, output);
process.stdout.write(`\nOK!\r\n`);
}
function main() {
const encoding = 'utf-8';
if (process.stdin.isTTY) {
// Handle generating types with an arg (e.g. URL or path to file)
if (process.argv.length > 3) {
console.error('Usage: typegen.js <openapi.json>');
process.exit(1);
}
if (process.argv[2]) {
const schema = new Buffer.from(process.argv[2], encoding);
generateTypes(schema);
} else {
generateTypes(OPENAPI_URL);
}
} else {
// Handle generating types from stdin
let schema = '';
process.stdin.setEncoding(encoding);
process.stdin.on('readable', function () {
const chunk = process.stdin.read();
if (chunk !== null) {
schema += chunk;
}
});
process.stdin.on('end', function () {
generateTypes(JSON.parse(schema));
});
}
}
main();
@@ -0,0 +1,124 @@
import { Box, Center, Spinner } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { GlobalHookIsolator } from 'app/components/GlobalHookIsolator';
import { GlobalModalIsolator } from 'app/components/GlobalModalIsolator';
import { clearStorage } from 'app/store/enhancers/reduxRemember/driver';
import Loading from 'common/components/Loading/Loading';
import { AdministratorSetup } from 'features/auth/components/AdministratorSetup';
import { LoginPage } from 'features/auth/components/LoginPage';
import { ProtectedRoute } from 'features/auth/components/ProtectedRoute';
import { UserManagement } from 'features/auth/components/UserManagement';
import { UserProfile } from 'features/auth/components/UserProfile';
import { AppContent } from 'features/ui/components/AppContent';
import { navigationApi } from 'features/ui/layouts/navigation-api';
import type { ReactNode } from 'react';
import { memo, useEffect } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Route, Routes, useNavigate } from 'react-router-dom';
import { useGetSetupStatusQuery } from 'services/api/endpoints/auth';
import AppErrorBoundaryFallback from './AppErrorBoundaryFallback';
import ThemeLocaleProvider from './ThemeLocaleProvider';
const errorBoundaryOnReset = () => {
clearStorage();
location.reload();
return false;
};
const MainApp = () => {
const isNavigationAPIConnected = useStore(navigationApi.$isConnected);
return (
<Box id="invoke-app-wrapper" w="100dvw" h="100dvh" position="relative" overflow="hidden">
{isNavigationAPIConnected ? <AppContent /> : <Loading />}
</Box>
);
};
const SetupChecker = () => {
const { data, isLoading } = useGetSetupStatusQuery();
const navigate = useNavigate();
// Check if user is already authenticated
const token = localStorage.getItem('auth_token');
const isAuthenticated = !!token;
useEffect(() => {
if (!isLoading && data) {
// If multiuser mode is disabled, go directly to the app
if (!data.multiuser_enabled) {
navigate('/app', { replace: true });
} else if (isAuthenticated) {
// In multiuser mode, check authentication
navigate('/app', { replace: true });
} else if (data.setup_required) {
navigate('/setup', { replace: true });
} else {
navigate('/login', { replace: true });
}
}
}, [data, isLoading, navigate, isAuthenticated]);
if (isLoading) {
return (
<Center w="100dvw" h="100dvh">
<Spinner size="xl" />
</Center>
);
}
return null;
};
/** Full-page wrapper for user management / profile pages rendered inside the protected area */
const FullPageWrapper = ({ children }: { children: ReactNode }) => (
<Box w="100dvw" h="100dvh" overflowY="auto" bg="base.900">
{children}
</Box>
);
const App = () => {
return (
<ThemeLocaleProvider>
<ErrorBoundary onReset={errorBoundaryOnReset} FallbackComponent={AppErrorBoundaryFallback}>
<Routes>
<Route path="/" element={<SetupChecker />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/setup" element={<AdministratorSetup />} />
<Route
path="/profile"
element={
<ProtectedRoute>
<FullPageWrapper>
<UserProfile />
</FullPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/users"
element={
<ProtectedRoute requireAdmin>
<FullPageWrapper>
<UserManagement />
</FullPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/*"
element={
<ProtectedRoute>
<MainApp />
</ProtectedRoute>
}
/>
</Routes>
<GlobalHookIsolator />
<GlobalModalIsolator />
</ErrorBoundary>
</ThemeLocaleProvider>
);
};
export default memo(App);
@@ -0,0 +1,76 @@
import { Button, Flex, Heading, Image, Link, Text } from '@invoke-ai/ui-library';
import { useClipboard } from 'common/hooks/useClipboard';
import { toast } from 'features/toast/toast';
import newGithubIssueUrl from 'new-github-issue-url';
import InvokeLogoYellow from 'public/assets/images/invoke-symbol-ylw-lrg.svg';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowCounterClockwiseBold, PiArrowSquareOutBold, PiCopyBold } from 'react-icons/pi';
import { serializeError } from 'serialize-error';
type Props = {
error: Error;
resetErrorBoundary: () => void;
};
const AppErrorBoundaryFallback = ({ error, resetErrorBoundary }: Props) => {
const { t } = useTranslation();
const clipboard = useClipboard();
const handleCopy = useCallback(() => {
const text = JSON.stringify(serializeError(error), null, 2);
clipboard.writeText(`\`\`\`\n${text}\n\`\`\``, () => {
toast({
id: 'ERROR_COPIED',
title: t('toast.errorCopied'),
});
});
}, [clipboard, error, t]);
const url = useMemo(() => {
return newGithubIssueUrl({
user: 'invoke-ai',
repo: 'InvokeAI',
template: 'BUG_REPORT.yml',
title: `[bug]: ${error.name}: ${error.message}`,
});
}, [error.message, error.name]);
return (
<Flex layerStyle="body" w="100dvw" h="100dvh" alignItems="center" justifyContent="center" p={4}>
<Flex layerStyle="first" flexDir="column" borderRadius="base" justifyContent="center" gap={8} p={16}>
<Flex alignItems="center" gap="2">
<Image src={InvokeLogoYellow} alt="invoke-logo" w="24px" h="24px" minW="24px" minH="24px" userSelect="none" />
<Heading fontSize="2xl">{t('common.somethingWentWrong')}</Heading>
</Flex>
<Flex
layerStyle="second"
px={8}
py={4}
gap={4}
borderRadius="base"
justifyContent="space-between"
alignItems="center"
>
<Text fontWeight="semibold" color="error.400">
{error.name}: {error.message}
</Text>
</Flex>
<Flex gap={4}>
<Button leftIcon={<PiArrowCounterClockwiseBold />} onClick={resetErrorBoundary}>
{t('accessibility.resetUI')}
</Button>
<Button leftIcon={<PiCopyBold />} onClick={handleCopy}>
{t('common.copyError')}
</Button>
<Link href={url} isExternal>
<Button leftIcon={<PiArrowSquareOutBold />}>{t('accessibility.createIssue')}</Button>
</Link>
</Flex>
</Flex>
</Flex>
);
};
export default memo(AppErrorBoundaryFallback);
@@ -0,0 +1,76 @@
import { useGlobalModifiersInit } from '@invoke-ai/ui-library';
import { setupListeners } from '@reduxjs/toolkit/query';
import { useSyncFaviconQueueStatus } from 'app/hooks/useSyncFaviconQueueStatus';
import { useSyncLangDirection } from 'app/hooks/useSyncLangDirection';
import { useSyncLoggingConfig } from 'app/logging/useSyncLoggingConfig';
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useFocusRegionWatcher } from 'common/hooks/focus';
import { useCloseChakraTooltipsOnDragFix } from 'common/hooks/useCloseChakraTooltipsOnDragFix';
import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
import { useTouchDeviceClass } from 'common/hooks/useTouchDeviceClass';
import { useDndMonitor } from 'features/dnd/useDndMonitor';
import { useDynamicPromptsWatcher } from 'features/dynamicPrompts/hooks/useDynamicPromptsWatcher';
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
import { useWorkflowBuilderWatcher } from 'features/nodes/components/sidePanel/workflow/IsolatedWorkflowBuilderWatcher';
import { useSyncExecutionState } from 'features/nodes/hooks/useNodeExecutionState';
import { useSyncNodeErrors } from 'features/nodes/store/util/fieldValidators';
import { useReadinessWatcher } from 'features/queue/store/readiness';
import { selectLanguage } from 'features/system/store/systemSelectors';
import { useNavigationApi } from 'features/ui/layouts/use-navigation-api';
import i18n from 'i18n';
import { memo, useEffect } from 'react';
import { useGetOpenAPISchemaQuery } from 'services/api/endpoints/appInfo';
import { useGetQueueCountsByDestinationQuery } from 'services/api/endpoints/queue';
import { useSocketIO } from 'services/events/useSocketIO';
const queueCountArg = { destination: 'canvas' };
/**
* GlobalHookIsolator is a logical component that runs global hooks in an isolated component, so that they do not
* cause needless re-renders of any other components.
*/
export const GlobalHookIsolator = memo(() => {
const language = useAppSelector(selectLanguage);
const dispatch = useAppDispatch();
// singleton!
useNavigationApi();
useReadinessWatcher();
useSocketIO();
useGlobalModifiersInit();
useGlobalHotkeys();
useGetOpenAPISchemaQuery();
useSyncLoggingConfig();
useCloseChakraTooltipsOnDragFix();
useTouchDeviceClass();
useDndMonitor();
useSyncNodeErrors();
useSyncLangDirection();
// Persistent subscription to the queue counts query - canvas relies on this to know if there are pending
// and/or in progress canvas sessions.
useGetQueueCountsByDestinationQuery(queueCountArg);
useSyncExecutionState();
useEffect(() => {
i18n.changeLanguage(language);
}, [language]);
useEffect(() => {
dispatch(appStarted());
}, [dispatch]);
useEffect(() => {
return setupListeners(dispatch);
}, [dispatch]);
useStarterModelsToast();
useSyncFaviconQueueStatus();
useFocusRegionWatcher();
useWorkflowBuilderWatcher();
useDynamicPromptsWatcher();
return null;
});
GlobalHookIsolator.displayName = 'GlobalHookIsolator';
@@ -0,0 +1,94 @@
import { useAppSelector } from 'app/store/storeHooks';
import { useIsRegionFocused } from 'common/hooks/focus';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { useLoadWorkflow } from 'features/gallery/hooks/useLoadWorkflow';
import { useRecallAll } from 'features/gallery/hooks/useRecallAllImageMetadata';
import { useRecallDimensions } from 'features/gallery/hooks/useRecallDimensions';
import { useRecallPrompts } from 'features/gallery/hooks/useRecallPrompts';
import { useRecallRemix } from 'features/gallery/hooks/useRecallRemix';
import { useRecallSeed } from 'features/gallery/hooks/useRecallSeed';
import { selectLastSelectedItem } from 'features/gallery/store/gallerySelectors';
import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData';
import { memo } from 'react';
import { useImageDTO } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types';
export const GlobalImageHotkeys = memo(() => {
useAssertSingleton('GlobalImageHotkeys');
const lastSelectedItem = useAppSelector(selectLastSelectedItem);
const imageDTO = useImageDTO(lastSelectedItem ?? null);
if (!imageDTO) {
return null;
}
return <GlobalImageHotkeysInternal imageDTO={imageDTO} />;
});
GlobalImageHotkeys.displayName = 'GlobalImageHotkeys';
const GlobalImageHotkeysInternal = memo(({ imageDTO }: { imageDTO: ImageDTO }) => {
const isGalleryFocused = useIsRegionFocused('gallery');
const isViewerFocused = useIsRegionFocused('viewer');
const isFocusOK = isGalleryFocused || isViewerFocused;
const recallAll = useRecallAll(imageDTO);
const recallRemix = useRecallRemix(imageDTO);
const recallPrompts = useRecallPrompts(imageDTO);
const recallSeed = useRecallSeed(imageDTO);
const recallDimensions = useRecallDimensions(imageDTO);
const loadWorkflow = useLoadWorkflow(imageDTO);
useRegisteredHotkeys({
id: 'loadWorkflow',
category: 'viewer',
callback: loadWorkflow.load,
options: { enabled: loadWorkflow.isEnabled && isFocusOK },
dependencies: [loadWorkflow, isFocusOK],
});
useRegisteredHotkeys({
id: 'recallAll',
category: 'viewer',
callback: recallAll.recall,
options: { enabled: recallAll.isEnabled && isFocusOK },
dependencies: [recallAll, isFocusOK],
});
useRegisteredHotkeys({
id: 'recallSeed',
category: 'viewer',
callback: recallSeed.recall,
options: { enabled: recallSeed.isEnabled && isFocusOK },
dependencies: [recallSeed, isFocusOK],
});
useRegisteredHotkeys({
id: 'recallPrompts',
category: 'viewer',
callback: recallPrompts.recall,
options: { enabled: recallPrompts.isEnabled && isFocusOK },
dependencies: [recallPrompts, isFocusOK],
});
useRegisteredHotkeys({
id: 'remix',
category: 'viewer',
callback: recallRemix.recall,
options: { enabled: recallRemix.isEnabled && isFocusOK },
dependencies: [recallRemix, isFocusOK],
});
useRegisteredHotkeys({
id: 'useSize',
category: 'viewer',
callback: recallDimensions.recall,
options: { enabled: recallDimensions.isEnabled && isFocusOK },
dependencies: [recallDimensions, isFocusOK],
});
return null;
});
GlobalImageHotkeysInternal.displayName = 'GlobalImageHotkeysInternal';
@@ -0,0 +1,66 @@
import { GlobalImageHotkeys } from 'app/components/GlobalImageHotkeys';
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
import { CanvasPasteModal } from 'features/controlLayers/components/CanvasPasteModal';
import { CanvasWorkflowIntegrationModal } from 'features/controlLayers/components/CanvasWorkflowIntegration/CanvasWorkflowIntegrationModal';
import { LoadCanvasProjectConfirmationAlertDialog } from 'features/controlLayers/components/LoadCanvasProjectConfirmationAlertDialog';
import { SaveCanvasProjectDialog } from 'features/controlLayers/components/SaveCanvasProjectDialog';
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
import { CropImageModal } from 'features/cropper/components/CropImageModal';
import { DeleteImageModal } from 'features/deleteImageModal/components/DeleteImageModal';
import { FullscreenDropzone } from 'features/dnd/FullscreenDropzone';
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal';
import { ImageContextMenu } from 'features/gallery/components/ContextMenu/ImageContextMenu';
import { WorkflowLibraryModal } from 'features/nodes/components/sidePanel/workflow/WorkflowLibrary/WorkflowLibraryModal';
import { CancelAllExceptCurrentQueueItemConfirmationAlertDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
import { ClearQueueConfirmationsAlertDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { DeleteAllExceptCurrentQueueItemConfirmationAlertDialog } from 'features/queue/components/DeleteAllExceptCurrentQueueItemConfirmationAlertDialog';
import { DeleteStylePresetDialog } from 'features/stylePresets/components/DeleteStylePresetDialog';
import { StylePresetModal } from 'features/stylePresets/components/StylePresetForm/StylePresetModal';
import RefreshAfterResetModal from 'features/system/components/SettingsModal/RefreshAfterResetModal';
import { VideosModal } from 'features/system/components/VideosModal/VideosModal';
import { DeleteWorkflowDialog } from 'features/workflowLibrary/components/DeleteLibraryWorkflowConfirmationAlertDialog';
import { LoadWorkflowConfirmationAlertDialog } from 'features/workflowLibrary/components/LoadWorkflowConfirmationAlertDialog';
import { LoadWorkflowFromGraphModal } from 'features/workflowLibrary/components/LoadWorkflowFromGraphModal/LoadWorkflowFromGraphModal';
import { NewWorkflowConfirmationAlertDialog } from 'features/workflowLibrary/components/NewWorkflowConfirmationAlertDialog';
import { SaveWorkflowAsDialog } from 'features/workflowLibrary/components/SaveWorkflowAsDialog';
import { memo } from 'react';
/**
* GlobalModalIsolator is a logical component that isolates global modal components, so that they do not cause needless
* re-renders of any other components.
*/
export const GlobalModalIsolator = memo(() => {
return (
<>
<DeleteImageModal />
<ChangeBoardModal />
<DynamicPromptsModal />
<StylePresetModal />
<WorkflowLibraryModal />
<CancelAllExceptCurrentQueueItemConfirmationAlertDialog />
<DeleteAllExceptCurrentQueueItemConfirmationAlertDialog />
<ClearQueueConfirmationsAlertDialog />
<NewWorkflowConfirmationAlertDialog />
<LoadWorkflowConfirmationAlertDialog />
<DeleteStylePresetDialog />
<DeleteWorkflowDialog />
<RefreshAfterResetModal />
<DeleteBoardModal />
<GlobalImageHotkeys />
<ImageContextMenu />
<FullscreenDropzone />
<VideosModal />
<SaveWorkflowAsDialog />
<CanvasManagerProviderGate>
<CanvasPasteModal />
<CanvasWorkflowIntegrationModal />
</CanvasManagerProviderGate>
<SaveCanvasProjectDialog />
<LoadCanvasProjectConfirmationAlertDialog />
<LoadWorkflowFromGraphModal />
<CropImageModal />
</>
);
});
GlobalModalIsolator.displayName = 'GlobalModalIsolator';
@@ -0,0 +1,61 @@
import 'i18n';
import { configureLogging } from 'app/logging/logger';
import { addStorageListeners } from 'app/store/enhancers/reduxRemember/driver';
import { $store } from 'app/store/nanostores/store';
import { createStore } from 'app/store/store';
import Loading from 'common/components/Loading/Loading';
import React, { lazy, useEffect, useState } from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
/*
* We need to configure logging before anything else happens - useLayoutEffect ensures we set this at the first
* possible opportunity.
*
* Once redux initializes, we will check the user's settings and update the logging config accordingly. See
* `useSyncLoggingConfig`.
*/
configureLogging(true, 'debug', '*');
const App = lazy(() => import('./App'));
const InvokeAIUI = () => {
const [didRehydrate, setDidRehydrate] = useState(false);
const [store] = useState(() =>
createStore({ persist: true, persistDebounce: 300, onRehydrated: () => setDidRehydrate(true) })
);
useEffect(() => {
$store.set(store);
if (import.meta.env.MODE === 'development') {
window.$store = $store;
}
const removeStorageListeners = addStorageListeners();
return () => {
removeStorageListeners();
$store.set(undefined);
if (import.meta.env.MODE === 'development') {
window.$store = undefined;
}
};
}, [store]);
if (!didRehydrate) {
return <Loading />;
}
return (
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<React.Suspense fallback={<Loading />}>
<App />
</React.Suspense>
</BrowserRouter>
</Provider>
</React.StrictMode>
);
};
export default InvokeAIUI;
@@ -0,0 +1,48 @@
import '@fontsource-variable/inter';
import 'overlayscrollbars/overlayscrollbars.css';
import '@xyflow/react/dist/base.css';
import 'common/components/OverlayScrollbars/overlayscrollbars.css';
import 'app/components/touchDevice.css';
import { ChakraProvider, DarkMode, extendTheme, theme as baseTheme, TOAST_OPTIONS } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { $direction } from 'app/hooks/useSyncLangDirection';
import type { ReactNode } from 'react';
import { memo, useMemo } from 'react';
type ThemeLocaleProviderProps = {
children: ReactNode;
};
const buildTheme = (direction: 'ltr' | 'rtl') => {
return extendTheme({
...baseTheme,
direction,
shadows: {
...baseTheme.shadows,
selected:
'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-500), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)',
hoverSelected:
'inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-400), inset 0px 0px 0px 4px var(--invoke-colors-invokeBlue-800)',
hoverUnselected:
'inset 0px 0px 0px 2px var(--invoke-colors-invokeBlue-300), inset 0px 0px 0px 3px var(--invoke-colors-invokeBlue-800)',
selectedForCompare:
'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-300), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)',
hoverSelectedForCompare:
'inset 0px 0px 0px 3px var(--invoke-colors-invokeGreen-200), inset 0px 0px 0px 4px var(--invoke-colors-invokeGreen-800)',
},
});
};
function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
const direction = useStore($direction);
const theme = useMemo(() => buildTheme(direction), [direction]);
return (
<ChakraProvider theme={theme} toastOptions={TOAST_OPTIONS}>
<DarkMode>{children}</DarkMode>
</ChakraProvider>
);
}
export default memo(ThemeLocaleProvider);
@@ -0,0 +1,5 @@
/* Hide tooltips after touch input, where hover can get stuck. */
.invokeai-touch-device [role='tooltip'] {
visibility: hidden !important;
opacity: 0 !important;
}
@@ -0,0 +1,15 @@
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
const css = readFileSync(new URL('./touchDevice.css', import.meta.url), 'utf8');
describe('touchDevice.css', () => {
it('hides tooltips only after touch input has been detected', () => {
expect(css).toMatch(/\.invokeai-touch-device\s+\[role='tooltip'\]\s*{/);
});
it('does not force all tooltips invisible', () => {
expect(css).not.toMatch(/@media\s*\([^)]*hover[^)]*\)/);
});
});
@@ -0,0 +1,2 @@
export const NUMPY_RAND_MIN = 0;
export const NUMPY_RAND_MAX = 4294967295;
@@ -0,0 +1,11 @@
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
const eslintConfig = readFileSync(new URL('../../eslint.config.mjs', import.meta.url), 'utf8');
describe('eslint config', () => {
it('includes React Compiler diagnostics from eslint-plugin-react-hooks', () => {
expect(eslintConfig).toContain("pluginReactHooks.configs['recommended-latest'].rules");
});
});
@@ -0,0 +1,33 @@
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { useEffect } from 'react';
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
const baseTitle = document.title;
const invokeLogoSVG = 'assets/images/invoke-favicon.svg';
const invokeAlertLogoSVG = 'assets/images/invoke-alert-favicon.svg';
const queryOptions = {
selectFromResult: (res) => ({
queueSize: res.data ? res.data.queue.pending + res.data.queue.in_progress : 0,
}),
} satisfies Parameters<typeof useGetQueueStatusQuery>[1];
const updateFavicon = (queueSize: number) => {
document.title = queueSize > 0 ? `(${queueSize}) ${baseTitle}` : baseTitle;
const faviconEl = document.getElementById('invoke-favicon');
if (faviconEl instanceof HTMLLinkElement) {
faviconEl.href = queueSize > 0 ? invokeAlertLogoSVG : invokeLogoSVG;
}
};
/**
* This hook synchronizes the queue status with the page's title and favicon.
* It should be considered a singleton and only used once in the component tree.
*/
export const useSyncFaviconQueueStatus = () => {
useAssertSingleton('useSyncFaviconQueueStatus');
const { queueSize } = useGetQueueStatusQuery(undefined, queryOptions);
useEffect(() => {
updateFavicon(queueSize);
}, [queueSize]);
};
@@ -0,0 +1,36 @@
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { atom } from 'nanostores';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
/**
* Global atom storing the language direction, to be consumed by the Chakra theme.
*
* Why do we need this? We have a kind of catch-22:
* - The Chakra theme needs to know the language direction to apply the correct styles.
* - The language direction is determined by i18n and the language selection.
* - We want our error boundary to be themed.
* - It's possible that i18n can throw if the language selection is invalid or not supported.
*
* Previously, we had the logic in this file in the theme provider, which wrapped the error boundary. The error
* was properly themed. But then, if i18n threw in the theme provider, the error boundary does not catch the
* error. The app would crash to a white screen.
*
* We tried swapping the component hierarchy so that the error boundary wraps the theme provider, but then the
* error boundary isn't themed!
*
* The solution is to move this i18n direction logic out of the theme provider and into a hook that we can use
* within the error boundary. The error boundary will be themed, _and_ catch any i18n errors.
*/
export const $direction = atom<'ltr' | 'rtl'>('ltr');
export const useSyncLangDirection = () => {
useAssertSingleton('useSyncLangDirection');
const { i18n, t } = useTranslation();
useEffect(() => {
const direction = i18n.dir();
$direction.set(direction);
document.body.dir = direction;
}, [i18n, t]);
};
@@ -0,0 +1,86 @@
import { createLogWriter } from '@roarr/browser-log-writer';
import { atom } from 'nanostores';
import type { Logger, MessageSerializer } from 'roarr';
import { ROARR, Roarr } from 'roarr';
import { z } from 'zod';
const serializeMessage: MessageSerializer = (message) => {
return JSON.stringify(message);
};
ROARR.serializeMessage = serializeMessage;
const BASE_CONTEXT = {};
const $logger = atom<Logger>(Roarr.child(BASE_CONTEXT));
export const zLogNamespace = z.enum([
'canvas',
'canvas-workflow-integration',
'config',
'dnd',
'events',
'gallery',
'generation',
'metadata',
'models',
'system',
'queue',
'workflows',
]);
export type LogNamespace = z.infer<typeof zLogNamespace>;
export const logger = (namespace: LogNamespace) => $logger.get().child({ namespace });
export const zLogLevel = z.enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal']);
export type LogLevel = z.infer<typeof zLogLevel>;
export const isLogLevel = (v: unknown): v is LogLevel => zLogLevel.safeParse(v).success;
// Translate human-readable log levels to numbers, used for log filtering
const LOG_LEVEL_MAP: Record<LogLevel, number> = {
trace: 10,
debug: 20,
info: 30,
warn: 40,
error: 50,
fatal: 60,
};
/**
* Configure logging, pushing settings to local storage.
*
* @param logIsEnabled Whether logging is enabled
* @param logLevel The log level
* @param logNamespaces A list of log namespaces to enable, or '*' to enable all
*/
export const configureLogging = (
logIsEnabled: boolean = true,
logLevel: LogLevel = 'warn',
logNamespaces: LogNamespace[] | '*'
): void => {
if (!logIsEnabled) {
// Disable console log output
localStorage.setItem('ROARR_LOG', 'false');
} else {
// Enable console log output
localStorage.setItem('ROARR_LOG', 'true');
// Use a filter to show only logs of the given level
let filter = `context.logLevel:>=${LOG_LEVEL_MAP[logLevel]}`;
const namespaces = logNamespaces === '*' ? zLogNamespace.options : logNamespaces;
if (namespaces.length > 0) {
filter += ` AND (${namespaces.map((ns) => `context.namespace:${ns}`).join(' OR ')})`;
} else {
// This effectively hides all logs because we use namespaces for all logs
filter += ' AND context.namespace:undefined';
}
localStorage.setItem('ROARR_FILTER', filter);
}
const styleOutput = localStorage.getItem('ROARR_STYLE_OUTPUT') === 'false' ? false : true;
ROARR.write = createLogWriter({ styleOutput });
};
@@ -0,0 +1,29 @@
import { configureLogging } from 'app/logging/logger';
import { useAppSelector } from 'app/store/storeHooks';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import {
selectSystemLogIsEnabled,
selectSystemLogLevel,
selectSystemLogNamespaces,
} from 'features/system/store/systemSlice';
import { useLayoutEffect } from 'react';
/**
* This hook synchronizes the logging configuration stored in Redux with the logging system, which uses localstorage.
*
* The sync is one-way: from Redux to localstorage. This means that changes made in the UI will be reflected in the
* logging system, but changes made directly to localstorage will not be reflected in the UI.
*
* See {@link configureLogging}
*/
export const useSyncLoggingConfig = () => {
useAssertSingleton('useSyncLoggingConfig');
const logLevel = useAppSelector(selectSystemLogLevel);
const logNamespaces = useAppSelector(selectSystemLogNamespaces);
const logIsEnabled = useAppSelector(selectSystemLogIsEnabled);
useLayoutEffect(() => {
configureLogging(logIsEnabled, logLevel, logNamespaces);
}, [logIsEnabled, logLevel, logNamespaces]);
};
@@ -0,0 +1,2 @@
export const EMPTY_ARRAY = [];
export const EMPTY_OBJECT = {};
@@ -0,0 +1,20 @@
import { objectEquals } from '@observ33r/object-equals';
import { createDraftSafeSelectorCreator, createSelectorCreator, lruMemoize } from '@reduxjs/toolkit';
/**
* A memoized selector creator that uses LRU cache and @observ33r/object-equals's objectEquals for equality check.
*/
export const createMemoizedSelector = createSelectorCreator({
memoize: lruMemoize,
memoizeOptions: {
resultEqualityCheck: objectEquals,
},
argsMemoize: lruMemoize,
});
export const getSelectorsOptions = {
createSelector: createDraftSafeSelectorCreator({
memoize: lruMemoize,
argsMemoize: lruMemoize,
}),
};
@@ -0,0 +1,211 @@
import { logger } from 'app/logging/logger';
import { StorageError } from 'app/store/enhancers/reduxRemember/errors';
import type { UseStore } from 'idb-keyval';
import { createStore as idbCreateStore, del as idbDel, get as idbGet } from 'idb-keyval';
import type { Driver } from 'redux-remember';
import { serializeError } from 'serialize-error';
import { buildV1Url, getBaseUrl } from 'services/api';
import type { JsonObject } from 'type-fest';
const log = logger('system');
const getUrl = (endpoint: 'get_by_key' | 'set_by_key' | 'delete', key?: string) => {
const baseUrl = getBaseUrl();
const query: Record<string, string> = {};
if (key) {
query['key'] = key;
}
const path = buildV1Url(`client_state/default/${endpoint}`, query);
const url = `${baseUrl}/${path}`;
return url;
};
// Persistence happens per slice. To track when persistence is in progress, maintain a ref count, incrementing
// it when a slice is being persisted and decrementing it when the persistence is done.
let persistRefCount = 0;
// Keep track of the last persisted state for each key to avoid unnecessary network requests.
//
// `redux-remember` persists individual slices of state, so we can implicity denylist a slice by not giving it a
// persist config.
//
// However, we may need to avoid persisting individual _fields_ of a slice. `redux-remember` does not provide a
// way to do this directly.
//
// To accomplish this, we add a layer of logic on top of the `redux-remember`. In the state serializer function
// provided to `redux-remember`, we can omit certain fields from the state that we do not want to persist. See
// the implementation in `store.ts` for this logic.
//
// This logic is unknown to `redux-remember`. When an omitted field changes, it will still attempt to persist the
// whole slice, even if the final, _serialized_ slice value is unchanged.
//
// To avoid unnecessary network requests, we keep track of the last persisted state for each key in this map.
// If the value to be persisted is the same as the last persisted value, we will skip the network request.
const lastPersistedState = new Map<string, string | undefined>();
// As of v6.3.0, we use server-backed storage for client state. This replaces the previous IndexedDB-based storage,
// which was implemented using `idb-keyval`.
//
// To facilitate a smooth transition, we implement a migration strategy that attempts to retrieve values from IndexedDB
// and persist them to the new server-backed storage. This is done on a best-effort basis.
// These constants were used in the previous IndexedDB-based storage implementation.
const IDB_DB_NAME = 'invoke';
const IDB_STORE_NAME = 'invoke-store';
const IDB_STORAGE_PREFIX = '@@invokeai-';
// Lazy store creation
let _idbKeyValStore: UseStore | null = null;
const getIdbKeyValStore = () => {
if (_idbKeyValStore === null) {
_idbKeyValStore = idbCreateStore(IDB_DB_NAME, IDB_STORE_NAME);
}
return _idbKeyValStore;
};
const getIdbKey = (key: string) => {
return `${IDB_STORAGE_PREFIX}${key}`;
};
// Helper to get auth headers for client_state requests
const getAuthHeaders = (): Record<string, string> => {
const headers: Record<string, string> = {};
// Safe access to localStorage (not available in Node.js test environment)
if (typeof window !== 'undefined' && window.localStorage) {
const token = localStorage.getItem('auth_token');
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
}
return headers;
};
const getItem = async (key: string) => {
try {
const url = getUrl('get_by_key', key);
const res = await fetch(url, {
method: 'GET',
headers: getAuthHeaders(),
});
if (!res.ok) {
throw new Error(`Response status: ${res.status}`);
}
const value = await res.json();
// Best-effort migration from IndexedDB to the new storage system
log.trace({ key, value }, 'Server-backed storage value retrieved');
if (!value) {
const idbKey = getIdbKey(key);
try {
// It's a bit tricky to query IndexedDB directly to check if value exists, so we use `idb-keyval` to do it.
// Thing is, `idb-keyval` requires you to create a store to query it. End result - we are creating a store
// even if we don't use it for anything besides checking if the key is present.
const idbKeyValStore = getIdbKeyValStore();
const idbValue = await idbGet(idbKey, idbKeyValStore);
if (idbValue) {
log.debug(
{ key, idbKey, idbValue },
'No value in server-backed storage, but found value in IndexedDB - attempting migration'
);
await idbDel(idbKey, idbKeyValStore);
await setItem(key, idbValue);
log.debug({ key, idbKey, idbValue }, 'Migration successful');
return idbValue;
}
} catch (error) {
// Just log if IndexedDB retrieval fails - this is a best-effort migration.
log.debug(
{ key, idbKey, error: serializeError(error) } as JsonObject,
'Error checking for or migrating from IndexedDB'
);
}
}
lastPersistedState.set(key, value);
log.trace({ key, last: lastPersistedState.get(key), next: value }, `Getting state for ${key}`);
return value;
} catch (originalError) {
throw new StorageError({
key,
originalError,
});
}
};
const setItem = async (key: string, value: string) => {
try {
persistRefCount++;
if (lastPersistedState.get(key) === value) {
log.trace(
{ key, last: lastPersistedState.get(key), next: value },
`Skipping persist for ${key} as value is unchanged`
);
return value;
}
log.trace({ key, last: lastPersistedState.get(key), next: value }, `Persisting state for ${key}`);
const url = getUrl('set_by_key', key);
const res = await fetch(url, {
method: 'POST',
body: value,
headers: getAuthHeaders(),
});
if (!res.ok) {
throw new Error(`Response status: ${res.status}`);
}
const resultValue = await res.json();
lastPersistedState.set(key, resultValue);
return resultValue;
} catch (originalError) {
throw new StorageError({
key,
value,
originalError,
});
} finally {
persistRefCount--;
if (persistRefCount < 0) {
log.trace('Persist ref count is negative, resetting to 0');
persistRefCount = 0;
}
}
};
export const reduxRememberDriver: Driver = { getItem, setItem };
export const clearStorage = async () => {
try {
persistRefCount++;
const url = getUrl('delete');
const res = await fetch(url, {
method: 'POST',
headers: getAuthHeaders(),
});
if (!res.ok) {
throw new Error(`Response status: ${res.status}`);
}
} catch {
log.error('Failed to reset client state');
} finally {
persistRefCount--;
lastPersistedState.clear();
if (persistRefCount < 0) {
log.trace('Persist ref count is negative, resetting to 0');
persistRefCount = 0;
}
}
};
export const addStorageListeners = () => {
const onBeforeUnload = (e: BeforeUnloadEvent) => {
if (persistRefCount > 0) {
e.preventDefault();
}
};
window.addEventListener('beforeunload', onBeforeUnload);
return () => {
window.removeEventListener('beforeunload', onBeforeUnload);
};
};
@@ -0,0 +1,41 @@
import { logger } from 'app/logging/logger';
import { PersistError, RehydrateError } from 'redux-remember';
import { serializeError } from 'serialize-error';
type StorageErrorArgs = {
key: string;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ // any is correct
value?: any;
originalError?: unknown;
};
export class StorageError extends Error {
key: string;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ // any is correct
value?: any;
originalError?: Error;
constructor({ key, value, originalError }: StorageErrorArgs) {
super(`Error setting ${key}`);
this.name = 'StorageSetError';
this.key = key;
if (value !== undefined) {
this.value = value;
}
if (originalError instanceof Error) {
this.originalError = originalError;
}
}
}
const log = logger('system');
export const errorHandler = (err: PersistError | RehydrateError) => {
if (err instanceof PersistError) {
log.error({ error: serializeError(err) }, 'Problem persisting state');
} else if (err instanceof RehydrateError) {
log.error({ error: serializeError(err) }, 'Problem rehydrating state');
} else {
log.error({ error: serializeError(err) }, 'Problem in persistence layer');
}
};
@@ -0,0 +1,29 @@
/* eslint-disable no-console */
// This is only enabled manually for debugging, console is allowed.
import type { Middleware, MiddlewareAPI } from '@reduxjs/toolkit';
import { diff } from 'jsondiffpatch';
/**
* Super simple logger middleware. Useful for debugging when the redux devtools are awkward.
*/
export const getDebugLoggerMiddleware =
(options?: { filter?: (action: unknown) => boolean; withDiff?: boolean; withNextState?: boolean }): Middleware =>
(api: MiddlewareAPI) =>
(next) =>
(action) => {
if (options?.filter?.(action)) {
return next(action);
}
const originalState = api.getState();
console.log('REDUX: dispatching', action);
const result = next(action);
const nextState = api.getState();
if (options?.withNextState) {
console.log('REDUX: next state', nextState);
}
if (options?.withDiff) {
console.log('REDUX: diff', diff(originalState, nextState));
}
return result;
};
@@ -0,0 +1,13 @@
import type { UnknownAction } from '@reduxjs/toolkit';
import { appInfoApi } from 'services/api/endpoints/appInfo';
export const actionSanitizer = <A extends UnknownAction>(action: A): A => {
if (appInfoApi.endpoints.getOpenAPISchema.matchFulfilled(action)) {
return {
...action,
payload: '<OpenAPI schema omitted>',
};
}
return action;
};
@@ -0,0 +1,16 @@
/**
* This is a list of actions that should be excluded in the Redux DevTools.
*/
export const actionsDenylist: string[] = [
// very spammy canvas actions
// 'canvas/setStageCoordinates',
// 'canvas/setStageScale',
// 'canvas/setBoundingBoxCoordinates',
// 'canvas/setBoundingBoxDimensions',
// 'canvas/addPointToCurrentLine',
// bazillions during generation
// 'socket/socketGeneratorProgress',
// 'socket/appSocketGeneratorProgress',
// this happens after every state change
// '@@REMEMBER_PERSISTED',
];
@@ -0,0 +1,3 @@
export const stateSanitizer = <S>(state: S): S => {
return state;
};
@@ -0,0 +1,56 @@
import { createAction } from '@reduxjs/toolkit';
import { logger } from 'app/logging/logger';
import type { AppStartListening } from 'app/store/store';
import { buildAdHocPostProcessingGraph } from 'features/nodes/util/graph/buildAdHocPostProcessingGraph';
import { toast } from 'features/toast/toast';
import { t } from 'i18next';
import { enqueueMutationFixedCacheKeyOptions, queueApi } from 'services/api/endpoints/queue';
import type { EnqueueBatchArg, ImageDTO } from 'services/api/types';
import type { JsonObject } from 'type-fest';
const log = logger('queue');
export const adHocPostProcessingRequested = createAction<{ imageDTO: ImageDTO }>(`upscaling/postProcessingRequested`);
export const addAdHocPostProcessingRequestedListener = (startAppListening: AppStartListening) => {
startAppListening({
actionCreator: adHocPostProcessingRequested,
effect: async (action, { dispatch, getState }) => {
const { imageDTO } = action.payload;
const state = getState();
const enqueueBatchArg: EnqueueBatchArg = {
prepend: true,
batch: {
graph: await buildAdHocPostProcessingGraph({
image: imageDTO,
state,
}),
runs: 1,
},
};
try {
const req = dispatch(
queueApi.endpoints.enqueueBatch.initiate(enqueueBatchArg, enqueueMutationFixedCacheKeyOptions)
);
const enqueueResult = await req.unwrap();
req.reset();
log.debug({ enqueueResult } as JsonObject, t('queue.graphQueued'));
} catch (error) {
log.error({ enqueueBatchArg } as JsonObject, t('queue.graphFailedToQueue'));
if (error instanceof Object && 'status' in error && error.status === 403) {
return;
} else {
toast({
id: 'GRAPH_QUEUE_FAILED',
title: t('queue.graphFailedToQueue'),
status: 'error',
});
}
}
},
});
};

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