Compare commits

..

2 Commits

Author SHA1 Message Date
8c6a8d072d remove tab character 2023-12-15 09:35:06 -05:00
ec52f15f4b add frontend build steps to pypi workflow 2023-12-15 09:30:37 -05:00
30 changed files with 152 additions and 180 deletions

View File

@ -21,16 +21,16 @@ jobs:
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Setup Node 18 - name: Setup Node 20
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '18' node-version: '20'
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v2 uses: pnpm/action-setup@v2
with: with:
version: '8.12.1' version: 8
- name: Install dependencies - name: Install dependencies
run: 'pnpm install --prefer-frozen-lockfile' run: 'pnpm install --prefer-frozen-lockfile'
- name: Typescript - name: Typescript

View File

@ -1,15 +1,13 @@
name: PyPI Release name: PyPI Release
on: on:
push:
paths:
- 'invokeai/version/invokeai_version.py'
workflow_dispatch: workflow_dispatch:
inputs:
publish_package:
description: 'Publish build on PyPi? [true/false]'
required: true
default: 'false'
jobs: jobs:
build-and-release: release:
if: github.repository == 'invoke-ai/InvokeAI' if: github.repository == 'invoke-ai/InvokeAI'
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
env: env:
@ -17,39 +15,33 @@ jobs:
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
TWINE_NON_INTERACTIVE: 1 TWINE_NON_INTERACTIVE: 1
steps: steps:
- name: Checkout - name: Checkout sources
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Node 18 - name: Setup Node 20
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '18' node-version: '20'
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v2 uses: pnpm/action-setup@v2
with: with:
version: '8.12.1' version: 8
- name: Install frontend dependencies - name: Install pnpm dependencies
run: pnpm install --prefer-frozen-lockfile
working-directory: invokeai/frontend/web working-directory: invokeai/frontend/web
run: 'pnpm install --prefer-frozen-lockfile'
- name: Build frontend - name: Build frontend
run: pnpm run build
working-directory: invokeai/frontend/web working-directory: invokeai/frontend/web
run: 'pnpm build'
- name: Install python dependencies - name: Install python deps
run: pip install --upgrade build twine run: pip install --upgrade build twine
- name: Build python package - name: Build wheel package
run: python3 -m build run: python3 -m build
- name: Upload build as workflow artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: dist
- name: Check distribution - name: Check distribution
run: twine check dist/* run: twine check dist/*
@ -62,6 +54,6 @@ jobs:
EXISTS=scripts.pypi_helper.local_on_pypi(); \ EXISTS=scripts.pypi_helper.local_on_pypi(); \
print(f'PACKAGE_EXISTS={EXISTS}')" >> $GITHUB_ENV print(f'PACKAGE_EXISTS={EXISTS}')" >> $GITHUB_ENV
- name: Publish build on PyPi - name: Upload package
if: env.PACKAGE_EXISTS == 'False' && env.TWINE_PASSWORD != '' && github.event.inputs.publish_package == 'true' if: env.PACKAGE_EXISTS == 'False' && env.TWINE_PASSWORD != ''
run: twine upload dist/* run: twine upload dist/*

View File

@ -23,7 +23,7 @@ This is done via Docker Desktop preferences
1. Make a copy of `env.sample` and name it `.env` (`cp env.sample .env` (Mac/Linux) or `copy example.env .env` (Windows)). Make changes as necessary. Set `INVOKEAI_ROOT` to an absolute path to: 1. Make a copy of `env.sample` and name it `.env` (`cp env.sample .env` (Mac/Linux) or `copy example.env .env` (Windows)). Make changes as necessary. Set `INVOKEAI_ROOT` to an absolute path to:
a. the desired location of the InvokeAI runtime directory, or a. the desired location of the InvokeAI runtime directory, or
b. an existing, v3.0.0 compatible runtime directory. b. an existing, v3.0.0 compatible runtime directory.
1. Execute `run.sh` 1. `docker compose up`
The image will be built automatically if needed. The image will be built automatically if needed.
@ -39,7 +39,7 @@ The Docker daemon on the system must be already set up to use the GPU. In case o
## Customize ## Customize
Check the `.env.sample` file. It contains some environment variables for running in Docker. Copy it, name it `.env`, and fill it in with your own values. Next time you run `run.sh`, your custom values will be used. Check the `.env.sample` file. It contains some environment variables for running in Docker. Copy it, name it `.env`, and fill it in with your own values. Next time you run `docker compose up`, your custom values will be used.
You can also set these values in `docker-compose.yml` directly, but `.env` will help avoid conflicts when code is updated. You can also set these values in `docker-compose.yml` directly, but `.env` will help avoid conflicts when code is updated.

11
docker/build.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
build_args=""
[[ -f ".env" ]] && build_args=$(awk '$1 ~ /\=[^$]/ {print "--build-arg " $0 " "}' .env)
echo "docker compose build args:"
echo $build_args
docker compose build $build_args

View File

@ -2,8 +2,23 @@
version: '3.8' version: '3.8'
x-invokeai: &invokeai services:
invokeai:
image: "local/invokeai:latest" image: "local/invokeai:latest"
# edit below to run on a container runtime other than nvidia-container-runtime.
# not yet tested with rocm/AMD GPUs
# Comment out the "deploy" section to run on CPU only
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
# For AMD support, comment out the deploy section above and uncomment the devices section below:
#devices:
# - /dev/kfd:/dev/kfd
# - /dev/dri:/dev/dri
build: build:
context: .. context: ..
dockerfile: docker/Dockerfile dockerfile: docker/Dockerfile
@ -35,27 +50,3 @@ x-invokeai: &invokeai
# - | # - |
# invokeai-model-install --yes --default-only --config_file ${INVOKEAI_ROOT}/config_custom.yaml # invokeai-model-install --yes --default-only --config_file ${INVOKEAI_ROOT}/config_custom.yaml
# invokeai-nodes-web --host 0.0.0.0 # invokeai-nodes-web --host 0.0.0.0
services:
invokeai-nvidia:
<<: *invokeai
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
invokeai-cpu:
<<: *invokeai
profiles:
- cpu
invokeai-rocm:
<<: *invokeai
devices:
- /dev/kfd:/dev/kfd
- /dev/dri:/dev/dri
profiles:
- rocm

View File

@ -1,28 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
run() { # This script is provided for backwards compatibility with the old docker setup.
local scriptdir=$(dirname "${BASH_SOURCE[0]}") # it doesn't do much aside from wrapping the usual docker compose CLI.
cd "$scriptdir" || exit 1
local build_args="" SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
local profile="" cd "$SCRIPTDIR" || exit 1
[[ -f ".env" ]] && docker compose up -d
build_args=$(awk '$1 ~ /=[^$]/ && $0 !~ /^#/ {print "--build-arg " $0 " "}' .env) && docker compose logs -f
profile="$(awk -F '=' '/GPU_DRIVER/ {print $2}' .env)"
local service_name="invokeai-$profile"
printf "%s\n" "docker compose build args:"
printf "%s\n" "$build_args"
docker compose build $build_args
unset build_args
printf "%s\n" "starting service $service_name"
docker compose --profile "$profile" up -d "$service_name"
docker compose logs -f
}
run

View File

@ -91,11 +91,9 @@ rm -rf InvokeAI-Installer
# copy content # copy content
mkdir InvokeAI-Installer mkdir InvokeAI-Installer
for f in templates *.txt *.reg; do for f in templates lib *.txt *.reg; do
cp -r ${f} InvokeAI-Installer/ cp -r ${f} InvokeAI-Installer/
done done
mkdir InvokeAI-Installer/lib
cp lib/*.py InvokeAI-Installer/lib
# Move the wheel # Move the wheel
mv dist/*.whl InvokeAI-Installer/lib/ mv dist/*.whl InvokeAI-Installer/lib/
@ -113,6 +111,6 @@ cp WinLongPathsEnabled.reg InvokeAI-Installer/
zip -r InvokeAI-installer-$VERSION.zip InvokeAI-Installer zip -r InvokeAI-installer-$VERSION.zip InvokeAI-Installer
# clean up # clean up
rm -rf InvokeAI-Installer tmp dist ../invokeai/frontend/web/dist/ rm -rf InvokeAI-Installer tmp dist
exit 0 exit 0

View File

@ -77,7 +77,7 @@ class CalculateImageTilesInvocation(BaseInvocation):
title="Calculate Image Tiles Even Split", title="Calculate Image Tiles Even Split",
tags=["tiles"], tags=["tiles"],
category="tiles", category="tiles",
version="1.1.0", version="1.0.0",
classification=Classification.Beta, classification=Classification.Beta,
) )
class CalculateImageTilesEvenSplitInvocation(BaseInvocation): class CalculateImageTilesEvenSplitInvocation(BaseInvocation):
@ -97,11 +97,11 @@ class CalculateImageTilesEvenSplitInvocation(BaseInvocation):
ge=1, ge=1,
description="Number of tiles to divide image into on the y axis", description="Number of tiles to divide image into on the y axis",
) )
overlap: int = InputField( overlap_fraction: float = InputField(
default=128, default=0.25,
ge=0, ge=0,
multiple_of=8, lt=1,
description="The overlap, in pixels, between adjacent tiles.", description="Overlap between adjacent tiles as a fraction of the tile's dimensions (0-1)",
) )
def invoke(self, context: InvocationContext) -> CalculateImageTilesOutput: def invoke(self, context: InvocationContext) -> CalculateImageTilesOutput:
@ -110,7 +110,7 @@ class CalculateImageTilesEvenSplitInvocation(BaseInvocation):
image_width=self.image_width, image_width=self.image_width,
num_tiles_x=self.num_tiles_x, num_tiles_x=self.num_tiles_x,
num_tiles_y=self.num_tiles_y, num_tiles_y=self.num_tiles_y,
overlap=self.overlap, overlap_fraction=self.overlap_fraction,
) )
return CalculateImageTilesOutput(tiles=tiles) return CalculateImageTilesOutput(tiles=tiles)

View File

@ -9,7 +9,7 @@ def lora_token_vector_length(checkpoint: dict) -> int:
:param checkpoint: The checkpoint :param checkpoint: The checkpoint
""" """
def _get_shape_1(key: str, tensor, checkpoint) -> int: def _get_shape_1(key, tensor, checkpoint):
lora_token_vector_length = None lora_token_vector_length = None
if "." not in key: if "." not in key:
@ -57,10 +57,6 @@ def lora_token_vector_length(checkpoint: dict) -> int:
for key, tensor in checkpoint.items(): for key, tensor in checkpoint.items():
if key.startswith("lora_unet_") and ("_attn2_to_k." in key or "_attn2_to_v." in key): if key.startswith("lora_unet_") and ("_attn2_to_k." in key or "_attn2_to_v." in key):
lora_token_vector_length = _get_shape_1(key, tensor, checkpoint) lora_token_vector_length = _get_shape_1(key, tensor, checkpoint)
elif key.startswith("lora_unet_") and (
"time_emb_proj.lora_down" in key
): # recognizes format at https://civitai.com/models/224641
lora_token_vector_length = _get_shape_1(key, tensor, checkpoint)
elif key.startswith("lora_te") and "_self_attn_" in key: elif key.startswith("lora_te") and "_self_attn_" in key:
tmp_length = _get_shape_1(key, tensor, checkpoint) tmp_length = _get_shape_1(key, tensor, checkpoint)
if key.startswith("lora_te_"): if key.startswith("lora_te_"):

View File

@ -400,8 +400,6 @@ class LoRACheckpointProbe(CheckpointProbeBase):
return BaseModelType.StableDiffusion1 return BaseModelType.StableDiffusion1
elif token_vector_length == 1024: elif token_vector_length == 1024:
return BaseModelType.StableDiffusion2 return BaseModelType.StableDiffusion2
elif token_vector_length == 1280:
return BaseModelType.StableDiffusionXL # recognizes format at https://civitai.com/models/224641
elif token_vector_length == 2048: elif token_vector_length == 2048:
return BaseModelType.StableDiffusionXL return BaseModelType.StableDiffusionXL
else: else:

View File

@ -102,7 +102,7 @@ def calc_tiles_with_overlap(
def calc_tiles_even_split( def calc_tiles_even_split(
image_height: int, image_width: int, num_tiles_x: int, num_tiles_y: int, overlap: int = 0 image_height: int, image_width: int, num_tiles_x: int, num_tiles_y: int, overlap_fraction: float = 0
) -> list[Tile]: ) -> list[Tile]:
"""Calculate the tile coordinates for a given image shape with the number of tiles requested. """Calculate the tile coordinates for a given image shape with the number of tiles requested.
@ -111,35 +111,31 @@ def calc_tiles_even_split(
image_width (int): The image width in px. image_width (int): The image width in px.
num_x_tiles (int): The number of tile to split the image into on the X-axis. num_x_tiles (int): The number of tile to split the image into on the X-axis.
num_y_tiles (int): The number of tile to split the image into on the Y-axis. num_y_tiles (int): The number of tile to split the image into on the Y-axis.
overlap (int, optional): The overlap between adjacent tiles in pixels. Defaults to 0. overlap_fraction (float, optional): The target overlap as fraction of the tiles size. Defaults to 0.
Returns: Returns:
list[Tile]: A list of tiles that cover the image shape. Ordered from left-to-right, top-to-bottom. list[Tile]: A list of tiles that cover the image shape. Ordered from left-to-right, top-to-bottom.
""" """
# Ensure the image is divisible by LATENT_SCALE_FACTOR
# Ensure tile size is divisible by 8
if image_width % LATENT_SCALE_FACTOR != 0 or image_height % LATENT_SCALE_FACTOR != 0: if image_width % LATENT_SCALE_FACTOR != 0 or image_height % LATENT_SCALE_FACTOR != 0:
raise ValueError(f"image size (({image_width}, {image_height})) must be divisible by {LATENT_SCALE_FACTOR}") raise ValueError(f"image size (({image_width}, {image_height})) must be divisible by {LATENT_SCALE_FACTOR}")
# Calculate the tile size based on the number of tiles and overlap, and ensure it's divisible by 8 (rounding down) # Calculate the overlap size based on the percentage and adjust it to be divisible by 8 (rounding up)
if num_tiles_x > 1: overlap_x = LATENT_SCALE_FACTOR * math.ceil(
# ensure the overlap is not more than the maximum overlap if we only have 1 tile then we dont care about overlap int((image_width / num_tiles_x) * overlap_fraction) / LATENT_SCALE_FACTOR
assert overlap <= image_width - (LATENT_SCALE_FACTOR * (num_tiles_x - 1)) )
tile_size_x = LATENT_SCALE_FACTOR * math.floor( overlap_y = LATENT_SCALE_FACTOR * math.ceil(
((image_width + overlap * (num_tiles_x - 1)) // num_tiles_x) / LATENT_SCALE_FACTOR int((image_height / num_tiles_y) * overlap_fraction) / LATENT_SCALE_FACTOR
) )
assert overlap < tile_size_x
else:
tile_size_x = image_width
if num_tiles_y > 1: # Calculate the tile size based on the number of tiles and overlap, and ensure it's divisible by 8 (rounding down)
# ensure the overlap is not more than the maximum overlap if we only have 1 tile then we dont care about overlap tile_size_x = LATENT_SCALE_FACTOR * math.floor(
assert overlap <= image_height - (LATENT_SCALE_FACTOR * (num_tiles_y - 1)) ((image_width + overlap_x * (num_tiles_x - 1)) // num_tiles_x) / LATENT_SCALE_FACTOR
tile_size_y = LATENT_SCALE_FACTOR * math.floor( )
((image_height + overlap * (num_tiles_y - 1)) // num_tiles_y) / LATENT_SCALE_FACTOR tile_size_y = LATENT_SCALE_FACTOR * math.floor(
) ((image_height + overlap_y * (num_tiles_y - 1)) // num_tiles_y) / LATENT_SCALE_FACTOR
assert overlap < tile_size_y )
else:
tile_size_y = image_height
# tiles[y * num_tiles_x + x] is the tile for the y'th row, x'th column. # tiles[y * num_tiles_x + x] is the tile for the y'th row, x'th column.
tiles: list[Tile] = [] tiles: list[Tile] = []
@ -147,7 +143,7 @@ def calc_tiles_even_split(
# Calculate tile coordinates. (Ignore overlap values for now.) # Calculate tile coordinates. (Ignore overlap values for now.)
for tile_idx_y in range(num_tiles_y): for tile_idx_y in range(num_tiles_y):
# Calculate the top and bottom of the row # Calculate the top and bottom of the row
top = tile_idx_y * (tile_size_y - overlap) top = tile_idx_y * (tile_size_y - overlap_y)
bottom = min(top + tile_size_y, image_height) bottom = min(top + tile_size_y, image_height)
# For the last row adjust bottom to be the height of the image # For the last row adjust bottom to be the height of the image
if tile_idx_y == num_tiles_y - 1: if tile_idx_y == num_tiles_y - 1:
@ -155,7 +151,7 @@ def calc_tiles_even_split(
for tile_idx_x in range(num_tiles_x): for tile_idx_x in range(num_tiles_x):
# Calculate the left & right coordinate of each tile # Calculate the left & right coordinate of each tile
left = tile_idx_x * (tile_size_x - overlap) left = tile_idx_x * (tile_size_x - overlap_x)
right = min(left + tile_size_x, image_width) right = min(left + tile_size_x, image_width)
# For the last tile in the row adjust right to be the width of the image # For the last tile in the row adjust right to be the width of the image
if tile_idx_x == num_tiles_x - 1: if tile_idx_x == num_tiles_x - 1:

View File

@ -727,6 +727,9 @@
"showMinimapnodes": "Mostrar el minimapa", "showMinimapnodes": "Mostrar el minimapa",
"reloadNodeTemplates": "Recargar las plantillas de nodos", "reloadNodeTemplates": "Recargar las plantillas de nodos",
"loadWorkflow": "Cargar el flujo de trabajo", "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" "downloadWorkflow": "Descargar el flujo de trabajo en un archivo JSON"
} }
} }

View File

@ -898,8 +898,11 @@
"zoomInNodes": "Ingrandire", "zoomInNodes": "Ingrandire",
"fitViewportNodes": "Adatta vista", "fitViewportNodes": "Adatta vista",
"showGraphNodes": "Mostra sovrapposizione grafico", "showGraphNodes": "Mostra sovrapposizione grafico",
"resetWorkflowDesc2": "Il ripristino dell'editor del flusso di lavoro cancellerà tutti i nodi, le connessioni e i dettagli del flusso di lavoro. I flussi di lavoro salvati non saranno interessati.",
"reloadNodeTemplates": "Ricarica i modelli di nodo", "reloadNodeTemplates": "Ricarica i modelli di nodo",
"loadWorkflow": "Importa flusso di lavoro JSON", "loadWorkflow": "Importa flusso di lavoro JSON",
"resetWorkflow": "Reimposta l'editor del flusso di lavoro",
"resetWorkflowDesc": "Sei sicuro di voler reimpostare l'editor del flusso di lavoro?",
"downloadWorkflow": "Esporta flusso di lavoro JSON", "downloadWorkflow": "Esporta flusso di lavoro JSON",
"scheduler": "Campionatore", "scheduler": "Campionatore",
"addNode": "Aggiungi nodo", "addNode": "Aggiungi nodo",
@ -1616,6 +1619,7 @@
"saveWorkflow": "Salva flusso di lavoro", "saveWorkflow": "Salva flusso di lavoro",
"openWorkflow": "Apri flusso di lavoro", "openWorkflow": "Apri flusso di lavoro",
"clearWorkflowSearchFilter": "Cancella il filtro di ricerca del flusso di lavoro", "clearWorkflowSearchFilter": "Cancella il filtro di ricerca del flusso di lavoro",
"workflowEditorReset": "Reimpostazione dell'editor del flusso di lavoro",
"workflowLibrary": "Libreria", "workflowLibrary": "Libreria",
"noRecentWorkflows": "Nessun flusso di lavoro recente", "noRecentWorkflows": "Nessun flusso di lavoro recente",
"workflowSaved": "Flusso di lavoro salvato", "workflowSaved": "Flusso di lavoro salvato",

View File

@ -844,6 +844,9 @@
"hideLegendNodes": "Typelegende veld verbergen", "hideLegendNodes": "Typelegende veld verbergen",
"reloadNodeTemplates": "Herlaad knooppuntsjablonen", "reloadNodeTemplates": "Herlaad knooppuntsjablonen",
"loadWorkflow": "Laad werkstroom", "loadWorkflow": "Laad werkstroom",
"resetWorkflow": "Herstel werkstroom",
"resetWorkflowDesc": "Weet je zeker dat je deze werkstroom wilt herstellen?",
"resetWorkflowDesc2": "Herstel van een werkstroom haalt alle knooppunten, randen en werkstroomdetails weg.",
"downloadWorkflow": "Download JSON van werkstroom", "downloadWorkflow": "Download JSON van werkstroom",
"booleanPolymorphicDescription": "Een verzameling Booleanse waarden.", "booleanPolymorphicDescription": "Een verzameling Booleanse waarden.",
"scheduler": "Planner", "scheduler": "Planner",

View File

@ -909,6 +909,9 @@
"hideLegendNodes": "Скрыть тип поля", "hideLegendNodes": "Скрыть тип поля",
"showMinimapnodes": "Показать миникарту", "showMinimapnodes": "Показать миникарту",
"loadWorkflow": "Загрузить рабочий процесс", "loadWorkflow": "Загрузить рабочий процесс",
"resetWorkflowDesc2": "Сброс рабочего процесса очистит все узлы, ребра и детали рабочего процесса.",
"resetWorkflow": "Сбросить рабочий процесс",
"resetWorkflowDesc": "Вы уверены, что хотите сбросить этот рабочий процесс?",
"reloadNodeTemplates": "Перезагрузить шаблоны узлов", "reloadNodeTemplates": "Перезагрузить шаблоны узлов",
"downloadWorkflow": "Скачать JSON рабочего процесса", "downloadWorkflow": "Скачать JSON рабочего процесса",
"booleanPolymorphicDescription": "Коллекция логических значений.", "booleanPolymorphicDescription": "Коллекция логических значений.",
@ -1596,6 +1599,7 @@
"saveWorkflow": "Сохранить рабочий процесс", "saveWorkflow": "Сохранить рабочий процесс",
"openWorkflow": "Открытый рабочий процесс", "openWorkflow": "Открытый рабочий процесс",
"clearWorkflowSearchFilter": "Очистить фильтр поиска рабочих процессов", "clearWorkflowSearchFilter": "Очистить фильтр поиска рабочих процессов",
"workflowEditorReset": "Сброс редактора рабочих процессов",
"workflowLibrary": "Библиотека", "workflowLibrary": "Библиотека",
"downloadWorkflow": "Скачать рабочий процесс", "downloadWorkflow": "Скачать рабочий процесс",
"noRecentWorkflows": "Нет недавних рабочих процессов", "noRecentWorkflows": "Нет недавних рабочих процессов",

View File

@ -892,8 +892,11 @@
}, },
"nodes": { "nodes": {
"zoomInNodes": "放大", "zoomInNodes": "放大",
"resetWorkflowDesc": "是否确定要重置工作流编辑器?",
"resetWorkflow": "重置工作流编辑器",
"loadWorkflow": "加载工作流", "loadWorkflow": "加载工作流",
"zoomOutNodes": "缩小", "zoomOutNodes": "缩小",
"resetWorkflowDesc2": "重置工作流编辑器将清除所有节点、边际和节点图详情。不影响已保存的工作流。",
"reloadNodeTemplates": "重载节点模板", "reloadNodeTemplates": "重载节点模板",
"hideGraphNodes": "隐藏节点图信息", "hideGraphNodes": "隐藏节点图信息",
"fitViewportNodes": "自适应视图", "fitViewportNodes": "自适应视图",
@ -1634,6 +1637,7 @@
"saveWorkflow": "保存工作流", "saveWorkflow": "保存工作流",
"openWorkflow": "打开工作流", "openWorkflow": "打开工作流",
"clearWorkflowSearchFilter": "清除工作流检索过滤器", "clearWorkflowSearchFilter": "清除工作流检索过滤器",
"workflowEditorReset": "工作流编辑器重置",
"workflowLibrary": "工作流库", "workflowLibrary": "工作流库",
"downloadWorkflow": "下载工作流", "downloadWorkflow": "下载工作流",
"noRecentWorkflows": "无最近工作流", "noRecentWorkflows": "无最近工作流",

View File

@ -144,7 +144,6 @@ export const buildCanvasImageToImageGraph = (
type: 'l2i', type: 'l2i',
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [
@ -256,7 +255,6 @@ export const buildCanvasImageToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -297,7 +295,6 @@ export const buildCanvasImageToImageGraph = (
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
fp32, fp32,
use_cache: false,
}; };
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image = (graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image =

View File

@ -191,7 +191,6 @@ export const buildCanvasInpaintGraph = (
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
reference: canvasInitImage, reference: canvasInitImage,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -199,7 +199,6 @@ export const buildCanvasOutpaintGraph = (
type: 'color_correct', type: 'color_correct',
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -266,7 +266,6 @@ export const buildCanvasSDXLImageToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -307,7 +306,6 @@ export const buildCanvasSDXLImageToImageGraph = (
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
fp32, fp32,
use_cache: false,
}; };
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image = (graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image =

View File

@ -196,7 +196,6 @@ export const buildCanvasSDXLInpaintGraph = (
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
reference: canvasInitImage, reference: canvasInitImage,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -204,7 +204,6 @@ export const buildCanvasSDXLOutpaintGraph = (
type: 'color_correct', type: 'color_correct',
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -258,7 +258,6 @@ export const buildCanvasSDXLTextToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -289,7 +288,6 @@ export const buildCanvasSDXLTextToImageGraph = (
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
fp32, fp32,
use_cache: false,
}; };
graph.edges.push({ graph.edges.push({

View File

@ -246,7 +246,6 @@ export const buildCanvasTextToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -277,7 +276,6 @@ export const buildCanvasTextToImageGraph = (
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
fp32, fp32,
use_cache: false,
}; };
graph.edges.push({ graph.edges.push({

View File

@ -143,7 +143,6 @@ export const buildLinearImageToImageGraph = (
// }, // },
fp32, fp32,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -154,7 +154,6 @@ export const buildLinearSDXLImageToImageGraph = (
// }, // },
fp32, fp32,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -127,7 +127,6 @@ export const buildLinearSDXLTextToImageGraph = (
id: LATENTS_TO_IMAGE, id: LATENTS_TO_IMAGE,
fp32, fp32,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -146,7 +146,6 @@ export const buildLinearTextToImageGraph = (
id: LATENTS_TO_IMAGE, id: LATENTS_TO_IMAGE,
fp32, fp32,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -1 +1 @@
__version__ = "3.5.0rc2" __version__ = "3.4.0post2"

View File

@ -305,7 +305,9 @@ def test_calc_tiles_min_overlap_input_validation(
def test_calc_tiles_even_split_single_tile(): def test_calc_tiles_even_split_single_tile():
"""Test calc_tiles_even_split() behavior when a single tile covers the image.""" """Test calc_tiles_even_split() behavior when a single tile covers the image."""
tiles = calc_tiles_even_split(image_height=512, image_width=1024, num_tiles_x=1, num_tiles_y=1, overlap=64) tiles = calc_tiles_even_split(
image_height=512, image_width=1024, num_tiles_x=1, num_tiles_y=1, overlap_fraction=0.25
)
expected_tiles = [ expected_tiles = [
Tile( Tile(
@ -320,34 +322,36 @@ def test_calc_tiles_even_split_single_tile():
def test_calc_tiles_even_split_evenly_divisible(): def test_calc_tiles_even_split_evenly_divisible():
"""Test calc_tiles_even_split() behavior when the image is evenly covered by multiple tiles.""" """Test calc_tiles_even_split() behavior when the image is evenly covered by multiple tiles."""
# Parameters mimic roughly the same output as the original tile generations of the same test name # Parameters mimic roughly the same output as the original tile generations of the same test name
tiles = calc_tiles_even_split(image_height=576, image_width=1600, num_tiles_x=3, num_tiles_y=2, overlap=64) tiles = calc_tiles_even_split(
image_height=576, image_width=1600, num_tiles_x=3, num_tiles_y=2, overlap_fraction=0.25
)
expected_tiles = [ expected_tiles = [
# Row 0 # Row 0
Tile( Tile(
coords=TBLR(top=0, bottom=320, left=0, right=576), coords=TBLR(top=0, bottom=320, left=0, right=624),
overlap=TBLR(top=0, bottom=64, left=0, right=64), overlap=TBLR(top=0, bottom=72, left=0, right=136),
), ),
Tile( Tile(
coords=TBLR(top=0, bottom=320, left=512, right=1088), coords=TBLR(top=0, bottom=320, left=488, right=1112),
overlap=TBLR(top=0, bottom=64, left=64, right=64), overlap=TBLR(top=0, bottom=72, left=136, right=136),
), ),
Tile( Tile(
coords=TBLR(top=0, bottom=320, left=1024, right=1600), coords=TBLR(top=0, bottom=320, left=976, right=1600),
overlap=TBLR(top=0, bottom=64, left=64, right=0), overlap=TBLR(top=0, bottom=72, left=136, right=0),
), ),
# Row 1 # Row 1
Tile( Tile(
coords=TBLR(top=256, bottom=576, left=0, right=576), coords=TBLR(top=248, bottom=576, left=0, right=624),
overlap=TBLR(top=64, bottom=0, left=0, right=64), overlap=TBLR(top=72, bottom=0, left=0, right=136),
), ),
Tile( Tile(
coords=TBLR(top=256, bottom=576, left=512, right=1088), coords=TBLR(top=248, bottom=576, left=488, right=1112),
overlap=TBLR(top=64, bottom=0, left=64, right=64), overlap=TBLR(top=72, bottom=0, left=136, right=136),
), ),
Tile( Tile(
coords=TBLR(top=256, bottom=576, left=1024, right=1600), coords=TBLR(top=248, bottom=576, left=976, right=1600),
overlap=TBLR(top=64, bottom=0, left=64, right=0), overlap=TBLR(top=72, bottom=0, left=136, right=0),
), ),
] ]
assert tiles == expected_tiles assert tiles == expected_tiles
@ -356,34 +360,36 @@ def test_calc_tiles_even_split_evenly_divisible():
def test_calc_tiles_even_split_not_evenly_divisible(): def test_calc_tiles_even_split_not_evenly_divisible():
"""Test calc_tiles_even_split() behavior when the image requires 'uneven' overlaps to achieve proper coverage.""" """Test calc_tiles_even_split() behavior when the image requires 'uneven' overlaps to achieve proper coverage."""
# Parameters mimic roughly the same output as the original tile generations of the same test name # Parameters mimic roughly the same output as the original tile generations of the same test name
tiles = calc_tiles_even_split(image_height=400, image_width=1200, num_tiles_x=3, num_tiles_y=2, overlap=64) tiles = calc_tiles_even_split(
image_height=400, image_width=1200, num_tiles_x=3, num_tiles_y=2, overlap_fraction=0.25
)
expected_tiles = [ expected_tiles = [
# Row 0 # Row 0
Tile( Tile(
coords=TBLR(top=0, bottom=232, left=0, right=440), coords=TBLR(top=0, bottom=224, left=0, right=464),
overlap=TBLR(top=0, bottom=64, left=0, right=64), overlap=TBLR(top=0, bottom=56, left=0, right=104),
), ),
Tile( Tile(
coords=TBLR(top=0, bottom=232, left=376, right=816), coords=TBLR(top=0, bottom=224, left=360, right=824),
overlap=TBLR(top=0, bottom=64, left=64, right=64), overlap=TBLR(top=0, bottom=56, left=104, right=104),
), ),
Tile( Tile(
coords=TBLR(top=0, bottom=232, left=752, right=1200), coords=TBLR(top=0, bottom=224, left=720, right=1200),
overlap=TBLR(top=0, bottom=64, left=64, right=0), overlap=TBLR(top=0, bottom=56, left=104, right=0),
), ),
# Row 1 # Row 1
Tile( Tile(
coords=TBLR(top=168, bottom=400, left=0, right=440), coords=TBLR(top=168, bottom=400, left=0, right=464),
overlap=TBLR(top=64, bottom=0, left=0, right=64), overlap=TBLR(top=56, bottom=0, left=0, right=104),
), ),
Tile( Tile(
coords=TBLR(top=168, bottom=400, left=376, right=816), coords=TBLR(top=168, bottom=400, left=360, right=824),
overlap=TBLR(top=64, bottom=0, left=64, right=64), overlap=TBLR(top=56, bottom=0, left=104, right=104),
), ),
Tile( Tile(
coords=TBLR(top=168, bottom=400, left=752, right=1200), coords=TBLR(top=168, bottom=400, left=720, right=1200),
overlap=TBLR(top=64, bottom=0, left=64, right=0), overlap=TBLR(top=56, bottom=0, left=104, right=0),
), ),
] ]
@ -393,26 +399,28 @@ def test_calc_tiles_even_split_not_evenly_divisible():
def test_calc_tiles_even_split_difficult_size(): def test_calc_tiles_even_split_difficult_size():
"""Test calc_tiles_even_split() behavior when the image is a difficult size to spilt evenly and keep div8.""" """Test calc_tiles_even_split() behavior when the image is a difficult size to spilt evenly and keep div8."""
# Parameters are a difficult size for other tile gen routines to calculate # Parameters are a difficult size for other tile gen routines to calculate
tiles = calc_tiles_even_split(image_height=1000, image_width=1000, num_tiles_x=2, num_tiles_y=2, overlap=64) tiles = calc_tiles_even_split(
image_height=1000, image_width=1000, num_tiles_x=2, num_tiles_y=2, overlap_fraction=0.25
)
expected_tiles = [ expected_tiles = [
# Row 0 # Row 0
Tile( Tile(
coords=TBLR(top=0, bottom=528, left=0, right=528), coords=TBLR(top=0, bottom=560, left=0, right=560),
overlap=TBLR(top=0, bottom=64, left=0, right=64), overlap=TBLR(top=0, bottom=128, left=0, right=128),
), ),
Tile( Tile(
coords=TBLR(top=0, bottom=528, left=464, right=1000), coords=TBLR(top=0, bottom=560, left=432, right=1000),
overlap=TBLR(top=0, bottom=64, left=64, right=0), overlap=TBLR(top=0, bottom=128, left=128, right=0),
), ),
# Row 1 # Row 1
Tile( Tile(
coords=TBLR(top=464, bottom=1000, left=0, right=528), coords=TBLR(top=432, bottom=1000, left=0, right=560),
overlap=TBLR(top=64, bottom=0, left=0, right=64), overlap=TBLR(top=128, bottom=0, left=0, right=128),
), ),
Tile( Tile(
coords=TBLR(top=464, bottom=1000, left=464, right=1000), coords=TBLR(top=432, bottom=1000, left=432, right=1000),
overlap=TBLR(top=64, bottom=0, left=64, right=0), overlap=TBLR(top=128, bottom=0, left=128, right=0),
), ),
] ]
@ -420,13 +428,11 @@ def test_calc_tiles_even_split_difficult_size():
@pytest.mark.parametrize( @pytest.mark.parametrize(
["image_height", "image_width", "num_tiles_x", "num_tiles_y", "overlap", "raises"], ["image_height", "image_width", "num_tiles_x", "num_tiles_y", "overlap_fraction", "raises"],
[ [
(128, 128, 1, 1, 127, False), # OK (128, 128, 1, 1, 0.25, False), # OK
(128, 128, 1, 1, 0, False), # OK (128, 128, 1, 1, 0, False), # OK
(128, 128, 2, 2, 0, False), # OK (128, 128, 2, 1, 0, False), # OK
(128, 128, 2, 1, 120, True), # overlap equals tile_height.
(128, 128, 1, 2, 120, True), # overlap equals tile_width.
(127, 127, 1, 1, 0, True), # image size must be dividable by 8 (127, 127, 1, 1, 0, True), # image size must be dividable by 8
], ],
) )
@ -435,15 +441,15 @@ def test_calc_tiles_even_split_input_validation(
image_width: int, image_width: int,
num_tiles_x: int, num_tiles_x: int,
num_tiles_y: int, num_tiles_y: int,
overlap: int, overlap_fraction: float,
raises: bool, raises: bool,
): ):
"""Test that calc_tiles_even_split() raises an exception if the inputs are invalid.""" """Test that calc_tiles_even_split() raises an exception if the inputs are invalid."""
if raises: if raises:
with pytest.raises((AssertionError, ValueError)): with pytest.raises(ValueError):
calc_tiles_even_split(image_height, image_width, num_tiles_x, num_tiles_y, overlap) calc_tiles_even_split(image_height, image_width, num_tiles_x, num_tiles_y, overlap_fraction)
else: else:
calc_tiles_even_split(image_height, image_width, num_tiles_x, num_tiles_y, overlap) calc_tiles_even_split(image_height, image_width, num_tiles_x, num_tiles_y, overlap_fraction)
############################################# #############################################