Compare commits

..

1 Commits

Author SHA1 Message Date
psychedelicious
5e6b5c8fd6 feat(queue): take one functionality in session processor
Executes the next queue item, then pauses. Does nothing if the queue is already running.
2023-11-30 21:17:35 +11:00
443 changed files with 219444 additions and 22759 deletions

View File

@@ -21,23 +21,13 @@ jobs:
if: github.event.pull_request.draft == false
runs-on: ubuntu-22.04
steps:
- name: Setup Node 20
uses: actions/setup-node@v4
- name: Setup Node 18
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Install dependencies
run: 'pnpm install --prefer-frozen-lockfile'
- name: Typescript
run: 'pnpm run lint:tsc'
- name: Madge
run: 'pnpm run lint:madge'
- name: ESLint
run: 'pnpm run lint:eslint'
- name: Prettier
run: 'pnpm run lint:prettier'
node-version: '18'
- uses: actions/checkout@v3
- run: 'yarn install --frozen-lockfile'
- run: 'yarn run lint:tsc'
- run: 'yarn run lint:madge'
- run: 'yarn run lint:eslint'
- run: 'yarn run lint:prettier'

3
.gitignore vendored
View File

@@ -16,7 +16,7 @@ __pycache__/
.Python
build/
develop-eggs/
dist/
# dist/
downloads/
eggs/
.eggs/
@@ -187,4 +187,3 @@ installer/install.bat
installer/install.sh
installer/update.bat
installer/update.sh
installer/InvokeAI-Installer/

View File

@@ -125,8 +125,8 @@ and go to http://localhost:9090.
You must have Python 3.10 through 3.11 installed on your machine. Earlier or
later versions are not supported.
Node.js also needs to be installed along with `pnpm` (can be installed with
the command `npm install -g pnpm` if needed)
Node.js also needs to be installed along with yarn (can be installed with
the command `npm install -g yarn` if needed)
1. Open a command-line window on your machine. The PowerShell is recommended for Windows.
2. Create a directory to install InvokeAI into. You'll need at least 15 GB of free space:

View File

@@ -120,7 +120,7 @@ Generate an image with a given prompt, record the seed of the image, and then
use the `prompt2prompt` syntax to substitute words in the original prompt for
words in a new prompt. This works for `img2img` as well.
For example, consider the prompt `a cat.swap(dog) playing with a ball in the forest`. Normally, because the words interact with each other when doing a stable diffusion image generation, these two prompts would generate different compositions:
For example, consider the prompt `a cat.swap(dog) playing with a ball in the forest`. Normally, because of the word words interact with each other when doing a stable diffusion image generation, these two prompts would generate different compositions:
- `a cat playing with a ball in the forest`
- `a dog playing with a ball in the forest`

View File

@@ -14,10 +14,6 @@ To use a community workflow, download the the `.json` node graph file and load i
- Community Nodes
+ [Average Images](#average-images)
+ [Clean Image Artifacts After Cut](#clean-image-artifacts-after-cut)
+ [Close Color Mask](#close-color-mask)
+ [Clothing Mask](#clothing-mask)
+ [Contrast Limited Adaptive Histogram Equalization](#contrast-limited-adaptive-histogram-equalization)
+ [Depth Map from Wavefront OBJ](#depth-map-from-wavefront-obj)
+ [Film Grain](#film-grain)
+ [Generative Grammar-Based Prompt Nodes](#generative-grammar-based-prompt-nodes)
@@ -26,22 +22,16 @@ To use a community workflow, download the the `.json` node graph file and load i
+ [Halftone](#halftone)
+ [Ideal Size](#ideal-size)
+ [Image and Mask Composition Pack](#image-and-mask-composition-pack)
+ [Image Dominant Color](#image-dominant-color)
+ [Image to Character Art Image Nodes](#image-to-character-art-image-nodes)
+ [Image Picker](#image-picker)
+ [Image Resize Plus](#image-resize-plus)
+ [Load Video Frame](#load-video-frame)
+ [Make 3D](#make-3d)
+ [Mask Operations](#mask-operations)
+ [Match Histogram](#match-histogram)
+ [Negative Image](#negative-image)
+ [Oobabooga](#oobabooga)
+ [Prompt Tools](#prompt-tools)
+ [Remote Image](#remote-image)
+ [Remove Background](#remove-background)
+ [Retroize](#retroize)
+ [Size Stepper Nodes](#size-stepper-nodes)
+ [Simple Skin Detection](#simple-skin-detection)
+ [Text font to Image](#text-font-to-image)
+ [Thresholding](#thresholding)
+ [Unsharp Mask](#unsharp-mask)
@@ -58,46 +48,6 @@ To use a community workflow, download the the `.json` node graph file and load i
**Node Link:** https://github.com/JPPhoto/average-images-node
--------------------------------
### Clean Image Artifacts After Cut
Description: Removes residual artifacts after an image is separated from its background.
Node Link: https://github.com/VeyDlin/clean-artifact-after-cut-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/clean-artifact-after-cut-node/master/.readme/node.png" width="500" />
--------------------------------
### Close Color Mask
Description: Generates a mask for images based on a closely matching color, useful for color-based selections.
Node Link: https://github.com/VeyDlin/close-color-mask-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/close-color-mask-node/master/.readme/node.png" width="500" />
--------------------------------
### Clothing Mask
Description: Employs a U2NET neural network trained for the segmentation of clothing items in images.
Node Link: https://github.com/VeyDlin/clothing-mask-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/clothing-mask-node/master/.readme/node.png" width="500" />
--------------------------------
### Contrast Limited Adaptive Histogram Equalization
Description: Enhances local image contrast using adaptive histogram equalization with contrast limiting.
Node Link: https://github.com/VeyDlin/clahe-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/clahe-node/master/.readme/node.png" width="500" />
--------------------------------
### Depth Map from Wavefront OBJ
@@ -214,16 +164,6 @@ This includes 15 Nodes:
</br><img src="https://raw.githubusercontent.com/dwringer/composition-nodes/main/composition_pack_overview.jpg" width="500" />
--------------------------------
### Image Dominant Color
Description: Identifies and extracts the dominant color from an image using k-means clustering.
Node Link: https://github.com/VeyDlin/image-dominant-color-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/image-dominant-color-node/master/.readme/node.png" width="500" />
--------------------------------
### Image to Character Art Image Nodes
@@ -245,17 +185,6 @@ View:
**Node Link:** https://github.com/JPPhoto/image-picker-node
--------------------------------
### Image Resize Plus
Description: Provides various image resizing options such as fill, stretch, fit, center, and crop.
Node Link: https://github.com/VeyDlin/image-resize-plus-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/image-resize-plus-node/master/.readme/node.png" width="500" />
--------------------------------
### Load Video Frame
@@ -280,16 +209,6 @@ View:
<img src="https://gitlab.com/srcrr/shift3d/-/raw/main/example-1.png" width="300" />
<img src="https://gitlab.com/srcrr/shift3d/-/raw/main/example-2.png" width="300" />
--------------------------------
### Mask Operations
Description: Offers logical operations (OR, SUB, AND) for combining and manipulating image masks.
Node Link: https://github.com/VeyDlin/mask-operations-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/mask-operations-node/master/.readme/node.png" width="500" />
--------------------------------
### Match Histogram
@@ -307,16 +226,6 @@ See full docs here: https://github.com/skunkworxdark/Prompt-tools-nodes/edit/mai
<img src="https://github.com/skunkworxdark/match_histogram/assets/21961335/ed12f329-a0ef-444a-9bae-129ed60d6097" width="300" />
--------------------------------
### Negative Image
Description: Creates a negative version of an image, effective for visual effects and mask inversion.
Node Link: https://github.com/VeyDlin/negative-image-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/negative-image-node/master/.readme/node.png" width="500" />
--------------------------------
### Oobabooga
@@ -380,15 +289,6 @@ See full docs here: https://github.com/skunkworxdark/Prompt-tools-nodes/edit/mai
**Node Link:** https://github.com/fieldOfView/InvokeAI-remote_image
--------------------------------
### Remove Background
Description: An integration of the rembg package to remove backgrounds from images using multiple U2NET models.
Node Link: https://github.com/VeyDlin/remove-background-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/remove-background-node/master/.readme/node.png" width="500" />
--------------------------------
### Retroize
@@ -401,17 +301,6 @@ View:
<img src="https://github.com/Ar7ific1al/InvokeAI_nodes_retroize/assets/2306586/de8b4fa6-324c-4c2d-b36c-297600c73974" width="500" />
--------------------------------
### Simple Skin Detection
Description: Detects skin in images based on predefined color thresholds.
Node Link: https://github.com/VeyDlin/simple-skin-detection-node
View:
</br><img src="https://raw.githubusercontent.com/VeyDlin/simple-skin-detection-node/master/.readme/node.png" width="500" />
--------------------------------
### Size Stepper Nodes
@@ -497,7 +386,6 @@ See full docs here: https://github.com/skunkworxdark/XYGrid_nodes/edit/main/READ
<img src="https://github.com/skunkworxdark/XYGrid_nodes/blob/main/images/collage.png" width="300" />
--------------------------------
### Example Node Template

View File

@@ -2,119 +2,43 @@
set -e
BCYAN="\e[1;36m"
BYELLOW="\e[1;33m"
BGREEN="\e[1;32m"
BRED="\e[1;31m"
RED="\e[31m"
RESET="\e[0m"
function is_bin_in_path {
builtin type -P "$1" &>/dev/null
}
function does_tag_exist {
git rev-parse --quiet --verify "refs/tags/$1" >/dev/null
}
function git_show_ref {
git show-ref --dereference $1 --abbrev 7
}
function git_show {
git show -s --format='%h %s' $1
}
cd "$(dirname "$0")"
echo -e "${BYELLOW}This script must be run from the installer directory!${RESET}"
echo "The current working directory is $(pwd)"
read -p "If that looks right, press any key to proceed, or CTRL-C to exit..."
echo
# Some machines only have `python3` in PATH, others have `python` - make an alias.
# We can use a function to approximate an alias within a non-interactive shell.
if ! is_bin_in_path python && is_bin_in_path python3; then
function python {
python3 "$@"
}
fi
if [[ -v "VIRTUAL_ENV" ]]; then
# we can't just call 'deactivate' because this function is not exported
# to the environment of this script from the bash process that runs the script
echo -e "${BRED}A virtual environment is activated. Please deactivate it before proceeding.${RESET}"
echo "A virtual environment is activated. Please deactivate it before proceeding".
exit -1
fi
VERSION=$(
cd ..
python -c "from invokeai.version import __version__ as version; print(version)"
)
VERSION=$(cd ..; python -c "from invokeai.version import __version__ as version; print(version)")
PATCH=""
VERSION="v${VERSION}${PATCH}"
LATEST_TAG="v3-latest"
echo "Building installer for version $VERSION..."
echo
echo Building installer for version $VERSION
echo "Be certain that you're in the 'installer' directory before continuing."
read -p "Press any key to continue, or CTRL-C to exit..."
if does_tag_exist $VERSION; then
echo -e "${BCYAN}${VERSION}${RESET} already exists:"
git_show_ref tags/$VERSION
echo
fi
if does_tag_exist $LATEST_TAG; then
echo -e "${BCYAN}${LATEST_TAG}${RESET} already exists:"
git_show_ref tags/$LATEST_TAG
echo
fi
echo -e "${BGREEN}HEAD${RESET}:"
git_show
echo
echo -e -n "Create tags ${BCYAN}${VERSION}${RESET} and ${BCYAN}${LATEST_TAG}${RESET} @ ${BGREEN}HEAD${RESET}, ${RED}deleting existing tags on remote${RESET}? "
read -e -p 'y/n [n]: ' input
read -e -p "Tag this repo with '${VERSION}' and '${LATEST_TAG}'? [n]: " input
RESPONSE=${input:='n'}
if [ "$RESPONSE" == 'y' ]; then
echo
echo -e "Deleting ${BCYAN}${VERSION}${RESET} tag on remote..."
git push origin :refs/tags/$VERSION
echo -e "Tagging ${BGREEN}HEAD${RESET} with ${BCYAN}${VERSION}${RESET} locally..."
if ! git tag -fa $VERSION; then
echo "Existing/invalid tag"
exit -1
git push origin :refs/tags/$VERSION
if ! git tag -fa $VERSION ; then
echo "Existing/invalid tag"
exit -1
fi
echo -e "Deleting ${BCYAN}${LATEST_TAG}${RESET} tag on remote..."
git push origin :refs/tags/$LATEST_TAG
echo -e "Tagging ${BGREEN}HEAD${RESET} with ${BCYAN}${LATEST_TAG}${RESET} locally..."
git tag -fa $LATEST_TAG
echo
echo -e "${BYELLOW}Remember to 'git push origin --tags'!${RESET}"
echo "remember to push --tags!"
fi
# ---------------------- FRONTEND ----------------------
# ----------------------
pushd ../invokeai/frontend/web >/dev/null
echo
echo "Installing frontend dependencies..."
echo
pnpm i --frozen-lockfile
echo
echo "Building frontend..."
echo
pnpm build
popd
# ---------------------- BACKEND ----------------------
echo
echo "Building wheel..."
echo
echo Building the wheel
# install the 'build' package in the user site packages, if needed
# could be improved by using a temporary venv, but it's tiny and harmless
@@ -122,15 +46,12 @@ if [[ $(python -c 'from importlib.util import find_spec; print(find_spec("build"
pip install --user build
fi
rm -rf ../build
rm -r ../build
python -m build --wheel --outdir dist/ ../.
# ----------------------
echo
echo "Building installer zip files for InvokeAI ${VERSION}..."
echo
echo Building installer zip fles for InvokeAI $VERSION
# get rid of any old ones
rm -f *.zip
@@ -151,7 +72,7 @@ cp install.sh.in InvokeAI-Installer/install.sh
chmod a+x InvokeAI-Installer/install.sh
# Windows
perl -p -e "s/^set INVOKEAI_VERSION=.*/set INVOKEAI_VERSION=$VERSION/" install.bat.in >InvokeAI-Installer/install.bat
perl -p -e "s/^set INVOKEAI_VERSION=.*/set INVOKEAI_VERSION=$VERSION/" install.bat.in > InvokeAI-Installer/install.bat
cp WinLongPathsEnabled.reg InvokeAI-Installer/
# Zip everything up

View File

@@ -2,6 +2,7 @@
from logging import Logger
from invokeai.app.services.workflow_image_records.workflow_image_records_sqlite import SqliteWorkflowImageRecordsStorage
from invokeai.backend.util.logging import InvokeAILogger
from invokeai.version.invokeai_version import __version__
@@ -29,7 +30,7 @@ from ..services.session_processor.session_processor_default import DefaultSessio
from ..services.session_queue.session_queue_sqlite import SqliteSessionQueue
from ..services.shared.default_graphs import create_system_graphs
from ..services.shared.graph import GraphExecutionState, LibraryGraph
from ..services.shared.sqlite.sqlite_database import SqliteDatabase
from ..services.shared.sqlite import SqliteDatabase
from ..services.urls.urls_default import LocalUrlService
from ..services.workflow_records.workflow_records_sqlite import SqliteWorkflowRecordsStorage
from .events import FastAPIEventService
@@ -93,6 +94,7 @@ class ApiDependencies:
session_processor = DefaultSessionProcessor()
session_queue = SqliteSessionQueue(db=db)
urls = LocalUrlService()
workflow_image_records = SqliteWorkflowImageRecordsStorage(db=db)
workflow_records = SqliteWorkflowRecordsStorage(db=db)
services = InvocationServices(
@@ -119,12 +121,14 @@ class ApiDependencies:
session_processor=session_processor,
session_queue=session_queue,
urls=urls,
workflow_image_records=workflow_image_records,
workflow_records=workflow_records,
)
create_system_graphs(services.graph_library)
ApiDependencies.invoker = Invoker(services)
db.clean()
@staticmethod

View File

@@ -1,11 +1,7 @@
import typing
from enum import Enum
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path
from platform import python_version
from typing import Optional
import torch
from fastapi import Body
from fastapi.routing import APIRouter
from pydantic import BaseModel, Field
@@ -44,24 +40,6 @@ class AppVersion(BaseModel):
version: str = Field(description="App version")
class AppDependencyVersions(BaseModel):
"""App depencency Versions Response"""
accelerate: str = Field(description="accelerate version")
compel: str = Field(description="compel version")
cuda: Optional[str] = Field(description="CUDA version")
diffusers: str = Field(description="diffusers version")
numpy: str = Field(description="Numpy version")
opencv: str = Field(description="OpenCV version")
onnx: str = Field(description="ONNX version")
pillow: str = Field(description="Pillow (PIL) version")
python: str = Field(description="Python version")
torch: str = Field(description="PyTorch version")
torchvision: str = Field(description="PyTorch Vision version")
transformers: str = Field(description="transformers version")
xformers: Optional[str] = Field(description="xformers version")
class AppConfig(BaseModel):
"""App Config Response"""
@@ -76,29 +54,6 @@ async def get_version() -> AppVersion:
return AppVersion(version=__version__)
@app_router.get("/app_deps", operation_id="get_app_deps", status_code=200, response_model=AppDependencyVersions)
async def get_app_deps() -> AppDependencyVersions:
try:
xformers = version("xformers")
except PackageNotFoundError:
xformers = None
return AppDependencyVersions(
accelerate=version("accelerate"),
compel=version("compel"),
cuda=torch.version.cuda,
diffusers=version("diffusers"),
numpy=version("numpy"),
opencv=version("opencv-python"),
onnx=version("onnx"),
pillow=version("pillow"),
python=python_version(),
torch=torch.version.__version__,
torchvision=version("torchvision"),
transformers=version("transformers"),
xformers=xformers,
)
@app_router.get("/config", operation_id="get_config", status_code=200, response_model=AppConfig)
async def get_config() -> AppConfig:
infill_methods = ["tile", "lama", "cv2"]

View File

@@ -8,11 +8,10 @@ from fastapi.routing import APIRouter
from PIL import Image
from pydantic import BaseModel, Field, ValidationError
from invokeai.app.invocations.baseinvocation import MetadataField, MetadataFieldValidator
from invokeai.app.invocations.baseinvocation import MetadataField, MetadataFieldValidator, WorkflowFieldValidator
from invokeai.app.services.image_records.image_records_common import ImageCategory, ImageRecordChanges, ResourceOrigin
from invokeai.app.services.images.images_common import ImageDTO, ImageUrlsDTO
from invokeai.app.services.shared.pagination import OffsetPaginatedResults
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID, WorkflowWithoutIDValidator
from ..dependencies import ApiDependencies
@@ -74,7 +73,7 @@ async def upload_image(
workflow_raw = pil_image.info.get("invokeai_workflow", None)
if workflow_raw is not None:
try:
workflow = WorkflowWithoutIDValidator.validate_json(workflow_raw)
workflow = WorkflowFieldValidator.validate_json(workflow_raw)
except ValidationError:
ApiDependencies.invoker.services.logger.warn("Failed to parse metadata for uploaded image")
pass
@@ -185,18 +184,6 @@ async def get_image_metadata(
raise HTTPException(status_code=404)
@images_router.get(
"/i/{image_name}/workflow", operation_id="get_image_workflow", response_model=Optional[WorkflowWithoutID]
)
async def get_image_workflow(
image_name: str = Path(description="The name of image whose workflow to get"),
) -> Optional[WorkflowWithoutID]:
try:
return ApiDependencies.invoker.services.images.get_workflow(image_name)
except Exception:
raise HTTPException(status_code=404)
@images_router.api_route(
"/i/{image_name}/full",
methods=["GET", "HEAD"],

View File

@@ -141,7 +141,7 @@ async def del_model_record(
status_code=201,
)
async def add_model_record(
config: Annotated[AnyModelConfig, Body(description="Model config", discriminator="type")],
config: Annotated[AnyModelConfig, Body(description="Model config", discriminator="type")]
) -> AnyModelConfig:
"""
Add a model using the configuration information appropriate for its type.

View File

@@ -93,6 +93,18 @@ async def Pause(
return ApiDependencies.invoker.services.session_processor.pause()
@session_queue_router.put(
"/{queue_id}/processor/take_one",
operation_id="take_one",
responses={200: {"model": SessionProcessorStatus}},
)
async def take_one(
queue_id: str = Path(description="The queue id to perform this operation on"),
) -> SessionProcessorStatus:
"""Executes the next-in-line queue item, pausing the processor afterwards. Has no effect if the queue is resumed."""
return ApiDependencies.invoker.services.session_processor.take_one()
@session_queue_router.put(
"/{queue_id}/cancel_by_batch_ids",
operation_id="cancel_by_batch_ids",

View File

@@ -1,19 +1,7 @@
from typing import Optional
from fastapi import APIRouter, Body, HTTPException, Path, Query
from fastapi import APIRouter, Path
from invokeai.app.api.dependencies import ApiDependencies
from invokeai.app.services.shared.pagination import PaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_common import SQLiteDirection
from invokeai.app.services.workflow_records.workflow_records_common import (
Workflow,
WorkflowCategory,
WorkflowNotFoundError,
WorkflowRecordDTO,
WorkflowRecordListItemDTO,
WorkflowRecordOrderBy,
WorkflowWithoutID,
)
from invokeai.app.invocations.baseinvocation import WorkflowField
workflows_router = APIRouter(prefix="/v1/workflows", tags=["workflows"])
@@ -22,76 +10,11 @@ workflows_router = APIRouter(prefix="/v1/workflows", tags=["workflows"])
"/i/{workflow_id}",
operation_id="get_workflow",
responses={
200: {"model": WorkflowRecordDTO},
200: {"model": WorkflowField},
},
)
async def get_workflow(
workflow_id: str = Path(description="The workflow to get"),
) -> WorkflowRecordDTO:
) -> WorkflowField:
"""Gets a workflow"""
try:
return ApiDependencies.invoker.services.workflow_records.get(workflow_id)
except WorkflowNotFoundError:
raise HTTPException(status_code=404, detail="Workflow not found")
@workflows_router.patch(
"/i/{workflow_id}",
operation_id="update_workflow",
responses={
200: {"model": WorkflowRecordDTO},
},
)
async def update_workflow(
workflow: Workflow = Body(description="The updated workflow", embed=True),
) -> WorkflowRecordDTO:
"""Updates a workflow"""
return ApiDependencies.invoker.services.workflow_records.update(workflow=workflow)
@workflows_router.delete(
"/i/{workflow_id}",
operation_id="delete_workflow",
)
async def delete_workflow(
workflow_id: str = Path(description="The workflow to delete"),
) -> None:
"""Deletes a workflow"""
ApiDependencies.invoker.services.workflow_records.delete(workflow_id)
@workflows_router.post(
"/",
operation_id="create_workflow",
responses={
200: {"model": WorkflowRecordDTO},
},
)
async def create_workflow(
workflow: WorkflowWithoutID = Body(description="The workflow to create", embed=True),
) -> WorkflowRecordDTO:
"""Creates a workflow"""
return ApiDependencies.invoker.services.workflow_records.create(workflow=workflow)
@workflows_router.get(
"/",
operation_id="list_workflows",
responses={
200: {"model": PaginatedResults[WorkflowRecordListItemDTO]},
},
)
async def list_workflows(
page: int = Query(default=0, description="The page to get"),
per_page: int = Query(default=10, description="The number of workflows per page"),
order_by: WorkflowRecordOrderBy = Query(
default=WorkflowRecordOrderBy.Name, description="The attribute to order by"
),
direction: SQLiteDirection = Query(default=SQLiteDirection.Ascending, description="The direction to order by"),
category: WorkflowCategory = Query(default=WorkflowCategory.User, description="The category of workflow to get"),
query: Optional[str] = Query(default=None, description="The text to query by (matches name and description)"),
) -> PaginatedResults[WorkflowRecordListItemDTO]:
"""Gets a page of workflows"""
return ApiDependencies.invoker.services.workflow_records.get_many(
page=page, per_page=per_page, order_by=order_by, direction=direction, query=query, category=category
)
return ApiDependencies.invoker.services.workflow_records.get(workflow_id)

View File

@@ -219,19 +219,18 @@ def overridden_redoc() -> HTMLResponse:
web_root_path = Path(list(web_dir.__path__)[0])
# Only serve the UI if we it has a build
if (web_root_path / "dist").exists():
# Cannot add headers to StaticFiles, so we must serve index.html with a custom route
# Add cache-control: no-store header to prevent caching of index.html, which leads to broken UIs at release
@app.get("/", include_in_schema=False, name="ui_root")
def get_index() -> FileResponse:
return FileResponse(Path(web_root_path, "dist/index.html"), headers={"Cache-Control": "no-store"})
# # Must mount *after* the other routes else it borks em
app.mount("/assets", StaticFiles(directory=Path(web_root_path, "dist/assets/")), name="assets")
app.mount("/locales", StaticFiles(directory=Path(web_root_path, "dist/locales/")), name="locales")
# Cannot add headers to StaticFiles, so we must serve index.html with a custom route
# Add cache-control: no-store header to prevent caching of index.html, which leads to broken UIs at release
@app.get("/", include_in_schema=False, name="ui_root")
def get_index() -> FileResponse:
return FileResponse(Path(web_root_path, "dist/index.html"), headers={"Cache-Control": "no-store"})
# # Must mount *after* the other routes else it borks em
app.mount("/static", StaticFiles(directory=Path(web_root_path, "static/")), name="static") # docs favicon is in here
app.mount("/assets", StaticFiles(directory=Path(web_root_path, "dist/assets/")), name="assets")
app.mount("/locales", StaticFiles(directory=Path(web_root_path, "dist/locales/")), name="locales")
def invoke_api() -> None:

View File

@@ -4,7 +4,6 @@ from __future__ import annotations
import inspect
import re
import warnings
from abc import ABC, abstractmethod
from enum import Enum
from inspect import signature
@@ -17,7 +16,6 @@ from pydantic.fields import FieldInfo, _Unset
from pydantic_core import PydanticUndefined
from invokeai.app.services.config.config_default import InvokeAIAppConfig
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID
from invokeai.app.shared.fields import FieldDescriptions
from invokeai.app.util.metaenum import MetaEnum
from invokeai.app.util.misc import uuid_string
@@ -454,7 +452,6 @@ class InvocationContext:
queue_id: str
queue_item_id: int
queue_batch_id: str
workflow: Optional[WorkflowWithoutID]
def __init__(
self,
@@ -463,14 +460,12 @@ class InvocationContext:
queue_item_id: int,
queue_batch_id: str,
graph_execution_state_id: str,
workflow: Optional[WorkflowWithoutID],
):
self.services = services
self.graph_execution_state_id = graph_execution_state_id
self.queue_id = queue_id
self.queue_item_id = queue_item_id
self.queue_batch_id = queue_batch_id
self.workflow = workflow
class BaseInvocationOutput(BaseModel):
@@ -710,10 +705,8 @@ class _Model(BaseModel):
pass
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=DeprecationWarning)
# Get all pydantic model attrs, methods, etc
RESERVED_PYDANTIC_FIELD_NAMES = {m[0] for m in inspect.getmembers(_Model())}
# Get all pydantic model attrs, methods, etc
RESERVED_PYDANTIC_FIELD_NAMES = {m[0] for m in inspect.getmembers(_Model())}
def validate_fields(model_fields: dict[str, FieldInfo], model_type: str) -> None:
@@ -814,9 +807,9 @@ def invocation(
cls.UIConfig.category = category
# Grab the node pack's name from the module name, if it's a custom node
is_custom_node = cls.__module__.rsplit(".", 1)[0] == "invokeai.app.invocations"
if is_custom_node:
cls.UIConfig.node_pack = cls.__module__.split(".")[0]
module_name = cls.__module__.split(".")[0]
if module_name.endswith(CUSTOM_NODE_PACK_SUFFIX):
cls.UIConfig.node_pack = module_name.split(CUSTOM_NODE_PACK_SUFFIX)[0]
else:
cls.UIConfig.node_pack = None
@@ -910,6 +903,24 @@ def invocation_output(
return wrapper
class WorkflowField(RootModel):
"""
Pydantic model for workflows with custom root of type dict[str, Any].
Workflows are stored without a strict schema.
"""
root: dict[str, Any] = Field(description="The workflow")
WorkflowFieldValidator = TypeAdapter(WorkflowField)
class WithWorkflow(BaseModel):
workflow: Optional[WorkflowField] = Field(
default=None, description=FieldDescriptions.workflow, json_schema_extra={"field_kind": FieldKind.NodeAttribute}
)
class MetadataField(RootModel):
"""
Pydantic model for metadata with custom root of type dict[str, Any].
@@ -932,13 +943,3 @@ class WithMetadata(BaseModel):
orig_required=False,
).model_dump(exclude_none=True),
)
class WithWorkflow:
workflow = None
def __init_subclass__(cls) -> None:
logger.warn(
f"{cls.__module__.split('.')[0]}.{cls.__name__}: WithWorkflow is deprecated. Use `context.workflow` to access the workflow."
)
super().__init_subclass__()

View File

@@ -39,6 +39,7 @@ from .baseinvocation import (
InvocationContext,
OutputField,
WithMetadata,
WithWorkflow,
invocation,
invocation_output,
)
@@ -128,7 +129,7 @@ class ControlNetInvocation(BaseInvocation):
# This invocation exists for other invocations to subclass it - do not register with @invocation!
class ImageProcessorInvocation(BaseInvocation, WithMetadata):
class ImageProcessorInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Base class for invocations that preprocess images for ControlNet"""
image: ImageField = InputField(description="The image to process")
@@ -152,7 +153,7 @@ class ImageProcessorInvocation(BaseInvocation, WithMetadata):
node_id=self.id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
"""Builds an ImageOutput and its ImageField"""
@@ -172,7 +173,7 @@ class ImageProcessorInvocation(BaseInvocation, WithMetadata):
title="Canny Processor",
tags=["controlnet", "canny"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class CannyImageProcessorInvocation(ImageProcessorInvocation):
"""Canny edge detection for ControlNet"""
@@ -195,7 +196,7 @@ class CannyImageProcessorInvocation(ImageProcessorInvocation):
title="HED (softedge) Processor",
tags=["controlnet", "hed", "softedge"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class HedImageProcessorInvocation(ImageProcessorInvocation):
"""Applies HED edge detection to image"""
@@ -224,7 +225,7 @@ class HedImageProcessorInvocation(ImageProcessorInvocation):
title="Lineart Processor",
tags=["controlnet", "lineart"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class LineartImageProcessorInvocation(ImageProcessorInvocation):
"""Applies line art processing to image"""
@@ -246,7 +247,7 @@ class LineartImageProcessorInvocation(ImageProcessorInvocation):
title="Lineart Anime Processor",
tags=["controlnet", "lineart", "anime"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class LineartAnimeImageProcessorInvocation(ImageProcessorInvocation):
"""Applies line art anime processing to image"""
@@ -269,7 +270,7 @@ class LineartAnimeImageProcessorInvocation(ImageProcessorInvocation):
title="Openpose Processor",
tags=["controlnet", "openpose", "pose"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class OpenposeImageProcessorInvocation(ImageProcessorInvocation):
"""Applies Openpose processing to image"""
@@ -294,7 +295,7 @@ class OpenposeImageProcessorInvocation(ImageProcessorInvocation):
title="Midas Depth Processor",
tags=["controlnet", "midas"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class MidasDepthImageProcessorInvocation(ImageProcessorInvocation):
"""Applies Midas depth processing to image"""
@@ -321,7 +322,7 @@ class MidasDepthImageProcessorInvocation(ImageProcessorInvocation):
title="Normal BAE Processor",
tags=["controlnet"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class NormalbaeImageProcessorInvocation(ImageProcessorInvocation):
"""Applies NormalBae processing to image"""
@@ -338,7 +339,7 @@ class NormalbaeImageProcessorInvocation(ImageProcessorInvocation):
@invocation(
"mlsd_image_processor", title="MLSD Processor", tags=["controlnet", "mlsd"], category="controlnet", version="1.2.0"
"mlsd_image_processor", title="MLSD Processor", tags=["controlnet", "mlsd"], category="controlnet", version="1.1.0"
)
class MlsdImageProcessorInvocation(ImageProcessorInvocation):
"""Applies MLSD processing to image"""
@@ -361,7 +362,7 @@ class MlsdImageProcessorInvocation(ImageProcessorInvocation):
@invocation(
"pidi_image_processor", title="PIDI Processor", tags=["controlnet", "pidi"], category="controlnet", version="1.2.0"
"pidi_image_processor", title="PIDI Processor", tags=["controlnet", "pidi"], category="controlnet", version="1.1.0"
)
class PidiImageProcessorInvocation(ImageProcessorInvocation):
"""Applies PIDI processing to image"""
@@ -388,7 +389,7 @@ class PidiImageProcessorInvocation(ImageProcessorInvocation):
title="Content Shuffle Processor",
tags=["controlnet", "contentshuffle"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class ContentShuffleImageProcessorInvocation(ImageProcessorInvocation):
"""Applies content shuffle processing to image"""
@@ -418,7 +419,7 @@ class ContentShuffleImageProcessorInvocation(ImageProcessorInvocation):
title="Zoe (Depth) Processor",
tags=["controlnet", "zoe", "depth"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class ZoeDepthImageProcessorInvocation(ImageProcessorInvocation):
"""Applies Zoe depth processing to image"""
@@ -434,7 +435,7 @@ class ZoeDepthImageProcessorInvocation(ImageProcessorInvocation):
title="Mediapipe Face Processor",
tags=["controlnet", "mediapipe", "face"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class MediapipeFaceProcessorInvocation(ImageProcessorInvocation):
"""Applies mediapipe face processing to image"""
@@ -457,7 +458,7 @@ class MediapipeFaceProcessorInvocation(ImageProcessorInvocation):
title="Leres (Depth) Processor",
tags=["controlnet", "leres", "depth"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class LeresImageProcessorInvocation(ImageProcessorInvocation):
"""Applies leres processing to image"""
@@ -486,7 +487,7 @@ class LeresImageProcessorInvocation(ImageProcessorInvocation):
title="Tile Resample Processor",
tags=["controlnet", "tile"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class TileResamplerProcessorInvocation(ImageProcessorInvocation):
"""Tile resampler processor"""
@@ -526,7 +527,7 @@ class TileResamplerProcessorInvocation(ImageProcessorInvocation):
title="Segment Anything Processor",
tags=["controlnet", "segmentanything"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class SegmentAnythingProcessorInvocation(ImageProcessorInvocation):
"""Applies segment anything processing to image"""
@@ -568,7 +569,7 @@ class SamDetectorReproducibleColors(SamDetector):
title="Color Map Processor",
tags=["controlnet"],
category="controlnet",
version="1.2.0",
version="1.1.0",
)
class ColorMapImageProcessorInvocation(ImageProcessorInvocation):
"""Generates a color map from the provided image"""

View File

@@ -6,6 +6,7 @@ import sys
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
from invokeai.app.invocations.baseinvocation import CUSTOM_NODE_PACK_SUFFIX
from invokeai.backend.util.logging import InvokeAILogger
logger = InvokeAILogger.get_logger()
@@ -33,7 +34,7 @@ for d in Path(__file__).parent.iterdir():
continue
# load the module, appending adding a suffix to identify it as a custom node pack
spec = spec_from_file_location(module_name, init.absolute())
spec = spec_from_file_location(f"{module_name}{CUSTOM_NODE_PACK_SUFFIX}", init.absolute())
if spec is None or spec.loader is None:
logger.warn(f"Could not load {init}")

View File

@@ -8,11 +8,11 @@ from PIL import Image, ImageOps
from invokeai.app.invocations.primitives import ImageField, ImageOutput
from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin
from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, invocation
from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, WithWorkflow, invocation
@invocation("cv_inpaint", title="OpenCV Inpaint", tags=["opencv", "inpaint"], category="inpaint", version="1.2.0")
class CvInpaintInvocation(BaseInvocation, WithMetadata):
@invocation("cv_inpaint", title="OpenCV Inpaint", tags=["opencv", "inpaint"], category="inpaint", version="1.1.0")
class CvInpaintInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Simple inpaint using opencv."""
image: ImageField = InputField(description="The image to inpaint")
@@ -41,7 +41,7 @@ class CvInpaintInvocation(BaseInvocation, WithMetadata):
node_id=self.id,
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(

View File

@@ -17,6 +17,7 @@ from invokeai.app.invocations.baseinvocation import (
InvocationContext,
OutputField,
WithMetadata,
WithWorkflow,
invocation,
invocation_output,
)
@@ -437,8 +438,8 @@ def get_faces_list(
return all_faces
@invocation("face_off", title="FaceOff", tags=["image", "faceoff", "face", "mask"], category="image", version="1.2.0")
class FaceOffInvocation(BaseInvocation, WithMetadata):
@invocation("face_off", title="FaceOff", tags=["image", "faceoff", "face", "mask"], category="image", version="1.1.0")
class FaceOffInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Bound, extract, and mask a face from an image using MediaPipe detection"""
image: ImageField = InputField(description="Image for face detection")
@@ -507,7 +508,7 @@ class FaceOffInvocation(BaseInvocation, WithMetadata):
node_id=self.id,
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
workflow=context.workflow,
workflow=self.workflow,
)
mask_dto = context.services.images.create(
@@ -531,8 +532,8 @@ class FaceOffInvocation(BaseInvocation, WithMetadata):
return output
@invocation("face_mask_detection", title="FaceMask", tags=["image", "face", "mask"], category="image", version="1.2.0")
class FaceMaskInvocation(BaseInvocation, WithMetadata):
@invocation("face_mask_detection", title="FaceMask", tags=["image", "face", "mask"], category="image", version="1.1.0")
class FaceMaskInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Face mask creation using mediapipe face detection"""
image: ImageField = InputField(description="Image to face detect")
@@ -626,7 +627,7 @@ class FaceMaskInvocation(BaseInvocation, WithMetadata):
node_id=self.id,
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
workflow=context.workflow,
workflow=self.workflow,
)
mask_dto = context.services.images.create(
@@ -649,9 +650,9 @@ class FaceMaskInvocation(BaseInvocation, WithMetadata):
@invocation(
"face_identifier", title="FaceIdentifier", tags=["image", "face", "identifier"], category="image", version="1.2.0"
"face_identifier", title="FaceIdentifier", tags=["image", "face", "identifier"], category="image", version="1.1.0"
)
class FaceIdentifierInvocation(BaseInvocation, WithMetadata):
class FaceIdentifierInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Outputs an image with detected face IDs printed on each face. For use with other FaceTools."""
image: ImageField = InputField(description="Image to face detect")
@@ -715,7 +716,7 @@ class FaceIdentifierInvocation(BaseInvocation, WithMetadata):
node_id=self.id,
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(

View File

@@ -13,7 +13,7 @@ from invokeai.app.shared.fields import FieldDescriptions
from invokeai.backend.image_util.invisible_watermark import InvisibleWatermark
from invokeai.backend.image_util.safety_checker import SafetyChecker
from .baseinvocation import BaseInvocation, Input, InputField, InvocationContext, WithMetadata, invocation
from .baseinvocation import BaseInvocation, Input, InputField, InvocationContext, WithMetadata, WithWorkflow, invocation
@invocation("show_image", title="Show Image", tags=["image"], category="image", version="1.0.0")
@@ -36,14 +36,8 @@ class ShowImageInvocation(BaseInvocation):
)
@invocation(
"blank_image",
title="Blank Image",
tags=["image"],
category="image",
version="1.2.0",
)
class BlankImageInvocation(BaseInvocation, WithMetadata):
@invocation("blank_image", title="Blank Image", tags=["image"], category="image", version="1.1.0")
class BlankImageInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Creates a blank image and forwards it to the pipeline"""
width: int = InputField(default=512, description="The width of the image")
@@ -62,7 +56,7 @@ class BlankImageInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -72,14 +66,8 @@ class BlankImageInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_crop",
title="Crop Image",
tags=["image", "crop"],
category="image",
version="1.2.0",
)
class ImageCropInvocation(BaseInvocation, WithMetadata):
@invocation("img_crop", title="Crop Image", tags=["image", "crop"], category="image", version="1.1.0")
class ImageCropInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Crops an image to a specified box. The box can be outside of the image."""
image: ImageField = InputField(description="The image to crop")
@@ -102,7 +90,7 @@ class ImageCropInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -167,14 +155,8 @@ class CenterPadCropInvocation(BaseInvocation):
)
@invocation(
"img_paste",
title="Paste Image",
tags=["image", "paste"],
category="image",
version="1.2.0",
)
class ImagePasteInvocation(BaseInvocation, WithMetadata):
@invocation("img_paste", title="Paste Image", tags=["image", "paste"], category="image", version="1.1.0")
class ImagePasteInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Pastes an image into another image."""
base_image: ImageField = InputField(description="The base image")
@@ -217,7 +199,7 @@ class ImagePasteInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -227,14 +209,8 @@ class ImagePasteInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"tomask",
title="Mask from Alpha",
tags=["image", "mask"],
category="image",
version="1.2.0",
)
class MaskFromAlphaInvocation(BaseInvocation, WithMetadata):
@invocation("tomask", title="Mask from Alpha", tags=["image", "mask"], category="image", version="1.1.0")
class MaskFromAlphaInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Extracts the alpha channel of an image as a mask."""
image: ImageField = InputField(description="The image to create the mask from")
@@ -255,7 +231,7 @@ class MaskFromAlphaInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -265,14 +241,8 @@ class MaskFromAlphaInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_mul",
title="Multiply Images",
tags=["image", "multiply"],
category="image",
version="1.2.0",
)
class ImageMultiplyInvocation(BaseInvocation, WithMetadata):
@invocation("img_mul", title="Multiply Images", tags=["image", "multiply"], category="image", version="1.1.0")
class ImageMultiplyInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Multiplies two images together using `PIL.ImageChops.multiply()`."""
image1: ImageField = InputField(description="The first image to multiply")
@@ -292,7 +262,7 @@ class ImageMultiplyInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -305,14 +275,8 @@ class ImageMultiplyInvocation(BaseInvocation, WithMetadata):
IMAGE_CHANNELS = Literal["A", "R", "G", "B"]
@invocation(
"img_chan",
title="Extract Image Channel",
tags=["image", "channel"],
category="image",
version="1.2.0",
)
class ImageChannelInvocation(BaseInvocation, WithMetadata):
@invocation("img_chan", title="Extract Image Channel", tags=["image", "channel"], category="image", version="1.1.0")
class ImageChannelInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Gets a channel from an image."""
image: ImageField = InputField(description="The image to get the channel from")
@@ -331,7 +295,7 @@ class ImageChannelInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -344,14 +308,8 @@ class ImageChannelInvocation(BaseInvocation, WithMetadata):
IMAGE_MODES = Literal["L", "RGB", "RGBA", "CMYK", "YCbCr", "LAB", "HSV", "I", "F"]
@invocation(
"img_conv",
title="Convert Image Mode",
tags=["image", "convert"],
category="image",
version="1.2.0",
)
class ImageConvertInvocation(BaseInvocation, WithMetadata):
@invocation("img_conv", title="Convert Image Mode", tags=["image", "convert"], category="image", version="1.1.0")
class ImageConvertInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Converts an image to a different mode."""
image: ImageField = InputField(description="The image to convert")
@@ -370,7 +328,7 @@ class ImageConvertInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -380,14 +338,8 @@ class ImageConvertInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_blur",
title="Blur Image",
tags=["image", "blur"],
category="image",
version="1.2.0",
)
class ImageBlurInvocation(BaseInvocation, WithMetadata):
@invocation("img_blur", title="Blur Image", tags=["image", "blur"], category="image", version="1.1.0")
class ImageBlurInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Blurs an image"""
image: ImageField = InputField(description="The image to blur")
@@ -411,7 +363,7 @@ class ImageBlurInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -441,14 +393,8 @@ PIL_RESAMPLING_MAP = {
}
@invocation(
"img_resize",
title="Resize Image",
tags=["image", "resize"],
category="image",
version="1.2.0",
)
class ImageResizeInvocation(BaseInvocation, WithMetadata):
@invocation("img_resize", title="Resize Image", tags=["image", "resize"], category="image", version="1.1.0")
class ImageResizeInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Resizes an image to specific dimensions"""
image: ImageField = InputField(description="The image to resize")
@@ -474,7 +420,7 @@ class ImageResizeInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -484,14 +430,8 @@ class ImageResizeInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_scale",
title="Scale Image",
tags=["image", "scale"],
category="image",
version="1.2.0",
)
class ImageScaleInvocation(BaseInvocation, WithMetadata):
@invocation("img_scale", title="Scale Image", tags=["image", "scale"], category="image", version="1.1.0")
class ImageScaleInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Scales an image by a factor"""
image: ImageField = InputField(description="The image to scale")
@@ -522,7 +462,7 @@ class ImageScaleInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -532,14 +472,8 @@ class ImageScaleInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_lerp",
title="Lerp Image",
tags=["image", "lerp"],
category="image",
version="1.2.0",
)
class ImageLerpInvocation(BaseInvocation, WithMetadata):
@invocation("img_lerp", title="Lerp Image", tags=["image", "lerp"], category="image", version="1.1.0")
class ImageLerpInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Linear interpolation of all pixels of an image"""
image: ImageField = InputField(description="The image to lerp")
@@ -562,7 +496,7 @@ class ImageLerpInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -572,14 +506,8 @@ class ImageLerpInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_ilerp",
title="Inverse Lerp Image",
tags=["image", "ilerp"],
category="image",
version="1.2.0",
)
class ImageInverseLerpInvocation(BaseInvocation, WithMetadata):
@invocation("img_ilerp", title="Inverse Lerp Image", tags=["image", "ilerp"], category="image", version="1.1.0")
class ImageInverseLerpInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Inverse linear interpolation of all pixels of an image"""
image: ImageField = InputField(description="The image to lerp")
@@ -602,7 +530,7 @@ class ImageInverseLerpInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -612,14 +540,8 @@ class ImageInverseLerpInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_nsfw",
title="Blur NSFW Image",
tags=["image", "nsfw"],
category="image",
version="1.2.0",
)
class ImageNSFWBlurInvocation(BaseInvocation, WithMetadata):
@invocation("img_nsfw", title="Blur NSFW Image", tags=["image", "nsfw"], category="image", version="1.1.0")
class ImageNSFWBlurInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Add blur to NSFW-flagged images"""
image: ImageField = InputField(description="The image to check")
@@ -644,7 +566,7 @@ class ImageNSFWBlurInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -665,9 +587,9 @@ class ImageNSFWBlurInvocation(BaseInvocation, WithMetadata):
title="Add Invisible Watermark",
tags=["image", "watermark"],
category="image",
version="1.2.0",
version="1.1.0",
)
class ImageWatermarkInvocation(BaseInvocation, WithMetadata):
class ImageWatermarkInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Add an invisible watermark to an image"""
image: ImageField = InputField(description="The image to check")
@@ -684,7 +606,7 @@ class ImageWatermarkInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -694,14 +616,8 @@ class ImageWatermarkInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"mask_edge",
title="Mask Edge",
tags=["image", "mask", "inpaint"],
category="image",
version="1.2.0",
)
class MaskEdgeInvocation(BaseInvocation, WithMetadata):
@invocation("mask_edge", title="Mask Edge", tags=["image", "mask", "inpaint"], category="image", version="1.1.0")
class MaskEdgeInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Applies an edge mask to an image"""
image: ImageField = InputField(description="The image to apply the mask to")
@@ -736,7 +652,7 @@ class MaskEdgeInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -751,9 +667,9 @@ class MaskEdgeInvocation(BaseInvocation, WithMetadata):
title="Combine Masks",
tags=["image", "mask", "multiply"],
category="image",
version="1.2.0",
version="1.1.0",
)
class MaskCombineInvocation(BaseInvocation, WithMetadata):
class MaskCombineInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Combine two masks together by multiplying them using `PIL.ImageChops.multiply()`."""
mask1: ImageField = InputField(description="The first mask to combine")
@@ -773,7 +689,7 @@ class MaskCombineInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -783,14 +699,8 @@ class MaskCombineInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"color_correct",
title="Color Correct",
tags=["image", "color"],
category="image",
version="1.2.0",
)
class ColorCorrectInvocation(BaseInvocation, WithMetadata):
@invocation("color_correct", title="Color Correct", tags=["image", "color"], category="image", version="1.1.0")
class ColorCorrectInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""
Shifts the colors of a target image to match the reference image, optionally
using a mask to only color-correct certain regions of the target image.
@@ -890,7 +800,7 @@ class ColorCorrectInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -900,14 +810,8 @@ class ColorCorrectInvocation(BaseInvocation, WithMetadata):
)
@invocation(
"img_hue_adjust",
title="Adjust Image Hue",
tags=["image", "hue"],
category="image",
version="1.2.0",
)
class ImageHueAdjustmentInvocation(BaseInvocation, WithMetadata):
@invocation("img_hue_adjust", title="Adjust Image Hue", tags=["image", "hue"], category="image", version="1.1.0")
class ImageHueAdjustmentInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Adjusts the Hue of an image."""
image: ImageField = InputField(description="The image to adjust")
@@ -936,7 +840,7 @@ class ImageHueAdjustmentInvocation(BaseInvocation, WithMetadata):
is_intermediate=self.is_intermediate,
session_id=context.graph_execution_state_id,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -1009,9 +913,9 @@ CHANNEL_FORMATS = {
"value",
],
category="image",
version="1.2.0",
version="1.1.0",
)
class ImageChannelOffsetInvocation(BaseInvocation, WithMetadata):
class ImageChannelOffsetInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Add or subtract a value from a specific color channel of an image."""
image: ImageField = InputField(description="The image to adjust")
@@ -1046,7 +950,7 @@ class ImageChannelOffsetInvocation(BaseInvocation, WithMetadata):
is_intermediate=self.is_intermediate,
session_id=context.graph_execution_state_id,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -1080,9 +984,9 @@ class ImageChannelOffsetInvocation(BaseInvocation, WithMetadata):
"value",
],
category="image",
version="1.2.0",
version="1.1.0",
)
class ImageChannelMultiplyInvocation(BaseInvocation, WithMetadata):
class ImageChannelMultiplyInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Scale a specific color channel of an image."""
image: ImageField = InputField(description="The image to adjust")
@@ -1121,7 +1025,7 @@ class ImageChannelMultiplyInvocation(BaseInvocation, WithMetadata):
node_id=self.id,
is_intermediate=self.is_intermediate,
session_id=context.graph_execution_state_id,
workflow=context.workflow,
workflow=self.workflow,
metadata=self.metadata,
)
@@ -1139,10 +1043,10 @@ class ImageChannelMultiplyInvocation(BaseInvocation, WithMetadata):
title="Save Image",
tags=["primitives", "image"],
category="primitives",
version="1.2.0",
version="1.1.0",
use_cache=False,
)
class SaveImageInvocation(BaseInvocation, WithMetadata):
class SaveImageInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Saves an image. Unlike an image primitive, this invocation stores a copy of the image."""
image: ImageField = InputField(description=FieldDescriptions.image)
@@ -1160,7 +1064,7 @@ class SaveImageInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -1178,7 +1082,7 @@ class SaveImageInvocation(BaseInvocation, WithMetadata):
version="1.0.1",
use_cache=False,
)
class LinearUIOutputInvocation(BaseInvocation, WithMetadata):
class LinearUIOutputInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Handles Linear UI Image Outputting tasks."""
image: ImageField = InputField(description=FieldDescriptions.image)

View File

@@ -13,7 +13,7 @@ from invokeai.backend.image_util.cv2_inpaint import cv2_inpaint
from invokeai.backend.image_util.lama import LaMA
from invokeai.backend.image_util.patchmatch import PatchMatch
from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, invocation
from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, WithWorkflow, invocation
from .image import PIL_RESAMPLING_MAP, PIL_RESAMPLING_MODES
@@ -118,8 +118,8 @@ def tile_fill_missing(im: Image.Image, tile_size: int = 16, seed: Optional[int]
return si
@invocation("infill_rgba", title="Solid Color Infill", tags=["image", "inpaint"], category="inpaint", version="1.2.0")
class InfillColorInvocation(BaseInvocation, WithMetadata):
@invocation("infill_rgba", title="Solid Color Infill", tags=["image", "inpaint"], category="inpaint", version="1.1.0")
class InfillColorInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Infills transparent areas of an image with a solid color"""
image: ImageField = InputField(description="The image to infill")
@@ -144,7 +144,7 @@ class InfillColorInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -154,8 +154,8 @@ class InfillColorInvocation(BaseInvocation, WithMetadata):
)
@invocation("infill_tile", title="Tile Infill", tags=["image", "inpaint"], category="inpaint", version="1.2.1")
class InfillTileInvocation(BaseInvocation, WithMetadata):
@invocation("infill_tile", title="Tile Infill", tags=["image", "inpaint"], category="inpaint", version="1.1.1")
class InfillTileInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Infills transparent areas of an image with tiles of the image"""
image: ImageField = InputField(description="The image to infill")
@@ -181,7 +181,7 @@ class InfillTileInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -192,9 +192,9 @@ class InfillTileInvocation(BaseInvocation, WithMetadata):
@invocation(
"infill_patchmatch", title="PatchMatch Infill", tags=["image", "inpaint"], category="inpaint", version="1.2.0"
"infill_patchmatch", title="PatchMatch Infill", tags=["image", "inpaint"], category="inpaint", version="1.1.0"
)
class InfillPatchMatchInvocation(BaseInvocation, WithMetadata):
class InfillPatchMatchInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Infills transparent areas of an image using the PatchMatch algorithm"""
image: ImageField = InputField(description="The image to infill")
@@ -235,7 +235,7 @@ class InfillPatchMatchInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -245,8 +245,8 @@ class InfillPatchMatchInvocation(BaseInvocation, WithMetadata):
)
@invocation("infill_lama", title="LaMa Infill", tags=["image", "inpaint"], category="inpaint", version="1.2.0")
class LaMaInfillInvocation(BaseInvocation, WithMetadata):
@invocation("infill_lama", title="LaMa Infill", tags=["image", "inpaint"], category="inpaint", version="1.1.0")
class LaMaInfillInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Infills transparent areas of an image using the LaMa model"""
image: ImageField = InputField(description="The image to infill")
@@ -264,7 +264,7 @@ class LaMaInfillInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -274,8 +274,8 @@ class LaMaInfillInvocation(BaseInvocation, WithMetadata):
)
@invocation("infill_cv2", title="CV2 Infill", tags=["image", "inpaint"], category="inpaint", version="1.2.0")
class CV2InfillInvocation(BaseInvocation, WithMetadata):
@invocation("infill_cv2", title="CV2 Infill", tags=["image", "inpaint"], category="inpaint", version="1.1.0")
class CV2InfillInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Infills transparent areas of an image using OpenCV Inpainting"""
image: ImageField = InputField(description="The image to infill")
@@ -293,7 +293,7 @@ class CV2InfillInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(

View File

@@ -64,6 +64,7 @@ from .baseinvocation import (
OutputField,
UIType,
WithMetadata,
WithWorkflow,
invocation,
invocation_output,
)
@@ -78,12 +79,6 @@ DEFAULT_PRECISION = choose_precision(choose_torch_device())
SAMPLER_NAME_VALUES = Literal[tuple(SCHEDULER_MAP.keys())]
# HACK: Many nodes are currently hard-coded to use a fixed latent scale factor of 8. This is fragile, and will need to
# be addressed if future models use a different latent scale factor. Also, note that there may be places where the scale
# factor is hard-coded to a literal '8' rather than using this constant.
# The ratio of image:latent dimensions is LATENT_SCALE_FACTOR:1, or 8:1.
LATENT_SCALE_FACTOR = 8
@invocation_output("scheduler_output")
class SchedulerOutput(BaseInvocationOutput):
@@ -399,9 +394,9 @@ class DenoiseLatentsInvocation(BaseInvocation):
exit_stack: ExitStack,
do_classifier_free_guidance: bool = True,
) -> List[ControlNetData]:
# Assuming fixed dimensional scaling of LATENT_SCALE_FACTOR.
control_height_resize = latents_shape[2] * LATENT_SCALE_FACTOR
control_width_resize = latents_shape[3] * LATENT_SCALE_FACTOR
# assuming fixed dimensional scaling of 8:1 for image:latents
control_height_resize = latents_shape[2] * 8
control_width_resize = latents_shape[3] * 8
if control_input is None:
control_list = None
elif isinstance(control_input, list) and len(control_input) == 0:
@@ -801,9 +796,9 @@ class DenoiseLatentsInvocation(BaseInvocation):
title="Latents to Image",
tags=["latents", "image", "vae", "l2i"],
category="latents",
version="1.2.0",
version="1.1.0",
)
class LatentsToImageInvocation(BaseInvocation, WithMetadata):
class LatentsToImageInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Generates an image from latents."""
latents: LatentsField = InputField(
@@ -885,7 +880,7 @@ class LatentsToImageInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(
@@ -914,12 +909,12 @@ class ResizeLatentsInvocation(BaseInvocation):
)
width: int = InputField(
ge=64,
multiple_of=LATENT_SCALE_FACTOR,
multiple_of=8,
description=FieldDescriptions.width,
)
height: int = InputField(
ge=64,
multiple_of=LATENT_SCALE_FACTOR,
multiple_of=8,
description=FieldDescriptions.width,
)
mode: LATENTS_INTERPOLATION_MODE = InputField(default="bilinear", description=FieldDescriptions.interp_mode)
@@ -933,7 +928,7 @@ class ResizeLatentsInvocation(BaseInvocation):
resized_latents = torch.nn.functional.interpolate(
latents.to(device),
size=(self.height // LATENT_SCALE_FACTOR, self.width // LATENT_SCALE_FACTOR),
size=(self.height // 8, self.width // 8),
mode=self.mode,
antialias=self.antialias if self.mode in ["bilinear", "bicubic"] else False,
)
@@ -1171,60 +1166,3 @@ class BlendLatentsInvocation(BaseInvocation):
# context.services.latents.set(name, resized_latents)
context.services.latents.save(name, blended_latents)
return build_latents_output(latents_name=name, latents=blended_latents)
# The Crop Latents node was copied from @skunkworxdark's implementation here:
# https://github.com/skunkworxdark/XYGrid_nodes/blob/74647fa9c1fa57d317a94bd43ca689af7f0aae5e/images_to_grids.py#L1117C1-L1167C80
@invocation(
"crop_latents",
title="Crop Latents",
tags=["latents", "crop"],
category="latents",
version="1.0.0",
)
# TODO(ryand): Named `CropLatentsCoreInvocation` to prevent a conflict with custom node `CropLatentsInvocation`.
# Currently, if the class names conflict then 'GET /openapi.json' fails.
class CropLatentsCoreInvocation(BaseInvocation):
"""Crops a latent-space tensor to a box specified in image-space. The box dimensions and coordinates must be
divisible by the latent scale factor of 8.
"""
latents: LatentsField = InputField(
description=FieldDescriptions.latents,
input=Input.Connection,
)
x: int = InputField(
ge=0,
multiple_of=LATENT_SCALE_FACTOR,
description="The left x coordinate (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space.",
)
y: int = InputField(
ge=0,
multiple_of=LATENT_SCALE_FACTOR,
description="The top y coordinate (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space.",
)
width: int = InputField(
ge=1,
multiple_of=LATENT_SCALE_FACTOR,
description="The width (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space.",
)
height: int = InputField(
ge=1,
multiple_of=LATENT_SCALE_FACTOR,
description="The height (in px) of the crop rectangle in image space. This value will be converted to a dimension in latent space.",
)
def invoke(self, context: InvocationContext) -> LatentsOutput:
latents = context.services.latents.get(self.latents.latents_name)
x1 = self.x // LATENT_SCALE_FACTOR
y1 = self.y // LATENT_SCALE_FACTOR
x2 = x1 + (self.width // LATENT_SCALE_FACTOR)
y2 = y1 + (self.height // LATENT_SCALE_FACTOR)
cropped_latents = latents[..., y1:y2, x1:x2]
name = f"{context.graph_execution_state_id}__{self.id}"
context.services.latents.save(name, cropped_latents)
return build_latents_output(latents_name=name, latents=cropped_latents)

View File

@@ -31,6 +31,7 @@ from .baseinvocation import (
UIComponent,
UIType,
WithMetadata,
WithWorkflow,
invocation,
invocation_output,
)
@@ -325,9 +326,9 @@ class ONNXTextToLatentsInvocation(BaseInvocation):
title="ONNX Latents to Image",
tags=["latents", "image", "vae", "onnx"],
category="image",
version="1.2.0",
version="1.1.0",
)
class ONNXLatentsToImageInvocation(BaseInvocation, WithMetadata):
class ONNXLatentsToImageInvocation(BaseInvocation, WithMetadata, WithWorkflow):
"""Generates an image from latents."""
latents: LatentsField = InputField(
@@ -377,7 +378,7 @@ class ONNXLatentsToImageInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(

View File

@@ -1,180 +0,0 @@
import numpy as np
from PIL import Image
from pydantic import BaseModel
from invokeai.app.invocations.baseinvocation import (
BaseInvocation,
BaseInvocationOutput,
InputField,
InvocationContext,
OutputField,
WithMetadata,
invocation,
invocation_output,
)
from invokeai.app.invocations.primitives import ImageField, ImageOutput
from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin
from invokeai.backend.tiles.tiles import calc_tiles_with_overlap, merge_tiles_with_linear_blending
from invokeai.backend.tiles.utils import Tile
class TileWithImage(BaseModel):
tile: Tile
image: ImageField
@invocation_output("calculate_image_tiles_output")
class CalculateImageTilesOutput(BaseInvocationOutput):
tiles: list[Tile] = OutputField(description="The tiles coordinates that cover a particular image shape.")
@invocation("calculate_image_tiles", title="Calculate Image Tiles", tags=["tiles"], category="tiles", version="1.0.0")
class CalculateImageTilesInvocation(BaseInvocation):
"""Calculate the coordinates and overlaps of tiles that cover a target image shape."""
image_width: int = InputField(ge=1, default=1024, description="The image width, in pixels, to calculate tiles for.")
image_height: int = InputField(
ge=1, default=1024, description="The image height, in pixels, to calculate tiles for."
)
tile_width: int = InputField(ge=1, default=576, description="The tile width, in pixels.")
tile_height: int = InputField(ge=1, default=576, description="The tile height, in pixels.")
overlap: int = InputField(
ge=0,
default=128,
description="The target overlap, in pixels, between adjacent tiles. Adjacent tiles will overlap by at least this amount",
)
def invoke(self, context: InvocationContext) -> CalculateImageTilesOutput:
tiles = calc_tiles_with_overlap(
image_height=self.image_height,
image_width=self.image_width,
tile_height=self.tile_height,
tile_width=self.tile_width,
overlap=self.overlap,
)
return CalculateImageTilesOutput(tiles=tiles)
@invocation_output("tile_to_properties_output")
class TileToPropertiesOutput(BaseInvocationOutput):
coords_left: int = OutputField(description="Left coordinate of the tile relative to its parent image.")
coords_right: int = OutputField(description="Right coordinate of the tile relative to its parent image.")
coords_top: int = OutputField(description="Top coordinate of the tile relative to its parent image.")
coords_bottom: int = OutputField(description="Bottom coordinate of the tile relative to its parent image.")
# HACK: The width and height fields are 'meta' fields that can easily be calculated from the other fields on this
# object. Including redundant fields that can cheaply/easily be re-calculated goes against conventional API design
# principles. These fields are included, because 1) they are often useful in tiled workflows, and 2) they are
# difficult to calculate in a workflow (even though it's just a couple of subtraction nodes the graph gets
# surprisingly complicated).
width: int = OutputField(description="The width of the tile. Equal to coords_right - coords_left.")
height: int = OutputField(description="The height of the tile. Equal to coords_bottom - coords_top.")
overlap_top: int = OutputField(description="Overlap between this tile and its top neighbor.")
overlap_bottom: int = OutputField(description="Overlap between this tile and its bottom neighbor.")
overlap_left: int = OutputField(description="Overlap between this tile and its left neighbor.")
overlap_right: int = OutputField(description="Overlap between this tile and its right neighbor.")
@invocation("tile_to_properties", title="Tile to Properties", tags=["tiles"], category="tiles", version="1.0.0")
class TileToPropertiesInvocation(BaseInvocation):
"""Split a Tile into its individual properties."""
tile: Tile = InputField(description="The tile to split into properties.")
def invoke(self, context: InvocationContext) -> TileToPropertiesOutput:
return TileToPropertiesOutput(
coords_left=self.tile.coords.left,
coords_right=self.tile.coords.right,
coords_top=self.tile.coords.top,
coords_bottom=self.tile.coords.bottom,
width=self.tile.coords.right - self.tile.coords.left,
height=self.tile.coords.bottom - self.tile.coords.top,
overlap_top=self.tile.overlap.top,
overlap_bottom=self.tile.overlap.bottom,
overlap_left=self.tile.overlap.left,
overlap_right=self.tile.overlap.right,
)
@invocation_output("pair_tile_image_output")
class PairTileImageOutput(BaseInvocationOutput):
tile_with_image: TileWithImage = OutputField(description="A tile description with its corresponding image.")
@invocation("pair_tile_image", title="Pair Tile with Image", tags=["tiles"], category="tiles", version="1.0.0")
class PairTileImageInvocation(BaseInvocation):
"""Pair an image with its tile properties."""
# TODO(ryand): The only reason that PairTileImage is needed is because the iterate/collect nodes don't preserve
# order. Can this be fixed?
image: ImageField = InputField(description="The tile image.")
tile: Tile = InputField(description="The tile properties.")
def invoke(self, context: InvocationContext) -> PairTileImageOutput:
return PairTileImageOutput(
tile_with_image=TileWithImage(
tile=self.tile,
image=self.image,
)
)
@invocation("merge_tiles_to_image", title="Merge Tiles to Image", tags=["tiles"], category="tiles", version="1.1.0")
class MergeTilesToImageInvocation(BaseInvocation, WithMetadata):
"""Merge multiple tile images into a single image."""
# Inputs
tiles_with_images: list[TileWithImage] = InputField(description="A list of tile images with tile properties.")
blend_amount: int = InputField(
ge=0,
description="The amount to blend adjacent tiles in pixels. Must be <= the amount of overlap between adjacent tiles.",
)
def invoke(self, context: InvocationContext) -> ImageOutput:
images = [twi.image for twi in self.tiles_with_images]
tiles = [twi.tile for twi in self.tiles_with_images]
# Infer the output image dimensions from the max/min tile limits.
height = 0
width = 0
for tile in tiles:
height = max(height, tile.coords.bottom)
width = max(width, tile.coords.right)
# Get all tile images for processing.
# TODO(ryand): It pains me that we spend time PNG decoding each tile from disk when they almost certainly
# existed in memory at an earlier point in the graph.
tile_np_images: list[np.ndarray] = []
for image in images:
pil_image = context.services.images.get_pil_image(image.image_name)
pil_image = pil_image.convert("RGB")
tile_np_images.append(np.array(pil_image))
# Prepare the output image buffer.
# Check the first tile to determine how many image channels are expected in the output.
channels = tile_np_images[0].shape[-1]
dtype = tile_np_images[0].dtype
np_image = np.zeros(shape=(height, width, channels), dtype=dtype)
merge_tiles_with_linear_blending(
dst_image=np_image, tiles=tiles, tile_images=tile_np_images, blend_amount=self.blend_amount
)
pil_image = Image.fromarray(np_image)
image_dto = context.services.images.create(
image=pil_image,
image_origin=ResourceOrigin.INTERNAL,
image_category=ImageCategory.GENERAL,
node_id=self.id,
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
)
return ImageOutput(
image=ImageField(image_name=image_dto.image_name),
width=image_dto.width,
height=image_dto.height,
)

View File

@@ -14,7 +14,7 @@ from invokeai.app.services.image_records.image_records_common import ImageCatego
from invokeai.backend.image_util.realesrgan.realesrgan import RealESRGAN
from invokeai.backend.util.devices import choose_torch_device
from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, invocation
from .baseinvocation import BaseInvocation, InputField, InvocationContext, WithMetadata, WithWorkflow, invocation
# TODO: Populate this from disk?
# TODO: Use model manager to load?
@@ -29,8 +29,8 @@ if choose_torch_device() == torch.device("mps"):
from torch import mps
@invocation("esrgan", title="Upscale (RealESRGAN)", tags=["esrgan", "upscale"], category="esrgan", version="1.3.0")
class ESRGANInvocation(BaseInvocation, WithMetadata):
@invocation("esrgan", title="Upscale (RealESRGAN)", tags=["esrgan", "upscale"], category="esrgan", version="1.2.0")
class ESRGANInvocation(BaseInvocation, WithWorkflow, WithMetadata):
"""Upscales an image using RealESRGAN."""
image: ImageField = InputField(description="The input image")
@@ -118,7 +118,7 @@ class ESRGANInvocation(BaseInvocation, WithMetadata):
session_id=context.graph_execution_state_id,
is_intermediate=self.is_intermediate,
metadata=self.metadata,
workflow=context.workflow,
workflow=self.workflow,
)
return ImageOutput(

View File

@@ -4,7 +4,7 @@ from typing import Optional, cast
from invokeai.app.services.image_records.image_records_common import ImageRecord, deserialize_image_record
from invokeai.app.services.shared.pagination import OffsetPaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.shared.sqlite import SqliteDatabase
from .board_image_records_base import BoardImageRecordStorageBase

View File

@@ -3,7 +3,7 @@ import threading
from typing import Union, cast
from invokeai.app.services.shared.pagination import OffsetPaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.shared.sqlite import SqliteDatabase
from invokeai.app.util.misc import uuid_string
from .board_records_base import BoardRecordStorageBase

View File

@@ -4,8 +4,7 @@ from typing import Optional
from PIL.Image import Image as PILImageType
from invokeai.app.invocations.baseinvocation import MetadataField
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID
from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField
class ImageFileStorageBase(ABC):
@@ -34,7 +33,7 @@ class ImageFileStorageBase(ABC):
image: PILImageType,
image_name: str,
metadata: Optional[MetadataField] = None,
workflow: Optional[WorkflowWithoutID] = None,
workflow: Optional[WorkflowField] = None,
thumbnail_size: int = 256,
) -> None:
"""Saves an image and a 256x256 WEBP thumbnail. Returns a tuple of the image name, thumbnail name, and created timestamp."""
@@ -44,8 +43,3 @@ class ImageFileStorageBase(ABC):
def delete(self, image_name: str) -> None:
"""Deletes an image and its thumbnail (if one exists)."""
pass
@abstractmethod
def get_workflow(self, image_name: str) -> Optional[WorkflowWithoutID]:
"""Gets the workflow of an image."""
pass

View File

@@ -7,9 +7,8 @@ from PIL import Image, PngImagePlugin
from PIL.Image import Image as PILImageType
from send2trash import send2trash
from invokeai.app.invocations.baseinvocation import MetadataField
from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField
from invokeai.app.services.invoker import Invoker
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID
from invokeai.app.util.thumbnails import get_thumbnail_name, make_thumbnail
from .image_files_base import ImageFileStorageBase
@@ -57,7 +56,7 @@ class DiskImageFileStorage(ImageFileStorageBase):
image: PILImageType,
image_name: str,
metadata: Optional[MetadataField] = None,
workflow: Optional[WorkflowWithoutID] = None,
workflow: Optional[WorkflowField] = None,
thumbnail_size: int = 256,
) -> None:
try:
@@ -65,19 +64,12 @@ class DiskImageFileStorage(ImageFileStorageBase):
image_path = self.get_path(image_name)
pnginfo = PngImagePlugin.PngInfo()
info_dict = {}
if metadata is not None:
metadata_json = metadata.model_dump_json()
info_dict["invokeai_metadata"] = metadata_json
pnginfo.add_text("invokeai_metadata", metadata_json)
pnginfo.add_text("invokeai_metadata", metadata.model_dump_json())
if workflow is not None:
workflow_json = workflow.model_dump_json()
info_dict["invokeai_workflow"] = workflow_json
pnginfo.add_text("invokeai_workflow", workflow_json)
pnginfo.add_text("invokeai_workflow", workflow.model_dump_json())
# When saving the image, the image object's info field is not populated. We need to set it
image.info = info_dict
image.save(
image_path,
"PNG",
@@ -129,13 +121,6 @@ class DiskImageFileStorage(ImageFileStorageBase):
path = path if isinstance(path, Path) else Path(path)
return path.exists()
def get_workflow(self, image_name: str) -> WorkflowWithoutID | None:
image = self.get(image_name)
workflow = image.info.get("invokeai_workflow", None)
if workflow is not None:
return WorkflowWithoutID.model_validate_json(workflow)
return None
def __validate_storage_folders(self) -> None:
"""Checks if the required output folders exist and create them if they don't"""
folders: list[Path] = [self.__output_folder, self.__thumbnails_folder]

View File

@@ -75,7 +75,6 @@ class ImageRecordStorageBase(ABC):
image_category: ImageCategory,
width: int,
height: int,
has_workflow: bool,
is_intermediate: Optional[bool] = False,
starred: Optional[bool] = False,
session_id: Optional[str] = None,

View File

@@ -100,7 +100,6 @@ IMAGE_DTO_COLS = ", ".join(
"height",
"session_id",
"node_id",
"has_workflow",
"is_intermediate",
"created_at",
"updated_at",
@@ -146,7 +145,6 @@ class ImageRecord(BaseModelExcludeNull):
"""The node ID that generated this image, if it is a generated image."""
starred: bool = Field(description="Whether this image is starred.")
"""Whether this image is starred."""
has_workflow: bool = Field(description="Whether this image has a workflow.")
class ImageRecordChanges(BaseModelExcludeNull, extra="allow"):
@@ -190,7 +188,6 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord:
deleted_at = image_dict.get("deleted_at", get_iso_timestamp())
is_intermediate = image_dict.get("is_intermediate", False)
starred = image_dict.get("starred", False)
has_workflow = image_dict.get("has_workflow", False)
return ImageRecord(
image_name=image_name,
@@ -205,5 +202,4 @@ def deserialize_image_record(image_dict: dict) -> ImageRecord:
deleted_at=deleted_at,
is_intermediate=is_intermediate,
starred=starred,
has_workflow=has_workflow,
)

View File

@@ -5,7 +5,7 @@ from typing import Optional, Union, cast
from invokeai.app.invocations.baseinvocation import MetadataField, MetadataFieldValidator
from invokeai.app.services.shared.pagination import OffsetPaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.shared.sqlite import SqliteDatabase
from .image_records_base import ImageRecordStorageBase
from .image_records_common import (
@@ -117,16 +117,6 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
"""
)
self._cursor.execute("PRAGMA table_info(images)")
columns = [column[1] for column in self._cursor.fetchall()]
if "has_workflow" not in columns:
self._cursor.execute(
"""--sql
ALTER TABLE images
ADD COLUMN has_workflow BOOLEAN DEFAULT FALSE;
"""
)
def get(self, image_name: str) -> ImageRecord:
try:
self._lock.acquire()
@@ -418,7 +408,6 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
image_category: ImageCategory,
width: int,
height: int,
has_workflow: bool,
is_intermediate: Optional[bool] = False,
starred: Optional[bool] = False,
session_id: Optional[str] = None,
@@ -440,10 +429,9 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
session_id,
metadata,
is_intermediate,
starred,
has_workflow
starred
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
""",
(
image_name,
@@ -456,7 +444,6 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
metadata_json,
is_intermediate,
starred,
has_workflow,
),
)
self._conn.commit()

View File

@@ -3,7 +3,7 @@ from typing import Callable, Optional
from PIL.Image import Image as PILImageType
from invokeai.app.invocations.baseinvocation import MetadataField
from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField
from invokeai.app.services.image_records.image_records_common import (
ImageCategory,
ImageRecord,
@@ -12,7 +12,6 @@ from invokeai.app.services.image_records.image_records_common import (
)
from invokeai.app.services.images.images_common import ImageDTO
from invokeai.app.services.shared.pagination import OffsetPaginatedResults
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID
class ImageServiceABC(ABC):
@@ -52,7 +51,7 @@ class ImageServiceABC(ABC):
board_id: Optional[str] = None,
is_intermediate: Optional[bool] = False,
metadata: Optional[MetadataField] = None,
workflow: Optional[WorkflowWithoutID] = None,
workflow: Optional[WorkflowField] = None,
) -> ImageDTO:
"""Creates an image, storing the file and its metadata."""
pass
@@ -86,11 +85,6 @@ class ImageServiceABC(ABC):
"""Gets an image's metadata."""
pass
@abstractmethod
def get_workflow(self, image_name: str) -> Optional[WorkflowWithoutID]:
"""Gets an image's workflow."""
pass
@abstractmethod
def get_path(self, image_name: str, thumbnail: bool = False) -> str:
"""Gets an image's path."""

View File

@@ -24,6 +24,11 @@ class ImageDTO(ImageRecord, ImageUrlsDTO):
default=None, description="The id of the board the image belongs to, if one exists."
)
"""The id of the board the image belongs to, if one exists."""
workflow_id: Optional[str] = Field(
default=None,
description="The workflow that generated this image.",
)
"""The workflow that generated this image."""
def image_record_to_dto(
@@ -31,6 +36,7 @@ def image_record_to_dto(
image_url: str,
thumbnail_url: str,
board_id: Optional[str],
workflow_id: Optional[str],
) -> ImageDTO:
"""Converts an image record to an image DTO."""
return ImageDTO(
@@ -38,4 +44,5 @@ def image_record_to_dto(
image_url=image_url,
thumbnail_url=thumbnail_url,
board_id=board_id,
workflow_id=workflow_id,
)

View File

@@ -2,10 +2,9 @@ from typing import Optional
from PIL.Image import Image as PILImageType
from invokeai.app.invocations.baseinvocation import MetadataField
from invokeai.app.invocations.baseinvocation import MetadataField, WorkflowField
from invokeai.app.services.invoker import Invoker
from invokeai.app.services.shared.pagination import OffsetPaginatedResults
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID
from ..image_files.image_files_common import (
ImageFileDeleteException,
@@ -43,7 +42,7 @@ class ImageService(ImageServiceABC):
board_id: Optional[str] = None,
is_intermediate: Optional[bool] = False,
metadata: Optional[MetadataField] = None,
workflow: Optional[WorkflowWithoutID] = None,
workflow: Optional[WorkflowField] = None,
) -> ImageDTO:
if image_origin not in ResourceOrigin:
raise InvalidOriginException
@@ -56,6 +55,12 @@ class ImageService(ImageServiceABC):
(width, height) = image.size
try:
if workflow is not None:
created_workflow = self.__invoker.services.workflow_records.create(workflow)
workflow_id = created_workflow.model_dump()["id"]
else:
workflow_id = None
# TODO: Consider using a transaction here to ensure consistency between storage and database
self.__invoker.services.image_records.save(
# Non-nullable fields
@@ -64,7 +69,6 @@ class ImageService(ImageServiceABC):
image_category=image_category,
width=width,
height=height,
has_workflow=workflow is not None,
# Meta fields
is_intermediate=is_intermediate,
# Nullable fields
@@ -74,6 +78,8 @@ class ImageService(ImageServiceABC):
)
if board_id is not None:
self.__invoker.services.board_image_records.add_image_to_board(board_id=board_id, image_name=image_name)
if workflow_id is not None:
self.__invoker.services.workflow_image_records.create(workflow_id=workflow_id, image_name=image_name)
self.__invoker.services.image_files.save(
image_name=image_name, image=image, metadata=metadata, workflow=workflow
)
@@ -137,6 +143,7 @@ class ImageService(ImageServiceABC):
image_url=self.__invoker.services.urls.get_image_url(image_name),
thumbnail_url=self.__invoker.services.urls.get_image_url(image_name, True),
board_id=self.__invoker.services.board_image_records.get_board_for_image(image_name),
workflow_id=self.__invoker.services.workflow_image_records.get_workflow_for_image(image_name),
)
return image_dto
@@ -157,15 +164,18 @@ class ImageService(ImageServiceABC):
self.__invoker.services.logger.error("Problem getting image DTO")
raise e
def get_workflow(self, image_name: str) -> Optional[WorkflowWithoutID]:
def get_workflow(self, image_name: str) -> Optional[WorkflowField]:
try:
return self.__invoker.services.image_files.get_workflow(image_name)
except ImageFileNotFoundException:
self.__invoker.services.logger.error("Image file not found")
raise
except Exception:
self.__invoker.services.logger.error("Problem getting image workflow")
workflow_id = self.__invoker.services.workflow_image_records.get_workflow_for_image(image_name)
if workflow_id is None:
return None
return self.__invoker.services.workflow_records.get(workflow_id)
except ImageRecordNotFoundException:
self.__invoker.services.logger.error("Image record not found")
raise
except Exception as e:
self.__invoker.services.logger.error("Problem getting image DTO")
raise e
def get_path(self, image_name: str, thumbnail: bool = False) -> str:
try:
@@ -213,6 +223,7 @@ class ImageService(ImageServiceABC):
image_url=self.__invoker.services.urls.get_image_url(r.image_name),
thumbnail_url=self.__invoker.services.urls.get_image_url(r.image_name, True),
board_id=self.__invoker.services.board_image_records.get_board_for_image(r.image_name),
workflow_id=self.__invoker.services.workflow_image_records.get_workflow_for_image(r.image_name),
)
for r in results.items
]

View File

@@ -108,7 +108,6 @@ class DefaultInvocationProcessor(InvocationProcessorABC):
queue_item_id=queue_item.session_queue_item_id,
queue_id=queue_item.session_queue_id,
queue_batch_id=queue_item.session_queue_batch_id,
workflow=queue_item.workflow,
)
)
@@ -179,7 +178,6 @@ class DefaultInvocationProcessor(InvocationProcessorABC):
session_queue_item_id=queue_item.session_queue_item_id,
session_queue_id=queue_item.session_queue_id,
graph_execution_state=graph_execution_state,
workflow=queue_item.workflow,
invoke_all=True,
)
except Exception as e:

View File

@@ -1,12 +1,9 @@
# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654)
import time
from typing import Optional
from pydantic import BaseModel, Field
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID
class InvocationQueueItem(BaseModel):
graph_execution_state_id: str = Field(description="The ID of the graph execution state")
@@ -18,6 +15,5 @@ class InvocationQueueItem(BaseModel):
session_queue_batch_id: str = Field(
description="The ID of the session batch from which this invocation queue item came"
)
workflow: Optional[WorkflowWithoutID] = Field(description="The workflow associated with this queue item")
invoke_all: bool = Field(default=False)
timestamp: float = Field(default_factory=time.time)

View File

@@ -28,6 +28,7 @@ if TYPE_CHECKING:
from .session_queue.session_queue_base import SessionQueueBase
from .shared.graph import GraphExecutionState, LibraryGraph
from .urls.urls_base import UrlServiceBase
from .workflow_image_records.workflow_image_records_base import WorkflowImageRecordsStorageBase
from .workflow_records.workflow_records_base import WorkflowRecordsStorageBase
@@ -58,6 +59,7 @@ class InvocationServices:
invocation_cache: "InvocationCacheBase"
names: "NameServiceBase"
urls: "UrlServiceBase"
workflow_image_records: "WorkflowImageRecordsStorageBase"
workflow_records: "WorkflowRecordsStorageBase"
def __init__(
@@ -85,6 +87,7 @@ class InvocationServices:
invocation_cache: "InvocationCacheBase",
names: "NameServiceBase",
urls: "UrlServiceBase",
workflow_image_records: "WorkflowImageRecordsStorageBase",
workflow_records: "WorkflowRecordsStorageBase",
):
self.board_images = board_images
@@ -110,4 +113,5 @@ class InvocationServices:
self.invocation_cache = invocation_cache
self.names = names
self.urls = urls
self.workflow_image_records = workflow_image_records
self.workflow_records = workflow_records

View File

@@ -2,8 +2,6 @@
from typing import Optional
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowWithoutID
from .invocation_queue.invocation_queue_common import InvocationQueueItem
from .invocation_services import InvocationServices
from .shared.graph import Graph, GraphExecutionState
@@ -24,7 +22,6 @@ class Invoker:
session_queue_item_id: int,
session_queue_batch_id: str,
graph_execution_state: GraphExecutionState,
workflow: Optional[WorkflowWithoutID] = None,
invoke_all: bool = False,
) -> Optional[str]:
"""Determines the next node to invoke and enqueues it, preparing if needed.
@@ -46,7 +43,6 @@ class Invoker:
session_queue_batch_id=session_queue_batch_id,
graph_execution_state_id=graph_execution_state.id,
invocation_id=invocation.id,
workflow=workflow,
invoke_all=invoke_all,
)
)

View File

@@ -5,7 +5,7 @@ from typing import Generic, Optional, TypeVar, get_args
from pydantic import BaseModel, TypeAdapter
from invokeai.app.services.shared.pagination import PaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.shared.sqlite import SqliteDatabase
from .item_storage_base import ItemStorageABC

View File

@@ -5,8 +5,6 @@ from typing import Union
import torch
from invokeai.app.services.invoker import Invoker
from .latents_storage_base import LatentsStorageBase
@@ -19,10 +17,6 @@ class DiskLatentsStorage(LatentsStorageBase):
self.__output_folder = output_folder if isinstance(output_folder, Path) else Path(output_folder)
self.__output_folder.mkdir(parents=True, exist_ok=True)
def start(self, invoker: Invoker) -> None:
self._invoker = invoker
self._delete_all_latents()
def get(self, name: str) -> torch.Tensor:
latent_path = self.get_path(name)
return torch.load(latent_path)
@@ -38,21 +32,3 @@ class DiskLatentsStorage(LatentsStorageBase):
def get_path(self, name: str) -> Path:
return self.__output_folder / name
def _delete_all_latents(self) -> None:
"""
Deletes all latents from disk.
Must be called after we have access to `self._invoker` (e.g. in `start()`).
"""
deleted_latents_count = 0
freed_space = 0
for latents_file in Path(self.__output_folder).glob("*"):
if latents_file.is_file():
freed_space += latents_file.stat().st_size
deleted_latents_count += 1
latents_file.unlink()
if deleted_latents_count > 0:
freed_space_in_mb = round(freed_space / 1024 / 1024, 2)
self._invoker.services.logger.info(
f"Deleted {deleted_latents_count} latents files (freed {freed_space_in_mb}MB)"
)

View File

@@ -5,8 +5,6 @@ from typing import Dict, Optional
import torch
from invokeai.app.services.invoker import Invoker
from .latents_storage_base import LatentsStorageBase
@@ -25,18 +23,6 @@ class ForwardCacheLatentsStorage(LatentsStorageBase):
self.__cache_ids = Queue()
self.__max_cache_size = max_cache_size
def start(self, invoker: Invoker) -> None:
self._invoker = invoker
start_op = getattr(self.__underlying_storage, "start", None)
if callable(start_op):
start_op(invoker)
def stop(self, invoker: Invoker) -> None:
self._invoker = invoker
stop_op = getattr(self.__underlying_storage, "stop", None)
if callable(stop_op):
stop_op(invoker)
def get(self, name: str) -> torch.Tensor:
cache_item = self.__get_cache(name)
if cache_item is not None:

View File

@@ -52,7 +52,7 @@ from invokeai.backend.model_manager.config import (
ModelType,
)
from ..shared.sqlite.sqlite_database import SqliteDatabase
from ..shared.sqlite import SqliteDatabase
from .model_records_base import (
CONFIG_FILE_VERSION,
DuplicateModelException,

View File

@@ -22,6 +22,11 @@ class SessionProcessorBase(ABC):
"""Pauses the session processor"""
pass
@abstractmethod
def take_one(self) -> SessionProcessorStatus:
"""Takes one session from the queue and executes it"""
pass
@abstractmethod
def get_status(self) -> SessionProcessorStatus:
"""Gets the status of the session processor"""

View File

@@ -25,6 +25,7 @@ class DefaultSessionProcessor(SessionProcessorBase):
self.__resume_event = ThreadEvent()
self.__stop_event = ThreadEvent()
self.__poll_now_event = ThreadEvent()
self.__take_one_event = ThreadEvent()
local_handler.register(event_name=EventServiceBase.queue_event, _func=self._on_queue_event)
@@ -36,6 +37,7 @@ class DefaultSessionProcessor(SessionProcessorBase):
"stop_event": self.__stop_event,
"poll_now_event": self.__poll_now_event,
"resume_event": self.__resume_event,
"take_one_event": self.__take_one_event,
},
)
self.__thread.start()
@@ -81,6 +83,13 @@ class DefaultSessionProcessor(SessionProcessorBase):
self.__resume_event.clear()
return self.get_status()
def take_one(self) -> SessionProcessorStatus:
if self.__queue_item is None and not self.__resume_event.is_set():
self.__resume_event.set()
self.__take_one_event.set()
self._poll_now()
return self.get_status()
def get_status(self) -> SessionProcessorStatus:
return SessionProcessorStatus(
is_started=self.__resume_event.is_set(),
@@ -92,9 +101,11 @@ class DefaultSessionProcessor(SessionProcessorBase):
stop_event: ThreadEvent,
poll_now_event: ThreadEvent,
resume_event: ThreadEvent,
take_one_event: ThreadEvent,
):
try:
stop_event.clear()
take_one_event.clear()
resume_event.set()
self.__threadLimit.acquire()
queue_item: Optional[SessionQueueItem] = None
@@ -114,11 +125,14 @@ class DefaultSessionProcessor(SessionProcessorBase):
session_queue_id=queue_item.queue_id,
session_queue_item_id=queue_item.item_id,
graph_execution_state=queue_item.session,
workflow=queue_item.workflow,
invoke_all=True,
)
queue_item = None
if take_one_event.is_set():
resume_event.clear()
take_one_event.clear()
if queue_item is None:
self.__invoker.services.logger.debug("Waiting for next polling interval or event")
poll_now_event.wait(POLLING_INTERVAL)

View File

@@ -8,10 +8,6 @@ from pydantic_core import to_jsonable_python
from invokeai.app.invocations.baseinvocation import BaseInvocation
from invokeai.app.services.shared.graph import Graph, GraphExecutionState, NodeNotFoundError
from invokeai.app.services.workflow_records.workflow_records_common import (
WorkflowWithoutID,
WorkflowWithoutIDValidator,
)
from invokeai.app.util.misc import uuid_string
# region Errors
@@ -70,9 +66,6 @@ class Batch(BaseModel):
batch_id: str = Field(default_factory=uuid_string, description="The ID of the batch")
data: Optional[BatchDataCollection] = Field(default=None, description="The batch data collection.")
graph: Graph = Field(description="The graph to initialize the session with")
workflow: Optional[WorkflowWithoutID] = Field(
default=None, description="The workflow to initialize the session with"
)
runs: int = Field(
default=1, ge=1, description="Int stating how many times to iterate through all possible batch indices"
)
@@ -171,14 +164,6 @@ def get_session(queue_item_dict: dict) -> GraphExecutionState:
return session
def get_workflow(queue_item_dict: dict) -> Optional[WorkflowWithoutID]:
workflow_raw = queue_item_dict.get("workflow", None)
if workflow_raw is not None:
workflow = WorkflowWithoutIDValidator.validate_json(workflow_raw, strict=False)
return workflow
return None
class SessionQueueItemWithoutGraph(BaseModel):
"""Session queue item without the full graph. Used for serialization."""
@@ -228,16 +213,12 @@ class SessionQueueItemDTO(SessionQueueItemWithoutGraph):
class SessionQueueItem(SessionQueueItemWithoutGraph):
session: GraphExecutionState = Field(description="The fully-populated session to be executed")
workflow: Optional[WorkflowWithoutID] = Field(
default=None, description="The workflow associated with this queue item"
)
@classmethod
def queue_item_from_dict(cls, queue_item_dict: dict) -> "SessionQueueItem":
# must parse these manually
queue_item_dict["field_values"] = get_field_values(queue_item_dict)
queue_item_dict["session"] = get_session(queue_item_dict)
queue_item_dict["workflow"] = get_workflow(queue_item_dict)
return SessionQueueItem(**queue_item_dict)
model_config = ConfigDict(
@@ -353,7 +334,7 @@ def populate_graph(graph: Graph, node_field_values: Iterable[NodeFieldValue]) ->
def create_session_nfv_tuples(
batch: Batch, maximum: int
) -> Generator[tuple[GraphExecutionState, list[NodeFieldValue], Optional[WorkflowWithoutID]], None, None]:
) -> Generator[tuple[GraphExecutionState, list[NodeFieldValue]], None, None]:
"""
Create all graph permutations from the given batch data and graph. Yields tuples
of the form (graph, batch_data_items) where batch_data_items is the list of BatchDataItems
@@ -384,7 +365,7 @@ def create_session_nfv_tuples(
return
flat_node_field_values = list(chain.from_iterable(d))
graph = populate_graph(batch.graph, flat_node_field_values)
yield (GraphExecutionState(graph=graph), flat_node_field_values, batch.workflow)
yield (GraphExecutionState(graph=graph), flat_node_field_values)
count += 1
@@ -410,14 +391,12 @@ def calc_session_count(batch: Batch) -> int:
class SessionQueueValueToInsert(NamedTuple):
"""A tuple of values to insert into the session_queue table"""
# Careful with the ordering of this - it must match the insert statement
queue_id: str # queue_id
session: str # session json
session_id: str # session_id
batch_id: str # batch_id
field_values: Optional[str] # field_values json
priority: int # priority
workflow: Optional[str] # workflow json
ValuesToInsert: TypeAlias = list[SessionQueueValueToInsert]
@@ -425,7 +404,7 @@ ValuesToInsert: TypeAlias = list[SessionQueueValueToInsert]
def prepare_values_to_insert(queue_id: str, batch: Batch, priority: int, max_new_queue_items: int) -> ValuesToInsert:
values_to_insert: ValuesToInsert = []
for session, field_values, workflow in create_session_nfv_tuples(batch, max_new_queue_items):
for session, field_values in create_session_nfv_tuples(batch, max_new_queue_items):
# sessions must have unique id
session.id = uuid_string()
values_to_insert.append(
@@ -437,7 +416,6 @@ def prepare_values_to_insert(queue_id: str, batch: Batch, priority: int, max_new
# must use pydantic_encoder bc field_values is a list of models
json.dumps(field_values, default=to_jsonable_python) if field_values else None, # field_values (json)
priority, # priority
json.dumps(workflow, default=to_jsonable_python) if workflow else None, # workflow (json)
)
)
return values_to_insert

View File

@@ -28,7 +28,7 @@ from invokeai.app.services.session_queue.session_queue_common import (
prepare_values_to_insert,
)
from invokeai.app.services.shared.pagination import CursorPaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.shared.sqlite import SqliteDatabase
class SqliteSessionQueue(SessionQueueBase):
@@ -42,8 +42,7 @@ class SqliteSessionQueue(SessionQueueBase):
self._set_in_progress_to_canceled()
prune_result = self.prune(DEFAULT_QUEUE_ID)
local_handler.register(event_name=EventServiceBase.queue_event, _func=self._on_session_event)
if prune_result.deleted > 0:
self.__invoker.services.logger.info(f"Pruned {prune_result.deleted} finished queue items")
self.__invoker.services.logger.info(f"Pruned {prune_result.deleted} finished queue items")
def __init__(self, db: SqliteDatabase) -> None:
super().__init__()
@@ -199,15 +198,6 @@ class SqliteSessionQueue(SessionQueueBase):
"""
)
self.__cursor.execute("PRAGMA table_info(session_queue)")
columns = [column[1] for column in self.__cursor.fetchall()]
if "workflow" not in columns:
self.__cursor.execute(
"""--sql
ALTER TABLE session_queue ADD COLUMN workflow TEXT;
"""
)
self.__conn.commit()
except Exception:
self.__conn.rollback()
@@ -290,8 +280,8 @@ class SqliteSessionQueue(SessionQueueBase):
self.__cursor.executemany(
"""--sql
INSERT INTO session_queue (queue_id, session, session_id, batch_id, field_values, priority, workflow)
VALUES (?, ?, ?, ?, ?, ?, ?)
INSERT INTO session_queue (queue_id, session, session_id, batch_id, field_values, priority)
VALUES (?, ?, ?, ?, ?, ?)
""",
values_to_insert,
)

View File

@@ -207,12 +207,10 @@ class IterateInvocationOutput(BaseInvocationOutput):
item: Any = OutputField(
description="The item being iterated over", title="Collection Item", ui_type=UIType._CollectionItem
)
index: int = OutputField(description="The index of the item", title="Index")
total: int = OutputField(description="The total number of items", title="Total")
# TODO: Fill this out and move to invocations
@invocation("iterate", version="1.1.0")
@invocation("iterate", version="1.0.0")
class IterateInvocation(BaseInvocation):
"""Iterates over a list of items"""
@@ -223,7 +221,7 @@ class IterateInvocation(BaseInvocation):
def invoke(self, context: InvocationContext) -> IterateInvocationOutput:
"""Produces the outputs as values"""
return IterateInvocationOutput(item=self.collection[self.index], index=self.index, total=len(self.collection))
return IterateInvocationOutput(item=self.collection[self.index])
@invocation_output("collect_output")

View File

@@ -0,0 +1,48 @@
import sqlite3
import threading
from logging import Logger
from invokeai.app.services.config import InvokeAIAppConfig
sqlite_memory = ":memory:"
class SqliteDatabase:
conn: sqlite3.Connection
lock: threading.RLock
_logger: Logger
_config: InvokeAIAppConfig
def __init__(self, config: InvokeAIAppConfig, logger: Logger):
self._logger = logger
self._config = config
if self._config.use_memory_db:
location = sqlite_memory
logger.info("Using in-memory database")
else:
db_path = self._config.db_path
db_path.parent.mkdir(parents=True, exist_ok=True)
location = str(db_path)
self._logger.info(f"Using database at {location}")
self.conn = sqlite3.connect(location, check_same_thread=False)
self.lock = threading.RLock()
self.conn.row_factory = sqlite3.Row
if self._config.log_sql:
self.conn.set_trace_callback(self._logger.debug)
self.conn.execute("PRAGMA foreign_keys = ON;")
def clean(self) -> None:
try:
self.lock.acquire()
self.conn.execute("VACUUM;")
self.conn.commit()
self._logger.info("Cleaned database")
except Exception as e:
self._logger.error(f"Error cleaning database: {e}")
raise e
finally:
self.lock.release()

View File

@@ -1,10 +0,0 @@
from enum import Enum
from invokeai.app.util.metaenum import MetaEnum
sqlite_memory = ":memory:"
class SQLiteDirection(str, Enum, metaclass=MetaEnum):
Ascending = "ASC"
Descending = "DESC"

View File

@@ -1,47 +0,0 @@
import sqlite3
import threading
from logging import Logger
from pathlib import Path
from invokeai.app.services.config import InvokeAIAppConfig
from invokeai.app.services.shared.sqlite.sqlite_common import sqlite_memory
class SqliteDatabase:
def __init__(self, config: InvokeAIAppConfig, logger: Logger):
self._logger = logger
self._config = config
if self._config.use_memory_db:
self.db_path = sqlite_memory
logger.info("Using in-memory database")
else:
db_path = self._config.db_path
db_path.parent.mkdir(parents=True, exist_ok=True)
self.db_path = str(db_path)
self._logger.info(f"Using database at {self.db_path}")
self.conn = sqlite3.connect(self.db_path, check_same_thread=False)
self.lock = threading.RLock()
self.conn.row_factory = sqlite3.Row
if self._config.log_sql:
self.conn.set_trace_callback(self._logger.debug)
self.conn.execute("PRAGMA foreign_keys = ON;")
def clean(self) -> None:
with self.lock:
try:
if self.db_path == sqlite_memory:
return
initial_db_size = Path(self.db_path).stat().st_size
self.conn.execute("VACUUM;")
self.conn.commit()
final_db_size = Path(self.db_path).stat().st_size
freed_space_in_mb = round((initial_db_size - final_db_size) / 1024 / 1024, 2)
if freed_space_in_mb > 0:
self._logger.info(f"Cleaned database (freed {freed_space_in_mb}MB)")
except Exception as e:
self._logger.error(f"Error cleaning database: {e}")
raise

View File

@@ -0,0 +1,23 @@
from abc import ABC, abstractmethod
from typing import Optional
class WorkflowImageRecordsStorageBase(ABC):
"""Abstract base class for the one-to-many workflow-image relationship record storage."""
@abstractmethod
def create(
self,
workflow_id: str,
image_name: str,
) -> None:
"""Creates a workflow-image record."""
pass
@abstractmethod
def get_workflow_for_image(
self,
image_name: str,
) -> Optional[str]:
"""Gets an image's workflow id, if it has one."""
pass

View File

@@ -0,0 +1,122 @@
import sqlite3
import threading
from typing import Optional, cast
from invokeai.app.services.shared.sqlite import SqliteDatabase
from invokeai.app.services.workflow_image_records.workflow_image_records_base import WorkflowImageRecordsStorageBase
class SqliteWorkflowImageRecordsStorage(WorkflowImageRecordsStorageBase):
"""SQLite implementation of WorkflowImageRecordsStorageBase."""
_conn: sqlite3.Connection
_cursor: sqlite3.Cursor
_lock: threading.RLock
def __init__(self, db: SqliteDatabase) -> None:
super().__init__()
self._lock = db.lock
self._conn = db.conn
self._cursor = self._conn.cursor()
try:
self._lock.acquire()
self._create_tables()
self._conn.commit()
finally:
self._lock.release()
def _create_tables(self) -> None:
# Create the `workflow_images` junction table.
self._cursor.execute(
"""--sql
CREATE TABLE IF NOT EXISTS workflow_images (
workflow_id TEXT NOT NULL,
image_name TEXT NOT NULL,
created_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
-- updated via trigger
updated_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
-- Soft delete, currently unused
deleted_at DATETIME,
-- enforce one-to-many relationship between workflows and images using PK
-- (we can extend this to many-to-many later)
PRIMARY KEY (image_name),
FOREIGN KEY (workflow_id) REFERENCES workflows (workflow_id) ON DELETE CASCADE,
FOREIGN KEY (image_name) REFERENCES images (image_name) ON DELETE CASCADE
);
"""
)
# Add index for workflow id
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_images_workflow_id ON workflow_images (workflow_id);
"""
)
# Add index for workflow id, sorted by created_at
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_images_workflow_id_created_at ON workflow_images (workflow_id, created_at);
"""
)
# Add trigger for `updated_at`.
self._cursor.execute(
"""--sql
CREATE TRIGGER IF NOT EXISTS tg_workflow_images_updated_at
AFTER UPDATE
ON workflow_images FOR EACH ROW
BEGIN
UPDATE workflow_images SET updated_at = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')
WHERE workflow_id = old.workflow_id AND image_name = old.image_name;
END;
"""
)
def create(
self,
workflow_id: str,
image_name: str,
) -> None:
"""Creates a workflow-image record."""
try:
self._lock.acquire()
self._cursor.execute(
"""--sql
INSERT INTO workflow_images (workflow_id, image_name)
VALUES (?, ?);
""",
(workflow_id, image_name),
)
self._conn.commit()
except sqlite3.Error as e:
self._conn.rollback()
raise e
finally:
self._lock.release()
def get_workflow_for_image(
self,
image_name: str,
) -> Optional[str]:
"""Gets an image's workflow id, if it has one."""
try:
self._lock.acquire()
self._cursor.execute(
"""--sql
SELECT workflow_id
FROM workflow_images
WHERE image_name = ?;
""",
(image_name,),
)
result = self._cursor.fetchone()
if result is None:
return None
return cast(str, result[0])
except sqlite3.Error as e:
self._conn.rollback()
raise e
finally:
self._lock.release()

View File

@@ -1,17 +0,0 @@
# Default Workflows
Workflows placed in this directory will be synced to the `workflow_library` as
_default workflows_ on app startup.
- Default workflows are not editable by users. If they are loaded and saved,
they will save as a copy of the default workflow.
- Default workflows must have the `meta.category` property set to `"default"`.
An exception will be raised during sync if this is not set correctly.
- Default workflows appear on the "Default Workflows" tab of the Workflow
Library.
After adding or updating default workflows, you **must** start the app up and
load them to ensure:
- The workflow loads without warning or errors
- The workflow runs successfully

View File

@@ -1,798 +0,0 @@
{
"name": "Text to Image - SD1.5",
"author": "InvokeAI",
"description": "Sample text to image workflow for Stable Diffusion 1.5/2",
"version": "1.1.0",
"contact": "invoke@invoke.ai",
"tags": "text2image, SD1.5, SD2, default",
"notes": "",
"exposedFields": [
{
"nodeId": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
"fieldName": "model"
},
{
"nodeId": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
"fieldName": "prompt"
},
{
"nodeId": "93dc02a4-d05b-48ed-b99c-c9b616af3402",
"fieldName": "prompt"
},
{
"nodeId": "55705012-79b9-4aac-9f26-c0b10309785b",
"fieldName": "width"
},
{
"nodeId": "55705012-79b9-4aac-9f26-c0b10309785b",
"fieldName": "height"
}
],
"meta": {
"category": "default",
"version": "2.0.0"
},
"nodes": [
{
"id": "93dc02a4-d05b-48ed-b99c-c9b616af3402",
"type": "invocation",
"data": {
"id": "93dc02a4-d05b-48ed-b99c-c9b616af3402",
"type": "compel",
"label": "Negative Compel Prompt",
"isOpen": true,
"notes": "",
"isIntermediate": true,
"useCache": true,
"version": "1.0.0",
"nodePack": "invokeai",
"inputs": {
"prompt": {
"id": "7739aff6-26cb-4016-8897-5a1fb2305e4e",
"name": "prompt",
"fieldKind": "input",
"label": "Negative Prompt",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "StringField"
},
"value": ""
},
"clip": {
"id": "48d23dce-a6ae-472a-9f8c-22a714ea5ce0",
"name": "clip",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ClipField"
}
}
},
"outputs": {
"conditioning": {
"id": "37cf3a9d-f6b7-4b64-8ff6-2558c5ecc447",
"name": "conditioning",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ConditioningField"
}
}
}
},
"width": 320,
"height": 259,
"position": {
"x": 1000,
"y": 350
}
},
{
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
"type": "invocation",
"data": {
"id": "55705012-79b9-4aac-9f26-c0b10309785b",
"type": "noise",
"label": "",
"isOpen": true,
"notes": "",
"isIntermediate": true,
"useCache": true,
"version": "1.0.1",
"nodePack": "invokeai",
"inputs": {
"seed": {
"id": "6431737c-918a-425d-a3b4-5d57e2f35d4d",
"name": "seed",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
},
"value": 0
},
"width": {
"id": "38fc5b66-fe6e-47c8-bba9-daf58e454ed7",
"name": "width",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
},
"value": 512
},
"height": {
"id": "16298330-e2bf-4872-a514-d6923df53cbb",
"name": "height",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
},
"value": 512
},
"use_cpu": {
"id": "c7c436d3-7a7a-4e76-91e4-c6deb271623c",
"name": "use_cpu",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "BooleanField"
},
"value": true
}
},
"outputs": {
"noise": {
"id": "50f650dc-0184-4e23-a927-0497a96fe954",
"name": "noise",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "LatentsField"
}
},
"width": {
"id": "bb8a452b-133d-42d1-ae4a-3843d7e4109a",
"name": "width",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
}
},
"height": {
"id": "35cfaa12-3b8b-4b7a-a884-327ff3abddd9",
"name": "height",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
}
}
}
},
"width": 320,
"height": 388,
"position": {
"x": 600,
"y": 325
}
},
{
"id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
"type": "invocation",
"data": {
"id": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
"type": "main_model_loader",
"label": "",
"isOpen": true,
"notes": "",
"isIntermediate": true,
"useCache": true,
"version": "1.0.0",
"nodePack": "invokeai",
"inputs": {
"model": {
"id": "993eabd2-40fd-44fe-bce7-5d0c7075ddab",
"name": "model",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "MainModelField"
},
"value": {
"model_name": "stable-diffusion-v1-5",
"base_model": "sd-1",
"model_type": "main"
}
}
},
"outputs": {
"unet": {
"id": "5c18c9db-328d-46d0-8cb9-143391c410be",
"name": "unet",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "UNetField"
}
},
"clip": {
"id": "6effcac0-ec2f-4bf5-a49e-a2c29cf921f4",
"name": "clip",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ClipField"
}
},
"vae": {
"id": "57683ba3-f5f5-4f58-b9a2-4b83dacad4a1",
"name": "vae",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "VaeField"
}
}
}
},
"width": 320,
"height": 226,
"position": {
"x": 600,
"y": 25
}
},
{
"id": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
"type": "invocation",
"data": {
"id": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
"type": "compel",
"label": "Positive Compel Prompt",
"isOpen": true,
"notes": "",
"isIntermediate": true,
"useCache": true,
"version": "1.0.0",
"nodePack": "invokeai",
"inputs": {
"prompt": {
"id": "7739aff6-26cb-4016-8897-5a1fb2305e4e",
"name": "prompt",
"fieldKind": "input",
"label": "Positive Prompt",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "StringField"
},
"value": "Super cute tiger cub, national geographic award-winning photograph"
},
"clip": {
"id": "48d23dce-a6ae-472a-9f8c-22a714ea5ce0",
"name": "clip",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ClipField"
}
}
},
"outputs": {
"conditioning": {
"id": "37cf3a9d-f6b7-4b64-8ff6-2558c5ecc447",
"name": "conditioning",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ConditioningField"
}
}
}
},
"width": 320,
"height": 259,
"position": {
"x": 1000,
"y": 25
}
},
{
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
"type": "invocation",
"data": {
"id": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
"type": "rand_int",
"label": "Random Seed",
"isOpen": false,
"notes": "",
"isIntermediate": true,
"useCache": false,
"version": "1.0.0",
"nodePack": "invokeai",
"inputs": {
"low": {
"id": "3ec65a37-60ba-4b6c-a0b2-553dd7a84b84",
"name": "low",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
},
"value": 0
},
"high": {
"id": "085f853a-1a5f-494d-8bec-e4ba29a3f2d1",
"name": "high",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
},
"value": 2147483647
}
},
"outputs": {
"value": {
"id": "812ade4d-7699-4261-b9fc-a6c9d2ab55ee",
"name": "value",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
}
}
}
},
"width": 320,
"height": 32,
"position": {
"x": 600,
"y": 275
}
},
{
"id": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
"type": "invocation",
"data": {
"id": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
"type": "denoise_latents",
"label": "",
"isOpen": true,
"notes": "",
"isIntermediate": true,
"useCache": true,
"version": "1.5.0",
"nodePack": "invokeai",
"inputs": {
"positive_conditioning": {
"id": "90b7f4f8-ada7-4028-8100-d2e54f192052",
"name": "positive_conditioning",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ConditioningField"
}
},
"negative_conditioning": {
"id": "9393779e-796c-4f64-b740-902a1177bf53",
"name": "negative_conditioning",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ConditioningField"
}
},
"noise": {
"id": "8e17f1e5-4f98-40b1-b7f4-86aeeb4554c1",
"name": "noise",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "LatentsField"
}
},
"steps": {
"id": "9b63302d-6bd2-42c9-ac13-9b1afb51af88",
"name": "steps",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
},
"value": 50
},
"cfg_scale": {
"id": "87dd04d3-870e-49e1-98bf-af003a810109",
"name": "cfg_scale",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": true,
"name": "FloatField"
},
"value": 7.5
},
"denoising_start": {
"id": "f369d80f-4931-4740-9bcd-9f0620719fab",
"name": "denoising_start",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "FloatField"
},
"value": 0
},
"denoising_end": {
"id": "747d10e5-6f02-445c-994c-0604d814de8c",
"name": "denoising_end",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "FloatField"
},
"value": 1
},
"scheduler": {
"id": "1de84a4e-3a24-4ec8-862b-16ce49633b9b",
"name": "scheduler",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "SchedulerField"
},
"value": "unipc"
},
"unet": {
"id": "ffa6fef4-3ce2-4bdb-9296-9a834849489b",
"name": "unet",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "UNetField"
}
},
"control": {
"id": "077b64cb-34be-4fcc-83f2-e399807a02bd",
"name": "control",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": true,
"name": "ControlField"
}
},
"ip_adapter": {
"id": "1d6948f7-3a65-4a65-a20c-768b287251aa",
"name": "ip_adapter",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": true,
"name": "IPAdapterField"
}
},
"t2i_adapter": {
"id": "75e67b09-952f-4083-aaf4-6b804d690412",
"name": "t2i_adapter",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": true,
"name": "T2IAdapterField"
}
},
"cfg_rescale_multiplier": {
"id": "9101f0a6-5fe0-4826-b7b3-47e5d506826c",
"name": "cfg_rescale_multiplier",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "FloatField"
},
"value": 0
},
"latents": {
"id": "334d4ba3-5a99-4195-82c5-86fb3f4f7d43",
"name": "latents",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "LatentsField"
}
},
"denoise_mask": {
"id": "0d3dbdbf-b014-4e95-8b18-ff2ff9cb0bfa",
"name": "denoise_mask",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "DenoiseMaskField"
}
}
},
"outputs": {
"latents": {
"id": "70fa5bbc-0c38-41bb-861a-74d6d78d2f38",
"name": "latents",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "LatentsField"
}
},
"width": {
"id": "98ee0e6c-82aa-4e8f-8be5-dc5f00ee47f0",
"name": "width",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
}
},
"height": {
"id": "e8cb184a-5e1a-47c8-9695-4b8979564f5d",
"name": "height",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
}
}
}
},
"width": 320,
"height": 703,
"position": {
"x": 1400,
"y": 25
}
},
{
"id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
"type": "invocation",
"data": {
"id": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
"type": "l2i",
"label": "",
"isOpen": true,
"notes": "",
"isIntermediate": false,
"useCache": true,
"version": "1.2.0",
"nodePack": "invokeai",
"inputs": {
"metadata": {
"id": "ab375f12-0042-4410-9182-29e30db82c85",
"name": "metadata",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "MetadataField"
}
},
"latents": {
"id": "3a7e7efd-bff5-47d7-9d48-615127afee78",
"name": "latents",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "LatentsField"
}
},
"vae": {
"id": "a1f5f7a1-0795-4d58-b036-7820c0b0ef2b",
"name": "vae",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "VaeField"
}
},
"tiled": {
"id": "da52059a-0cee-4668-942f-519aa794d739",
"name": "tiled",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "BooleanField"
},
"value": false
},
"fp32": {
"id": "c4841df3-b24e-4140-be3b-ccd454c2522c",
"name": "fp32",
"fieldKind": "input",
"label": "",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "BooleanField"
},
"value": true
}
},
"outputs": {
"image": {
"id": "72d667d0-cf85-459d-abf2-28bd8b823fe7",
"name": "image",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "ImageField"
}
},
"width": {
"id": "c8c907d8-1066-49d1-b9a6-83bdcd53addc",
"name": "width",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
}
},
"height": {
"id": "230f359c-b4ea-436c-b372-332d7dcdca85",
"name": "height",
"fieldKind": "output",
"type": {
"isCollection": false,
"isCollectionOrScalar": false,
"name": "IntegerField"
}
}
}
},
"width": 320,
"height": 266,
"position": {
"x": 1800,
"y": 25
}
}
],
"edges": [
{
"id": "reactflow__edge-ea94bc37-d995-4a83-aa99-4af42479f2f2value-55705012-79b9-4aac-9f26-c0b10309785bseed",
"source": "ea94bc37-d995-4a83-aa99-4af42479f2f2",
"target": "55705012-79b9-4aac-9f26-c0b10309785b",
"type": "default",
"sourceHandle": "value",
"targetHandle": "seed"
},
{
"id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8clip-7d8bf987-284f-413a-b2fd-d825445a5d6cclip",
"source": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
"target": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
"type": "default",
"sourceHandle": "clip",
"targetHandle": "clip"
},
{
"id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8clip-93dc02a4-d05b-48ed-b99c-c9b616af3402clip",
"source": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
"target": "93dc02a4-d05b-48ed-b99c-c9b616af3402",
"type": "default",
"sourceHandle": "clip",
"targetHandle": "clip"
},
{
"id": "reactflow__edge-55705012-79b9-4aac-9f26-c0b10309785bnoise-eea2702a-19fb-45b5-9d75-56b4211ec03cnoise",
"source": "55705012-79b9-4aac-9f26-c0b10309785b",
"target": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
"type": "default",
"sourceHandle": "noise",
"targetHandle": "noise"
},
{
"id": "reactflow__edge-7d8bf987-284f-413a-b2fd-d825445a5d6cconditioning-eea2702a-19fb-45b5-9d75-56b4211ec03cpositive_conditioning",
"source": "7d8bf987-284f-413a-b2fd-d825445a5d6c",
"target": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
"type": "default",
"sourceHandle": "conditioning",
"targetHandle": "positive_conditioning"
},
{
"id": "reactflow__edge-93dc02a4-d05b-48ed-b99c-c9b616af3402conditioning-eea2702a-19fb-45b5-9d75-56b4211ec03cnegative_conditioning",
"source": "93dc02a4-d05b-48ed-b99c-c9b616af3402",
"target": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
"type": "default",
"sourceHandle": "conditioning",
"targetHandle": "negative_conditioning"
},
{
"id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8unet-eea2702a-19fb-45b5-9d75-56b4211ec03cunet",
"source": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
"target": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
"type": "default",
"sourceHandle": "unet",
"targetHandle": "unet"
},
{
"id": "reactflow__edge-eea2702a-19fb-45b5-9d75-56b4211ec03clatents-58c957f5-0d01-41fc-a803-b2bbf0413d4flatents",
"source": "eea2702a-19fb-45b5-9d75-56b4211ec03c",
"target": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
"type": "default",
"sourceHandle": "latents",
"targetHandle": "latents"
},
{
"id": "reactflow__edge-c8d55139-f380-4695-b7f2-8b3d1e1e3db8vae-58c957f5-0d01-41fc-a803-b2bbf0413d4fvae",
"source": "c8d55139-f380-4695-b7f2-8b3d1e1e3db8",
"target": "58c957f5-0d01-41fc-a803-b2bbf0413d4f",
"type": "default",
"sourceHandle": "vae",
"targetHandle": "vae"
}
]
}

View File

@@ -1,50 +1,17 @@
from abc import ABC, abstractmethod
from typing import Optional
from invokeai.app.services.shared.pagination import PaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_common import SQLiteDirection
from invokeai.app.services.workflow_records.workflow_records_common import (
Workflow,
WorkflowCategory,
WorkflowRecordDTO,
WorkflowRecordListItemDTO,
WorkflowRecordOrderBy,
WorkflowWithoutID,
)
from invokeai.app.invocations.baseinvocation import WorkflowField
class WorkflowRecordsStorageBase(ABC):
"""Base class for workflow storage services."""
@abstractmethod
def get(self, workflow_id: str) -> WorkflowRecordDTO:
def get(self, workflow_id: str) -> WorkflowField:
"""Get workflow by id."""
pass
@abstractmethod
def create(self, workflow: WorkflowWithoutID) -> WorkflowRecordDTO:
def create(self, workflow: WorkflowField) -> WorkflowField:
"""Creates a workflow."""
pass
@abstractmethod
def update(self, workflow: Workflow) -> WorkflowRecordDTO:
"""Updates a workflow."""
pass
@abstractmethod
def delete(self, workflow_id: str) -> None:
"""Deletes a workflow."""
pass
@abstractmethod
def get_many(
self,
page: int,
per_page: int,
order_by: WorkflowRecordOrderBy,
direction: SQLiteDirection,
category: WorkflowCategory,
query: Optional[str],
) -> PaginatedResults[WorkflowRecordListItemDTO]:
"""Gets many workflows."""
pass

View File

@@ -1,106 +1,2 @@
import datetime
from enum import Enum
from typing import Any, Union
import semver
from pydantic import BaseModel, ConfigDict, Field, JsonValue, TypeAdapter, field_validator
from invokeai.app.util.metaenum import MetaEnum
__workflow_meta_version__ = semver.Version.parse("1.0.0")
class ExposedField(BaseModel):
nodeId: str
fieldName: str
class WorkflowNotFoundError(Exception):
"""Raised when a workflow is not found"""
class WorkflowRecordOrderBy(str, Enum, metaclass=MetaEnum):
"""The order by options for workflow records"""
CreatedAt = "created_at"
UpdatedAt = "updated_at"
OpenedAt = "opened_at"
Name = "name"
class WorkflowCategory(str, Enum, metaclass=MetaEnum):
User = "user"
Default = "default"
class WorkflowMeta(BaseModel):
version: str = Field(description="The version of the workflow schema.")
category: WorkflowCategory = Field(
default=WorkflowCategory.User, description="The category of the workflow (user or default)."
)
@field_validator("version")
def validate_version(cls, version: str):
try:
semver.Version.parse(version)
return version
except Exception:
raise ValueError(f"Invalid workflow meta version: {version}")
def to_semver(self) -> semver.Version:
return semver.Version.parse(self.version)
class WorkflowWithoutID(BaseModel):
name: str = Field(description="The name of the workflow.")
author: str = Field(description="The author of the workflow.")
description: str = Field(description="The description of the workflow.")
version: str = Field(description="The version of the workflow.")
contact: str = Field(description="The contact of the workflow.")
tags: str = Field(description="The tags of the workflow.")
notes: str = Field(description="The notes of the workflow.")
exposedFields: list[ExposedField] = Field(description="The exposed fields of the workflow.")
meta: WorkflowMeta = Field(description="The meta of the workflow.")
# TODO: nodes and edges are very loosely typed
nodes: list[dict[str, JsonValue]] = Field(description="The nodes of the workflow.")
edges: list[dict[str, JsonValue]] = Field(description="The edges of the workflow.")
model_config = ConfigDict(extra="forbid")
WorkflowWithoutIDValidator = TypeAdapter(WorkflowWithoutID)
class Workflow(WorkflowWithoutID):
id: str = Field(description="The id of the workflow.")
WorkflowValidator = TypeAdapter(Workflow)
class WorkflowRecordDTOBase(BaseModel):
workflow_id: str = Field(description="The id of the workflow.")
name: str = Field(description="The name of the workflow.")
created_at: Union[datetime.datetime, str] = Field(description="The created timestamp of the workflow.")
updated_at: Union[datetime.datetime, str] = Field(description="The updated timestamp of the workflow.")
opened_at: Union[datetime.datetime, str] = Field(description="The opened timestamp of the workflow.")
class WorkflowRecordDTO(WorkflowRecordDTOBase):
workflow: Workflow = Field(description="The workflow.")
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "WorkflowRecordDTO":
data["workflow"] = WorkflowValidator.validate_json(data.get("workflow", ""))
return WorkflowRecordDTOValidator.validate_python(data)
WorkflowRecordDTOValidator = TypeAdapter(WorkflowRecordDTO)
class WorkflowRecordListItemDTO(WorkflowRecordDTOBase):
description: str = Field(description="The description of the workflow.")
category: WorkflowCategory = Field(description="The description of the workflow.")
WorkflowRecordListItemDTOValidator = TypeAdapter(WorkflowRecordListItemDTO)

View File

@@ -1,26 +1,20 @@
from pathlib import Path
from typing import Optional
import sqlite3
import threading
from invokeai.app.invocations.baseinvocation import WorkflowField, WorkflowFieldValidator
from invokeai.app.services.invoker import Invoker
from invokeai.app.services.shared.pagination import PaginatedResults
from invokeai.app.services.shared.sqlite.sqlite_common import SQLiteDirection
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.shared.sqlite import SqliteDatabase
from invokeai.app.services.workflow_records.workflow_records_base import WorkflowRecordsStorageBase
from invokeai.app.services.workflow_records.workflow_records_common import (
Workflow,
WorkflowCategory,
WorkflowNotFoundError,
WorkflowRecordDTO,
WorkflowRecordListItemDTO,
WorkflowRecordListItemDTOValidator,
WorkflowRecordOrderBy,
WorkflowWithoutID,
WorkflowWithoutIDValidator,
)
from invokeai.app.services.workflow_records.workflow_records_common import WorkflowNotFoundError
from invokeai.app.util.misc import uuid_string
class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase):
_invoker: Invoker
_conn: sqlite3.Connection
_cursor: sqlite3.Cursor
_lock: threading.RLock
def __init__(self, db: SqliteDatabase) -> None:
super().__init__()
self._lock = db.lock
@@ -30,25 +24,14 @@ class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase):
def start(self, invoker: Invoker) -> None:
self._invoker = invoker
self._sync_default_workflows()
def get(self, workflow_id: str) -> WorkflowRecordDTO:
"""Gets a workflow by ID. Updates the opened_at column."""
def get(self, workflow_id: str) -> WorkflowField:
try:
self._lock.acquire()
self._cursor.execute(
"""--sql
UPDATE workflow_library
SET opened_at = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')
WHERE workflow_id = ?;
""",
(workflow_id,),
)
self._conn.commit()
self._cursor.execute(
"""--sql
SELECT workflow_id, workflow, name, created_at, updated_at, opened_at
FROM workflow_library
SELECT workflow
FROM workflows
WHERE workflow_id = ?;
""",
(workflow_id,),
@@ -56,28 +39,25 @@ class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase):
row = self._cursor.fetchone()
if row is None:
raise WorkflowNotFoundError(f"Workflow with id {workflow_id} not found")
return WorkflowRecordDTO.from_dict(dict(row))
return WorkflowFieldValidator.validate_json(row[0])
except Exception:
self._conn.rollback()
raise
finally:
self._lock.release()
def create(self, workflow: WorkflowWithoutID) -> WorkflowRecordDTO:
def create(self, workflow: WorkflowField) -> WorkflowField:
try:
# Only user workflows may be created by this method
assert workflow.meta.category is WorkflowCategory.User
workflow_with_id = Workflow(**workflow.model_dump(), id=uuid_string())
# workflows do not have ids until they are saved
workflow_id = uuid_string()
workflow.root["id"] = workflow_id
self._lock.acquire()
self._cursor.execute(
"""--sql
INSERT OR IGNORE INTO workflow_library (
workflow_id,
workflow
)
VALUES (?, ?);
INSERT INTO workflows(workflow)
VALUES (?);
""",
(workflow_with_id.id, workflow_with_id.model_dump_json()),
(workflow.model_dump_json(),),
)
self._conn.commit()
except Exception:
@@ -85,232 +65,35 @@ class SqliteWorkflowRecordsStorage(WorkflowRecordsStorageBase):
raise
finally:
self._lock.release()
return self.get(workflow_with_id.id)
def update(self, workflow: Workflow) -> WorkflowRecordDTO:
try:
self._lock.acquire()
self._cursor.execute(
"""--sql
UPDATE workflow_library
SET workflow = ?
WHERE workflow_id = ? AND category = 'user';
""",
(workflow.model_dump_json(), workflow.id),
)
self._conn.commit()
except Exception:
self._conn.rollback()
raise
finally:
self._lock.release()
return self.get(workflow.id)
def delete(self, workflow_id: str) -> None:
try:
self._lock.acquire()
self._cursor.execute(
"""--sql
DELETE from workflow_library
WHERE workflow_id = ? AND category = 'user';
""",
(workflow_id,),
)
self._conn.commit()
except Exception:
self._conn.rollback()
raise
finally:
self._lock.release()
return None
def get_many(
self,
page: int,
per_page: int,
order_by: WorkflowRecordOrderBy,
direction: SQLiteDirection,
category: WorkflowCategory,
query: Optional[str] = None,
) -> PaginatedResults[WorkflowRecordListItemDTO]:
try:
self._lock.acquire()
# sanitize!
assert order_by in WorkflowRecordOrderBy
assert direction in SQLiteDirection
assert category in WorkflowCategory
count_query = "SELECT COUNT(*) FROM workflow_library WHERE category = ?"
main_query = """
SELECT
workflow_id,
category,
name,
description,
created_at,
updated_at,
opened_at
FROM workflow_library
WHERE category = ?
"""
main_params: list[int | str] = [category.value]
count_params: list[int | str] = [category.value]
stripped_query = query.strip() if query else None
if stripped_query:
wildcard_query = "%" + stripped_query + "%"
main_query += " AND name LIKE ? OR description LIKE ? "
count_query += " AND name LIKE ? OR description LIKE ?;"
main_params.extend([wildcard_query, wildcard_query])
count_params.extend([wildcard_query, wildcard_query])
main_query += f" ORDER BY {order_by.value} {direction.value} LIMIT ? OFFSET ?;"
main_params.extend([per_page, page * per_page])
self._cursor.execute(main_query, main_params)
rows = self._cursor.fetchall()
workflows = [WorkflowRecordListItemDTOValidator.validate_python(dict(row)) for row in rows]
self._cursor.execute(count_query, count_params)
total = self._cursor.fetchone()[0]
pages = int(total / per_page) + 1
return PaginatedResults(
items=workflows,
page=page,
per_page=per_page,
pages=pages,
total=total,
)
except Exception:
self._conn.rollback()
raise
finally:
self._lock.release()
def _sync_default_workflows(self) -> None:
"""Syncs default workflows to the database. Internal use only."""
"""
An enhancement might be to only update workflows that have changed. This would require stable
default workflow IDs, and properly incrementing the workflow version.
It's much simpler to just replace them all with whichever workflows are in the directory.
The downside is that the `updated_at` and `opened_at` timestamps for default workflows are
meaningless, as they are overwritten every time the server starts.
"""
try:
self._lock.acquire()
workflows: list[Workflow] = []
workflows_dir = Path(__file__).parent / Path("default_workflows")
workflow_paths = workflows_dir.glob("*.json")
for path in workflow_paths:
bytes_ = path.read_bytes()
workflow_without_id = WorkflowWithoutIDValidator.validate_json(bytes_)
workflow = Workflow(**workflow_without_id.model_dump(), id=uuid_string())
workflows.append(workflow)
# Only default workflows may be managed by this method
assert all(w.meta.category is WorkflowCategory.Default for w in workflows)
self._cursor.execute(
"""--sql
DELETE FROM workflow_library
WHERE category = 'default';
"""
)
for w in workflows:
self._cursor.execute(
"""--sql
INSERT OR REPLACE INTO workflow_library (
workflow_id,
workflow
)
VALUES (?, ?);
""",
(w.id, w.model_dump_json()),
)
self._conn.commit()
except Exception:
self._conn.rollback()
raise
finally:
self._lock.release()
return self.get(workflow_id)
def _create_tables(self) -> None:
try:
self._lock.acquire()
self._cursor.execute(
"""--sql
CREATE TABLE IF NOT EXISTS workflow_library (
workflow_id TEXT NOT NULL PRIMARY KEY,
CREATE TABLE IF NOT EXISTS workflows (
workflow TEXT NOT NULL,
workflow_id TEXT GENERATED ALWAYS AS (json_extract(workflow, '$.id')) VIRTUAL NOT NULL UNIQUE, -- gets implicit index
created_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
-- updated via trigger
updated_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
-- updated manually when retrieving workflow
opened_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
-- Generated columns, needed for indexing and searching
category TEXT GENERATED ALWAYS as (json_extract(workflow, '$.meta.category')) VIRTUAL NOT NULL,
name TEXT GENERATED ALWAYS as (json_extract(workflow, '$.name')) VIRTUAL NOT NULL,
description TEXT GENERATED ALWAYS as (json_extract(workflow, '$.description')) VIRTUAL NOT NULL
updated_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')) -- updated via trigger
);
"""
)
self._cursor.execute(
"""--sql
CREATE TRIGGER IF NOT EXISTS tg_workflow_library_updated_at
CREATE TRIGGER IF NOT EXISTS tg_workflows_updated_at
AFTER UPDATE
ON workflow_library FOR EACH ROW
ON workflows FOR EACH ROW
BEGIN
UPDATE workflow_library
UPDATE workflows
SET updated_at = STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')
WHERE workflow_id = old.workflow_id;
END;
"""
)
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_library_created_at ON workflow_library(created_at);
"""
)
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_library_updated_at ON workflow_library(updated_at);
"""
)
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_library_opened_at ON workflow_library(opened_at);
"""
)
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_library_category ON workflow_library(category);
"""
)
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_library_name ON workflow_library(name);
"""
)
self._cursor.execute(
"""--sql
CREATE INDEX IF NOT EXISTS idx_workflow_library_description ON workflow_library(description);
"""
)
# We do not need the original `workflows` table or `workflow_images` junction table.
self._cursor.execute(
"""--sql
DROP TABLE IF EXISTS workflow_images;
"""
)
self._cursor.execute(
"""--sql
DROP TABLE IF EXISTS workflows;
"""
)
self._conn.commit()
except Exception:
self._conn.rollback()

View File

@@ -192,33 +192,20 @@ class ModelPatcher:
trigger += f"-!pad-{i}"
return f"<{trigger}>"
def _get_ti_embedding(model_embeddings, ti):
# for SDXL models, select the embedding that matches the text encoder's dimensions
if ti.embedding_2 is not None:
return (
ti.embedding_2
if ti.embedding_2.shape[1] == model_embeddings.weight.data[0].shape[0]
else ti.embedding
)
else:
return ti.embedding
# modify tokenizer
new_tokens_added = 0
for ti_name, ti in ti_list:
ti_embedding = _get_ti_embedding(text_encoder.get_input_embeddings(), ti)
for i in range(ti_embedding.shape[0]):
for i in range(ti.embedding.shape[0]):
new_tokens_added += ti_tokenizer.add_tokens(_get_trigger(ti_name, i))
# modify text_encoder
text_encoder.resize_token_embeddings(init_tokens_count + new_tokens_added, pad_to_multiple_of)
model_embeddings = text_encoder.get_input_embeddings()
for ti_name, _ in ti_list:
for ti_name, ti in ti_list:
ti_tokens = []
for i in range(ti_embedding.shape[0]):
embedding = ti_embedding[i]
for i in range(ti.embedding.shape[0]):
embedding = ti.embedding[i]
trigger = _get_trigger(ti_name, i)
token_id = ti_tokenizer.convert_tokens_to_ids(trigger)
@@ -286,7 +273,6 @@ class ModelPatcher:
class TextualInversionModel:
embedding: torch.Tensor # [n, 768]|[n, 1280]
embedding_2: Optional[torch.Tensor] = None # [n, 768]|[n, 1280] - for SDXL models
@classmethod
def from_checkpoint(
@@ -310,8 +296,8 @@ class TextualInversionModel:
if "string_to_param" in state_dict:
if len(state_dict["string_to_param"]) > 1:
print(
f'Warn: Embedding "{file_path.name}" contains multiple tokens, which is not supported. The first',
" token will be used.",
f'Warn: Embedding "{file_path.name}" contains multiple tokens, which is not supported. The first'
" token will be used."
)
result.embedding = next(iter(state_dict["string_to_param"].values()))
@@ -320,11 +306,6 @@ class TextualInversionModel:
elif "emb_params" in state_dict:
result.embedding = state_dict["emb_params"]
# v5(sdxl safetensors file)
elif "clip_g" in state_dict and "clip_l" in state_dict:
result.embedding = state_dict["clip_g"]
result.embedding_2 = state_dict["clip_l"]
# v4(diffusers bin files)
else:
result.embedding = next(iter(state_dict.values()))
@@ -361,13 +342,6 @@ class TextualInversionManager(BaseTextualInversionManager):
if token_id in self.pad_tokens:
new_token_ids.extend(self.pad_tokens[token_id])
# Do not exceed the max model input size
# The -2 here is compensating for compensate compel.embeddings_provider.get_token_ids(),
# which first removes and then adds back the start and end tokens.
max_length = list(self.tokenizer.max_model_input_sizes.values())[0] - 2
if len(new_token_ids) > max_length:
new_token_ids = new_token_ids[0:max_length]
return new_token_ids
@@ -516,31 +490,24 @@ class ONNXModelPatcher:
trigger += f"-!pad-{i}"
return f"<{trigger}>"
# modify text_encoder
orig_embeddings = text_encoder.tensors["text_model.embeddings.token_embedding.weight"]
# modify tokenizer
new_tokens_added = 0
for ti_name, ti in ti_list:
if ti.embedding_2 is not None:
ti_embedding = (
ti.embedding_2 if ti.embedding_2.shape[1] == orig_embeddings.shape[0] else ti.embedding
)
else:
ti_embedding = ti.embedding
for i in range(ti_embedding.shape[0]):
for i in range(ti.embedding.shape[0]):
new_tokens_added += ti_tokenizer.add_tokens(_get_trigger(ti_name, i))
# modify text_encoder
orig_embeddings = text_encoder.tensors["text_model.embeddings.token_embedding.weight"]
embeddings = np.concatenate(
(np.copy(orig_embeddings), np.zeros((new_tokens_added, orig_embeddings.shape[1]))),
axis=0,
)
for ti_name, _ in ti_list:
for ti_name, ti in ti_list:
ti_tokens = []
for i in range(ti_embedding.shape[0]):
embedding = ti_embedding[i].detach().numpy()
for i in range(ti.embedding.shape[0]):
embedding = ti.embedding[i].detach().numpy()
trigger = _get_trigger(ti_name, i)
token_id = ti_tokenizer.convert_tokens_to_ids(trigger)

View File

@@ -373,16 +373,12 @@ class TextualInversionCheckpointProbe(CheckpointProbeBase):
token_dim = list(checkpoint["string_to_param"].values())[0].shape[-1]
elif "emb_params" in checkpoint:
token_dim = checkpoint["emb_params"].shape[-1]
elif "clip_g" in checkpoint:
token_dim = checkpoint["clip_g"].shape[-1]
else:
token_dim = list(checkpoint.values())[0].shape[0]
if token_dim == 768:
return BaseModelType.StableDiffusion1
elif token_dim == 1024:
return BaseModelType.StableDiffusion2
elif token_dim == 1280:
return BaseModelType.StableDiffusionXL
else:
return None

View File

@@ -11,7 +11,7 @@ from invokeai.app.services.model_records import (
DuplicateModelException,
ModelRecordServiceSQL,
)
from invokeai.app.services.shared.sqlite.sqlite_database import SqliteDatabase
from invokeai.app.services.shared.sqlite import SqliteDatabase
from invokeai.backend.model_manager.config import (
AnyModelConfig,
BaseModelType,

View File

@@ -1,201 +0,0 @@
import math
from typing import Union
import numpy as np
from invokeai.backend.tiles.utils import TBLR, Tile, paste
def calc_tiles_with_overlap(
image_height: int, image_width: int, tile_height: int, tile_width: int, overlap: int = 0
) -> list[Tile]:
"""Calculate the tile coordinates for a given image shape under a simple tiling scheme with overlaps.
Args:
image_height (int): The image height in px.
image_width (int): The image width in px.
tile_height (int): The tile height in px. All tiles will have this height.
tile_width (int): The tile width in px. All tiles will have this width.
overlap (int, optional): The target overlap between adjacent tiles. If the tiles do not evenly cover the image
shape, then the last row/column of tiles will overlap more than this. Defaults to 0.
Returns:
list[Tile]: A list of tiles that cover the image shape. Ordered from left-to-right, top-to-bottom.
"""
assert image_height >= tile_height
assert image_width >= tile_width
assert overlap < tile_height
assert overlap < tile_width
non_overlap_per_tile_height = tile_height - overlap
non_overlap_per_tile_width = tile_width - overlap
num_tiles_y = math.ceil((image_height - overlap) / non_overlap_per_tile_height)
num_tiles_x = math.ceil((image_width - overlap) / non_overlap_per_tile_width)
# tiles[y * num_tiles_x + x] is the tile for the y'th row, x'th column.
tiles: list[Tile] = []
# Calculate tile coordinates. (Ignore overlap values for now.)
for tile_idx_y in range(num_tiles_y):
for tile_idx_x in range(num_tiles_x):
tile = Tile(
coords=TBLR(
top=tile_idx_y * non_overlap_per_tile_height,
bottom=tile_idx_y * non_overlap_per_tile_height + tile_height,
left=tile_idx_x * non_overlap_per_tile_width,
right=tile_idx_x * non_overlap_per_tile_width + tile_width,
),
overlap=TBLR(top=0, bottom=0, left=0, right=0),
)
if tile.coords.bottom > image_height:
# If this tile would go off the bottom of the image, shift it so that it is aligned with the bottom
# of the image.
tile.coords.bottom = image_height
tile.coords.top = image_height - tile_height
if tile.coords.right > image_width:
# If this tile would go off the right edge of the image, shift it so that it is aligned with the
# right edge of the image.
tile.coords.right = image_width
tile.coords.left = image_width - tile_width
tiles.append(tile)
def get_tile_or_none(idx_y: int, idx_x: int) -> Union[Tile, None]:
if idx_y < 0 or idx_y > num_tiles_y or idx_x < 0 or idx_x > num_tiles_x:
return None
return tiles[idx_y * num_tiles_x + idx_x]
# Iterate over tiles again and calculate overlaps.
for tile_idx_y in range(num_tiles_y):
for tile_idx_x in range(num_tiles_x):
cur_tile = get_tile_or_none(tile_idx_y, tile_idx_x)
top_neighbor_tile = get_tile_or_none(tile_idx_y - 1, tile_idx_x)
left_neighbor_tile = get_tile_or_none(tile_idx_y, tile_idx_x - 1)
assert cur_tile is not None
# Update cur_tile top-overlap and corresponding top-neighbor bottom-overlap.
if top_neighbor_tile is not None:
cur_tile.overlap.top = max(0, top_neighbor_tile.coords.bottom - cur_tile.coords.top)
top_neighbor_tile.overlap.bottom = cur_tile.overlap.top
# Update cur_tile left-overlap and corresponding left-neighbor right-overlap.
if left_neighbor_tile is not None:
cur_tile.overlap.left = max(0, left_neighbor_tile.coords.right - cur_tile.coords.left)
left_neighbor_tile.overlap.right = cur_tile.overlap.left
return tiles
def merge_tiles_with_linear_blending(
dst_image: np.ndarray, tiles: list[Tile], tile_images: list[np.ndarray], blend_amount: int
):
"""Merge a set of image tiles into `dst_image` with linear blending between the tiles.
We expect every tile edge to either:
1) have an overlap of 0, because it is aligned with the image edge, or
2) have an overlap >= blend_amount.
If neither of these conditions are satisfied, we raise an exception.
The linear blending is centered at the halfway point of the overlap between adjacent tiles.
Args:
dst_image (np.ndarray): The destination image. Shape: (H, W, C).
tiles (list[Tile]): The list of tiles describing the locations of the respective `tile_images`.
tile_images (list[np.ndarray]): The tile images to merge into `dst_image`.
blend_amount (int): The amount of blending (in px) between adjacent overlapping tiles.
"""
# Sort tiles and images first by left x coordinate, then by top y coordinate. During tile processing, we want to
# iterate over tiles left-to-right, top-to-bottom.
tiles_and_images = list(zip(tiles, tile_images, strict=True))
tiles_and_images = sorted(tiles_and_images, key=lambda x: x[0].coords.left)
tiles_and_images = sorted(tiles_and_images, key=lambda x: x[0].coords.top)
# Organize tiles into rows.
tile_and_image_rows: list[list[tuple[Tile, np.ndarray]]] = []
cur_tile_and_image_row: list[tuple[Tile, np.ndarray]] = []
first_tile_in_cur_row, _ = tiles_and_images[0]
for tile_and_image in tiles_and_images:
tile, _ = tile_and_image
if not (
tile.coords.top == first_tile_in_cur_row.coords.top
and tile.coords.bottom == first_tile_in_cur_row.coords.bottom
):
# Store the previous row, and start a new one.
tile_and_image_rows.append(cur_tile_and_image_row)
cur_tile_and_image_row = []
first_tile_in_cur_row, _ = tile_and_image
cur_tile_and_image_row.append(tile_and_image)
tile_and_image_rows.append(cur_tile_and_image_row)
# Prepare 1D linear gradients for blending.
gradient_left_x = np.linspace(start=0.0, stop=1.0, num=blend_amount)
gradient_top_y = np.linspace(start=0.0, stop=1.0, num=blend_amount)
# Convert shape: (blend_amount, ) -> (blend_amount, 1). The extra dimension enables the gradient to be applied
# to a 2D image via broadcasting. Note that no additional dimension is needed on gradient_left_x for
# broadcasting to work correctly.
gradient_top_y = np.expand_dims(gradient_top_y, axis=1)
for tile_and_image_row in tile_and_image_rows:
first_tile_in_row, _ = tile_and_image_row[0]
row_height = first_tile_in_row.coords.bottom - first_tile_in_row.coords.top
row_image = np.zeros((row_height, dst_image.shape[1], dst_image.shape[2]), dtype=dst_image.dtype)
# Blend the tiles in the row horizontally.
for tile, tile_image in tile_and_image_row:
# We expect the tiles to be ordered left-to-right. For each tile, we construct a mask that applies linear
# blending to the left of the current tile. The inverse linear blending is automatically applied to the
# right of the tiles that have already been pasted by the paste(...) operation.
tile_height, tile_width, _ = tile_image.shape
mask = np.ones(shape=(tile_height, tile_width), dtype=np.float64)
# Left blending:
if tile.overlap.left > 0:
assert tile.overlap.left >= blend_amount
# Center the blending gradient in the middle of the overlap.
blend_start_left = tile.overlap.left // 2 - blend_amount // 2
# The region left of the blending region is masked completely.
mask[:, :blend_start_left] = 0.0
# Apply the blend gradient to the mask.
mask[:, blend_start_left : blend_start_left + blend_amount] = gradient_left_x
# For visual debugging:
# tile_image[:, blend_start_left : blend_start_left + blend_amount] = 0
paste(
dst_image=row_image,
src_image=tile_image,
box=TBLR(
top=0, bottom=tile.coords.bottom - tile.coords.top, left=tile.coords.left, right=tile.coords.right
),
mask=mask,
)
# Blend the row into the dst_image vertically.
# We construct a mask that applies linear blending to the top of the current row. The inverse linear blending is
# automatically applied to the bottom of the tiles that have already been pasted by the paste(...) operation.
mask = np.ones(shape=(row_image.shape[0], row_image.shape[1]), dtype=np.float64)
# Top blending:
# (See comments under 'Left blending' for an explanation of the logic.)
# We assume that the entire row has the same vertical overlaps as the first_tile_in_row.
if first_tile_in_row.overlap.top > 0:
assert first_tile_in_row.overlap.top >= blend_amount
blend_start_top = first_tile_in_row.overlap.top // 2 - blend_amount // 2
mask[:blend_start_top, :] = 0.0
mask[blend_start_top : blend_start_top + blend_amount, :] = gradient_top_y
# For visual debugging:
# row_image[blend_start_top : blend_start_top + blend_amount, :] = 0
paste(
dst_image=dst_image,
src_image=row_image,
box=TBLR(
top=first_tile_in_row.coords.top,
bottom=first_tile_in_row.coords.bottom,
left=0,
right=row_image.shape[1],
),
mask=mask,
)

View File

@@ -1,47 +0,0 @@
from typing import Optional
import numpy as np
from pydantic import BaseModel, Field
class TBLR(BaseModel):
top: int
bottom: int
left: int
right: int
def __eq__(self, other):
return (
self.top == other.top
and self.bottom == other.bottom
and self.left == other.left
and self.right == other.right
)
class Tile(BaseModel):
coords: TBLR = Field(description="The coordinates of this tile relative to its parent image.")
overlap: TBLR = Field(description="The amount of overlap with adjacent tiles on each side of this tile.")
def __eq__(self, other):
return self.coords == other.coords and self.overlap == other.overlap
def paste(dst_image: np.ndarray, src_image: np.ndarray, box: TBLR, mask: Optional[np.ndarray] = None):
"""Paste a source image into a destination image.
Args:
dst_image (torch.Tensor): The destination image to paste into. Shape: (H, W, C).
src_image (torch.Tensor): The source image to paste. Shape: (H, W, C). H and W must be compatible with 'box'.
box (TBLR): Box defining the region in the 'dst_image' where 'src_image' will be pasted.
mask (Optional[torch.Tensor]): A mask that defines the blending between 'src_image' and 'dst_image'.
Range: [0.0, 1.0], Shape: (H, W). The output is calculate per-pixel according to
`src * mask + dst * (1 - mask)`.
"""
if mask is None:
dst_image[box.top : box.bottom, box.left : box.right] = src_image
else:
mask = np.expand_dims(mask, -1)
dst_image_box = dst_image[box.top : box.bottom, box.left : box.right]
dst_image[box.top : box.bottom, box.left : box.right] = src_image * mask + dst_image_box * (1.0 - mask)

View File

@@ -342,13 +342,14 @@ class InvokeAILogger(object): # noqa D102
cls, name: str = "InvokeAI", config: InvokeAIAppConfig = InvokeAIAppConfig.get_config()
) -> logging.Logger: # noqa D102
if name in cls.loggers:
return cls.loggers[name]
logger = logging.getLogger(name)
logger = cls.loggers[name]
logger.handlers.clear()
else:
logger = logging.getLogger(name)
logger.setLevel(config.log_level.upper()) # yes, strings work here
for ch in cls.get_loggers(config):
logger.addHandler(ch)
cls.loggers[name] = logger
cls.loggers[name] = logger
return cls.loggers[name]
@classmethod
@@ -357,7 +358,7 @@ class InvokeAILogger(object): # noqa D102
handlers = []
for handler in handler_strs:
handler_name, *args = handler.split("=", 2)
arg = args[0] if len(args) > 0 else None
args = args[0] if len(args) > 0 else None
# console and file get the fancy formatter.
# syslog gets a simple one
@@ -369,16 +370,16 @@ class InvokeAILogger(object): # noqa D102
handlers.append(ch)
elif handler_name == "syslog":
ch = cls._parse_syslog_args(arg)
ch = cls._parse_syslog_args(args)
handlers.append(ch)
elif handler_name == "file":
ch = cls._parse_file_args(arg)
ch = cls._parse_file_args(args)
ch.setFormatter(formatter())
handlers.append(ch)
elif handler_name == "http":
ch = cls._parse_http_args(arg)
ch = cls._parse_http_args(args)
handlers.append(ch)
return handlers

View File

@@ -32,9 +32,9 @@ sd-1/main/Analog-Diffusion:
description: An SD-1.5 model trained on diverse analog photographs (2.13 GB)
repo_id: wavymulder/Analog-Diffusion
recommended: False
sd-1/main/Deliberate_v5:
sd-1/main/Deliberate:
description: Versatile model that produces detailed images up to 768px (4.27 GB)
path: https://huggingface.co/XpucT/Deliberate/resolve/main/Deliberate_v5.safetensors
repo_id: XpucT/Deliberate
recommended: False
sd-1/main/Dungeons-and-Diffusion:
description: Dungeons & Dragons characters (2.13 GB)

View File

@@ -11,7 +11,6 @@ module.exports = {
'plugin:react-hooks/recommended',
'plugin:react/jsx-runtime',
'prettier',
'plugin:storybook/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
@@ -27,7 +26,6 @@ module.exports = {
'eslint-plugin-react-hooks',
'i18next',
'path',
'unused-imports',
],
root: true,
rules: {
@@ -46,16 +44,9 @@ module.exports = {
radix: 'error',
'space-before-blocks': 'error',
'import/prefer-default-export': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': [
'@typescript-eslint/no-unused-vars': [
'warn',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
],
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',

View File

@@ -9,8 +9,7 @@ lerna-debug.log*
node_modules
# We want to distribute the repo
dist
dist/**
# dist
dist-ssr
*.local
@@ -39,4 +38,4 @@ stats.html
# Yalc
.yalc
yalc.lock
yalc.lock

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
cd invokeai/frontend/web/ && npm run lint-staged

View File

@@ -1,6 +1,5 @@
dist/
public/locales/*.json
!public/locales/en.json
.husky/
node_modules/
patches/
@@ -12,4 +11,3 @@ index.html
src/services/api/schema.d.ts
static/
src/theme/css/overlayscrollbars.css
pnpm-lock.yaml

View File

@@ -1,21 +0,0 @@
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-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
core: {
disableTelemetry: true,
},
};
export default config;

View File

@@ -1,6 +0,0 @@
import { addons } from '@storybook/manager-api';
import { themes } from '@storybook/theming';
addons.setConfig({
theme: themes.dark,
});

View File

@@ -1,47 +0,0 @@
import { Preview } from '@storybook/react';
import { themes } from '@storybook/theming';
import i18n from 'i18next';
import React from 'react';
import { initReactI18next } from 'react-i18next';
import { Provider } from 'react-redux';
import GlobalHotkeys from '../src/app/components/GlobalHotkeys';
import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider';
import { createStore } from '../src/app/store/store';
// 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';
i18n.use(initReactI18next).init({
lng: 'en',
resources: {
en: { translation: translationEN },
},
debug: true,
interpolation: {
escapeValue: false,
},
returnNull: false,
});
const store = createStore(undefined, false);
const preview: Preview = {
decorators: [
(Story) => (
<Provider store={store}>
<ThemeLocaleProvider>
<GlobalHotkeys />
<Story />
</ThemeLocaleProvider>
</Provider>
),
],
parameters: {
docs: {
theme: themes.dark,
},
},
};
export default preview;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
yarn-path ".yarn/releases/yarn-1.22.19.cjs"

View File

@@ -0,0 +1 @@
yarnPath: .yarn/releases/yarn-1.22.19.cjs

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,280 @@
import{I as s,ie as T,v as l,$ as A,ig as R,aa as V,ih as z,ii as j,ij as D,ik as F,il as G,im as W,io as K,az as H,ip as U,iq as Y}from"./index-f820e2e3.js";import{M as Z}from"./MantineProvider-a6a1d85c.js";var P=String.raw,E=P`
:root,
:host {
--chakra-vh: 100vh;
}
@supports (height: -webkit-fill-available) {
:root,
:host {
--chakra-vh: -webkit-fill-available;
}
}
@supports (height: -moz-fill-available) {
:root,
:host {
--chakra-vh: -moz-fill-available;
}
}
@supports (height: 100dvh) {
:root,
:host {
--chakra-vh: 100dvh;
}
}
`,B=()=>s.jsx(T,{styles:E}),J=({scope:e=""})=>s.jsx(T,{styles:P`
html {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
font-family: system-ui, sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
touch-action: manipulation;
}
body {
position: relative;
min-height: 100%;
margin: 0;
font-feature-settings: "kern";
}
${e} :where(*, *::before, *::after) {
border-width: 0;
border-style: solid;
box-sizing: border-box;
word-wrap: break-word;
}
main {
display: block;
}
${e} hr {
border-top-width: 1px;
box-sizing: content-box;
height: 0;
overflow: visible;
}
${e} :where(pre, code, kbd,samp) {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 1em;
}
${e} a {
background-color: transparent;
color: inherit;
text-decoration: inherit;
}
${e} abbr[title] {
border-bottom: none;
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
${e} :where(b, strong) {
font-weight: bold;
}
${e} small {
font-size: 80%;
}
${e} :where(sub,sup) {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
${e} sub {
bottom: -0.25em;
}
${e} sup {
top: -0.5em;
}
${e} img {
border-style: none;
}
${e} :where(button, input, optgroup, select, textarea) {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
margin: 0;
}
${e} :where(button, input) {
overflow: visible;
}
${e} :where(button, select) {
text-transform: none;
}
${e} :where(
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner
) {
border-style: none;
padding: 0;
}
${e} fieldset {
padding: 0.35em 0.75em 0.625em;
}
${e} legend {
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
${e} progress {
vertical-align: baseline;
}
${e} textarea {
overflow: auto;
}
${e} :where([type="checkbox"], [type="radio"]) {
box-sizing: border-box;
padding: 0;
}
${e} input[type="number"]::-webkit-inner-spin-button,
${e} input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none !important;
}
${e} input[type="number"] {
-moz-appearance: textfield;
}
${e} input[type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
${e} input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none !important;
}
${e} ::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
${e} details {
display: block;
}
${e} summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
${e} :where(
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre
) {
margin: 0;
}
${e} button {
background: transparent;
padding: 0;
}
${e} fieldset {
margin: 0;
padding: 0;
}
${e} :where(ol, ul) {
margin: 0;
padding: 0;
}
${e} textarea {
resize: vertical;
}
${e} :where(button, [role="button"]) {
cursor: pointer;
}
${e} button::-moz-focus-inner {
border: 0 !important;
}
${e} table {
border-collapse: collapse;
}
${e} :where(h1, h2, h3, h4, h5, h6) {
font-size: inherit;
font-weight: inherit;
}
${e} :where(button, input, optgroup, select, textarea) {
padding: 0;
line-height: inherit;
color: inherit;
}
${e} :where(img, svg, video, canvas, audio, iframe, embed, object) {
display: block;
}
${e} :where(img, video) {
max-width: 100%;
height: auto;
}
[data-js-focus-visible]
:focus:not([data-focus-visible-added]):not(
[data-focus-visible-disabled]
) {
outline: none;
box-shadow: none;
}
${e} select::-ms-expand {
display: none;
}
${E}
`}),g={light:"chakra-ui-light",dark:"chakra-ui-dark"};function Q(e={}){const{preventTransition:o=!0}=e,n={setDataset:r=>{const t=o?n.preventTransition():void 0;document.documentElement.dataset.theme=r,document.documentElement.style.colorScheme=r,t==null||t()},setClassName(r){document.body.classList.add(r?g.dark:g.light),document.body.classList.remove(r?g.light:g.dark)},query(){return window.matchMedia("(prefers-color-scheme: dark)")},getSystemTheme(r){var t;return((t=n.query().matches)!=null?t:r==="dark")?"dark":"light"},addListener(r){const t=n.query(),i=a=>{r(a.matches?"dark":"light")};return typeof t.addListener=="function"?t.addListener(i):t.addEventListener("change",i),()=>{typeof t.removeListener=="function"?t.removeListener(i):t.removeEventListener("change",i)}},preventTransition(){const r=document.createElement("style");return r.appendChild(document.createTextNode("*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}")),document.head.appendChild(r),()=>{window.getComputedStyle(document.body),requestAnimationFrame(()=>{requestAnimationFrame(()=>{document.head.removeChild(r)})})}}};return n}var X="chakra-ui-color-mode";function L(e){return{ssr:!1,type:"localStorage",get(o){if(!(globalThis!=null&&globalThis.document))return o;let n;try{n=localStorage.getItem(e)||o}catch{}return n||o},set(o){try{localStorage.setItem(e,o)}catch{}}}}var ee=L(X),M=()=>{};function S(e,o){return e.type==="cookie"&&e.ssr?e.get(o):o}function O(e){const{value:o,children:n,options:{useSystemColorMode:r,initialColorMode:t,disableTransitionOnChange:i}={},colorModeManager:a=ee}=e,d=t==="dark"?"dark":"light",[u,p]=l.useState(()=>S(a,d)),[y,b]=l.useState(()=>S(a)),{getSystemTheme:w,setClassName:k,setDataset:x,addListener:$}=l.useMemo(()=>Q({preventTransition:i}),[i]),v=t==="system"&&!u?y:u,c=l.useCallback(m=>{const f=m==="system"?w():m;p(f),k(f==="dark"),x(f),a.set(f)},[a,w,k,x]);A(()=>{t==="system"&&b(w())},[]),l.useEffect(()=>{const m=a.get();if(m){c(m);return}if(t==="system"){c("system");return}c(d)},[a,d,t,c]);const C=l.useCallback(()=>{c(v==="dark"?"light":"dark")},[v,c]);l.useEffect(()=>{if(r)return $(c)},[r,$,c]);const N=l.useMemo(()=>({colorMode:o??v,toggleColorMode:o?M:C,setColorMode:o?M:c,forced:o!==void 0}),[v,C,c,o]);return s.jsx(R.Provider,{value:N,children:n})}O.displayName="ColorModeProvider";var te=["borders","breakpoints","colors","components","config","direction","fonts","fontSizes","fontWeights","letterSpacings","lineHeights","radii","shadows","sizes","space","styles","transition","zIndices"];function re(e){return V(e)?te.every(o=>Object.prototype.hasOwnProperty.call(e,o)):!1}function h(e){return typeof e=="function"}function oe(...e){return o=>e.reduce((n,r)=>r(n),o)}var ne=e=>function(...n){let r=[...n],t=n[n.length-1];return re(t)&&r.length>1?r=r.slice(0,r.length-1):t=e,oe(...r.map(i=>a=>h(i)?i(a):ae(a,i)))(t)},ie=ne(j);function ae(...e){return z({},...e,_)}function _(e,o,n,r){if((h(e)||h(o))&&Object.prototype.hasOwnProperty.call(r,n))return(...t)=>{const i=h(e)?e(...t):e,a=h(o)?o(...t):o;return z({},i,a,_)}}var q=l.createContext({getDocument(){return document},getWindow(){return window}});q.displayName="EnvironmentContext";function I(e){const{children:o,environment:n,disabled:r}=e,t=l.useRef(null),i=l.useMemo(()=>n||{getDocument:()=>{var d,u;return(u=(d=t.current)==null?void 0:d.ownerDocument)!=null?u:document},getWindow:()=>{var d,u;return(u=(d=t.current)==null?void 0:d.ownerDocument.defaultView)!=null?u:window}},[n]),a=!r||!n;return s.jsxs(q.Provider,{value:i,children:[o,a&&s.jsx("span",{id:"__chakra_env",hidden:!0,ref:t})]})}I.displayName="EnvironmentProvider";var se=e=>{const{children:o,colorModeManager:n,portalZIndex:r,resetScope:t,resetCSS:i=!0,theme:a={},environment:d,cssVarsRoot:u,disableEnvironment:p,disableGlobalStyle:y}=e,b=s.jsx(I,{environment:d,disabled:p,children:o});return s.jsx(D,{theme:a,cssVarsRoot:u,children:s.jsxs(O,{colorModeManager:n,options:a.config,children:[i?s.jsx(J,{scope:t}):s.jsx(B,{}),!y&&s.jsx(F,{}),r?s.jsx(G,{zIndex:r,children:b}):b]})})},le=e=>function({children:n,theme:r=e,toastOptions:t,...i}){return s.jsxs(se,{theme:r,...i,children:[s.jsx(W,{value:t==null?void 0:t.defaultOptions,children:n}),s.jsx(K,{...t})]})},de=le(j);const ue=()=>l.useMemo(()=>({colorScheme:"dark",fontFamily:"'Inter Variable', sans-serif",components:{ScrollArea:{defaultProps:{scrollbarSize:10},styles:{scrollbar:{"&:hover":{backgroundColor:"var(--invokeai-colors-baseAlpha-300)"}},thumb:{backgroundColor:"var(--invokeai-colors-baseAlpha-300)"}}}}}),[]),ce=L("@@invokeai-color-mode");function me({children:e}){const{i18n:o}=H(),n=o.dir(),r=l.useMemo(()=>ie({...U,direction:n}),[n]);l.useEffect(()=>{document.body.dir=n},[n]);const t=ue();return s.jsx(Z,{theme:t,children:s.jsx(de,{theme:r,colorModeManager:ce,toastOptions:Y,children:e})})}const ve=l.memo(me);export{ve as default};

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

25
invokeai/frontend/web/dist/index.html vendored Normal file
View File

@@ -0,0 +1,25 @@
<!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>InvokeAI - A Stable Diffusion Toolkit</title>
<link rel="shortcut icon" type="icon" href="./assets/favicon-0d253ced.ico" />
<style>
html,
body {
padding: 0;
margin: 0;
}
</style>
<script type="module" crossorigin src="./assets/index-f820e2e3.js"></script>
</head>
<body dir="ltr">
<div id="root"></div>
</body>
</html>

View File

@@ -0,0 +1,504 @@
{
"common": {
"hotkeysLabel": "مفاتيح الأختصار",
"languagePickerLabel": "منتقي اللغة",
"reportBugLabel": "بلغ عن خطأ",
"settingsLabel": "إعدادات",
"img2img": "صورة إلى صورة",
"unifiedCanvas": "لوحة موحدة",
"nodes": "عقد",
"langArabic": "العربية",
"nodesDesc": "نظام مبني على العقد لإنتاج الصور قيد التطوير حاليًا. تبقى على اتصال مع تحديثات حول هذه الميزة المذهلة.",
"postProcessing": "معالجة بعد الإصدار",
"postProcessDesc1": "Invoke AI توفر مجموعة واسعة من ميزات المعالجة بعد الإصدار. تحسين الصور واستعادة الوجوه متاحين بالفعل في واجهة الويب. يمكنك الوصول إليهم من الخيارات المتقدمة في قائمة الخيارات في علامة التبويب Text To Image و Image To Image. يمكن أيضًا معالجة الصور مباشرةً باستخدام أزرار الإجراء على الصورة فوق عرض الصورة الحالي أو في العارض.",
"postProcessDesc2": "سيتم إصدار واجهة رسومية مخصصة قريبًا لتسهيل عمليات المعالجة بعد الإصدار المتقدمة.",
"postProcessDesc3": "واجهة سطر الأوامر Invoke AI توفر ميزات أخرى عديدة بما في ذلك Embiggen.",
"training": "تدريب",
"trainingDesc1": "تدفق خاص مخصص لتدريب تضميناتك الخاصة ونقاط التحقق باستخدام العكس النصي و دريم بوث من واجهة الويب.",
"trainingDesc2": " استحضر الذكاء الصناعي يدعم بالفعل تدريب تضمينات مخصصة باستخدام العكس النصي باستخدام السكريبت الرئيسي.",
"upload": "رفع",
"close": "إغلاق",
"load": "تحميل",
"back": "الى الخلف",
"statusConnected": "متصل",
"statusDisconnected": "غير متصل",
"statusError": "خطأ",
"statusPreparing": "جاري التحضير",
"statusProcessingCanceled": "تم إلغاء المعالجة",
"statusProcessingComplete": "اكتمال المعالجة",
"statusGenerating": "جاري التوليد",
"statusGeneratingTextToImage": "جاري توليد النص إلى الصورة",
"statusGeneratingImageToImage": "جاري توليد الصورة إلى الصورة",
"statusGeneratingInpainting": "جاري توليد Inpainting",
"statusGeneratingOutpainting": "جاري توليد Outpainting",
"statusGenerationComplete": "اكتمال التوليد",
"statusIterationComplete": "اكتمال التكرار",
"statusSavingImage": "جاري حفظ الصورة",
"statusRestoringFaces": "جاري استعادة الوجوه",
"statusRestoringFacesGFPGAN": "تحسيت الوجوه (جي إف بي جان)",
"statusRestoringFacesCodeFormer": "تحسين الوجوه (كود فورمر)",
"statusUpscaling": "تحسين الحجم",
"statusUpscalingESRGAN": "تحسين الحجم (إي إس آر جان)",
"statusLoadingModel": "تحميل النموذج",
"statusModelChanged": "تغير النموذج"
},
"gallery": {
"generations": "الأجيال",
"showGenerations": "عرض الأجيال",
"uploads": "التحميلات",
"showUploads": "عرض التحميلات",
"galleryImageSize": "حجم الصورة",
"galleryImageResetSize": "إعادة ضبط الحجم",
"gallerySettings": "إعدادات المعرض",
"maintainAspectRatio": "الحفاظ على نسبة الأبعاد",
"autoSwitchNewImages": "التبديل التلقائي إلى الصور الجديدة",
"singleColumnLayout": "تخطيط عمود واحد",
"allImagesLoaded": "تم تحميل جميع الصور",
"loadMore": "تحميل المزيد",
"noImagesInGallery": "لا توجد صور في المعرض"
},
"hotkeys": {
"keyboardShortcuts": "مفاتيح الأزرار المختصرة",
"appHotkeys": "مفاتيح التطبيق",
"generalHotkeys": "مفاتيح عامة",
"galleryHotkeys": "مفاتيح المعرض",
"unifiedCanvasHotkeys": "مفاتيح اللوحةالموحدة ",
"invoke": {
"title": "أدعو",
"desc": "إنشاء صورة"
},
"cancel": {
"title": "إلغاء",
"desc": "إلغاء إنشاء الصورة"
},
"focusPrompt": {
"title": "تركيز الإشعار",
"desc": "تركيز منطقة الإدخال الإشعار"
},
"toggleOptions": {
"title": "تبديل الخيارات",
"desc": "فتح وإغلاق لوحة الخيارات"
},
"pinOptions": {
"title": "خيارات التثبيت",
"desc": "ثبت لوحة الخيارات"
},
"toggleViewer": {
"title": "تبديل العارض",
"desc": "فتح وإغلاق مشاهد الصور"
},
"toggleGallery": {
"title": "تبديل المعرض",
"desc": "فتح وإغلاق درابزين المعرض"
},
"maximizeWorkSpace": {
"title": "تكبير مساحة العمل",
"desc": "إغلاق اللوحات وتكبير مساحة العمل"
},
"changeTabs": {
"title": "تغيير الألسنة",
"desc": "التبديل إلى مساحة عمل أخرى"
},
"consoleToggle": {
"title": "تبديل الطرفية",
"desc": "فتح وإغلاق الطرفية"
},
"setPrompt": {
"title": "ضبط التشعب",
"desc": "استخدم تشعب الصورة الحالية"
},
"setSeed": {
"title": "ضبط البذور",
"desc": "استخدم بذور الصورة الحالية"
},
"setParameters": {
"title": "ضبط المعلمات",
"desc": "استخدم جميع المعلمات الخاصة بالصورة الحالية"
},
"restoreFaces": {
"title": "استعادة الوجوه",
"desc": "استعادة الصورة الحالية"
},
"upscale": {
"title": "تحسين الحجم",
"desc": "تحسين حجم الصورة الحالية"
},
"showInfo": {
"title": "عرض المعلومات",
"desc": "عرض معلومات البيانات الخاصة بالصورة الحالية"
},
"sendToImageToImage": {
"title": "أرسل إلى صورة إلى صورة",
"desc": "أرسل الصورة الحالية إلى صورة إلى صورة"
},
"deleteImage": {
"title": "حذف الصورة",
"desc": "حذف الصورة الحالية"
},
"closePanels": {
"title": "أغلق اللوحات",
"desc": "يغلق اللوحات المفتوحة"
},
"previousImage": {
"title": "الصورة السابقة",
"desc": "عرض الصورة السابقة في الصالة"
},
"nextImage": {
"title": "الصورة التالية",
"desc": "عرض الصورة التالية في الصالة"
},
"toggleGalleryPin": {
"title": "تبديل تثبيت الصالة",
"desc": "يثبت ويفتح تثبيت الصالة على الواجهة الرسومية"
},
"increaseGalleryThumbSize": {
"title": "زيادة حجم صورة الصالة",
"desc": "يزيد حجم الصور المصغرة في الصالة"
},
"decreaseGalleryThumbSize": {
"title": "انقاص حجم صورة الصالة",
"desc": "ينقص حجم الصور المصغرة في الصالة"
},
"selectBrush": {
"title": "تحديد الفرشاة",
"desc": "يحدد الفرشاة على اللوحة"
},
"selectEraser": {
"title": "تحديد الممحاة",
"desc": "يحدد الممحاة على اللوحة"
},
"decreaseBrushSize": {
"title": "تصغير حجم الفرشاة",
"desc": "يصغر حجم الفرشاة/الممحاة على اللوحة"
},
"increaseBrushSize": {
"title": "زيادة حجم الفرشاة",
"desc": "يزيد حجم فرشة اللوحة / الممحاة"
},
"decreaseBrushOpacity": {
"title": "تخفيض شفافية الفرشاة",
"desc": "يخفض شفافية فرشة اللوحة"
},
"increaseBrushOpacity": {
"title": "زيادة شفافية الفرشاة",
"desc": "يزيد شفافية فرشة اللوحة"
},
"moveTool": {
"title": "أداة التحريك",
"desc": "يتيح التحرك في اللوحة"
},
"fillBoundingBox": {
"title": "ملء الصندوق المحدد",
"desc": "يملأ الصندوق المحدد بلون الفرشاة"
},
"eraseBoundingBox": {
"title": "محو الصندوق المحدد",
"desc": "يمحو منطقة الصندوق المحدد"
},
"colorPicker": {
"title": "اختيار منتقي اللون",
"desc": "يختار منتقي اللون الخاص باللوحة"
},
"toggleSnap": {
"title": "تبديل التأكيد",
"desc": "يبديل تأكيد الشبكة"
},
"quickToggleMove": {
"title": "تبديل سريع للتحريك",
"desc": "يبديل مؤقتا وضع التحريك"
},
"toggleLayer": {
"title": "تبديل الطبقة",
"desc": "يبديل إختيار الطبقة القناع / الأساسية"
},
"clearMask": {
"title": "مسح القناع",
"desc": "مسح القناع بأكمله"
},
"hideMask": {
"title": "إخفاء الكمامة",
"desc": "إخفاء وإظهار الكمامة"
},
"showHideBoundingBox": {
"title": "إظهار / إخفاء علبة التحديد",
"desc": "تبديل ظهور علبة التحديد"
},
"mergeVisible": {
"title": "دمج الطبقات الظاهرة",
"desc": "دمج جميع الطبقات الظاهرة في اللوحة"
},
"saveToGallery": {
"title": "حفظ إلى صالة الأزياء",
"desc": "حفظ اللوحة الحالية إلى صالة الأزياء"
},
"copyToClipboard": {
"title": "نسخ إلى الحافظة",
"desc": "نسخ اللوحة الحالية إلى الحافظة"
},
"downloadImage": {
"title": "تنزيل الصورة",
"desc": "تنزيل اللوحة الحالية"
},
"undoStroke": {
"title": "تراجع عن الخط",
"desc": "تراجع عن خط الفرشاة"
},
"redoStroke": {
"title": "إعادة الخط",
"desc": "إعادة خط الفرشاة"
},
"resetView": {
"title": "إعادة تعيين العرض",
"desc": "إعادة تعيين عرض اللوحة"
},
"previousStagingImage": {
"title": "الصورة السابقة في المرحلة التجريبية",
"desc": "الصورة السابقة في منطقة المرحلة التجريبية"
},
"nextStagingImage": {
"title": "الصورة التالية في المرحلة التجريبية",
"desc": "الصورة التالية في منطقة المرحلة التجريبية"
},
"acceptStagingImage": {
"title": "قبول الصورة في المرحلة التجريبية",
"desc": "قبول الصورة الحالية في منطقة المرحلة التجريبية"
}
},
"modelManager": {
"modelManager": "مدير النموذج",
"model": "نموذج",
"allModels": "جميع النماذج",
"checkpointModels": "نقاط التحقق",
"diffusersModels": "المصادر المتعددة",
"safetensorModels": "التنسورات الآمنة",
"modelAdded": "تمت إضافة النموذج",
"modelUpdated": "تم تحديث النموذج",
"modelEntryDeleted": "تم حذف مدخل النموذج",
"cannotUseSpaces": "لا يمكن استخدام المساحات",
"addNew": "إضافة جديد",
"addNewModel": "إضافة نموذج جديد",
"addCheckpointModel": "إضافة نقطة تحقق / نموذج التنسور الآمن",
"addDiffuserModel": "إضافة مصادر متعددة",
"addManually": "إضافة يدويًا",
"manual": "يدوي",
"name": "الاسم",
"nameValidationMsg": "أدخل اسما لنموذجك",
"description": "الوصف",
"descriptionValidationMsg": "أضف وصفا لنموذجك",
"config": "تكوين",
"configValidationMsg": "مسار الملف الإعدادي لنموذجك.",
"modelLocation": "موقع النموذج",
"modelLocationValidationMsg": "موقع النموذج على الجهاز الخاص بك.",
"repo_id": "معرف المستودع",
"repoIDValidationMsg": "المستودع الإلكتروني لنموذجك",
"vaeLocation": "موقع فاي إي",
"vaeLocationValidationMsg": "موقع فاي إي على الجهاز الخاص بك.",
"vaeRepoID": "معرف مستودع فاي إي",
"vaeRepoIDValidationMsg": "المستودع الإلكتروني فاي إي",
"width": "عرض",
"widthValidationMsg": "عرض افتراضي لنموذجك.",
"height": "ارتفاع",
"heightValidationMsg": "ارتفاع افتراضي لنموذجك.",
"addModel": "أضف نموذج",
"updateModel": "تحديث النموذج",
"availableModels": "النماذج المتاحة",
"search": "بحث",
"load": "تحميل",
"active": "نشط",
"notLoaded": "غير محمل",
"cached": "مخبأ",
"checkpointFolder": "مجلد التدقيق",
"clearCheckpointFolder": "مسح مجلد التدقيق",
"findModels": "إيجاد النماذج",
"scanAgain": "فحص مرة أخرى",
"modelsFound": "النماذج الموجودة",
"selectFolder": "حدد المجلد",
"selected": "تم التحديد",
"selectAll": "حدد الكل",
"deselectAll": "إلغاء تحديد الكل",
"showExisting": "إظهار الموجود",
"addSelected": "أضف المحدد",
"modelExists": "النموذج موجود",
"selectAndAdd": "حدد وأضف النماذج المدرجة أدناه",
"noModelsFound": "لم يتم العثور على نماذج",
"delete": "حذف",
"deleteModel": "حذف النموذج",
"deleteConfig": "حذف التكوين",
"deleteMsg1": "هل أنت متأكد من رغبتك في حذف إدخال النموذج هذا من استحضر الذكاء الصناعي",
"deleteMsg2": "هذا لن يحذف ملف نقطة التحكم للنموذج من القرص الخاص بك. يمكنك إعادة إضافتهم إذا كنت ترغب في ذلك.",
"formMessageDiffusersModelLocation": "موقع النموذج للمصعد",
"formMessageDiffusersModelLocationDesc": "يرجى إدخال واحد على الأقل.",
"formMessageDiffusersVAELocation": "موقع فاي إي",
"formMessageDiffusersVAELocationDesc": "إذا لم يتم توفيره، سيبحث استحضر الذكاء الصناعي عن ملف فاي إي داخل موقع النموذج المعطى أعلاه."
},
"parameters": {
"images": "الصور",
"steps": "الخطوات",
"cfgScale": "مقياس الإعداد الذاتي للجملة",
"width": "عرض",
"height": "ارتفاع",
"seed": "بذرة",
"randomizeSeed": "تبديل بذرة",
"shuffle": "تشغيل",
"noiseThreshold": "عتبة الضوضاء",
"perlinNoise": "ضجيج برلين",
"variations": "تباينات",
"variationAmount": "كمية التباين",
"seedWeights": "أوزان البذور",
"faceRestoration": "استعادة الوجه",
"restoreFaces": "استعادة الوجوه",
"type": "نوع",
"strength": "قوة",
"upscaling": "تصغير",
"upscale": "تصغير",
"upscaleImage": "تصغير الصورة",
"scale": "مقياس",
"otherOptions": "خيارات أخرى",
"seamlessTiling": "تجهيز بلاستيكي بدون تشققات",
"hiresOptim": "تحسين الدقة العالية",
"imageFit": "ملائمة الصورة الأولية لحجم الخرج",
"codeformerFidelity": "الوثوقية",
"scaleBeforeProcessing": "تحجيم قبل المعالجة",
"scaledWidth": "العرض المحجوب",
"scaledHeight": "الارتفاع المحجوب",
"infillMethod": "طريقة التعبئة",
"tileSize": "حجم البلاطة",
"boundingBoxHeader": "صندوق التحديد",
"seamCorrectionHeader": "تصحيح التشقق",
"infillScalingHeader": "التعبئة والتحجيم",
"img2imgStrength": "قوة صورة إلى صورة",
"toggleLoopback": "تبديل الإعادة",
"sendTo": "أرسل إلى",
"sendToImg2Img": "أرسل إلى صورة إلى صورة",
"sendToUnifiedCanvas": "أرسل إلى الخطوط الموحدة",
"copyImage": "نسخ الصورة",
"copyImageToLink": "نسخ الصورة إلى الرابط",
"downloadImage": "تحميل الصورة",
"openInViewer": "فتح في العارض",
"closeViewer": "إغلاق العارض",
"usePrompt": "استخدم المحث",
"useSeed": "استخدام البذور",
"useAll": "استخدام الكل",
"useInitImg": "استخدام الصورة الأولية",
"info": "معلومات",
"initialImage": "الصورة الأولية",
"showOptionsPanel": "إظهار لوحة الخيارات"
},
"settings": {
"models": "موديلات",
"displayInProgress": "عرض الصور المؤرشفة",
"saveSteps": "حفظ الصور كل n خطوات",
"confirmOnDelete": "تأكيد عند الحذف",
"displayHelpIcons": "عرض أيقونات المساعدة",
"enableImageDebugging": "تمكين التصحيح عند التصوير",
"resetWebUI": "إعادة تعيين واجهة الويب",
"resetWebUIDesc1": "إعادة تعيين واجهة الويب يعيد فقط ذاكرة التخزين المؤقت للمتصفح لصورك وإعداداتك المذكورة. لا يحذف أي صور من القرص.",
"resetWebUIDesc2": "إذا لم تظهر الصور في الصالة أو إذا كان شيء آخر غير ناجح، يرجى المحاولة إعادة تعيين قبل تقديم مشكلة على جيت هب.",
"resetComplete": "تم إعادة تعيين واجهة الويب. تحديث الصفحة لإعادة التحميل."
},
"toast": {
"tempFoldersEmptied": "تم تفريغ مجلد المؤقت",
"uploadFailed": "فشل التحميل",
"uploadFailedUnableToLoadDesc": "تعذر تحميل الملف",
"downloadImageStarted": "بدأ تنزيل الصورة",
"imageCopied": "تم نسخ الصورة",
"imageLinkCopied": "تم نسخ رابط الصورة",
"imageNotLoaded": "لم يتم تحميل أي صورة",
"imageNotLoadedDesc": "لم يتم العثور على صورة لإرسالها إلى وحدة الصورة",
"imageSavedToGallery": "تم حفظ الصورة في المعرض",
"canvasMerged": "تم دمج الخط",
"sentToImageToImage": "تم إرسال إلى صورة إلى صورة",
"sentToUnifiedCanvas": "تم إرسال إلى لوحة موحدة",
"parametersSet": "تم تعيين المعلمات",
"parametersNotSet": "لم يتم تعيين المعلمات",
"parametersNotSetDesc": "لم يتم العثور على معلمات بيانية لهذه الصورة.",
"parametersFailed": "حدث مشكلة في تحميل المعلمات",
"parametersFailedDesc": "تعذر تحميل صورة البدء.",
"seedSet": "تم تعيين البذرة",
"seedNotSet": "لم يتم تعيين البذرة",
"seedNotSetDesc": "تعذر العثور على البذرة لهذه الصورة.",
"promptSet": "تم تعيين الإشعار",
"promptNotSet": "Prompt Not Set",
"promptNotSetDesc": "تعذر العثور على الإشعار لهذه الصورة.",
"upscalingFailed": "فشل التحسين",
"faceRestoreFailed": "فشل استعادة الوجه",
"metadataLoadFailed": "فشل تحميل البيانات الوصفية",
"initialImageSet": "تم تعيين الصورة الأولية",
"initialImageNotSet": "لم يتم تعيين الصورة الأولية",
"initialImageNotSetDesc": "تعذر تحميل الصورة الأولية"
},
"tooltip": {
"feature": {
"prompt": "هذا هو حقل التحذير. يشمل التحذير عناصر الإنتاج والمصطلحات الأسلوبية. يمكنك إضافة الأوزان (أهمية الرمز) في التحذير أيضًا، ولكن أوامر CLI والمعلمات لن تعمل.",
"gallery": "تعرض Gallery منتجات من مجلد الإخراج عندما يتم إنشاؤها. تخزن الإعدادات داخل الملفات ويتم الوصول إليها عن طريق قائمة السياق.",
"other": "ستمكن هذه الخيارات من وضع عمليات معالجة بديلة لـاستحضر الذكاء الصناعي. سيؤدي 'الزخرفة بلا جدران' إلى إنشاء أنماط تكرارية في الإخراج. 'دقة عالية' هي الإنتاج خلال خطوتين عبر صورة إلى صورة: استخدم هذا الإعداد عندما ترغب في توليد صورة أكبر وأكثر تجانبًا دون العيوب. ستستغرق الأشياء وقتًا أطول من نص إلى صورة المعتاد.",
"seed": "يؤثر قيمة البذور على الضوضاء الأولي الذي يتم تكوين الصورة منه. يمكنك استخدام البذور الخاصة بالصور السابقة. 'عتبة الضوضاء' يتم استخدامها لتخفيف العناصر الخللية في قيم CFG العالية (جرب مدى 0-10), و Perlin لإضافة ضوضاء Perlin أثناء الإنتاج: كلا منهما يعملان على إضافة التنوع إلى النتائج الخاصة بك.",
"variations": "جرب التغيير مع قيمة بين 0.1 و 1.0 لتغيير النتائج لبذور معينة. التغييرات المثيرة للاهتمام للبذور تكون بين 0.1 و 0.3.",
"upscale": "استخدم إي إس آر جان لتكبير الصورة على الفور بعد الإنتاج.",
"faceCorrection": "تصحيح الوجه باستخدام جي إف بي جان أو كود فورمر: يكتشف الخوارزمية الوجوه في الصورة وتصحح أي عيوب. قيمة عالية ستغير الصورة أكثر، مما يؤدي إلى وجوه أكثر جمالا. كود فورمر بدقة أعلى يحتفظ بالصورة الأصلية على حساب تصحيح وجه أكثر قوة.",
"imageToImage": "تحميل صورة إلى صورة أي صورة كأولية، والتي يتم استخدامها لإنشاء صورة جديدة مع التشعيب. كلما كانت القيمة أعلى، كلما تغيرت نتيجة الصورة. من الممكن أن تكون القيم بين 0.0 و 1.0، وتوصي النطاق الموصى به هو .25-.75",
"boundingBox": "مربع الحدود هو نفس الإعدادات العرض والارتفاع لنص إلى صورة أو صورة إلى صورة. فقط المنطقة في المربع سيتم معالجتها.",
"seamCorrection": "يتحكم بالتعامل مع الخطوط المرئية التي تحدث بين الصور المولدة في سطح اللوحة.",
"infillAndScaling": "إدارة أساليب التعبئة (المستخدمة على المناطق المخفية أو الممحوة في سطح اللوحة) والزيادة في الحجم (مفيدة لحجوزات الإطارات الصغيرة)."
}
},
"unifiedCanvas": {
"layer": "طبقة",
"base": "قاعدة",
"mask": "قناع",
"maskingOptions": "خيارات القناع",
"enableMask": "مكن القناع",
"preserveMaskedArea": "الحفاظ على المنطقة المقنعة",
"clearMask": "مسح القناع",
"brush": "فرشاة",
"eraser": "ممحاة",
"fillBoundingBox": "ملئ إطار الحدود",
"eraseBoundingBox": "مسح إطار الحدود",
"colorPicker": "اختيار اللون",
"brushOptions": "خيارات الفرشاة",
"brushSize": "الحجم",
"move": "تحريك",
"resetView": "إعادة تعيين العرض",
"mergeVisible": "دمج الظاهر",
"saveToGallery": "حفظ إلى المعرض",
"copyToClipboard": "نسخ إلى الحافظة",
"downloadAsImage": "تنزيل على شكل صورة",
"undo": "تراجع",
"redo": "إعادة",
"clearCanvas": "مسح سبيكة الكاملة",
"canvasSettings": "إعدادات سبيكة الكاملة",
"showIntermediates": "إظهار الوسطاء",
"showGrid": "إظهار الشبكة",
"snapToGrid": "الالتفاف إلى الشبكة",
"darkenOutsideSelection": "تعمية خارج التحديد",
"autoSaveToGallery": "حفظ تلقائي إلى المعرض",
"saveBoxRegionOnly": "حفظ منطقة الصندوق فقط",
"limitStrokesToBox": "تحديد عدد الخطوط إلى الصندوق",
"showCanvasDebugInfo": "إظهار معلومات تصحيح سبيكة الكاملة",
"clearCanvasHistory": "مسح تاريخ سبيكة الكاملة",
"clearHistory": "مسح التاريخ",
"clearCanvasHistoryMessage": "مسح تاريخ اللوحة تترك اللوحة الحالية عائمة، ولكن تمسح بشكل غير قابل للتراجع تاريخ التراجع والإعادة.",
"clearCanvasHistoryConfirm": "هل أنت متأكد من رغبتك في مسح تاريخ اللوحة؟",
"emptyTempImageFolder": "إفراغ مجلد الصور المؤقتة",
"emptyFolder": "إفراغ المجلد",
"emptyTempImagesFolderMessage": "إفراغ مجلد الصور المؤقتة يؤدي أيضًا إلى إعادة تعيين اللوحة الموحدة بشكل كامل. وهذا يشمل كل تاريخ التراجع / الإعادة والصور في منطقة التخزين وطبقة الأساس لللوحة.",
"emptyTempImagesFolderConfirm": "هل أنت متأكد من رغبتك في إفراغ مجلد الصور المؤقتة؟",
"activeLayer": "الطبقة النشطة",
"canvasScale": "مقياس اللوحة",
"boundingBox": "صندوق الحدود",
"scaledBoundingBox": "صندوق الحدود المكبر",
"boundingBoxPosition": "موضع صندوق الحدود",
"canvasDimensions": "أبعاد اللوحة",
"canvasPosition": "موضع اللوحة",
"cursorPosition": "موضع المؤشر",
"previous": "السابق",
"next": "التالي",
"accept": "قبول",
"showHide": "إظهار/إخفاء",
"discardAll": "تجاهل الكل",
"betaClear": "مسح",
"betaDarkenOutside": "ظل الخارج",
"betaLimitToBox": "تحديد إلى الصندوق",
"betaPreserveMasked": "المحافظة على المخفية"
}
}

View File

@@ -0,0 +1,973 @@
{
"common": {
"languagePickerLabel": "Sprachauswahl",
"reportBugLabel": "Fehler melden",
"settingsLabel": "Einstellungen",
"img2img": "Bild zu Bild",
"nodes": "Knoten Editor",
"langGerman": "Deutsch",
"nodesDesc": "Ein knotenbasiertes System, für die Erzeugung von Bildern, ist derzeit in der Entwicklung. Bleiben Sie gespannt auf Updates zu dieser fantastischen Funktion.",
"postProcessing": "Nachbearbeitung",
"postProcessDesc1": "InvokeAI bietet eine breite Palette von Nachbearbeitungsfunktionen. Bildhochskalierung und Gesichtsrekonstruktion sind bereits in der WebUI verfügbar. Sie können sie über das Menü Erweiterte Optionen der Reiter Text in Bild und Bild in Bild aufrufen. Sie können Bilder auch direkt bearbeiten, indem Sie die Schaltflächen für Bildaktionen oberhalb der aktuellen Bildanzeige oder im Viewer verwenden.",
"postProcessDesc2": "Eine spezielle Benutzeroberfläche wird in Kürze veröffentlicht, um erweiterte Nachbearbeitungs-Workflows zu erleichtern.",
"postProcessDesc3": "Die InvokeAI Kommandozeilen-Schnittstelle bietet verschiedene andere Funktionen, darunter Embiggen.",
"training": "trainieren",
"trainingDesc1": "Ein spezieller Arbeitsablauf zum Trainieren Ihrer eigenen Embeddings und Checkpoints mit Textual Inversion und Dreambooth über die Weboberfläche.",
"trainingDesc2": "InvokeAI unterstützt bereits das Training von benutzerdefinierten Embeddings mit Textual Inversion unter Verwendung des Hauptskripts.",
"upload": "Hochladen",
"close": "Schließen",
"load": "Laden",
"statusConnected": "Verbunden",
"statusDisconnected": "Getrennt",
"statusError": "Fehler",
"statusPreparing": "Vorbereiten",
"statusProcessingCanceled": "Verarbeitung abgebrochen",
"statusProcessingComplete": "Verarbeitung komplett",
"statusGenerating": "Generieren",
"statusGeneratingTextToImage": "Erzeugen von Text zu Bild",
"statusGeneratingImageToImage": "Erzeugen von Bild zu Bild",
"statusGeneratingInpainting": "Erzeuge Inpainting",
"statusGeneratingOutpainting": "Erzeuge Outpainting",
"statusGenerationComplete": "Generierung abgeschlossen",
"statusIterationComplete": "Iteration abgeschlossen",
"statusSavingImage": "Speichere Bild",
"statusRestoringFaces": "Gesichter restaurieren",
"statusRestoringFacesGFPGAN": "Gesichter restaurieren (GFPGAN)",
"statusRestoringFacesCodeFormer": "Gesichter restaurieren (CodeFormer)",
"statusUpscaling": "Hochskalierung",
"statusUpscalingESRGAN": "Hochskalierung (ESRGAN)",
"statusLoadingModel": "Laden des Modells",
"statusModelChanged": "Modell Geändert",
"cancel": "Abbrechen",
"accept": "Annehmen",
"back": "Zurück",
"langEnglish": "Englisch",
"langDutch": "Niederländisch",
"langFrench": "Französisch",
"langItalian": "Italienisch",
"langPortuguese": "Portugiesisch",
"langRussian": "Russisch",
"langUkranian": "Ukrainisch",
"hotkeysLabel": "Tastenkombinationen",
"githubLabel": "Github",
"discordLabel": "Discord",
"txt2img": "Text zu Bild",
"postprocessing": "Nachbearbeitung",
"langPolish": "Polnisch",
"langJapanese": "Japanisch",
"langArabic": "Arabisch",
"langKorean": "Koreanisch",
"langHebrew": "Hebräisch",
"langSpanish": "Spanisch",
"t2iAdapter": "T2I Adapter",
"communityLabel": "Gemeinschaft",
"dontAskMeAgain": "Frag mich nicht nochmal",
"loadingInvokeAI": "Lade Invoke AI",
"statusMergedModels": "Modelle zusammengeführt",
"areYouSure": "Bist du dir sicher?",
"statusConvertingModel": "Model konvertieren",
"on": "An",
"nodeEditor": "Knoten Editor",
"statusMergingModels": "Modelle zusammenführen",
"langSimplifiedChinese": "Vereinfachtes Chinesisch",
"ipAdapter": "IP Adapter",
"controlAdapter": "Control Adapter",
"auto": "Automatisch",
"controlNet": "ControlNet",
"imageFailedToLoad": "Kann Bild nicht laden",
"statusModelConverted": "Model konvertiert",
"modelManager": "Model Manager",
"lightMode": "Heller Modus",
"generate": "Erstellen",
"learnMore": "Mehr lernen",
"darkMode": "Dunkler Modus",
"loading": "Lade",
"random": "Zufall",
"batch": "Stapel-Manager",
"advanced": "Erweitert",
"langBrPortuguese": "Portugiesisch (Brasilien)",
"unifiedCanvas": "Einheitliche Leinwand",
"openInNewTab": "In einem neuem Tab öffnen",
"statusProcessing": "wird bearbeitet",
"linear": "Linear",
"imagePrompt": "Bild Prompt"
},
"gallery": {
"generations": "Erzeugungen",
"showGenerations": "Zeige Erzeugnisse",
"uploads": "Uploads",
"showUploads": "Zeige Uploads",
"galleryImageSize": "Bildgröße",
"galleryImageResetSize": "Größe zurücksetzen",
"gallerySettings": "Galerie-Einstellungen",
"maintainAspectRatio": "Seitenverhältnis beibehalten",
"autoSwitchNewImages": "Automatisch zu neuen Bildern wechseln",
"singleColumnLayout": "Einspaltiges Layout",
"allImagesLoaded": "Alle Bilder geladen",
"loadMore": "Mehr laden",
"noImagesInGallery": "Keine Bilder in der Galerie",
"loading": "Lade",
"preparingDownload": "bereite Download vor",
"preparingDownloadFailed": "Problem beim Download vorbereiten",
"deleteImage": "Lösche Bild",
"images": "Bilder",
"copy": "Kopieren",
"download": "Runterladen",
"setCurrentImage": "Setze aktuelle Bild",
"featuresWillReset": "Wenn Sie dieses Bild löschen, werden diese Funktionen sofort zurückgesetzt.",
"deleteImageBin": "Gelöschte Bilder werden an den Papierkorb Ihres Betriebssystems gesendet.",
"unableToLoad": "Galerie kann nicht geladen werden",
"downloadSelection": "Auswahl herunterladen",
"currentlyInUse": "Dieses Bild wird derzeit in den folgenden Funktionen verwendet:",
"deleteImagePermanent": "Gelöschte Bilder können nicht wiederhergestellt werden.",
"autoAssignBoardOnClick": "Board per Klick automatisch zuweisen"
},
"hotkeys": {
"keyboardShortcuts": "Tastenkürzel",
"appHotkeys": "App-Tastenkombinationen",
"generalHotkeys": "Allgemeine Tastenkürzel",
"galleryHotkeys": "Galerie Tastenkürzel",
"unifiedCanvasHotkeys": "Unified Canvas Tastenkürzel",
"invoke": {
"desc": "Ein Bild erzeugen",
"title": "Invoke"
},
"cancel": {
"title": "Abbrechen",
"desc": "Bilderzeugung abbrechen"
},
"focusPrompt": {
"title": "Fokussiere Prompt",
"desc": "Fokussieren des Eingabefeldes für den Prompt"
},
"toggleOptions": {
"title": "Optionen umschalten",
"desc": "Öffnen und Schließen des Optionsfeldes"
},
"pinOptions": {
"title": "Optionen anheften",
"desc": "Anheften des Optionsfeldes"
},
"toggleViewer": {
"title": "Bildbetrachter umschalten",
"desc": "Bildbetrachter öffnen und schließen"
},
"toggleGallery": {
"title": "Galerie umschalten",
"desc": "Öffnen und Schließen des Galerie-Schubfachs"
},
"maximizeWorkSpace": {
"title": "Arbeitsbereich maximieren",
"desc": "Schließen Sie die Panels und maximieren Sie den Arbeitsbereich"
},
"changeTabs": {
"title": "Tabs wechseln",
"desc": "Zu einem anderen Arbeitsbereich wechseln"
},
"consoleToggle": {
"title": "Konsole Umschalten",
"desc": "Konsole öffnen und schließen"
},
"setPrompt": {
"title": "Prompt setzen",
"desc": "Verwende den Prompt des aktuellen Bildes"
},
"setSeed": {
"title": "Seed setzen",
"desc": "Verwende den Seed des aktuellen Bildes"
},
"setParameters": {
"title": "Parameter setzen",
"desc": "Alle Parameter des aktuellen Bildes verwenden"
},
"restoreFaces": {
"title": "Gesicht restaurieren",
"desc": "Das aktuelle Bild restaurieren"
},
"upscale": {
"title": "Hochskalieren",
"desc": "Das aktuelle Bild hochskalieren"
},
"showInfo": {
"title": "Info anzeigen",
"desc": "Metadaten des aktuellen Bildes anzeigen"
},
"sendToImageToImage": {
"title": "An Bild zu Bild senden",
"desc": "Aktuelles Bild an Bild zu Bild senden"
},
"deleteImage": {
"title": "Bild löschen",
"desc": "Aktuelles Bild löschen"
},
"closePanels": {
"title": "Panels schließen",
"desc": "Schließt offene Panels"
},
"previousImage": {
"title": "Vorheriges Bild",
"desc": "Vorheriges Bild in der Galerie anzeigen"
},
"nextImage": {
"title": "Nächstes Bild",
"desc": "Nächstes Bild in Galerie anzeigen"
},
"toggleGalleryPin": {
"title": "Galerie anheften umschalten",
"desc": "Heftet die Galerie an die Benutzeroberfläche bzw. löst die sie"
},
"increaseGalleryThumbSize": {
"title": "Größe der Galeriebilder erhöhen",
"desc": "Vergrößert die Galerie-Miniaturansichten"
},
"decreaseGalleryThumbSize": {
"title": "Größe der Galeriebilder verringern",
"desc": "Verringert die Größe der Galerie-Miniaturansichten"
},
"selectBrush": {
"title": "Pinsel auswählen",
"desc": "Wählt den Leinwandpinsel aus"
},
"selectEraser": {
"title": "Radiergummi auswählen",
"desc": "Wählt den Radiergummi für die Leinwand aus"
},
"decreaseBrushSize": {
"title": "Pinselgröße verkleinern",
"desc": "Verringert die Größe des Pinsels/Radiergummis"
},
"increaseBrushSize": {
"title": "Pinselgröße erhöhen",
"desc": "Erhöht die Größe des Pinsels/Radiergummis"
},
"decreaseBrushOpacity": {
"title": "Deckkraft des Pinsels vermindern",
"desc": "Verringert die Deckkraft des Pinsels"
},
"increaseBrushOpacity": {
"title": "Deckkraft des Pinsels erhöhen",
"desc": "Erhöht die Deckkraft des Pinsels"
},
"moveTool": {
"title": "Verschieben Werkzeug",
"desc": "Ermöglicht die Navigation auf der Leinwand"
},
"fillBoundingBox": {
"title": "Begrenzungsrahmen füllen",
"desc": "Füllt den Begrenzungsrahmen mit Pinselfarbe"
},
"eraseBoundingBox": {
"title": "Begrenzungsrahmen löschen",
"desc": "Löscht den Bereich des Begrenzungsrahmens"
},
"colorPicker": {
"title": "Farbpipette",
"desc": "Farben aus dem Bild aufnehmen"
},
"toggleSnap": {
"title": "Einrasten umschalten",
"desc": "Schaltet Einrasten am Raster ein und aus"
},
"quickToggleMove": {
"title": "Schnell Verschiebemodus",
"desc": "Schaltet vorübergehend den Verschiebemodus um"
},
"toggleLayer": {
"title": "Ebene umschalten",
"desc": "Schaltet die Auswahl von Maske/Basisebene um"
},
"clearMask": {
"title": "Lösche Maske",
"desc": "Die gesamte Maske löschen"
},
"hideMask": {
"title": "Maske ausblenden",
"desc": "Maske aus- und einblenden"
},
"showHideBoundingBox": {
"title": "Begrenzungsrahmen ein-/ausblenden",
"desc": "Sichtbarkeit des Begrenzungsrahmens ein- und ausschalten"
},
"mergeVisible": {
"title": "Sichtbares Zusammenführen",
"desc": "Alle sichtbaren Ebenen der Leinwand zusammenführen"
},
"saveToGallery": {
"title": "In Galerie speichern",
"desc": "Aktuelle Leinwand in Galerie speichern"
},
"copyToClipboard": {
"title": "In die Zwischenablage kopieren",
"desc": "Aktuelle Leinwand in die Zwischenablage kopieren"
},
"downloadImage": {
"title": "Bild herunterladen",
"desc": "Aktuelle Leinwand herunterladen"
},
"undoStroke": {
"title": "Pinselstrich rückgängig machen",
"desc": "Einen Pinselstrich rückgängig machen"
},
"redoStroke": {
"title": "Pinselstrich wiederherstellen",
"desc": "Einen Pinselstrich wiederherstellen"
},
"resetView": {
"title": "Ansicht zurücksetzen",
"desc": "Leinwandansicht zurücksetzen"
},
"previousStagingImage": {
"title": "Vorheriges Staging-Bild",
"desc": "Bild des vorherigen Staging-Bereichs"
},
"nextStagingImage": {
"title": "Nächstes Staging-Bild",
"desc": "Bild des nächsten Staging-Bereichs"
},
"acceptStagingImage": {
"title": "Staging-Bild akzeptieren",
"desc": "Akzeptieren Sie das aktuelle Bild des Staging-Bereichs"
},
"nodesHotkeys": "Knoten Tastenkürzel",
"addNodes": {
"title": "Knotenpunkt hinzufügen",
"desc": "Öffnet das Menü zum Hinzufügen von Knoten"
}
},
"modelManager": {
"modelAdded": "Model hinzugefügt",
"modelUpdated": "Model aktualisiert",
"modelEntryDeleted": "Modelleintrag gelöscht",
"cannotUseSpaces": "Leerzeichen können nicht verwendet werden",
"addNew": "Neue hinzufügen",
"addNewModel": "Neues Model hinzufügen",
"addManually": "Manuell hinzufügen",
"nameValidationMsg": "Geben Sie einen Namen für Ihr Model ein",
"description": "Beschreibung",
"descriptionValidationMsg": "Fügen Sie eine Beschreibung für Ihr Model hinzu",
"config": "Konfiguration",
"configValidationMsg": "Pfad zur Konfigurationsdatei Ihres Models.",
"modelLocation": "Ort des Models",
"modelLocationValidationMsg": "Pfad zum Speicherort Ihres Models",
"vaeLocation": "VAE Ort",
"vaeLocationValidationMsg": "Pfad zum Speicherort Ihres VAE.",
"width": "Breite",
"widthValidationMsg": "Standardbreite Ihres Models.",
"height": "Höhe",
"heightValidationMsg": "Standardbhöhe Ihres Models.",
"addModel": "Model hinzufügen",
"updateModel": "Model aktualisieren",
"availableModels": "Verfügbare Models",
"search": "Suche",
"load": "Laden",
"active": "Aktiv",
"notLoaded": "nicht geladen",
"cached": "zwischengespeichert",
"checkpointFolder": "Checkpoint-Ordner",
"clearCheckpointFolder": "Checkpoint-Ordner löschen",
"findModels": "Models finden",
"scanAgain": "Erneut scannen",
"modelsFound": "Models gefunden",
"selectFolder": "Ordner auswählen",
"selected": "Ausgewählt",
"selectAll": "Alles auswählen",
"deselectAll": "Alle abwählen",
"showExisting": "Vorhandene anzeigen",
"addSelected": "Auswahl hinzufügen",
"modelExists": "Model existiert",
"selectAndAdd": "Unten aufgeführte Models auswählen und hinzufügen",
"noModelsFound": "Keine Models gefunden",
"delete": "Löschen",
"deleteModel": "Model löschen",
"deleteConfig": "Konfiguration löschen",
"deleteMsg1": "Möchten Sie diesen Model-Eintrag wirklich aus InvokeAI löschen?",
"deleteMsg2": "Dadurch WIRD das Modell von der Festplatte gelöscht WENN es im InvokeAI Root Ordner liegt. Wenn es in einem anderem Ordner liegt wird das Modell NICHT von der Festplatte gelöscht.",
"customConfig": "Benutzerdefinierte Konfiguration",
"invokeRoot": "InvokeAI Ordner",
"formMessageDiffusersVAELocationDesc": "Falls nicht angegeben, sucht InvokeAI nach der VAE-Datei innerhalb des oben angegebenen Modell Speicherortes.",
"checkpointModels": "Kontrollpunkte",
"convert": "Umwandeln",
"addCheckpointModel": "Kontrollpunkt / SafeTensors Modell hinzufügen",
"allModels": "Alle Modelle",
"alpha": "Alpha",
"addDifference": "Unterschied hinzufügen",
"convertToDiffusersHelpText2": "Bei diesem Vorgang wird Ihr Eintrag im Modell-Manager durch die Diffusor-Version desselben Modells ersetzt.",
"convertToDiffusersHelpText5": "Bitte stellen Sie sicher, dass Sie über genügend Speicherplatz verfügen. Die Modelle sind in der Regel zwischen 2 GB und 7 GB groß.",
"convertToDiffusersHelpText3": "Ihre Kontrollpunktdatei auf der Festplatte wird NICHT gelöscht oder in irgendeiner Weise verändert. Sie können Ihren Kontrollpunkt dem Modell-Manager wieder hinzufügen, wenn Sie dies wünschen.",
"convertToDiffusersHelpText4": "Dies ist ein einmaliger Vorgang. Er kann je nach den Spezifikationen Ihres Computers etwa 30-60 Sekunden dauern.",
"convertToDiffusersHelpText6": "Möchten Sie dieses Modell konvertieren?",
"custom": "Benutzerdefiniert",
"modelConverted": "Modell umgewandelt",
"inverseSigmoid": "Inverses Sigmoid",
"invokeAIFolder": "Invoke AI Ordner",
"formMessageDiffusersModelLocationDesc": "Bitte geben Sie mindestens einen an.",
"customSaveLocation": "Benutzerdefinierter Speicherort",
"formMessageDiffusersVAELocation": "VAE Speicherort",
"mergedModelCustomSaveLocation": "Benutzerdefinierter Pfad",
"modelMergeHeaderHelp2": "Nur Diffusers sind für die Zusammenführung verfügbar. Wenn Sie ein Kontrollpunktmodell zusammenführen möchten, konvertieren Sie es bitte zuerst in Diffusers.",
"manual": "Manuell",
"modelManager": "Modell Manager",
"modelMergeAlphaHelp": "Alpha steuert die Überblendungsstärke für die Modelle. Niedrigere Alphawerte führen zu einem geringeren Einfluss des zweiten Modells.",
"modelMergeHeaderHelp1": "Sie können bis zu drei verschiedene Modelle miteinander kombinieren, um eine Mischung zu erstellen, die Ihren Bedürfnissen entspricht.",
"ignoreMismatch": "Unstimmigkeiten zwischen ausgewählten Modellen ignorieren",
"model": "Modell",
"convertToDiffusersSaveLocation": "Speicherort",
"pathToCustomConfig": "Pfad zur benutzerdefinierten Konfiguration",
"v1": "v1",
"modelMergeInterpAddDifferenceHelp": "In diesem Modus wird zunächst Modell 3 von Modell 2 subtrahiert. Die resultierende Version wird mit Modell 1 mit dem oben eingestellten Alphasatz gemischt.",
"modelTwo": "Modell 2",
"modelOne": "Modell 1",
"v2_base": "v2 (512px)",
"scanForModels": "Nach Modellen suchen",
"name": "Name",
"safetensorModels": "SafeTensors",
"pickModelType": "Modell Typ auswählen",
"sameFolder": "Gleicher Ordner",
"modelThree": "Modell 3",
"v2_768": "v2 (768px)",
"none": "Nix",
"repoIDValidationMsg": "Online Repo Ihres Modells",
"vaeRepoIDValidationMsg": "Online Repo Ihrer VAE",
"importModels": "Importiere Modelle",
"merge": "Zusammenführen",
"addDiffuserModel": "Diffusers hinzufügen",
"advanced": "Erweitert",
"closeAdvanced": "Schließe Erweitert",
"convertingModelBegin": "Konvertiere Modell. Bitte warten.",
"customConfigFileLocation": "Benutzerdefinierte Konfiguration Datei Speicherort",
"baseModel": "Basis Modell",
"convertToDiffusers": "Konvertiere zu Diffusers",
"diffusersModels": "Diffusers",
"noCustomLocationProvided": "Kein benutzerdefinierter Standort angegeben",
"onnxModels": "Onnx",
"vaeRepoID": "VAE-Repo-ID",
"weightedSum": "Gewichtete Summe",
"syncModelsDesc": "Wenn Ihre Modelle nicht mit dem Backend synchronisiert sind, können Sie sie mit dieser Option aktualisieren. Dies ist im Allgemeinen praktisch, wenn Sie Ihre models.yaml-Datei manuell aktualisieren oder Modelle zum InvokeAI-Stammordner hinzufügen, nachdem die Anwendung gestartet wurde.",
"vae": "VAE",
"noModels": "Keine Modelle gefunden",
"statusConverting": "Konvertieren",
"sigmoid": "Sigmoid",
"predictionType": "Vorhersagetyp (für Stable Diffusion 2.x-Modelle und gelegentliche Stable Diffusion 1.x-Modelle)",
"selectModel": "Wählen Sie Modell aus",
"repo_id": "Repo-ID",
"modelSyncFailed": "Modellsynchronisierung fehlgeschlagen",
"quickAdd": "Schnell hinzufügen",
"simpleModelDesc": "Geben Sie einen Pfad zu einem lokalen Diffusers-Modell, einem lokalen Checkpoint-/Safetensors-Modell, einer HuggingFace-Repo-ID oder einer Checkpoint-/Diffusers-Modell-URL an.",
"modelDeleted": "Modell gelöscht",
"inpainting": "v1 Ausmalen",
"modelUpdateFailed": "Modellaktualisierung fehlgeschlagen",
"useCustomConfig": "Benutzerdefinierte Konfiguration verwenden",
"settings": "Einstellungen",
"modelConversionFailed": "Modellkonvertierung fehlgeschlagen",
"syncModels": "Modelle synchronisieren",
"mergedModelSaveLocation": "Speicherort",
"modelType": "Modelltyp",
"modelsMerged": "Modelle zusammengeführt",
"modelsMergeFailed": "Modellzusammenführung fehlgeschlagen",
"convertToDiffusersHelpText1": "Dieses Modell wird in das 🧨 Diffusers-Format konvertiert.",
"modelsSynced": "Modelle synchronisiert",
"vaePrecision": "VAE-Präzision",
"mergeModels": "Modelle zusammenführen",
"interpolationType": "Interpolationstyp",
"oliveModels": "Olives",
"variant": "Variante",
"loraModels": "LoRAs",
"modelDeleteFailed": "Modell konnte nicht gelöscht werden",
"mergedModelName": "Zusammengeführter Modellname"
},
"parameters": {
"images": "Bilder",
"steps": "Schritte",
"cfgScale": "CFG-Skala",
"width": "Breite",
"height": "Höhe",
"randomizeSeed": "Zufälliger Seed",
"shuffle": "Mischen",
"noiseThreshold": "Rausch-Schwellenwert",
"perlinNoise": "Perlin-Rauschen",
"variations": "Variationen",
"variationAmount": "Höhe der Abweichung",
"seedWeights": "Seed-Gewichte",
"faceRestoration": "Gesichtsrestaurierung",
"restoreFaces": "Gesichter wiederherstellen",
"type": "Art",
"strength": "Stärke",
"upscaling": "Hochskalierung",
"upscale": "Hochskalieren (Shift + U)",
"upscaleImage": "Bild hochskalieren",
"scale": "Maßstab",
"otherOptions": "Andere Optionen",
"seamlessTiling": "Nahtlose Kacheln",
"hiresOptim": "High-Res-Optimierung",
"imageFit": "Ausgangsbild an Ausgabegröße anpassen",
"codeformerFidelity": "Glaubwürdigkeit",
"scaleBeforeProcessing": "Skalieren vor der Verarbeitung",
"scaledWidth": "Skaliert W",
"scaledHeight": "Skaliert H",
"infillMethod": "Infill-Methode",
"tileSize": "Kachelgröße",
"boundingBoxHeader": "Begrenzungsrahmen",
"seamCorrectionHeader": "Nahtkorrektur",
"infillScalingHeader": "Infill und Skalierung",
"img2imgStrength": "Bild-zu-Bild-Stärke",
"toggleLoopback": "Loopback umschalten",
"sendTo": "Senden an",
"sendToImg2Img": "Senden an Bild zu Bild",
"sendToUnifiedCanvas": "Senden an Unified Canvas",
"copyImageToLink": "Bild-Link kopieren",
"downloadImage": "Bild herunterladen",
"openInViewer": "Im Viewer öffnen",
"closeViewer": "Viewer schließen",
"usePrompt": "Prompt verwenden",
"useSeed": "Seed verwenden",
"useAll": "Alle verwenden",
"useInitImg": "Ausgangsbild verwenden",
"initialImage": "Ursprüngliches Bild",
"showOptionsPanel": "Optionsleiste zeigen",
"cancel": {
"setType": "Abbruchart festlegen",
"immediate": "Sofort abbrechen",
"schedule": "Abbrechen nach der aktuellen Iteration",
"isScheduled": "Abbrechen"
},
"copyImage": "Bild kopieren",
"denoisingStrength": "Stärke der Entrauschung",
"symmetry": "Symmetrie",
"imageToImage": "Bild zu Bild",
"info": "Information",
"general": "Allgemein",
"hiresStrength": "High Res Stärke",
"hidePreview": "Verstecke Vorschau",
"showPreview": "Zeige Vorschau"
},
"settings": {
"displayInProgress": "Bilder in Bearbeitung anzeigen",
"saveSteps": "Speichern der Bilder alle n Schritte",
"confirmOnDelete": "Bestätigen beim Löschen",
"displayHelpIcons": "Hilfesymbole anzeigen",
"enableImageDebugging": "Bild-Debugging aktivieren",
"resetWebUI": "Web-Oberfläche zurücksetzen",
"resetWebUIDesc1": "Das Zurücksetzen der Web-Oberfläche setzt nur den lokalen Cache des Browsers mit Ihren Bildern und gespeicherten Einstellungen zurück. Es werden keine Bilder von der Festplatte gelöscht.",
"resetWebUIDesc2": "Wenn die Bilder nicht in der Galerie angezeigt werden oder etwas anderes nicht funktioniert, versuchen Sie bitte, die Einstellungen zurückzusetzen, bevor Sie einen Fehler auf GitHub melden.",
"resetComplete": "Die Web-Oberfläche wurde zurückgesetzt.",
"models": "Modelle",
"useSlidersForAll": "Schieberegler für alle Optionen verwenden"
},
"toast": {
"tempFoldersEmptied": "Temp-Ordner geleert",
"uploadFailed": "Hochladen fehlgeschlagen",
"uploadFailedUnableToLoadDesc": "Datei kann nicht geladen werden",
"downloadImageStarted": "Bild wird heruntergeladen",
"imageCopied": "Bild kopiert",
"imageLinkCopied": "Bildlink kopiert",
"imageNotLoaded": "Kein Bild geladen",
"imageNotLoadedDesc": "Konnte kein Bild finden",
"imageSavedToGallery": "Bild in die Galerie gespeichert",
"canvasMerged": "Leinwand zusammengeführt",
"sentToImageToImage": "Gesendet an Bild zu Bild",
"sentToUnifiedCanvas": "Gesendet an Unified Canvas",
"parametersSet": "Parameter festlegen",
"parametersNotSet": "Parameter nicht festgelegt",
"parametersNotSetDesc": "Keine Metadaten für dieses Bild gefunden.",
"parametersFailed": "Problem beim Laden der Parameter",
"parametersFailedDesc": "Ausgangsbild kann nicht geladen werden.",
"seedSet": "Seed festlegen",
"seedNotSet": "Saatgut nicht festgelegt",
"seedNotSetDesc": "Für dieses Bild wurde kein Seed gefunden.",
"promptSet": "Prompt festgelegt",
"promptNotSet": "Prompt nicht festgelegt",
"promptNotSetDesc": "Für dieses Bild wurde kein Prompt gefunden.",
"upscalingFailed": "Hochskalierung fehlgeschlagen",
"faceRestoreFailed": "Gesichtswiederherstellung fehlgeschlagen",
"metadataLoadFailed": "Metadaten konnten nicht geladen werden",
"initialImageSet": "Ausgangsbild festgelegt",
"initialImageNotSet": "Ausgangsbild nicht festgelegt",
"initialImageNotSetDesc": "Ausgangsbild konnte nicht geladen werden"
},
"tooltip": {
"feature": {
"prompt": "Dies ist das Prompt-Feld. Ein Prompt enthält Generierungsobjekte und stilistische Begriffe. Sie können auch Gewichtungen (Token-Bedeutung) dem Prompt hinzufügen, aber CLI-Befehle und Parameter funktionieren nicht.",
"gallery": "Die Galerie zeigt erzeugte Bilder aus dem Ausgabeordner an, sobald sie erstellt wurden. Die Einstellungen werden in den Dateien gespeichert und können über das Kontextmenü aufgerufen werden.",
"other": "Mit diesen Optionen werden alternative Verarbeitungsmodi für InvokeAI aktiviert. 'Nahtlose Kachelung' erzeugt sich wiederholende Muster in der Ausgabe. 'Hohe Auflösungen' werden in zwei Schritten mit img2img erzeugt: Verwenden Sie diese Einstellung, wenn Sie ein größeres und kohärenteres Bild ohne Artefakte wünschen. Es dauert länger als das normale txt2img.",
"seed": "Der Seed-Wert beeinflusst das Ausgangsrauschen, aus dem das Bild erstellt wird. Sie können die bereits vorhandenen Seeds von früheren Bildern verwenden. 'Der Rauschschwellenwert' wird verwendet, um Artefakte bei hohen CFG-Werten abzuschwächen (versuchen Sie es im Bereich 0-10), und Perlin, um während der Erzeugung Perlin-Rauschen hinzuzufügen: Beide dienen dazu, Ihre Ergebnisse zu variieren.",
"variations": "Versuchen Sie eine Variation mit einem Wert zwischen 0,1 und 1,0, um das Ergebnis für ein bestimmtes Seed zu ändern. Interessante Variationen des Seeds liegen zwischen 0,1 und 0,3.",
"upscale": "Verwenden Sie ESRGAN, um das Bild unmittelbar nach der Erzeugung zu vergrößern.",
"faceCorrection": "Gesichtskorrektur mit GFPGAN oder Codeformer: Der Algorithmus erkennt Gesichter im Bild und korrigiert alle Fehler. Ein hoher Wert verändert das Bild stärker, was zu attraktiveren Gesichtern führt. Codeformer mit einer höheren Genauigkeit bewahrt das Originalbild auf Kosten einer stärkeren Gesichtskorrektur.",
"imageToImage": "Bild zu Bild lädt ein beliebiges Bild als Ausgangsbild, aus dem dann zusammen mit dem Prompt ein neues Bild erzeugt wird. Je höher der Wert ist, desto stärker wird das Ergebnisbild verändert. Werte von 0,0 bis 1,0 sind möglich, der empfohlene Bereich ist .25-.75",
"boundingBox": "Der Begrenzungsrahmen ist derselbe wie die Einstellungen für Breite und Höhe bei Text zu Bild oder Bild zu Bild. Es wird nur der Bereich innerhalb des Rahmens verarbeitet.",
"seamCorrection": "Steuert die Behandlung von sichtbaren Übergängen, die zwischen den erzeugten Bildern auf der Leinwand auftreten.",
"infillAndScaling": "Verwalten Sie Infill-Methoden (für maskierte oder gelöschte Bereiche der Leinwand) und Skalierung (nützlich für kleine Begrenzungsrahmengrößen)."
}
},
"unifiedCanvas": {
"layer": "Ebene",
"base": "Basis",
"mask": "Maske",
"maskingOptions": "Maskierungsoptionen",
"enableMask": "Maske aktivieren",
"preserveMaskedArea": "Maskierten Bereich bewahren",
"clearMask": "Maske löschen",
"brush": "Pinsel",
"eraser": "Radierer",
"fillBoundingBox": "Begrenzungsrahmen füllen",
"eraseBoundingBox": "Begrenzungsrahmen löschen",
"colorPicker": "Farbpipette",
"brushOptions": "Pinseloptionen",
"brushSize": "Größe",
"move": "Bewegen",
"resetView": "Ansicht zurücksetzen",
"mergeVisible": "Sichtbare Zusammenführen",
"saveToGallery": "In Galerie speichern",
"copyToClipboard": "In Zwischenablage kopieren",
"downloadAsImage": "Als Bild herunterladen",
"undo": "Rückgängig",
"redo": "Wiederherstellen",
"clearCanvas": "Leinwand löschen",
"canvasSettings": "Leinwand-Einstellungen",
"showIntermediates": "Zwischenprodukte anzeigen",
"showGrid": "Gitternetz anzeigen",
"snapToGrid": "Am Gitternetz einrasten",
"darkenOutsideSelection": "Außerhalb der Auswahl verdunkeln",
"autoSaveToGallery": "Automatisch in Galerie speichern",
"saveBoxRegionOnly": "Nur Auswahlbox speichern",
"limitStrokesToBox": "Striche auf Box beschränken",
"showCanvasDebugInfo": "Zusätzliche Informationen zur Leinwand anzeigen",
"clearCanvasHistory": "Leinwand-Verlauf löschen",
"clearHistory": "Verlauf löschen",
"clearCanvasHistoryMessage": "Wenn Sie den Verlauf der Leinwand löschen, bleibt die aktuelle Leinwand intakt, aber der Verlauf der Rückgängig- und Wiederherstellung wird unwiderruflich gelöscht.",
"clearCanvasHistoryConfirm": "Sind Sie sicher, dass Sie den Verlauf der Leinwand löschen möchten?",
"emptyTempImageFolder": "Temp-Image Ordner leeren",
"emptyFolder": "Leerer Ordner",
"emptyTempImagesFolderMessage": "Wenn Sie den Ordner für temporäre Bilder leeren, wird auch der Unified Canvas vollständig zurückgesetzt. Dies umfasst den gesamten Verlauf der Rückgängig-/Wiederherstellungsvorgänge, die Bilder im Bereitstellungsbereich und die Leinwand-Basisebene.",
"emptyTempImagesFolderConfirm": "Sind Sie sicher, dass Sie den temporären Ordner leeren wollen?",
"activeLayer": "Aktive Ebene",
"canvasScale": "Leinwand Maßstab",
"boundingBox": "Begrenzungsrahmen",
"scaledBoundingBox": "Skalierter Begrenzungsrahmen",
"boundingBoxPosition": "Begrenzungsrahmen Position",
"canvasDimensions": "Maße der Leinwand",
"canvasPosition": "Leinwandposition",
"cursorPosition": "Position des Cursors",
"previous": "Vorherige",
"next": "Nächste",
"accept": "Akzeptieren",
"showHide": "Einblenden/Ausblenden",
"discardAll": "Alles verwerfen",
"betaClear": "Löschen",
"betaDarkenOutside": "Außen abdunkeln",
"betaLimitToBox": "Begrenzung auf das Feld",
"betaPreserveMasked": "Maskiertes bewahren",
"antialiasing": "Kantenglättung",
"showResultsOn": "Zeige Ergebnisse (An)",
"showResultsOff": "Zeige Ergebnisse (Aus)"
},
"accessibility": {
"modelSelect": "Model Auswahl",
"uploadImage": "Bild hochladen",
"previousImage": "Voriges Bild",
"useThisParameter": "Benutze diesen Parameter",
"copyMetadataJson": "Kopiere Metadaten JSON",
"zoomIn": "Vergrößern",
"rotateClockwise": "Im Uhrzeigersinn drehen",
"flipHorizontally": "Horizontal drehen",
"flipVertically": "Vertikal drehen",
"modifyConfig": "Optionen einstellen",
"toggleAutoscroll": "Auroscroll ein/ausschalten",
"toggleLogViewer": "Log Betrachter ein/ausschalten",
"showOptionsPanel": "Zeige Optionen",
"reset": "Zurücksetzten",
"nextImage": "Nächstes Bild",
"zoomOut": "Verkleinern",
"rotateCounterClockwise": "Gegen den Uhrzeigersinn verdrehen",
"showGalleryPanel": "Galeriefenster anzeigen",
"exitViewer": "Betrachten beenden",
"menu": "Menü",
"loadMore": "Mehr laden",
"invokeProgressBar": "Invoke Fortschrittsanzeige"
},
"boards": {
"autoAddBoard": "Automatisches Hinzufügen zum Ordner",
"topMessage": "Dieser Ordner enthält Bilder die in den folgenden Funktionen verwendet werden:",
"move": "Bewegen",
"menuItemAutoAdd": "Automatisches Hinzufügen zu diesem Ordner",
"myBoard": "Meine Ordner",
"searchBoard": "Ordner durchsuchen...",
"noMatching": "Keine passenden Ordner",
"selectBoard": "Ordner aussuchen",
"cancel": "Abbrechen",
"addBoard": "Ordner hinzufügen",
"uncategorized": "Nicht kategorisiert",
"downloadBoard": "Ordner runterladen",
"changeBoard": "Ordner wechseln",
"loading": "Laden...",
"clearSearch": "Suche leeren",
"bottomMessage": "Durch das Löschen dieses Ordners und seiner Bilder werden alle Funktionen zurückgesetzt, die sie derzeit verwenden."
},
"controlnet": {
"showAdvanced": "Zeige Erweitert",
"contentShuffleDescription": "Mischt den Inhalt von einem Bild",
"addT2IAdapter": "$t(common.t2iAdapter) hinzufügen",
"importImageFromCanvas": "Importieren Bild von Zeichenfläche",
"lineartDescription": "Konvertiere Bild zu Lineart",
"importMaskFromCanvas": "Importiere Maske von Zeichenfläche",
"hed": "HED",
"hideAdvanced": "Verstecke Erweitert",
"contentShuffle": "Inhalt mischen",
"controlNetEnabledT2IDisabled": "$t(common.controlNet) ist aktiv, $t(common.t2iAdapter) ist deaktiviert",
"ipAdapterModel": "Adapter Modell",
"beginEndStepPercent": "Start / Ende Step Prozent",
"duplicate": "Kopieren",
"f": "F",
"h": "H",
"depthMidasDescription": "Tiefenmap erstellen mit Midas",
"controlnet": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.controlNet))",
"t2iEnabledControlNetDisabled": "$t(common.t2iAdapter) ist aktiv, $t(common.controlNet) ist deaktiviert",
"weight": "Breite",
"selectModel": "Wähle ein Modell",
"depthMidas": "Tiefe (Midas)",
"w": "W",
"addControlNet": "$t(common.controlNet) hinzufügen",
"none": "Kein",
"incompatibleBaseModel": "Inkompatibles Basismodell:",
"enableControlnet": "Aktiviere ControlNet",
"detectResolution": "Auflösung erkennen",
"controlNetT2IMutexDesc": "$t(common.controlNet) und $t(common.t2iAdapter) zur gleichen Zeit wird nicht unterstützt.",
"ip_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.ipAdapter))",
"fill": "Füllen",
"addIPAdapter": "$t(common.ipAdapter) hinzufügen",
"colorMapDescription": "Erstelle eine Farbkarte von diesem Bild",
"t2i_adapter": "$t(controlnet.controlAdapter_one) #{{number}} ($t(common.t2iAdapter))",
"imageResolution": "Bild Auflösung",
"depthZoe": "Tiefe (Zoe)",
"colorMap": "Farbe",
"lowThreshold": "Niedrige Schwelle",
"highThreshold": "Hohe Schwelle",
"toggleControlNet": "Schalten ControlNet um",
"delete": "Löschen",
"controlAdapter_one": "Control Adapter",
"controlAdapter_other": "Control Adapters",
"colorMapTileSize": "Tile Größe",
"depthZoeDescription": "Tiefenmap erstellen mit Zoe",
"setControlImageDimensions": "Setze Control Bild Auflösung auf Breite/Höhe",
"handAndFace": "Hand und Gesicht",
"enableIPAdapter": "Aktiviere IP Adapter",
"resize": "Größe ändern",
"resetControlImage": "Zurücksetzen vom Referenz Bild",
"balanced": "Ausgewogen",
"prompt": "Prompt",
"resizeMode": "Größenänderungsmodus",
"processor": "Prozessor",
"saveControlImage": "Speichere Referenz Bild",
"safe": "Speichern",
"ipAdapterImageFallback": "Kein IP Adapter Bild ausgewählt",
"resetIPAdapterImage": "Zurücksetzen vom IP Adapter Bild",
"pidi": "PIDI",
"normalBae": "Normales BAE",
"mlsdDescription": "Minimalistischer Liniensegmentdetektor",
"openPoseDescription": "Schätzung der menschlichen Pose mit Openpose",
"control": "Kontrolle",
"coarse": "Coarse",
"crop": "Zuschneiden",
"pidiDescription": "PIDI-Bildverarbeitung",
"mediapipeFace": "Mediapipe Gesichter",
"mlsd": "M-LSD",
"controlMode": "Steuermodus",
"cannyDescription": "Canny Ecken Erkennung",
"lineart": "Lineart",
"lineartAnimeDescription": "Lineart-Verarbeitung im Anime-Stil",
"minConfidence": "Minimales Vertrauen",
"megaControl": "Mega-Kontrolle",
"autoConfigure": "Prozessor automatisch konfigurieren",
"normalBaeDescription": "Normale BAE-Verarbeitung",
"noneDescription": "Es wurde keine Verarbeitung angewendet",
"openPose": "Openpose",
"lineartAnime": "Lineart Anime",
"mediapipeFaceDescription": "Gesichtserkennung mit Mediapipe",
"canny": "Canny",
"hedDescription": "Ganzheitlich verschachtelte Kantenerkennung",
"scribble": "Scribble",
"maxFaces": "Maximal Anzahl Gesichter"
},
"queue": {
"status": "Status",
"cancelTooltip": "Aktuellen Aufgabe abbrechen",
"queueEmpty": "Warteschlange leer",
"in_progress": "In Arbeit",
"queueFront": "An den Anfang der Warteschlange tun",
"completed": "Fertig",
"queueBack": "In die Warteschlange",
"clearFailed": "Probleme beim leeren der Warteschlange",
"clearSucceeded": "Warteschlange geleert",
"pause": "Pause",
"cancelSucceeded": "Auftrag abgebrochen",
"queue": "Warteschlange",
"batch": "Stapel",
"pending": "Ausstehend",
"clear": "Leeren",
"prune": "Leeren",
"total": "Gesamt",
"canceled": "Abgebrochen",
"clearTooltip": "Abbrechen und alle Aufträge leeren",
"current": "Aktuell",
"failed": "Fehler",
"cancelItem": "Abbruch Auftrag",
"next": "Nächste",
"cancel": "Abbruch",
"session": "Sitzung",
"queueTotal": "{{total}} Gesamt",
"resume": "Wieder aufnehmen",
"item": "Auftrag",
"notReady": "Warteschlange noch nicht bereit",
"batchValues": "Stapel Werte",
"queueCountPrediction": "{{predicted}} zur Warteschlange hinzufügen",
"queuedCount": "{{pending}} wartenden Elemente",
"clearQueueAlertDialog": "Die Warteschlange leeren, stoppt den aktuellen Prozess und leert die Warteschlange komplett.",
"completedIn": "Fertig in",
"cancelBatchSucceeded": "Stapel abgebrochen",
"cancelBatch": "Stapel stoppen",
"enqueueing": "Stapel in der Warteschlange",
"queueMaxExceeded": "Maximum von {{max_queue_size}} Elementen erreicht, würde {{skip}} Elemente überspringen",
"cancelBatchFailed": "Problem beim Abbruch vom Stapel",
"clearQueueAlertDialog2": "bist du sicher die Warteschlange zu leeren?",
"pruneSucceeded": "{{item_count}} abgeschlossene Elemente aus der Warteschlange entfernt",
"pauseSucceeded": "Prozessor angehalten",
"cancelFailed": "Problem beim Stornieren des Auftrags",
"pauseFailed": "Problem beim Anhalten des Prozessors",
"front": "Vorne",
"pruneTooltip": "Bereinigen Sie {{item_count}} abgeschlossene Aufträge",
"resumeFailed": "Problem beim wieder aufnehmen von Prozessor",
"pruneFailed": "Problem beim leeren der Warteschlange",
"pauseTooltip": "Pause von Prozessor",
"back": "Hinten",
"resumeSucceeded": "Prozessor wieder aufgenommen",
"resumeTooltip": "Prozessor wieder aufnehmen"
},
"metadata": {
"negativePrompt": "Negativ Beschreibung",
"metadata": "Meta-Data",
"strength": "Bild zu Bild stärke",
"imageDetails": "Bild Details",
"model": "Modell",
"noImageDetails": "Keine Bild Details gefunden",
"cfgScale": "CFG-Skala",
"fit": "Bild zu Bild passen",
"height": "Höhe",
"noMetaData": "Keine Meta-Data gefunden",
"width": "Breite",
"createdBy": "Erstellt von",
"steps": "Schritte",
"seamless": "Nahtlos",
"positivePrompt": "Positiver Prompt",
"generationMode": "Generierungsmodus",
"Threshold": "Noise Schwelle",
"seed": "Samen",
"perlin": "Perlin Noise",
"hiresFix": "Optimierung für hohe Auflösungen",
"initImage": "Erstes Bild",
"variations": "Samengewichtspaare",
"vae": "VAE",
"workflow": "Arbeitsablauf",
"scheduler": "Scheduler",
"noRecallParameters": "Es wurden keine Parameter zum Abrufen gefunden"
},
"popovers": {
"noiseUseCPU": {
"heading": "Nutze Prozessor rauschen"
},
"paramModel": {
"heading": "Modell"
},
"paramIterations": {
"heading": "Iterationen"
},
"paramCFGScale": {
"heading": "CFG-Skala"
},
"paramSteps": {
"heading": "Schritte"
},
"lora": {
"heading": "LoRA Gewichte"
},
"infillMethod": {
"heading": "Füllmethode"
},
"paramVAE": {
"heading": "VAE"
}
},
"ui": {
"lockRatio": "Verhältnis sperren",
"hideProgressImages": "Verstecke Prozess Bild",
"showProgressImages": "Zeige Prozess Bild"
},
"invocationCache": {
"disable": "Deaktivieren",
"misses": "Cache Nötig",
"hits": "Cache Treffer",
"enable": "Aktivieren",
"clear": "Leeren",
"maxCacheSize": "Maximale Cache Größe",
"cacheSize": "Cache Größe"
},
"embedding": {
"noMatchingEmbedding": "Keine passenden Embeddings",
"addEmbedding": "Embedding hinzufügen",
"incompatibleModel": "Inkompatibles Basismodell:"
},
"nodes": {
"booleanPolymorphicDescription": "Eine Sammlung boolescher Werte.",
"colorFieldDescription": "Eine RGBA-Farbe.",
"conditioningCollection": "Konditionierungssammlung",
"addNode": "Knoten hinzufügen",
"conditioningCollectionDescription": "Konditionierung kann zwischen Knoten weitergegeben werden.",
"colorPolymorphic": "Farbpolymorph",
"colorCodeEdgesHelp": "Farbkodieren Sie Kanten entsprechend ihren verbundenen Feldern",
"animatedEdges": "Animierte Kanten",
"booleanCollectionDescription": "Eine Sammlung boolescher Werte.",
"colorField": "Farbe",
"collectionItem": "Objekt in Sammlung",
"animatedEdgesHelp": "Animieren Sie ausgewählte Kanten und Kanten, die mit ausgewählten Knoten verbunden sind",
"cannotDuplicateConnection": "Es können keine doppelten Verbindungen erstellt werden",
"booleanPolymorphic": "Boolesche Polymorphie",
"colorPolymorphicDescription": "Eine Sammlung von Farben.",
"clipFieldDescription": "Tokenizer- und text_encoder-Untermodelle.",
"clipField": "Clip",
"colorCollection": "Eine Sammlung von Farben.",
"boolean": "Boolesche Werte",
"currentImage": "Aktuelles Bild",
"booleanDescription": "Boolesche Werte sind wahr oder falsch.",
"collection": "Sammlung",
"cannotConnectInputToInput": "Eingang kann nicht mit Eingang verbunden werden",
"conditioningField": "Konditionierung",
"cannotConnectOutputToOutput": "Ausgang kann nicht mit Ausgang verbunden werden",
"booleanCollection": "Boolesche Werte Sammlung",
"cannotConnectToSelf": "Es kann keine Verbindung zu sich selbst hergestellt werden",
"colorCodeEdges": "Farbkodierte Kanten",
"addNodeToolTip": "Knoten hinzufügen (Umschalt+A, Leertaste)"
},
"hrf": {
"enableHrf": "Aktivieren Sie die Korrektur für hohe Auflösungen",
"upscaleMethod": "Vergrößerungsmethoden",
"enableHrfTooltip": "Generieren Sie mit einer niedrigeren Anfangsauflösung, skalieren Sie auf die Basisauflösung hoch und führen Sie dann Image-to-Image aus.",
"metadata": {
"strength": "Hochauflösender Fix Stärke",
"enabled": "Hochauflösender Fix aktiviert",
"method": "Hochauflösender Fix Methode"
},
"hrf": "Hochauflösender Fix",
"hrfStrength": "Hochauflösende Fix Stärke",
"strengthTooltip": "Niedrigere Werte führen zu weniger Details, wodurch potenzielle Artefakte reduziert werden können."
},
"models": {
"noMatchingModels": "Keine passenden Modelle",
"loading": "lade",
"noMatchingLoRAs": "Keine passenden LoRAs",
"noLoRAsAvailable": "Keine LoRAs verfügbar",
"noModelsAvailable": "Keine Modelle verfügbar",
"selectModel": "Wählen ein Modell aus",
"noRefinerModelsInstalled": "Keine SDXL Refiner-Modelle installiert",
"noLoRAsInstalled": "Keine LoRAs installiert",
"selectLoRA": "Wählen ein LoRA aus"
}
}

1558
invokeai/frontend/web/dist/locales/en.json vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,737 @@
{
"common": {
"hotkeysLabel": "Atajos de teclado",
"languagePickerLabel": "Selector de idioma",
"reportBugLabel": "Reportar errores",
"settingsLabel": "Ajustes",
"img2img": "Imagen a Imagen",
"unifiedCanvas": "Lienzo Unificado",
"nodes": "Editor del flujo de trabajo",
"langSpanish": "Español",
"nodesDesc": "Un sistema de generación de imágenes basado en nodos, actualmente se encuentra en desarrollo. Mantente pendiente a nuestras actualizaciones acerca de esta fabulosa funcionalidad.",
"postProcessing": "Post-procesamiento",
"postProcessDesc1": "Invoke AI ofrece una gran variedad de funciones de post-procesamiento, El aumento de tamaño y Restauración de Rostros ya se encuentran disponibles en la interfaz web, puedes acceder desde el menú de Opciones Avanzadas en las pestañas de Texto a Imagen y de Imagen a Imagen. También puedes acceder a estas funciones directamente mediante el botón de acciones en el menú superior de la imagen actual o en el visualizador.",
"postProcessDesc2": "Una interfaz de usuario dedicada se lanzará pronto para facilitar flujos de trabajo de postprocesamiento más avanzado.",
"postProcessDesc3": "La Interfaz de Línea de Comandos de Invoke AI ofrece muchas otras características, incluyendo -Embiggen-.",
"training": "Entrenamiento",
"trainingDesc1": "Un flujo de trabajo dedicado para el entrenamiento de sus propios -embeddings- y puntos de control utilizando Inversión Textual y Dreambooth desde la interfaz web.",
"trainingDesc2": "InvokeAI ya admite el entrenamiento de incrustaciones personalizadas mediante la inversión textual mediante el script principal.",
"upload": "Subir imagen",
"close": "Cerrar",
"load": "Cargar",
"statusConnected": "Conectado",
"statusDisconnected": "Desconectado",
"statusError": "Error",
"statusPreparing": "Preparando",
"statusProcessingCanceled": "Procesamiento Cancelado",
"statusProcessingComplete": "Procesamiento Completo",
"statusGenerating": "Generando",
"statusGeneratingTextToImage": "Generando Texto a Imagen",
"statusGeneratingImageToImage": "Generando Imagen a Imagen",
"statusGeneratingInpainting": "Generando pintura interior",
"statusGeneratingOutpainting": "Generando pintura exterior",
"statusGenerationComplete": "Generación Completa",
"statusIterationComplete": "Iteración Completa",
"statusSavingImage": "Guardando Imagen",
"statusRestoringFaces": "Restaurando Rostros",
"statusRestoringFacesGFPGAN": "Restaurando Rostros (GFPGAN)",
"statusRestoringFacesCodeFormer": "Restaurando Rostros (CodeFormer)",
"statusUpscaling": "Aumentando Tamaño",
"statusUpscalingESRGAN": "Restaurando Rostros(ESRGAN)",
"statusLoadingModel": "Cargando Modelo",
"statusModelChanged": "Modelo cambiado",
"statusMergedModels": "Modelos combinados",
"githubLabel": "Github",
"discordLabel": "Discord",
"langEnglish": "Inglés",
"langDutch": "Holandés",
"langFrench": "Francés",
"langGerman": "Alemán",
"langItalian": "Italiano",
"langArabic": "Árabe",
"langJapanese": "Japones",
"langPolish": "Polaco",
"langBrPortuguese": "Portugués brasileño",
"langRussian": "Ruso",
"langSimplifiedChinese": "Chino simplificado",
"langUkranian": "Ucraniano",
"back": "Atrás",
"statusConvertingModel": "Convertir el modelo",
"statusModelConverted": "Modelo adaptado",
"statusMergingModels": "Fusionar modelos",
"langPortuguese": "Portugués",
"langKorean": "Coreano",
"langHebrew": "Hebreo",
"loading": "Cargando",
"loadingInvokeAI": "Cargando invocar a la IA",
"postprocessing": "Tratamiento posterior",
"txt2img": "De texto a imagen",
"accept": "Aceptar",
"cancel": "Cancelar",
"linear": "Lineal",
"random": "Aleatorio",
"generate": "Generar",
"openInNewTab": "Abrir en una nueva pestaña",
"dontAskMeAgain": "No me preguntes de nuevo",
"areYouSure": "¿Estas seguro?",
"imagePrompt": "Indicación de imagen",
"batch": "Administrador de lotes",
"darkMode": "Modo oscuro",
"lightMode": "Modo claro",
"modelManager": "Administrador de modelos",
"communityLabel": "Comunidad"
},
"gallery": {
"generations": "Generaciones",
"showGenerations": "Mostrar Generaciones",
"uploads": "Subidas de archivos",
"showUploads": "Mostar Subidas",
"galleryImageSize": "Tamaño de la imagen",
"galleryImageResetSize": "Restablecer tamaño de la imagen",
"gallerySettings": "Ajustes de la galería",
"maintainAspectRatio": "Mantener relación de aspecto",
"autoSwitchNewImages": "Auto seleccionar Imágenes nuevas",
"singleColumnLayout": "Diseño de una columna",
"allImagesLoaded": "Todas las imágenes cargadas",
"loadMore": "Cargar más",
"noImagesInGallery": "No hay imágenes para mostrar",
"deleteImage": "Eliminar Imagen",
"deleteImageBin": "Las imágenes eliminadas se enviarán a la papelera de tu sistema operativo.",
"deleteImagePermanent": "Las imágenes eliminadas no se pueden restaurar.",
"images": "Imágenes",
"assets": "Activos",
"autoAssignBoardOnClick": "Asignación automática de tableros al hacer clic"
},
"hotkeys": {
"keyboardShortcuts": "Atajos de teclado",
"appHotkeys": "Atajos de applicación",
"generalHotkeys": "Atajos generales",
"galleryHotkeys": "Atajos de galería",
"unifiedCanvasHotkeys": "Atajos de lienzo unificado",
"invoke": {
"title": "Invocar",
"desc": "Generar una imagen"
},
"cancel": {
"title": "Cancelar",
"desc": "Cancelar el proceso de generación de imagen"
},
"focusPrompt": {
"title": "Mover foco a Entrada de texto",
"desc": "Mover foco hacia el campo de texto de la Entrada"
},
"toggleOptions": {
"title": "Alternar opciones",
"desc": "Mostar y ocultar el panel de opciones"
},
"pinOptions": {
"title": "Fijar opciones",
"desc": "Fijar el panel de opciones"
},
"toggleViewer": {
"title": "Alternar visor",
"desc": "Mostar y ocultar el visor de imágenes"
},
"toggleGallery": {
"title": "Alternar galería",
"desc": "Mostar y ocultar la galería de imágenes"
},
"maximizeWorkSpace": {
"title": "Maximizar espacio de trabajo",
"desc": "Cerrar otros páneles y maximizar el espacio de trabajo"
},
"changeTabs": {
"title": "Cambiar",
"desc": "Cambiar entre áreas de trabajo"
},
"consoleToggle": {
"title": "Alternar consola",
"desc": "Mostar y ocultar la consola"
},
"setPrompt": {
"title": "Establecer Entrada",
"desc": "Usar el texto de entrada de la imagen actual"
},
"setSeed": {
"title": "Establecer semilla",
"desc": "Usar la semilla de la imagen actual"
},
"setParameters": {
"title": "Establecer parámetros",
"desc": "Usar todos los parámetros de la imagen actual"
},
"restoreFaces": {
"title": "Restaurar rostros",
"desc": "Restaurar rostros en la imagen actual"
},
"upscale": {
"title": "Aumentar resolución",
"desc": "Aumentar la resolución de la imagen actual"
},
"showInfo": {
"title": "Mostrar información",
"desc": "Mostar metadatos de la imagen actual"
},
"sendToImageToImage": {
"title": "Enviar hacia Imagen a Imagen",
"desc": "Enviar imagen actual hacia Imagen a Imagen"
},
"deleteImage": {
"title": "Eliminar imagen",
"desc": "Eliminar imagen actual"
},
"closePanels": {
"title": "Cerrar páneles",
"desc": "Cerrar los páneles abiertos"
},
"previousImage": {
"title": "Imagen anterior",
"desc": "Muetra la imagen anterior en la galería"
},
"nextImage": {
"title": "Imagen siguiente",
"desc": "Muetra la imagen siguiente en la galería"
},
"toggleGalleryPin": {
"title": "Alternar fijado de galería",
"desc": "Fijar o desfijar la galería en la interfaz"
},
"increaseGalleryThumbSize": {
"title": "Aumentar imagen en galería",
"desc": "Aumenta el tamaño de las miniaturas de la galería"
},
"decreaseGalleryThumbSize": {
"title": "Reducir imagen en galería",
"desc": "Reduce el tamaño de las miniaturas de la galería"
},
"selectBrush": {
"title": "Seleccionar pincel",
"desc": "Selecciona el pincel en el lienzo"
},
"selectEraser": {
"title": "Seleccionar borrador",
"desc": "Selecciona el borrador en el lienzo"
},
"decreaseBrushSize": {
"title": "Disminuir tamaño de herramienta",
"desc": "Disminuye el tamaño del pincel/borrador en el lienzo"
},
"increaseBrushSize": {
"title": "Aumentar tamaño del pincel",
"desc": "Aumenta el tamaño del pincel en el lienzo"
},
"decreaseBrushOpacity": {
"title": "Disminuir opacidad del pincel",
"desc": "Disminuye la opacidad del pincel en el lienzo"
},
"increaseBrushOpacity": {
"title": "Aumentar opacidad del pincel",
"desc": "Aumenta la opacidad del pincel en el lienzo"
},
"moveTool": {
"title": "Herramienta de movimiento",
"desc": "Permite navegar por el lienzo"
},
"fillBoundingBox": {
"title": "Rellenar Caja contenedora",
"desc": "Rellena la caja contenedora con el color seleccionado"
},
"eraseBoundingBox": {
"title": "Borrar Caja contenedora",
"desc": "Borra el contenido dentro de la caja contenedora"
},
"colorPicker": {
"title": "Selector de color",
"desc": "Selecciona un color del lienzo"
},
"toggleSnap": {
"title": "Alternar ajuste de cuadrícula",
"desc": "Activa o desactiva el ajuste automático a la cuadrícula"
},
"quickToggleMove": {
"title": "Alternar movimiento rápido",
"desc": "Activa momentáneamente la herramienta de movimiento"
},
"toggleLayer": {
"title": "Alternar capa",
"desc": "Alterna entre las capas de máscara y base"
},
"clearMask": {
"title": "Limpiar máscara",
"desc": "Limpia toda la máscara actual"
},
"hideMask": {
"title": "Ocultar máscara",
"desc": "Oculta o muetre la máscara actual"
},
"showHideBoundingBox": {
"title": "Alternar caja contenedora",
"desc": "Muestra u oculta la caja contenedora"
},
"mergeVisible": {
"title": "Consolida capas visibles",
"desc": "Consolida todas las capas visibles en una sola"
},
"saveToGallery": {
"title": "Guardar en galería",
"desc": "Guardar la imagen actual del lienzo en la galería"
},
"copyToClipboard": {
"title": "Copiar al portapapeles",
"desc": "Copiar el lienzo actual al portapapeles"
},
"downloadImage": {
"title": "Descargar imagen",
"desc": "Descargar la imagen actual del lienzo"
},
"undoStroke": {
"title": "Deshar trazo",
"desc": "Desahacer el último trazo del pincel"
},
"redoStroke": {
"title": "Rehacer trazo",
"desc": "Rehacer el último trazo del pincel"
},
"resetView": {
"title": "Restablecer vista",
"desc": "Restablecer la vista del lienzo"
},
"previousStagingImage": {
"title": "Imagen anterior",
"desc": "Imagen anterior en el área de preparación"
},
"nextStagingImage": {
"title": "Imagen siguiente",
"desc": "Siguiente imagen en el área de preparación"
},
"acceptStagingImage": {
"title": "Aceptar imagen",
"desc": "Aceptar la imagen actual en el área de preparación"
},
"addNodes": {
"title": "Añadir Nodos",
"desc": "Abre el menú para añadir nodos"
},
"nodesHotkeys": "Teclas de acceso rápido a los nodos"
},
"modelManager": {
"modelManager": "Gestor de Modelos",
"model": "Modelo",
"modelAdded": "Modelo añadido",
"modelUpdated": "Modelo actualizado",
"modelEntryDeleted": "Endrada de Modelo eliminada",
"cannotUseSpaces": "No se pueden usar Spaces",
"addNew": "Añadir nuevo",
"addNewModel": "Añadir nuevo modelo",
"addManually": "Añadir manualmente",
"manual": "Manual",
"name": "Nombre",
"nameValidationMsg": "Introduce un nombre para tu modelo",
"description": "Descripción",
"descriptionValidationMsg": "Introduce una descripción para tu modelo",
"config": "Configurar",
"configValidationMsg": "Ruta del archivo de configuración del modelo.",
"modelLocation": "Ubicación del Modelo",
"modelLocationValidationMsg": "Ruta del archivo de modelo.",
"vaeLocation": "Ubicación VAE",
"vaeLocationValidationMsg": "Ruta del archivo VAE.",
"width": "Ancho",
"widthValidationMsg": "Ancho predeterminado de tu modelo.",
"height": "Alto",
"heightValidationMsg": "Alto predeterminado de tu modelo.",
"addModel": "Añadir Modelo",
"updateModel": "Actualizar Modelo",
"availableModels": "Modelos disponibles",
"search": "Búsqueda",
"load": "Cargar",
"active": "activo",
"notLoaded": "no cargado",
"cached": "en caché",
"checkpointFolder": "Directorio de Checkpoint",
"clearCheckpointFolder": "Limpiar directorio de checkpoint",
"findModels": "Buscar modelos",
"scanAgain": "Escanear de nuevo",
"modelsFound": "Modelos encontrados",
"selectFolder": "Selecciona un directorio",
"selected": "Seleccionado",
"selectAll": "Seleccionar todo",
"deselectAll": "Deseleccionar todo",
"showExisting": "Mostrar existentes",
"addSelected": "Añadir seleccionados",
"modelExists": "Modelo existente",
"selectAndAdd": "Selecciona de la lista un modelo para añadir",
"noModelsFound": "No se encontró ningún modelo",
"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.",
"safetensorModels": "SafeTensors",
"addDiffuserModel": "Añadir difusores",
"inpainting": "v1 Repintado",
"repoIDValidationMsg": "Repositorio en línea de tu modelo",
"checkpointModels": "Puntos de control",
"convertToDiffusersHelpText4": "Este proceso se realiza una sola vez. Puede tardar entre 30 y 60 segundos dependiendo de las especificaciones de tu ordenador.",
"diffusersModels": "Difusores",
"addCheckpointModel": "Agregar modelo de punto de control/Modelo Safetensor",
"vaeRepoID": "Identificador del repositorio de VAE",
"vaeRepoIDValidationMsg": "Repositorio en línea de tú VAE",
"formMessageDiffusersModelLocation": "Difusores Modelo Ubicación",
"formMessageDiffusersModelLocationDesc": "Por favor, introduzca al menos uno.",
"formMessageDiffusersVAELocation": "Ubicación VAE",
"formMessageDiffusersVAELocationDesc": "Si no se proporciona, InvokeAI buscará el archivo VAE dentro de la ubicación del modelo indicada anteriormente.",
"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?",
"convertToDiffusersSaveLocation": "Guardar ubicación",
"v1": "v1",
"statusConverting": "Adaptar",
"modelConverted": "Modelo adaptado",
"sameFolder": "La misma carpeta",
"invokeRoot": "Carpeta InvokeAI",
"custom": "Personalizado",
"customSaveLocation": "Ubicación personalizada para guardar",
"merge": "Fusión",
"modelsMerged": "Modelos fusionados",
"mergeModels": "Combinar modelos",
"modelOne": "Modelo 1",
"modelTwo": "Modelo 2",
"modelThree": "Modelo 3",
"mergedModelName": "Nombre del modelo combinado",
"alpha": "Alfa",
"interpolationType": "Tipo de interpolación",
"mergedModelSaveLocation": "Guardar ubicación",
"mergedModelCustomSaveLocation": "Ruta personalizada",
"invokeAIFolder": "Invocar carpeta de la inteligencia artificial",
"modelMergeHeaderHelp2": "Sólo se pueden fusionar difusores. Si desea fusionar un modelo de punto de control, conviértalo primero en difusores.",
"modelMergeAlphaHelp": "Alfa controla la fuerza de mezcla de los modelos. Los valores alfa más bajos reducen la influencia del segundo modelo.",
"modelMergeInterpAddDifferenceHelp": "En este modo, el Modelo 3 se sustrae primero del Modelo 2. La versión resultante se mezcla con el Modelo 1 con la tasa alfa establecida anteriormente. La versión resultante se mezcla con el Modelo 1 con la tasa alfa establecida anteriormente.",
"ignoreMismatch": "Ignorar discrepancias entre modelos seleccionados",
"modelMergeHeaderHelp1": "Puede unir hasta tres modelos diferentes para crear una combinación que se adapte a sus necesidades.",
"inverseSigmoid": "Sigmoideo inverso",
"weightedSum": "Modelo de suma ponderada",
"sigmoid": "Función sigmoide",
"allModels": "Todos los modelos",
"repo_id": "Identificador del repositorio",
"pathToCustomConfig": "Ruta a la configuración personalizada",
"customConfig": "Configuración personalizada",
"v2_base": "v2 (512px)",
"none": "ninguno",
"pickModelType": "Elige el tipo de modelo",
"v2_768": "v2 (768px)",
"addDifference": "Añadir una diferencia",
"scanForModels": "Buscar modelos",
"vae": "VAE",
"variant": "Variante",
"baseModel": "Modelo básico",
"modelConversionFailed": "Conversión al modelo fallida",
"selectModel": "Seleccionar un modelo",
"modelUpdateFailed": "Error al actualizar el modelo",
"modelsMergeFailed": "Fusión del modelo fallida",
"convertingModelBegin": "Convirtiendo el modelo. Por favor, espere.",
"modelDeleted": "Modelo eliminado",
"modelDeleteFailed": "Error al borrar el modelo",
"noCustomLocationProvided": "No se proporcionó una ubicación personalizada",
"importModels": "Importar los modelos",
"settings": "Ajustes",
"syncModels": "Sincronizar las plantillas",
"syncModelsDesc": "Si tus plantillas no están sincronizados con el backend, puedes actualizarlas usando esta opción. Esto suele ser útil en los casos en los que actualizas manualmente tu archivo models.yaml o añades plantillas a la carpeta raíz de InvokeAI después de que la aplicación haya arrancado.",
"modelsSynced": "Plantillas sincronizadas",
"modelSyncFailed": "La sincronización de la plantilla falló",
"loraModels": "LoRA",
"onnxModels": "Onnx",
"oliveModels": "Olives"
},
"parameters": {
"images": "Imágenes",
"steps": "Pasos",
"cfgScale": "Escala CFG",
"width": "Ancho",
"height": "Alto",
"seed": "Semilla",
"randomizeSeed": "Semilla aleatoria",
"shuffle": "Semilla aleatoria",
"noiseThreshold": "Umbral de Ruido",
"perlinNoise": "Ruido Perlin",
"variations": "Variaciones",
"variationAmount": "Cantidad de Variación",
"seedWeights": "Peso de las semillas",
"faceRestoration": "Restauración de Rostros",
"restoreFaces": "Restaurar rostros",
"type": "Tipo",
"strength": "Fuerza",
"upscaling": "Aumento de resolución",
"upscale": "Aumentar resolución",
"upscaleImage": "Aumentar la resolución de la imagen",
"scale": "Escala",
"otherOptions": "Otras opciones",
"seamlessTiling": "Mosaicos sin parches",
"hiresOptim": "Optimización de Alta Resolución",
"imageFit": "Ajuste tamaño de imagen inicial al tamaño objetivo",
"codeformerFidelity": "Fidelidad",
"scaleBeforeProcessing": "Redimensionar antes de procesar",
"scaledWidth": "Ancho escalado",
"scaledHeight": "Alto escalado",
"infillMethod": "Método de relleno",
"tileSize": "Tamaño del mosaico",
"boundingBoxHeader": "Caja contenedora",
"seamCorrectionHeader": "Corrección de parches",
"infillScalingHeader": "Remplazo y escalado",
"img2imgStrength": "Peso de Imagen a Imagen",
"toggleLoopback": "Alternar Retroalimentación",
"sendTo": "Enviar a",
"sendToImg2Img": "Enviar a Imagen a Imagen",
"sendToUnifiedCanvas": "Enviar a Lienzo Unificado",
"copyImageToLink": "Copiar imagen a enlace",
"downloadImage": "Descargar imagen",
"openInViewer": "Abrir en Visor",
"closeViewer": "Cerrar Visor",
"usePrompt": "Usar Entrada",
"useSeed": "Usar Semilla",
"useAll": "Usar Todo",
"useInitImg": "Usar Imagen Inicial",
"info": "Información",
"initialImage": "Imagen Inicial",
"showOptionsPanel": "Mostrar panel de opciones",
"symmetry": "Simetría",
"vSymmetryStep": "Paso de simetría V",
"hSymmetryStep": "Paso de simetría H",
"cancel": {
"immediate": "Cancelar inmediatamente",
"schedule": "Cancelar tras la iteración actual",
"isScheduled": "Cancelando",
"setType": "Tipo de cancelación"
},
"copyImage": "Copiar la imagen",
"general": "General",
"imageToImage": "Imagen a imagen",
"denoisingStrength": "Intensidad de la eliminación del ruido",
"hiresStrength": "Alta resistencia",
"showPreview": "Mostrar la vista previa",
"hidePreview": "Ocultar la vista previa",
"noiseSettings": "Ruido",
"seamlessXAxis": "Eje x",
"seamlessYAxis": "Eje y",
"scheduler": "Programador",
"boundingBoxWidth": "Anchura del recuadro",
"boundingBoxHeight": "Altura del recuadro",
"positivePromptPlaceholder": "Prompt Positivo",
"negativePromptPlaceholder": "Prompt Negativo",
"controlNetControlMode": "Modo de control",
"clipSkip": "Omitir el CLIP",
"aspectRatio": "Relación",
"maskAdjustmentsHeader": "Ajustes de la máscara",
"maskBlur": "Difuminar",
"maskBlurMethod": "Método del desenfoque",
"seamHighThreshold": "Alto",
"seamLowThreshold": "Bajo",
"coherencePassHeader": "Parámetros de la coherencia",
"compositingSettingsHeader": "Ajustes de la composición",
"coherenceSteps": "Pasos",
"coherenceStrength": "Fuerza",
"patchmatchDownScaleSize": "Reducir a escala",
"coherenceMode": "Modo"
},
"settings": {
"models": "Modelos",
"displayInProgress": "Mostrar las imágenes del progreso",
"saveSteps": "Guardar imágenes cada n pasos",
"confirmOnDelete": "Confirmar antes de eliminar",
"displayHelpIcons": "Mostrar iconos de ayuda",
"enableImageDebugging": "Habilitar depuración de imágenes",
"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.",
"useSlidersForAll": "Utilice controles deslizantes para todas las opciones",
"general": "General",
"consoleLogLevel": "Nivel del registro",
"shouldLogToConsole": "Registro de la consola",
"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",
"favoriteSchedulers": "Programadores favoritos",
"favoriteSchedulersPlaceholder": "No hay programadores favoritos",
"showAdvancedOptions": "Mostrar las opciones avanzadas",
"alternateCanvasLayout": "Diseño alternativo del lienzo",
"beta": "Beta",
"enableNodesEditor": "Activar el editor de nodos",
"experimental": "Experimental",
"autoChangeDimensions": "Actualiza W/H a los valores predeterminados del modelo cuando se modifica"
},
"toast": {
"tempFoldersEmptied": "Directorio temporal vaciado",
"uploadFailed": "Error al subir archivo",
"uploadFailedUnableToLoadDesc": "No se pudo cargar la imágen",
"downloadImageStarted": "Descargando imágen",
"imageCopied": "Imágen copiada",
"imageLinkCopied": "Enlace de imágen copiado",
"imageNotLoaded": "No se cargó la imágen",
"imageNotLoadedDesc": "No se pudo encontrar la imagen",
"imageSavedToGallery": "Imágen guardada en la galería",
"canvasMerged": "Lienzo consolidado",
"sentToImageToImage": "Enviar hacia Imagen a Imagen",
"sentToUnifiedCanvas": "Enviar hacia Lienzo Consolidado",
"parametersSet": "Parámetros establecidos",
"parametersNotSet": "Parámetros no establecidos",
"parametersNotSetDesc": "No se encontraron metadatos para esta imágen.",
"parametersFailed": "Error cargando parámetros",
"parametersFailedDesc": "No fue posible cargar la imagen inicial.",
"seedSet": "Semilla establecida",
"seedNotSet": "Semilla no establecida",
"seedNotSetDesc": "No se encontró una semilla para esta imágen.",
"promptSet": "Entrada establecida",
"promptNotSet": "Entrada no establecida",
"promptNotSetDesc": "No se encontró una entrada para esta imágen.",
"upscalingFailed": "Error al aumentar tamaño de imagn",
"faceRestoreFailed": "Restauración de rostro fallida",
"metadataLoadFailed": "Error al cargar metadatos",
"initialImageSet": "Imágen inicial establecida",
"initialImageNotSet": "Imagen inicial no establecida",
"initialImageNotSetDesc": "Error al establecer la imágen inicial",
"serverError": "Error en el servidor",
"disconnected": "Desconectado del servidor",
"canceled": "Procesando la cancelación",
"connected": "Conectado al servidor",
"problemCopyingImageLink": "No se puede copiar el enlace de la imagen",
"uploadFailedInvalidUploadDesc": "Debe ser una sola imagen PNG o JPEG",
"parameterSet": "Conjunto de parámetros",
"parameterNotSet": "Parámetro no configurado",
"nodesSaved": "Nodos guardados",
"nodesLoadedFailed": "Error al cargar los nodos",
"nodesLoaded": "Nodos cargados",
"nodesCleared": "Nodos borrados",
"problemCopyingImage": "No se puede copiar la imagen",
"nodesNotValidJSON": "JSON no válido",
"nodesCorruptedGraph": "No se puede cargar. El gráfico parece estar dañado.",
"nodesUnrecognizedTypes": "No se puede cargar. El gráfico tiene tipos no reconocidos",
"nodesNotValidGraph": "Gráfico del nodo InvokeAI no válido",
"nodesBrokenConnections": "No se puede cargar. Algunas conexiones están rotas."
},
"tooltip": {
"feature": {
"prompt": "Este campo tomará todo el texto de entrada, incluidos tanto los términos de contenido como los estilísticos. Si bien se pueden incluir pesos en la solicitud, los comandos/parámetros estándar de línea de comandos no funcionarán.",
"gallery": "Conforme se generan nuevas invocaciones, los archivos del directorio de salida se mostrarán aquí. Las generaciones tienen opciones adicionales para configurar nuevas generaciones.",
"other": "Estas opciones habilitarán modos de procesamiento alternativos para Invoke. 'Seamless mosaico' creará patrones repetitivos en la salida. 'Alta resolución' es la generación en dos pasos con img2img: use esta configuración cuando desee una imagen más grande y más coherente sin artefactos. tomar más tiempo de lo habitual txt2img.",
"seed": "Los valores de semilla proporcionan un conjunto inicial de ruido que guían el proceso de eliminación de ruido y se pueden aleatorizar o rellenar con una semilla de una invocación anterior. La función Umbral se puede usar para mitigar resultados indeseables a valores CFG más altos (intente entre 0-10), y Perlin se puede usar para agregar ruido Perlin al proceso de eliminación de ruido. Ambos sirven para agregar variación a sus salidas.",
"variations": "Pruebe una variación con una cantidad entre 0 y 1 para cambiar la imagen de salida para la semilla establecida. Se encuentran variaciones interesantes en la semilla entre 0.1 y 0.3.",
"upscale": "Usando ESRGAN, puede aumentar la resolución de salida sin requerir un ancho/alto más alto en la generación inicial.",
"faceCorrection": "Usando GFPGAN o Codeformer, la corrección de rostros intentará identificar rostros en las salidas y corregir cualquier defecto/anormalidad. Los valores de fuerza más altos aplicarán una presión correctiva más fuerte en las salidas, lo que resultará en rostros más atractivos. Con Codeformer, una mayor fidelidad intentará preservar la imagen original, a expensas de la fuerza de corrección de rostros.",
"imageToImage": "Imagen a Imagen permite cargar una imagen inicial, que InvokeAI usará para guiar el proceso de generación, junto con una solicitud. Un valor más bajo para esta configuración se parecerá más a la imagen original. Se aceptan valores entre 0-1, y se recomienda un rango de .25-.75",
"boundingBox": "La caja delimitadora es análoga a las configuraciones de Ancho y Alto para Texto a Imagen o Imagen a Imagen. Solo se procesará el área en la caja.",
"seamCorrection": "Controla el manejo de parches visibles que pueden ocurrir cuando se pega una imagen generada de nuevo en el lienzo.",
"infillAndScaling": "Administra los métodos de relleno (utilizados en áreas enmascaradas o borradas del lienzo) y la escala (útil para tamaños de caja delimitadora pequeños)."
}
},
"unifiedCanvas": {
"layer": "Capa",
"base": "Base",
"mask": "Máscara",
"maskingOptions": "Opciones de máscara",
"enableMask": "Habilitar Máscara",
"preserveMaskedArea": "Preservar área enmascarada",
"clearMask": "Limpiar máscara",
"brush": "Pincel",
"eraser": "Borrador",
"fillBoundingBox": "Rellenar Caja Contenedora",
"eraseBoundingBox": "Eliminar Caja Contenedora",
"colorPicker": "Selector de color",
"brushOptions": "Opciones de pincel",
"brushSize": "Tamaño",
"move": "Mover",
"resetView": "Restablecer vista",
"mergeVisible": "Consolidar vista",
"saveToGallery": "Guardar en galería",
"copyToClipboard": "Copiar al portapapeles",
"downloadAsImage": "Descargar como imagen",
"undo": "Deshacer",
"redo": "Rehacer",
"clearCanvas": "Limpiar lienzo",
"canvasSettings": "Ajustes de lienzo",
"showIntermediates": "Mostrar intermedios",
"showGrid": "Mostrar cuadrícula",
"snapToGrid": "Ajustar a cuadrícula",
"darkenOutsideSelection": "Oscurecer fuera de la selección",
"autoSaveToGallery": "Guardar automáticamente en galería",
"saveBoxRegionOnly": "Guardar solo región dentro de la caja",
"limitStrokesToBox": "Limitar trazos a la caja",
"showCanvasDebugInfo": "Mostrar la información adicional del lienzo",
"clearCanvasHistory": "Limpiar historial de lienzo",
"clearHistory": "Limpiar historial",
"clearCanvasHistoryMessage": "Limpiar el historial de lienzo también restablece completamente el lienzo unificado. Esto incluye todo el historial de deshacer/rehacer, las imágenes en el área de preparación y la capa base del lienzo.",
"clearCanvasHistoryConfirm": "¿Está seguro de que desea limpiar el historial del lienzo?",
"emptyTempImageFolder": "Vaciar directorio de imágenes temporales",
"emptyFolder": "Vaciar directorio",
"emptyTempImagesFolderMessage": "Vaciar el directorio de imágenes temporales también restablece completamente el lienzo unificado. Esto incluye todo el historial de deshacer/rehacer, las imágenes en el área de preparación y la capa base del lienzo.",
"emptyTempImagesFolderConfirm": "¿Está seguro de que desea vaciar el directorio temporal?",
"activeLayer": "Capa activa",
"canvasScale": "Escala de lienzo",
"boundingBox": "Caja contenedora",
"scaledBoundingBox": "Caja contenedora escalada",
"boundingBoxPosition": "Posición de caja contenedora",
"canvasDimensions": "Dimensiones de lienzo",
"canvasPosition": "Posición de lienzo",
"cursorPosition": "Posición del cursor",
"previous": "Anterior",
"next": "Siguiente",
"accept": "Aceptar",
"showHide": "Mostrar/Ocultar",
"discardAll": "Descartar todo",
"betaClear": "Limpiar",
"betaDarkenOutside": "Oscurecer fuera",
"betaLimitToBox": "Limitar a caja",
"betaPreserveMasked": "Preservar área enmascarada",
"antialiasing": "Suavizado"
},
"accessibility": {
"invokeProgressBar": "Activar la barra de progreso",
"modelSelect": "Seleccionar modelo",
"reset": "Reiniciar",
"uploadImage": "Cargar imagen",
"previousImage": "Imagen anterior",
"nextImage": "Siguiente imagen",
"useThisParameter": "Utiliza este parámetro",
"copyMetadataJson": "Copiar los metadatos JSON",
"exitViewer": "Salir del visor",
"zoomIn": "Acercar",
"zoomOut": "Alejar",
"rotateCounterClockwise": "Girar en sentido antihorario",
"rotateClockwise": "Girar en sentido horario",
"flipHorizontally": "Voltear horizontalmente",
"flipVertically": "Voltear verticalmente",
"modifyConfig": "Modificar la configuración",
"toggleAutoscroll": "Activar el autodesplazamiento",
"toggleLogViewer": "Alternar el visor de registros",
"showOptionsPanel": "Mostrar el panel lateral",
"menu": "Menú"
},
"ui": {
"hideProgressImages": "Ocultar el progreso de la imagen",
"showProgressImages": "Mostrar el progreso de la imagen",
"swapSizes": "Cambiar los tamaños",
"lockRatio": "Proporción del bloqueo"
},
"nodes": {
"showGraphNodes": "Mostrar la superposición de los gráficos",
"zoomInNodes": "Acercar",
"hideMinimapnodes": "Ocultar el minimapa",
"fitViewportNodes": "Ajustar la vista",
"zoomOutNodes": "Alejar",
"hideGraphNodes": "Ocultar la superposición de los gráficos",
"hideLegendNodes": "Ocultar la leyenda del tipo de campo",
"showLegendNodes": "Mostrar la leyenda del tipo de campo",
"showMinimapnodes": "Mostrar el minimapa",
"reloadNodeTemplates": "Recargar las plantillas de nodos",
"loadWorkflow": "Cargar el flujo de trabajo",
"resetWorkflow": "Reiniciar e flujo de trabajo",
"resetWorkflowDesc": "¿Está seguro de que deseas restablecer este flujo de trabajo?",
"resetWorkflowDesc2": "Al reiniciar el flujo de trabajo se borrarán todos los nodos, aristas y detalles del flujo de trabajo.",
"downloadWorkflow": "Descargar el flujo de trabajo en un archivo JSON"
}
}

View File

@@ -0,0 +1,114 @@
{
"accessibility": {
"reset": "Resetoi",
"useThisParameter": "Käytä tätä parametria",
"modelSelect": "Mallin Valinta",
"exitViewer": "Poistu katselimesta",
"uploadImage": "Lataa kuva",
"copyMetadataJson": "Kopioi metadata JSON:iin",
"invokeProgressBar": "Invoken edistymispalkki",
"nextImage": "Seuraava kuva",
"previousImage": "Edellinen kuva",
"zoomIn": "Lähennä",
"flipHorizontally": "Käännä vaakasuoraan",
"zoomOut": "Loitonna",
"rotateCounterClockwise": "Kierrä vastapäivään",
"rotateClockwise": "Kierrä myötäpäivään",
"flipVertically": "Käännä pystysuoraan",
"modifyConfig": "Muokkaa konfiguraatiota",
"toggleAutoscroll": "Kytke automaattinen vieritys",
"toggleLogViewer": "Kytke lokin katselutila",
"showOptionsPanel": "Näytä asetukset"
},
"common": {
"postProcessDesc2": "Erillinen käyttöliittymä tullaan julkaisemaan helpottaaksemme työnkulkua jälkikäsittelyssä.",
"training": "Kouluta",
"statusLoadingModel": "Ladataan mallia",
"statusModelChanged": "Malli vaihdettu",
"statusConvertingModel": "Muunnetaan mallia",
"statusModelConverted": "Malli muunnettu",
"langFrench": "Ranska",
"langItalian": "Italia",
"languagePickerLabel": "Kielen valinta",
"hotkeysLabel": "Pikanäppäimet",
"reportBugLabel": "Raportoi Bugista",
"langPolish": "Puola",
"langDutch": "Hollanti",
"settingsLabel": "Asetukset",
"githubLabel": "Github",
"langGerman": "Saksa",
"langPortuguese": "Portugali",
"discordLabel": "Discord",
"langEnglish": "Englanti",
"langRussian": "Venäjä",
"langUkranian": "Ukraina",
"langSpanish": "Espanja",
"upload": "Lataa",
"statusMergedModels": "Mallit yhdistelty",
"img2img": "Kuva kuvaksi",
"nodes": "Solmut",
"nodesDesc": "Solmupohjainen järjestelmä kuvien generoimiseen on parhaillaan kehitteillä. Pysy kuulolla päivityksistä tähän uskomattomaan ominaisuuteen liittyen.",
"postProcessDesc1": "Invoke AI tarjoaa monenlaisia jälkikäsittelyominaisuukisa. Kuvan laadun skaalaus sekä kasvojen korjaus ovat jo saatavilla WebUI:ssä. Voit ottaa ne käyttöön lisäasetusten valikosta teksti kuvaksi sekä kuva kuvaksi -välilehdiltä. Voit myös suoraan prosessoida kuvia käyttämällä kuvan toimintapainikkeita nykyisen kuvan yläpuolella tai tarkastelussa.",
"postprocessing": "Jälkikäsitellään",
"postProcessing": "Jälkikäsitellään",
"cancel": "Peruuta",
"close": "Sulje",
"accept": "Hyväksy",
"statusConnected": "Yhdistetty",
"statusError": "Virhe",
"statusProcessingComplete": "Prosessointi valmis",
"load": "Lataa",
"back": "Takaisin",
"statusGeneratingTextToImage": "Generoidaan tekstiä kuvaksi",
"trainingDesc2": "InvokeAI tukee jo mukautettujen upotusten kouluttamista tekstin inversiolla käyttäen pääskriptiä.",
"statusDisconnected": "Yhteys katkaistu",
"statusPreparing": "Valmistellaan",
"statusIterationComplete": "Iteraatio valmis",
"statusMergingModels": "Yhdistellään malleja",
"statusProcessingCanceled": "Valmistelu peruutettu",
"statusSavingImage": "Tallennetaan kuvaa",
"statusGeneratingImageToImage": "Generoidaan kuvaa kuvaksi",
"statusRestoringFacesGFPGAN": "Korjataan kasvoja (GFPGAN)",
"statusRestoringFacesCodeFormer": "Korjataan kasvoja (CodeFormer)",
"statusGeneratingInpainting": "Generoidaan sisällemaalausta",
"statusGeneratingOutpainting": "Generoidaan ulosmaalausta",
"statusRestoringFaces": "Korjataan kasvoja",
"loadingInvokeAI": "Ladataan Invoke AI:ta",
"loading": "Ladataan",
"statusGenerating": "Generoidaan",
"txt2img": "Teksti kuvaksi",
"trainingDesc1": "Erillinen työnkulku omien upotusten ja tarkastuspisteiden kouluttamiseksi käyttäen tekstin inversiota ja dreamboothia selaimen käyttöliittymässä.",
"postProcessDesc3": "Invoke AI:n komentorivi tarjoaa paljon muita ominaisuuksia, kuten esimerkiksi Embiggenin.",
"unifiedCanvas": "Yhdistetty kanvas",
"statusGenerationComplete": "Generointi valmis"
},
"gallery": {
"uploads": "Lataukset",
"showUploads": "Näytä lataukset",
"galleryImageResetSize": "Resetoi koko",
"maintainAspectRatio": "Säilytä kuvasuhde",
"galleryImageSize": "Kuvan koko",
"showGenerations": "Näytä generaatiot",
"singleColumnLayout": "Yhden sarakkeen asettelu",
"generations": "Generoinnit",
"gallerySettings": "Gallerian asetukset",
"autoSwitchNewImages": "Vaihda uusiin kuviin automaattisesti",
"allImagesLoaded": "Kaikki kuvat ladattu",
"noImagesInGallery": "Ei kuvia galleriassa",
"loadMore": "Lataa lisää"
},
"hotkeys": {
"keyboardShortcuts": "näppäimistön pikavalinnat",
"appHotkeys": "Sovelluksen pikanäppäimet",
"generalHotkeys": "Yleiset pikanäppäimet",
"galleryHotkeys": "Gallerian pikanäppäimet",
"unifiedCanvasHotkeys": "Yhdistetyn kanvaan pikanäppäimet",
"cancel": {
"desc": "Peruuta kuvan luominen",
"title": "Peruuta"
},
"invoke": {
"desc": "Luo kuva"
}
}
}

View File

@@ -0,0 +1,531 @@
{
"common": {
"hotkeysLabel": "Raccourcis clavier",
"languagePickerLabel": "Sélecteur de langue",
"reportBugLabel": "Signaler un bug",
"settingsLabel": "Paramètres",
"img2img": "Image en image",
"unifiedCanvas": "Canvas unifié",
"nodes": "Nœuds",
"langFrench": "Français",
"nodesDesc": "Un système basé sur les nœuds pour la génération d'images est actuellement en développement. Restez à l'écoute pour des mises à jour à ce sujet.",
"postProcessing": "Post-traitement",
"postProcessDesc1": "Invoke AI offre une grande variété de fonctionnalités de post-traitement. Le redimensionnement d'images et la restauration de visages sont déjà disponibles dans la WebUI. Vous pouvez y accéder à partir du menu 'Options avancées' des onglets 'Texte vers image' et 'Image vers image'. Vous pouvez également traiter les images directement en utilisant les boutons d'action d'image au-dessus de l'affichage d'image actuel ou dans le visualiseur.",
"postProcessDesc2": "Une interface dédiée sera bientôt disponible pour faciliter les workflows de post-traitement plus avancés.",
"postProcessDesc3": "L'interface en ligne de commande d'Invoke AI offre diverses autres fonctionnalités, notamment Embiggen.",
"training": "Formation",
"trainingDesc1": "Un workflow dédié pour former vos propres embeddings et checkpoints en utilisant Textual Inversion et Dreambooth depuis l'interface web.",
"trainingDesc2": "InvokeAI prend déjà en charge la formation d'embeddings personnalisés en utilisant Textual Inversion en utilisant le script principal.",
"upload": "Télécharger",
"close": "Fermer",
"load": "Charger",
"back": "Retour",
"statusConnected": "En ligne",
"statusDisconnected": "Hors ligne",
"statusError": "Erreur",
"statusPreparing": "Préparation",
"statusProcessingCanceled": "Traitement annulé",
"statusProcessingComplete": "Traitement terminé",
"statusGenerating": "Génération",
"statusGeneratingTextToImage": "Génération Texte vers Image",
"statusGeneratingImageToImage": "Génération Image vers Image",
"statusGeneratingInpainting": "Génération de réparation",
"statusGeneratingOutpainting": "Génération de complétion",
"statusGenerationComplete": "Génération terminée",
"statusIterationComplete": "Itération terminée",
"statusSavingImage": "Sauvegarde de l'image",
"statusRestoringFaces": "Restauration des visages",
"statusRestoringFacesGFPGAN": "Restauration des visages (GFPGAN)",
"statusRestoringFacesCodeFormer": "Restauration des visages (CodeFormer)",
"statusUpscaling": "Mise à échelle",
"statusUpscalingESRGAN": "Mise à échelle (ESRGAN)",
"statusLoadingModel": "Chargement du modèle",
"statusModelChanged": "Modèle changé",
"discordLabel": "Discord",
"githubLabel": "Github",
"accept": "Accepter",
"statusMergingModels": "Mélange des modèles",
"loadingInvokeAI": "Chargement de Invoke AI",
"cancel": "Annuler",
"langEnglish": "Anglais",
"statusConvertingModel": "Conversion du modèle",
"statusModelConverted": "Modèle converti",
"loading": "Chargement",
"statusMergedModels": "Modèles mélangés",
"txt2img": "Texte vers image",
"postprocessing": "Post-Traitement"
},
"gallery": {
"generations": "Générations",
"showGenerations": "Afficher les générations",
"uploads": "Téléchargements",
"showUploads": "Afficher les téléchargements",
"galleryImageSize": "Taille de l'image",
"galleryImageResetSize": "Réinitialiser la taille",
"gallerySettings": "Paramètres de la galerie",
"maintainAspectRatio": "Maintenir le rapport d'aspect",
"autoSwitchNewImages": "Basculer automatiquement vers de nouvelles images",
"singleColumnLayout": "Mise en page en colonne unique",
"allImagesLoaded": "Toutes les images chargées",
"loadMore": "Charger plus",
"noImagesInGallery": "Aucune image dans la galerie"
},
"hotkeys": {
"keyboardShortcuts": "Raccourcis clavier",
"appHotkeys": "Raccourcis de l'application",
"generalHotkeys": "Raccourcis généraux",
"galleryHotkeys": "Raccourcis de la galerie",
"unifiedCanvasHotkeys": "Raccourcis du canvas unifié",
"invoke": {
"title": "Invoquer",
"desc": "Générer une image"
},
"cancel": {
"title": "Annuler",
"desc": "Annuler la génération d'image"
},
"focusPrompt": {
"title": "Prompt de focus",
"desc": "Mettre en focus la zone de saisie de la commande"
},
"toggleOptions": {
"title": "Affichage des options",
"desc": "Afficher et masquer le panneau d'options"
},
"pinOptions": {
"title": "Epinglage des options",
"desc": "Epingler le panneau d'options"
},
"toggleViewer": {
"title": "Affichage de la visionneuse",
"desc": "Afficher et masquer la visionneuse d'image"
},
"toggleGallery": {
"title": "Affichage de la galerie",
"desc": "Afficher et masquer la galerie"
},
"maximizeWorkSpace": {
"title": "Maximiser la zone de travail",
"desc": "Fermer les panneaux et maximiser la zone de travail"
},
"changeTabs": {
"title": "Changer d'onglet",
"desc": "Passer à un autre espace de travail"
},
"consoleToggle": {
"title": "Affichage de la console",
"desc": "Afficher et masquer la console"
},
"setPrompt": {
"title": "Définir le prompt",
"desc": "Utiliser le prompt de l'image actuelle"
},
"setSeed": {
"title": "Définir la graine",
"desc": "Utiliser la graine de l'image actuelle"
},
"setParameters": {
"title": "Définir les paramètres",
"desc": "Utiliser tous les paramètres de l'image actuelle"
},
"restoreFaces": {
"title": "Restaurer les visages",
"desc": "Restaurer l'image actuelle"
},
"upscale": {
"title": "Agrandir",
"desc": "Agrandir l'image actuelle"
},
"showInfo": {
"title": "Afficher les informations",
"desc": "Afficher les informations de métadonnées de l'image actuelle"
},
"sendToImageToImage": {
"title": "Envoyer à l'image à l'image",
"desc": "Envoyer l'image actuelle à l'image à l'image"
},
"deleteImage": {
"title": "Supprimer l'image",
"desc": "Supprimer l'image actuelle"
},
"closePanels": {
"title": "Fermer les panneaux",
"desc": "Fermer les panneaux ouverts"
},
"previousImage": {
"title": "Image précédente",
"desc": "Afficher l'image précédente dans la galerie"
},
"nextImage": {
"title": "Image suivante",
"desc": "Afficher l'image suivante dans la galerie"
},
"toggleGalleryPin": {
"title": "Activer/désactiver l'épinglage de la galerie",
"desc": "Épingle ou dépingle la galerie à l'interface"
},
"increaseGalleryThumbSize": {
"title": "Augmenter la taille des miniatures de la galerie",
"desc": "Augmente la taille des miniatures de la galerie"
},
"decreaseGalleryThumbSize": {
"title": "Diminuer la taille des miniatures de la galerie",
"desc": "Diminue la taille des miniatures de la galerie"
},
"selectBrush": {
"title": "Sélectionner un pinceau",
"desc": "Sélectionne le pinceau de la toile"
},
"selectEraser": {
"title": "Sélectionner un gomme",
"desc": "Sélectionne la gomme de la toile"
},
"decreaseBrushSize": {
"title": "Diminuer la taille du pinceau",
"desc": "Diminue la taille du pinceau/gomme de la toile"
},
"increaseBrushSize": {
"title": "Augmenter la taille du pinceau",
"desc": "Augmente la taille du pinceau/gomme de la toile"
},
"decreaseBrushOpacity": {
"title": "Diminuer l'opacité du pinceau",
"desc": "Diminue l'opacité du pinceau de la toile"
},
"increaseBrushOpacity": {
"title": "Augmenter l'opacité du pinceau",
"desc": "Augmente l'opacité du pinceau de la toile"
},
"moveTool": {
"title": "Outil de déplacement",
"desc": "Permet la navigation sur la toile"
},
"fillBoundingBox": {
"title": "Remplir la boîte englobante",
"desc": "Remplit la boîte englobante avec la couleur du pinceau"
},
"eraseBoundingBox": {
"title": "Effacer la boîte englobante",
"desc": "Efface la zone de la boîte englobante"
},
"colorPicker": {
"title": "Sélectionnez le sélecteur de couleur",
"desc": "Sélectionne le sélecteur de couleur de la toile"
},
"toggleSnap": {
"title": "Basculer Snap",
"desc": "Basculer Snap à la grille"
},
"quickToggleMove": {
"title": "Basculer rapidement déplacer",
"desc": "Basculer temporairement le mode Déplacer"
},
"toggleLayer": {
"title": "Basculer la couche",
"desc": "Basculer la sélection de la couche masque/base"
},
"clearMask": {
"title": "Effacer le masque",
"desc": "Effacer entièrement le masque"
},
"hideMask": {
"title": "Masquer le masque",
"desc": "Masquer et démasquer le masque"
},
"showHideBoundingBox": {
"title": "Afficher/Masquer la boîte englobante",
"desc": "Basculer la visibilité de la boîte englobante"
},
"mergeVisible": {
"title": "Fusionner visible",
"desc": "Fusionner toutes les couches visibles de la toile"
},
"saveToGallery": {
"title": "Enregistrer dans la galerie",
"desc": "Enregistrer la toile actuelle dans la galerie"
},
"copyToClipboard": {
"title": "Copier dans le presse-papiers",
"desc": "Copier la toile actuelle dans le presse-papiers"
},
"downloadImage": {
"title": "Télécharger l'image",
"desc": "Télécharger la toile actuelle"
},
"undoStroke": {
"title": "Annuler le trait",
"desc": "Annuler un coup de pinceau"
},
"redoStroke": {
"title": "Rétablir le trait",
"desc": "Rétablir un coup de pinceau"
},
"resetView": {
"title": "Réinitialiser la vue",
"desc": "Réinitialiser la vue de la toile"
},
"previousStagingImage": {
"title": "Image de mise en scène précédente",
"desc": "Image précédente de la zone de mise en scène"
},
"nextStagingImage": {
"title": "Image de mise en scène suivante",
"desc": "Image suivante de la zone de mise en scène"
},
"acceptStagingImage": {
"title": "Accepter l'image de mise en scène",
"desc": "Accepter l'image actuelle de la zone de mise en scène"
}
},
"modelManager": {
"modelManager": "Gestionnaire de modèle",
"model": "Modèle",
"allModels": "Tous les modèles",
"checkpointModels": "Points de contrôle",
"diffusersModels": "Diffuseurs",
"safetensorModels": "SafeTensors",
"modelAdded": "Modèle ajouté",
"modelUpdated": "Modèle mis à jour",
"modelEntryDeleted": "Entrée de modèle supprimée",
"cannotUseSpaces": "Ne peut pas utiliser d'espaces",
"addNew": "Ajouter un nouveau",
"addNewModel": "Ajouter un nouveau modèle",
"addCheckpointModel": "Ajouter un modèle de point de contrôle / SafeTensor",
"addDiffuserModel": "Ajouter des diffuseurs",
"addManually": "Ajouter manuellement",
"manual": "Manuel",
"name": "Nom",
"nameValidationMsg": "Entrez un nom pour votre modèle",
"description": "Description",
"descriptionValidationMsg": "Ajoutez une description pour votre modèle",
"config": "Config",
"configValidationMsg": "Chemin vers le fichier de configuration de votre modèle.",
"modelLocation": "Emplacement du modèle",
"modelLocationValidationMsg": "Chemin vers où votre modèle est situé localement.",
"repo_id": "ID de dépôt",
"repoIDValidationMsg": "Dépôt en ligne de votre modèle",
"vaeLocation": "Emplacement VAE",
"vaeLocationValidationMsg": "Chemin vers où votre VAE est situé.",
"vaeRepoID": "ID de dépôt VAE",
"vaeRepoIDValidationMsg": "Dépôt en ligne de votre VAE",
"width": "Largeur",
"widthValidationMsg": "Largeur par défaut de votre modèle.",
"height": "Hauteur",
"heightValidationMsg": "Hauteur par défaut de votre modèle.",
"addModel": "Ajouter un modèle",
"updateModel": "Mettre à jour le modèle",
"availableModels": "Modèles disponibles",
"search": "Rechercher",
"load": "Charger",
"active": "actif",
"notLoaded": "non chargé",
"cached": "en cache",
"checkpointFolder": "Dossier de point de contrôle",
"clearCheckpointFolder": "Effacer le dossier de point de contrôle",
"findModels": "Trouver des modèles",
"scanAgain": "Scanner à nouveau",
"modelsFound": "Modèles trouvés",
"selectFolder": "Sélectionner un dossier",
"selected": "Sélectionné",
"selectAll": "Tout sélectionner",
"deselectAll": "Tout désélectionner",
"showExisting": "Afficher existant",
"addSelected": "Ajouter sélectionné",
"modelExists": "Modèle existant",
"selectAndAdd": "Sélectionner et ajouter les modèles listés ci-dessous",
"noModelsFound": "Aucun modèle trouvé",
"delete": "Supprimer",
"deleteModel": "Supprimer le modèle",
"deleteConfig": "Supprimer la configuration",
"deleteMsg1": "Voulez-vous vraiment supprimer cette entrée de modèle dans InvokeAI ?",
"deleteMsg2": "Cela n'effacera pas le fichier de point de contrôle du modèle de votre disque. Vous pouvez les réajouter si vous le souhaitez.",
"formMessageDiffusersModelLocation": "Emplacement du modèle de diffuseurs",
"formMessageDiffusersModelLocationDesc": "Veuillez en entrer au moins un.",
"formMessageDiffusersVAELocation": "Emplacement VAE",
"formMessageDiffusersVAELocationDesc": "Si non fourni, InvokeAI recherchera le fichier VAE à l'emplacement du modèle donné ci-dessus."
},
"parameters": {
"images": "Images",
"steps": "Etapes",
"cfgScale": "CFG Echelle",
"width": "Largeur",
"height": "Hauteur",
"seed": "Graine",
"randomizeSeed": "Graine Aléatoire",
"shuffle": "Mélanger",
"noiseThreshold": "Seuil de Bruit",
"perlinNoise": "Bruit de Perlin",
"variations": "Variations",
"variationAmount": "Montant de Variation",
"seedWeights": "Poids des Graines",
"faceRestoration": "Restauration de Visage",
"restoreFaces": "Restaurer les Visages",
"type": "Type",
"strength": "Force",
"upscaling": "Agrandissement",
"upscale": "Agrandir",
"upscaleImage": "Image en Agrandissement",
"scale": "Echelle",
"otherOptions": "Autres Options",
"seamlessTiling": "Carreau Sans Joint",
"hiresOptim": "Optimisation Haute Résolution",
"imageFit": "Ajuster Image Initiale à la Taille de Sortie",
"codeformerFidelity": "Fidélité",
"scaleBeforeProcessing": "Echelle Avant Traitement",
"scaledWidth": "Larg. Échelle",
"scaledHeight": "Haut. Échelle",
"infillMethod": "Méthode de Remplissage",
"tileSize": "Taille des Tuiles",
"boundingBoxHeader": "Boîte Englobante",
"seamCorrectionHeader": "Correction des Joints",
"infillScalingHeader": "Remplissage et Mise à l'Échelle",
"img2imgStrength": "Force de l'Image à l'Image",
"toggleLoopback": "Activer/Désactiver la Boucle",
"sendTo": "Envoyer à",
"sendToImg2Img": "Envoyer à Image à Image",
"sendToUnifiedCanvas": "Envoyer au Canvas Unifié",
"copyImage": "Copier Image",
"copyImageToLink": "Copier l'Image en Lien",
"downloadImage": "Télécharger Image",
"openInViewer": "Ouvrir dans le visualiseur",
"closeViewer": "Fermer le visualiseur",
"usePrompt": "Utiliser la suggestion",
"useSeed": "Utiliser la graine",
"useAll": "Tout utiliser",
"useInitImg": "Utiliser l'image initiale",
"info": "Info",
"initialImage": "Image initiale",
"showOptionsPanel": "Afficher le panneau d'options"
},
"settings": {
"models": "Modèles",
"displayInProgress": "Afficher les images en cours",
"saveSteps": "Enregistrer les images tous les n étapes",
"confirmOnDelete": "Confirmer la suppression",
"displayHelpIcons": "Afficher les icônes d'aide",
"enableImageDebugging": "Activer le débogage d'image",
"resetWebUI": "Réinitialiser l'interface Web",
"resetWebUIDesc1": "Réinitialiser l'interface Web ne réinitialise que le cache local du navigateur de vos images et de vos paramètres enregistrés. Cela n'efface pas les images du disque.",
"resetWebUIDesc2": "Si les images ne s'affichent pas dans la galerie ou si quelque chose d'autre ne fonctionne pas, veuillez essayer de réinitialiser avant de soumettre une demande sur GitHub.",
"resetComplete": "L'interface Web a été réinitialisée. Rafraîchissez la page pour recharger."
},
"toast": {
"tempFoldersEmptied": "Dossiers temporaires vidés",
"uploadFailed": "Téléchargement échoué",
"uploadFailedUnableToLoadDesc": "Impossible de charger le fichier",
"downloadImageStarted": "Téléchargement de l'image démarré",
"imageCopied": "Image copiée",
"imageLinkCopied": "Lien d'image copié",
"imageNotLoaded": "Aucune image chargée",
"imageNotLoadedDesc": "Aucune image trouvée pour envoyer à module d'image",
"imageSavedToGallery": "Image enregistrée dans la galerie",
"canvasMerged": "Canvas fusionné",
"sentToImageToImage": "Envoyé à Image à Image",
"sentToUnifiedCanvas": "Envoyé à Canvas unifié",
"parametersSet": "Paramètres définis",
"parametersNotSet": "Paramètres non définis",
"parametersNotSetDesc": "Aucune métadonnée trouvée pour cette image.",
"parametersFailed": "Problème de chargement des paramètres",
"parametersFailedDesc": "Impossible de charger l'image d'initiation.",
"seedSet": "Graine définie",
"seedNotSet": "Graine non définie",
"seedNotSetDesc": "Impossible de trouver la graine pour cette image.",
"promptSet": "Invite définie",
"promptNotSet": "Invite non définie",
"promptNotSetDesc": "Impossible de trouver l'invite pour cette image.",
"upscalingFailed": "Échec de la mise à l'échelle",
"faceRestoreFailed": "Échec de la restauration du visage",
"metadataLoadFailed": "Échec du chargement des métadonnées",
"initialImageSet": "Image initiale définie",
"initialImageNotSet": "Image initiale non définie",
"initialImageNotSetDesc": "Impossible de charger l'image initiale"
},
"tooltip": {
"feature": {
"prompt": "Ceci est le champ prompt. Le prompt inclut des objets de génération et des termes stylistiques. Vous pouvez également ajouter un poids (importance du jeton) dans le prompt, mais les commandes CLI et les paramètres ne fonctionneront pas.",
"gallery": "La galerie affiche les générations à partir du dossier de sortie à mesure qu'elles sont créées. Les paramètres sont stockés dans des fichiers et accessibles via le menu contextuel.",
"other": "Ces options activent des modes de traitement alternatifs pour Invoke. 'Tuilage seamless' créera des motifs répétitifs dans la sortie. 'Haute résolution' est la génération en deux étapes avec img2img : utilisez ce paramètre lorsque vous souhaitez une image plus grande et plus cohérente sans artefacts. Cela prendra plus de temps que d'habitude txt2img.",
"seed": "La valeur de grain affecte le bruit initial à partir duquel l'image est formée. Vous pouvez utiliser les graines déjà existantes provenant d'images précédentes. 'Seuil de bruit' est utilisé pour atténuer les artefacts à des valeurs CFG élevées (essayez la plage de 0 à 10), et Perlin pour ajouter du bruit Perlin pendant la génération : les deux servent à ajouter de la variété à vos sorties.",
"variations": "Essayez une variation avec une valeur comprise entre 0,1 et 1,0 pour changer le résultat pour une graine donnée. Des variations intéressantes de la graine sont entre 0,1 et 0,3.",
"upscale": "Utilisez ESRGAN pour agrandir l'image immédiatement après la génération.",
"faceCorrection": "Correction de visage avec GFPGAN ou Codeformer : l'algorithme détecte les visages dans l'image et corrige tout défaut. La valeur élevée changera plus l'image, ce qui donnera des visages plus attirants. Codeformer avec une fidélité plus élevée préserve l'image originale au prix d'une correction de visage plus forte.",
"imageToImage": "Image to Image charge n'importe quelle image en tant qu'initiale, qui est ensuite utilisée pour générer une nouvelle avec le prompt. Plus la valeur est élevée, plus l'image de résultat changera. Des valeurs de 0,0 à 1,0 sont possibles, la plage recommandée est de 0,25 à 0,75",
"boundingBox": "La boîte englobante est la même que les paramètres Largeur et Hauteur pour Texte à Image ou Image à Image. Seulement la zone dans la boîte sera traitée.",
"seamCorrection": "Contrôle la gestion des coutures visibles qui se produisent entre les images générées sur la toile.",
"infillAndScaling": "Gérer les méthodes de remplissage (utilisées sur les zones masquées ou effacées de la toile) et le redimensionnement (utile pour les petites tailles de boîte englobante)."
}
},
"unifiedCanvas": {
"layer": "Couche",
"base": "Base",
"mask": "Masque",
"maskingOptions": "Options de masquage",
"enableMask": "Activer le masque",
"preserveMaskedArea": "Préserver la zone masquée",
"clearMask": "Effacer le masque",
"brush": "Pinceau",
"eraser": "Gomme",
"fillBoundingBox": "Remplir la boîte englobante",
"eraseBoundingBox": "Effacer la boîte englobante",
"colorPicker": "Sélecteur de couleur",
"brushOptions": "Options de pinceau",
"brushSize": "Taille",
"move": "Déplacer",
"resetView": "Réinitialiser la vue",
"mergeVisible": "Fusionner les visibles",
"saveToGallery": "Enregistrer dans la galerie",
"copyToClipboard": "Copier dans le presse-papiers",
"downloadAsImage": "Télécharger en tant qu'image",
"undo": "Annuler",
"redo": "Refaire",
"clearCanvas": "Effacer le canvas",
"canvasSettings": "Paramètres du canvas",
"showIntermediates": "Afficher les intermédiaires",
"showGrid": "Afficher la grille",
"snapToGrid": "Aligner sur la grille",
"darkenOutsideSelection": "Assombrir à l'extérieur de la sélection",
"autoSaveToGallery": "Enregistrement automatique dans la galerie",
"saveBoxRegionOnly": "Enregistrer uniquement la région de la boîte",
"limitStrokesToBox": "Limiter les traits à la boîte",
"showCanvasDebugInfo": "Afficher les informations de débogage du canvas",
"clearCanvasHistory": "Effacer l'historique du canvas",
"clearHistory": "Effacer l'historique",
"clearCanvasHistoryMessage": "Effacer l'historique du canvas laisse votre canvas actuel intact, mais efface de manière irréversible l'historique annuler et refaire.",
"clearCanvasHistoryConfirm": "Voulez-vous vraiment effacer l'historique du canvas ?",
"emptyTempImageFolder": "Vider le dossier d'images temporaires",
"emptyFolder": "Vider le dossier",
"emptyTempImagesFolderMessage": "Vider le dossier d'images temporaires réinitialise également complètement le canvas unifié. Cela inclut tout l'historique annuler/refaire, les images dans la zone de mise en attente et la couche de base du canvas.",
"emptyTempImagesFolderConfirm": "Voulez-vous vraiment vider le dossier temporaire ?",
"activeLayer": "Calque actif",
"canvasScale": "Échelle du canevas",
"boundingBox": "Boîte englobante",
"scaledBoundingBox": "Boîte englobante mise à l'échelle",
"boundingBoxPosition": "Position de la boîte englobante",
"canvasDimensions": "Dimensions du canevas",
"canvasPosition": "Position du canevas",
"cursorPosition": "Position du curseur",
"previous": "Précédent",
"next": "Suivant",
"accept": "Accepter",
"showHide": "Afficher/Masquer",
"discardAll": "Tout abandonner",
"betaClear": "Effacer",
"betaDarkenOutside": "Assombrir à l'extérieur",
"betaLimitToBox": "Limiter à la boîte",
"betaPreserveMasked": "Conserver masqué"
},
"accessibility": {
"uploadImage": "Charger une image",
"reset": "Réinitialiser",
"nextImage": "Image suivante",
"previousImage": "Image précédente",
"useThisParameter": "Utiliser ce paramètre",
"zoomIn": "Zoom avant",
"zoomOut": "Zoom arrière",
"showOptionsPanel": "Montrer la page d'options",
"modelSelect": "Choix du modèle",
"invokeProgressBar": "Barre de Progression Invoke",
"copyMetadataJson": "Copie des métadonnées JSON",
"menu": "Menu"
}
}

View File

@@ -0,0 +1,575 @@
{
"modelManager": {
"cannotUseSpaces": "לא ניתן להשתמש ברווחים",
"addNew": "הוסף חדש",
"vaeLocationValidationMsg": "נתיב למקום שבו ממוקם ה- VAE שלך.",
"height": "גובה",
"load": "טען",
"search": "חיפוש",
"heightValidationMsg": "גובה ברירת המחדל של המודל שלך.",
"addNewModel": "הוסף מודל חדש",
"allModels": "כל המודלים",
"checkpointModels": "נקודות ביקורת",
"diffusersModels": "מפזרים",
"safetensorModels": "טנסורים בטוחים",
"modelAdded": "מודל התווסף",
"modelUpdated": "מודל עודכן",
"modelEntryDeleted": "רשומת המודל נמחקה",
"addCheckpointModel": "הוסף נקודת ביקורת / מודל טנסור בטוח",
"addDiffuserModel": "הוסף מפזרים",
"addManually": "הוספה ידנית",
"manual": "ידני",
"name": "שם",
"description": "תיאור",
"descriptionValidationMsg": "הוסף תיאור למודל שלך",
"config": "תצורה",
"configValidationMsg": "נתיב לקובץ התצורה של המודל שלך.",
"modelLocation": "מיקום המודל",
"modelLocationValidationMsg": "נתיב למקום שבו המודל שלך ממוקם באופן מקומי.",
"repo_id": "מזהה מאגר",
"repoIDValidationMsg": "מאגר מקוון של המודל שלך",
"vaeLocation": "מיקום VAE",
"vaeRepoIDValidationMsg": "המאגר המקוון של VAE שלך",
"width": "רוחב",
"widthValidationMsg": "רוחב ברירת המחדל של המודל שלך.",
"addModel": "הוסף מודל",
"updateModel": "עדכן מודל",
"active": "פעיל",
"modelsFound": "מודלים נמצאו",
"cached": "נשמר במטמון",
"checkpointFolder": "תיקיית נקודות ביקורת",
"findModels": "מצא מודלים",
"scanAgain": "סרוק מחדש",
"selectFolder": "בחירת תיקייה",
"selected": "נבחר",
"selectAll": "בחר הכל",
"deselectAll": "ביטול בחירת הכל",
"showExisting": "הצג קיים",
"addSelected": "הוסף פריטים שנבחרו",
"modelExists": "המודל קיים",
"selectAndAdd": "בחר והוסך מודלים המפורטים להלן",
"deleteModel": "מחיקת מודל",
"deleteConfig": "מחיקת תצורה",
"formMessageDiffusersModelLocation": "מיקום מפזרי המודל",
"formMessageDiffusersModelLocationDesc": "נא להזין לפחות אחד.",
"convertToDiffusersHelpText5": "אנא ודא/י שיש לך מספיק מקום בדיסק. גדלי מודלים בדרך כלל הינם בין 4GB-7GB.",
"convertToDiffusersHelpText1": "מודל זה יומר לפורמט 🧨 המפזרים.",
"convertToDiffusersHelpText2": "תהליך זה יחליף את הרשומה של מנהל המודלים שלך בגרסת המפזרים של אותו המודל.",
"convertToDiffusersHelpText6": "האם ברצונך להמיר מודל זה?",
"convertToDiffusersSaveLocation": "שמירת מיקום",
"inpainting": "v1 צביעת תוך",
"statusConverting": "ממיר",
"modelConverted": "מודל הומר",
"sameFolder": "אותה תיקיה",
"custom": "התאמה אישית",
"merge": "מזג",
"modelsMerged": "מודלים מוזגו",
"mergeModels": "מזג מודלים",
"modelOne": "מודל 1",
"customSaveLocation": "מיקום שמירה מותאם אישית",
"alpha": "אלפא",
"mergedModelSaveLocation": "שמירת מיקום",
"mergedModelCustomSaveLocation": "נתיב מותאם אישית",
"ignoreMismatch": "התעלמות מאי-התאמות בין מודלים שנבחרו",
"modelMergeHeaderHelp1": "ניתן למזג עד שלושה מודלים שונים כדי ליצור שילוב שמתאים לצרכים שלכם.",
"modelMergeAlphaHelp": "אלפא שולט בחוזק מיזוג עבור המודלים. ערכי אלפא נמוכים יותר מובילים להשפעה נמוכה יותר של המודל השני.",
"nameValidationMsg": "הכנס שם למודל שלך",
"vaeRepoID": "מזהה מאגר ה VAE",
"modelManager": "מנהל המודלים",
"model": "מודל",
"availableModels": "מודלים זמינים",
"notLoaded": "לא נטען",
"clearCheckpointFolder": "נקה את תיקיית נקודות הביקורת",
"noModelsFound": "לא נמצאו מודלים",
"delete": "מחיקה",
"deleteMsg1": "האם אתה בטוח שברצונך למחוק רשומת מודל זו מ- InvokeAI?",
"deleteMsg2": "פעולה זו לא תמחק את קובץ נקודת הביקורת מהדיסק שלך. ניתן לקרוא אותם מחדש במידת הצורך.",
"formMessageDiffusersVAELocation": "מיקום VAE",
"formMessageDiffusersVAELocationDesc": "במידה ולא מסופק, InvokeAI תחפש את קובץ ה-VAE במיקום המודל המופיע לעיל.",
"convertToDiffusers": "המרה למפזרים",
"convert": "המרה",
"modelTwo": "מודל 2",
"modelThree": "מודל 3",
"mergedModelName": "שם מודל ממוזג",
"v1": "v1",
"invokeRoot": "תיקיית InvokeAI",
"customConfig": "תצורה מותאמת אישית",
"pathToCustomConfig": "נתיב לתצורה מותאמת אישית",
"interpolationType": "סוג אינטרפולציה",
"invokeAIFolder": "תיקיית InvokeAI",
"sigmoid": "סיגמואיד",
"weightedSum": "סכום משוקלל",
"modelMergeHeaderHelp2": "רק מפזרים זמינים למיזוג. אם ברצונך למזג מודל של נקודת ביקורת, המר אותו תחילה למפזרים.",
"inverseSigmoid": "הפוך סיגמואיד",
"convertToDiffusersHelpText3": "קובץ נקודת הביקורת שלך בדיסק לא יימחק או ישונה בכל מקרה. אתה יכול להוסיף את נקודת הביקורת שלך למנהל המודלים שוב אם תרצה בכך.",
"convertToDiffusersHelpText4": "זהו תהליך חד פעמי בלבד. התהליך עשוי לקחת בסביבות 30-60 שניות, תלוי במפרט המחשב שלך.",
"modelMergeInterpAddDifferenceHelp": "במצב זה, מודל 3 מופחת תחילה ממודל 2. הגרסה המתקבלת משולבת עם מודל 1 עם קצב האלפא שנקבע לעיל."
},
"common": {
"nodesDesc": "מערכת מבוססת צמתים עבור יצירת תמונות עדיין תחת פיתוח. השארו קשובים לעדכונים עבור הפיצ׳ר המדהים הזה.",
"languagePickerLabel": "בחירת שפה",
"githubLabel": "גיטהאב",
"discordLabel": "דיסקורד",
"settingsLabel": "הגדרות",
"langEnglish": "אנגלית",
"langDutch": "הולנדית",
"langArabic": "ערבית",
"langFrench": "צרפתית",
"langGerman": "גרמנית",
"langJapanese": "יפנית",
"langBrPortuguese": "פורטוגזית",
"langRussian": "רוסית",
"langSimplifiedChinese": "סינית",
"langUkranian": "אוקראינית",
"langSpanish": "ספרדית",
"img2img": "תמונה לתמונה",
"unifiedCanvas": "קנבס מאוחד",
"nodes": "צמתים",
"postProcessing": "לאחר עיבוד",
"postProcessDesc2": "תצוגה ייעודית תשוחרר בקרוב על מנת לתמוך בתהליכים ועיבודים מורכבים.",
"postProcessDesc3": "ממשק שורת הפקודה של Invoke AI מציע תכונות שונות אחרות כולל Embiggen.",
"close": "סגירה",
"statusConnected": "מחובר",
"statusDisconnected": "מנותק",
"statusError": "שגיאה",
"statusPreparing": "בהכנה",
"statusProcessingCanceled": "עיבוד בוטל",
"statusProcessingComplete": "עיבוד הסתיים",
"statusGenerating": "מייצר",
"statusGeneratingTextToImage": "מייצר טקסט לתמונה",
"statusGeneratingImageToImage": "מייצר תמונה לתמונה",
"statusGeneratingInpainting": "מייצר ציור לתוך",
"statusGeneratingOutpainting": "מייצר ציור החוצה",
"statusIterationComplete": "איטרציה הסתיימה",
"statusRestoringFaces": "משחזר פרצופים",
"statusRestoringFacesCodeFormer": "משחזר פרצופים (CodeFormer)",
"statusUpscaling": "העלאת קנה מידה",
"statusUpscalingESRGAN": "העלאת קנה מידה (ESRGAN)",
"statusModelChanged": "מודל השתנה",
"statusConvertingModel": "ממיר מודל",
"statusModelConverted": "מודל הומר",
"statusMergingModels": "מיזוג מודלים",
"statusMergedModels": "מודלים מוזגו",
"hotkeysLabel": "מקשים חמים",
"reportBugLabel": "דווח באג",
"langItalian": "איטלקית",
"upload": "העלאה",
"langPolish": "פולנית",
"training": "אימון",
"load": "טעינה",
"back": "אחורה",
"statusSavingImage": "שומר תמונה",
"statusGenerationComplete": "ייצור הסתיים",
"statusRestoringFacesGFPGAN": "משחזר פרצופים (GFPGAN)",
"statusLoadingModel": "טוען מודל",
"trainingDesc2": "InvokeAI כבר תומך באימון הטמעות מותאמות אישית באמצעות היפוך טקסט באמצעות הסקריפט הראשי.",
"postProcessDesc1": "InvokeAI מציעה מגוון רחב של תכונות עיבוד שלאחר. העלאת קנה מידה של תמונה ושחזור פנים כבר זמינים בממשק המשתמש. ניתן לגשת אליהם מתפריט 'אפשרויות מתקדמות' בכרטיסיות 'טקסט לתמונה' ו'תמונה לתמונה'. ניתן גם לעבד תמונות ישירות, באמצעות לחצני הפעולה של התמונה מעל תצוגת התמונה הנוכחית או בתוך המציג.",
"trainingDesc1": "תהליך עבודה ייעודי לאימון ההטמעות ונקודות הביקורת שלך באמצעות היפוך טקסט ו-Dreambooth מממשק המשתמש."
},
"hotkeys": {
"toggleGallery": {
"desc": "פתח וסגור את מגירת הגלריה",
"title": "הצג את הגלריה"
},
"keyboardShortcuts": "קיצורי מקלדת",
"appHotkeys": "קיצורי אפליקציה",
"generalHotkeys": "קיצורי דרך כלליים",
"galleryHotkeys": "קיצורי דרך של הגלריה",
"unifiedCanvasHotkeys": "קיצורי דרך לקנבס המאוחד",
"invoke": {
"title": "הפעל",
"desc": "צור תמונה"
},
"focusPrompt": {
"title": "התמקדות על הבקשה",
"desc": "התמקדות על איזור הקלדת הבקשה"
},
"toggleOptions": {
"desc": "פתח וסגור את פאנל ההגדרות",
"title": "הצג הגדרות"
},
"pinOptions": {
"title": "הצמד הגדרות",
"desc": "הצמד את פאנל ההגדרות"
},
"toggleViewer": {
"title": "הצג את חלון ההצגה",
"desc": "פתח וסגור את מציג התמונות"
},
"changeTabs": {
"title": "החלף לשוניות",
"desc": "החלף לאיזור עבודה אחר"
},
"consoleToggle": {
"desc": "פתח וסגור את הקונסול",
"title": "הצג קונסול"
},
"setPrompt": {
"title": "הגדרת בקשה",
"desc": "שימוש בבקשה של התמונה הנוכחית"
},
"restoreFaces": {
"desc": "שחזור התמונה הנוכחית",
"title": "שחזור פרצופים"
},
"upscale": {
"title": "הגדלת קנה מידה",
"desc": "הגדל את התמונה הנוכחית"
},
"showInfo": {
"title": "הצג מידע",
"desc": "הצגת פרטי מטא-נתונים של התמונה הנוכחית"
},
"sendToImageToImage": {
"title": "שלח לתמונה לתמונה",
"desc": "שלח תמונה נוכחית לתמונה לתמונה"
},
"deleteImage": {
"title": "מחק תמונה",
"desc": "מחק את התמונה הנוכחית"
},
"closePanels": {
"title": "סגור לוחות",
"desc": "סוגר לוחות פתוחים"
},
"previousImage": {
"title": "תמונה קודמת",
"desc": "הצג את התמונה הקודמת בגלריה"
},
"toggleGalleryPin": {
"title": "הצג את מצמיד הגלריה",
"desc": "הצמדה וביטול הצמדה של הגלריה לממשק המשתמש"
},
"decreaseGalleryThumbSize": {
"title": "הקטנת גודל תמונת גלריה",
"desc": "מקטין את גודל התמונות הממוזערות של הגלריה"
},
"selectBrush": {
"desc": "בוחר את מברשת הקנבס",
"title": "בחר מברשת"
},
"selectEraser": {
"title": "בחר מחק",
"desc": "בוחר את מחק הקנבס"
},
"decreaseBrushSize": {
"title": "הקטנת גודל המברשת",
"desc": "מקטין את גודל מברשת הקנבס/מחק"
},
"increaseBrushSize": {
"desc": "מגדיל את גודל מברשת הקנבס/מחק",
"title": "הגדלת גודל המברשת"
},
"decreaseBrushOpacity": {
"title": "הפחת את אטימות המברשת",
"desc": "מקטין את האטימות של מברשת הקנבס"
},
"increaseBrushOpacity": {
"title": "הגדל את אטימות המברשת",
"desc": "מגביר את האטימות של מברשת הקנבס"
},
"moveTool": {
"title": "כלי הזזה",
"desc": "מאפשר ניווט על קנבס"
},
"fillBoundingBox": {
"desc": "ממלא את התיבה התוחמת בצבע מברשת",
"title": "מילוי תיבה תוחמת"
},
"eraseBoundingBox": {
"desc": "מוחק את אזור התיבה התוחמת",
"title": "מחק תיבה תוחמת"
},
"colorPicker": {
"title": "בחר בבורר צבעים",
"desc": "בוחר את בורר צבעי הקנבס"
},
"toggleSnap": {
"title": "הפעל הצמדה",
"desc": "מפעיל הצמדה לרשת"
},
"quickToggleMove": {
"title": "הפעלה מהירה להזזה",
"desc": "מפעיל זמנית את מצב ההזזה"
},
"toggleLayer": {
"title": "הפעל שכבה",
"desc": "הפעל בחירת שכבת בסיס/מסיכה"
},
"clearMask": {
"title": "נקה מסיכה",
"desc": "נקה את כל המסכה"
},
"hideMask": {
"desc": "הסתרה והצגה של מסיכה",
"title": "הסתר מסיכה"
},
"showHideBoundingBox": {
"title": "הצגה/הסתרה של תיבה תוחמת",
"desc": "הפעל תצוגה של התיבה התוחמת"
},
"mergeVisible": {
"title": "מיזוג תוכן גלוי",
"desc": "מיזוג כל השכבות הגלויות של הקנבס"
},
"saveToGallery": {
"title": "שמור לגלריה",
"desc": "שמור את הקנבס הנוכחי בגלריה"
},
"copyToClipboard": {
"title": "העתק ללוח ההדבקה",
"desc": "העתק את הקנבס הנוכחי ללוח ההדבקה"
},
"downloadImage": {
"title": "הורד תמונה",
"desc": "הורד את הקנבס הנוכחי"
},
"undoStroke": {
"title": "בטל משיכה",
"desc": "בטל משיכת מברשת"
},
"redoStroke": {
"title": "בצע שוב משיכה",
"desc": "ביצוע מחדש של משיכת מברשת"
},
"resetView": {
"title": "איפוס תצוגה",
"desc": "אפס תצוגת קנבס"
},
"previousStagingImage": {
"desc": "תמונת אזור ההערכות הקודמת",
"title": "תמונת הערכות קודמת"
},
"nextStagingImage": {
"title": "תמנות הערכות הבאה",
"desc": "תמונת אזור ההערכות הבאה"
},
"acceptStagingImage": {
"desc": "אשר את תמונת איזור ההערכות הנוכחית",
"title": "אשר תמונת הערכות"
},
"cancel": {
"desc": "ביטול יצירת תמונה",
"title": "ביטול"
},
"maximizeWorkSpace": {
"title": "מקסם את איזור העבודה",
"desc": "סגור פאנלים ומקסם את איזור העבודה"
},
"setSeed": {
"title": "הגדר זרע",
"desc": "השתמש בזרע התמונה הנוכחית"
},
"setParameters": {
"title": "הגדרת פרמטרים",
"desc": "שימוש בכל הפרמטרים של התמונה הנוכחית"
},
"increaseGalleryThumbSize": {
"title": "הגדל את גודל תמונת הגלריה",
"desc": "מגדיל את התמונות הממוזערות של הגלריה"
},
"nextImage": {
"title": "תמונה הבאה",
"desc": "הצג את התמונה הבאה בגלריה"
}
},
"gallery": {
"uploads": "העלאות",
"galleryImageSize": "גודל תמונה",
"gallerySettings": "הגדרות גלריה",
"maintainAspectRatio": "שמור על יחס רוחב-גובה",
"autoSwitchNewImages": "החלף אוטומטית לתמונות חדשות",
"singleColumnLayout": "תצוגת עמודה אחת",
"allImagesLoaded": "כל התמונות נטענו",
"loadMore": "טען עוד",
"noImagesInGallery": "אין תמונות בגלריה",
"galleryImageResetSize": "איפוס גודל",
"generations": "דורות",
"showGenerations": "הצג דורות",
"showUploads": "הצג העלאות"
},
"parameters": {
"images": "תמונות",
"steps": "צעדים",
"cfgScale": "סולם CFG",
"width": "רוחב",
"height": "גובה",
"seed": "זרע",
"imageToImage": "תמונה לתמונה",
"randomizeSeed": "זרע אקראי",
"variationAmount": "כמות וריאציה",
"seedWeights": "משקלי זרע",
"faceRestoration": "שחזור פנים",
"restoreFaces": "שחזר פנים",
"type": "סוג",
"strength": "חוזק",
"upscale": "הגדלת קנה מידה",
"upscaleImage": "הגדלת קנה מידת התמונה",
"denoisingStrength": "חוזק מנטרל הרעש",
"otherOptions": "אפשרויות אחרות",
"hiresOptim": "אופטימיזצית רזולוציה גבוהה",
"hiresStrength": "חוזק רזולוציה גבוהה",
"codeformerFidelity": "דבקות",
"scaleBeforeProcessing": "שנה קנה מידה לפני עיבוד",
"scaledWidth": "קנה מידה לאחר שינוי W",
"scaledHeight": "קנה מידה לאחר שינוי H",
"infillMethod": "שיטת מילוי",
"tileSize": "גודל אריח",
"boundingBoxHeader": "תיבה תוחמת",
"seamCorrectionHeader": "תיקון תפר",
"infillScalingHeader": "מילוי וקנה מידה",
"toggleLoopback": "הפעל לולאה חוזרת",
"symmetry": "סימטריה",
"vSymmetryStep": "צעד סימטריה V",
"hSymmetryStep": "צעד סימטריה H",
"cancel": {
"schedule": "ביטול לאחר האיטרציה הנוכחית",
"isScheduled": "מבטל",
"immediate": "ביטול מיידי",
"setType": "הגדר סוג ביטול"
},
"sendTo": "שליחה אל",
"copyImage": "העתקת תמונה",
"downloadImage": "הורדת תמונה",
"sendToImg2Img": "שליחה לתמונה לתמונה",
"sendToUnifiedCanvas": "שליחה אל קנבס מאוחד",
"openInViewer": "פתח במציג",
"closeViewer": "סגור מציג",
"usePrompt": "שימוש בבקשה",
"useSeed": "שימוש בזרע",
"useAll": "שימוש בהכל",
"useInitImg": "שימוש בתמונה ראשונית",
"info": "פרטים",
"showOptionsPanel": "הצג חלונית אפשרויות",
"shuffle": "ערבוב",
"noiseThreshold": "סף רעש",
"perlinNoise": "רעש פרלין",
"variations": "וריאציות",
"imageFit": "התאמת תמונה ראשונית לגודל הפלט",
"general": "כללי",
"upscaling": "מגדיל את קנה מידה",
"scale": "סולם",
"seamlessTiling": "ריצוף חלק",
"img2imgStrength": "חוזק תמונה לתמונה",
"initialImage": "תמונה ראשונית",
"copyImageToLink": "העתקת תמונה לקישור"
},
"settings": {
"models": "מודלים",
"displayInProgress": "הצגת תמונות בתהליך",
"confirmOnDelete": "אישור בעת המחיקה",
"useSlidersForAll": "שימוש במחוונים לכל האפשרויות",
"resetWebUI": "איפוס ממשק משתמש",
"resetWebUIDesc1": "איפוס ממשק המשתמש האינטרנטי מאפס רק את המטמון המקומי של הדפדפן של התמונות וההגדרות שנשמרו. זה לא מוחק תמונות מהדיסק.",
"resetComplete": "ממשק המשתמש אופס. יש לבצע רענון דף בכדי לטעון אותו מחדש.",
"enableImageDebugging": "הפעלת איתור באגים בתמונה",
"displayHelpIcons": "הצג סמלי עזרה",
"saveSteps": "שמירת תמונות כל n צעדים",
"resetWebUIDesc2": "אם תמונות לא מופיעות בגלריה או שמשהו אחר לא עובד, נא לנסות איפוס /או אתחול לפני שליחת תקלה ב-GitHub."
},
"toast": {
"uploadFailed": "העלאה נכשלה",
"imageCopied": "התמונה הועתקה",
"imageLinkCopied": "קישור תמונה הועתק",
"imageNotLoadedDesc": "לא נמצאה תמונה לשליחה למודול תמונה לתמונה",
"imageSavedToGallery": "התמונה נשמרה בגלריה",
"canvasMerged": "קנבס מוזג",
"sentToImageToImage": "נשלח לתמונה לתמונה",
"sentToUnifiedCanvas": "נשלח אל קנבס מאוחד",
"parametersSet": "הגדרת פרמטרים",
"parametersNotSet": "פרמטרים לא הוגדרו",
"parametersNotSetDesc": "לא נמצאו מטא-נתונים עבור תמונה זו.",
"parametersFailedDesc": "לא ניתן לטעון תמונת התחלה.",
"seedSet": "זרע הוגדר",
"seedNotSetDesc": "לא ניתן היה למצוא זרע לתמונה זו.",
"promptNotSetDesc": "לא היתה אפשרות למצוא בקשה עבור תמונה זו.",
"metadataLoadFailed": "טעינת מטא-נתונים נכשלה",
"initialImageSet": "סט תמונה ראשוני",
"initialImageNotSet": "התמונה הראשונית לא הוגדרה",
"initialImageNotSetDesc": "לא ניתן היה לטעון את התמונה הראשונית",
"uploadFailedUnableToLoadDesc": "לא ניתן לטעון את הקובץ",
"tempFoldersEmptied": "התיקייה הזמנית רוקנה",
"downloadImageStarted": "הורדת התמונה החלה",
"imageNotLoaded": "לא נטענה תמונה",
"parametersFailed": "בעיה בטעינת פרמטרים",
"promptNotSet": "בקשה לא הוגדרה",
"upscalingFailed": "העלאת קנה המידה נכשלה",
"faceRestoreFailed": "שחזור הפנים נכשל",
"seedNotSet": "זרע לא הוגדר",
"promptSet": "בקשה הוגדרה"
},
"tooltip": {
"feature": {
"gallery": "הגלריה מציגה יצירות מתיקיית הפלטים בעת יצירתם. ההגדרות מאוחסנות בתוך קבצים ונגישות באמצעות תפריט הקשר.",
"upscale": "השתמש ב-ESRGAN כדי להגדיל את התמונה מיד לאחר היצירה.",
"imageToImage": "תמונה לתמונה טוענת כל תמונה כראשונית, המשמשת לאחר מכן ליצירת תמונה חדשה יחד עם הבקשה. ככל שהערך גבוה יותר, כך תמונת התוצאה תשתנה יותר. ערכים מ- 0.0 עד 1.0 אפשריים, הטווח המומלץ הוא .25-.75",
"seamCorrection": "שליטה בטיפול בתפרים גלויים המתרחשים בין תמונות שנוצרו על בד הציור.",
"prompt": "זהו שדה הבקשה. הבקשה כוללת אובייקטי יצירה ומונחים סגנוניים. באפשרותך להוסיף משקל (חשיבות אסימון) גם בשורת הפקודה, אך פקודות ופרמטרים של CLI לא יפעלו.",
"variations": "נסה וריאציה עם ערך בין 0.1 ל- 1.0 כדי לשנות את התוצאה עבור זרע נתון. וריאציות מעניינות של הזרע הן בין 0.1 ל -0.3.",
"other": "אפשרויות אלה יאפשרו מצבי עיבוד חלופיים עבור ההרצה. 'ריצוף חלק' ייצור תבניות חוזרות בפלט. 'רזולוציה גבוהה' נוצר בשני שלבים עם img2img: השתמש בהגדרה זו כאשר אתה רוצה תמונה גדולה וקוהרנטית יותר ללא חפצים. פעולה זאת תקח יותר זמן מפעולת טקסט לתמונה רגילה.",
"faceCorrection": "תיקון פנים עם GFPGAN או Codeformer: האלגוריתם מזהה פרצופים בתמונה ומתקן כל פגם. ערך גבוה ישנה את התמונה יותר, וכתוצאה מכך הפרצופים יהיו אטרקטיביים יותר. Codeformer עם נאמנות גבוהה יותר משמר את התמונה המקורית על חשבון תיקון פנים חזק יותר.",
"seed": "ערך הזרע משפיע על הרעש הראשוני שממנו נוצרת התמונה. אתה יכול להשתמש בזרעים שכבר קיימים מתמונות קודמות. 'סף רעש' משמש להפחתת חפצים בערכי CFG גבוהים (נסה את טווח 0-10), ופרלין כדי להוסיף רעשי פרלין במהלך היצירה: שניהם משמשים להוספת וריאציה לתפוקות שלך.",
"infillAndScaling": "נהל שיטות מילוי (המשמשות באזורים עם מסיכה או אזורים שנמחקו בבד הציור) ושינוי קנה מידה (שימושי לגדלים קטנים של תיבות תוחמות).",
"boundingBox": "התיבה התוחמת זהה להגדרות 'רוחב' ו'גובה' עבור 'טקסט לתמונה' או 'תמונה לתמונה'. רק האזור בתיבה יעובד."
}
},
"unifiedCanvas": {
"layer": "שכבה",
"base": "בסיס",
"maskingOptions": "אפשרויות מסכות",
"enableMask": "הפעלת מסיכה",
"colorPicker": "בוחר הצבעים",
"preserveMaskedArea": "שימור איזור ממוסך",
"clearMask": "ניקוי מסיכה",
"brush": "מברשת",
"eraser": "מחק",
"fillBoundingBox": "מילוי תיבה תוחמת",
"eraseBoundingBox": "מחק תיבה תוחמת",
"copyToClipboard": "העתק ללוח ההדבקה",
"downloadAsImage": "הורדה כתמונה",
"undo": "ביטול",
"redo": "ביצוע מחדש",
"clearCanvas": "ניקוי קנבס",
"showGrid": "הצגת רשת",
"snapToGrid": "הצמדה לרשת",
"darkenOutsideSelection": "הכהיית בחירה חיצונית",
"saveBoxRegionOnly": "שמירת איזור תיבה בלבד",
"limitStrokesToBox": "הגבלת משיכות לקופסא",
"showCanvasDebugInfo": "הצגת מידע איתור באגים בקנבס",
"clearCanvasHistory": "ניקוי הסטוריית קנבס",
"clearHistory": "ניקוי היסטוריה",
"clearCanvasHistoryConfirm": "האם את/ה בטוח/ה שברצונך לנקות את היסטוריית הקנבס?",
"emptyFolder": "ריקון תיקייה",
"emptyTempImagesFolderConfirm": "האם את/ה בטוח/ה שברצונך לרוקן את התיקיה הזמנית?",
"activeLayer": "שכבה פעילה",
"canvasScale": "קנה מידה של קנבס",
"betaLimitToBox": "הגבל לקופסא",
"betaDarkenOutside": "הכההת הבחוץ",
"canvasDimensions": "מידות קנבס",
"previous": "הקודם",
"next": "הבא",
"accept": "אישור",
"showHide": "הצג/הסתר",
"discardAll": "בטל הכל",
"betaClear": "איפוס",
"boundingBox": "תיבה תוחמת",
"scaledBoundingBox": "תיבה תוחמת לאחר שינוי קנה מידה",
"betaPreserveMasked": "שמר מסיכה",
"brushOptions": "אפשרויות מברשת",
"brushSize": "גודל",
"mergeVisible": "מיזוג תוכן גלוי",
"move": "הזזה",
"resetView": "איפוס תצוגה",
"saveToGallery": "שמור לגלריה",
"canvasSettings": "הגדרות קנבס",
"showIntermediates": "הצגת מתווכים",
"autoSaveToGallery": "שמירה אוטומטית בגלריה",
"emptyTempImageFolder": "ריקון תיקיית תמונות זמניות",
"clearCanvasHistoryMessage": "ניקוי היסטוריית הקנבס משאיר את הקנבס הנוכחי ללא שינוי, אך מנקה באופן בלתי הפיך את היסטוריית הביטול והביצוע מחדש.",
"emptyTempImagesFolderMessage": "ריקון תיקיית התמונה הזמנית גם מאפס באופן מלא את הקנבס המאוחד. זה כולל את כל היסטוריית הביטול/ביצוע מחדש, תמונות באזור ההערכות ושכבת הבסיס של בד הציור.",
"boundingBoxPosition": "מיקום תיבה תוחמת",
"canvasPosition": "מיקום קנבס",
"cursorPosition": "מיקום הסמן",
"mask": "מסכה"
}
}

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