Merge branch 'main' into simplify-docker-compose-setup

This commit is contained in:
Millun Atluri 2023-12-17 17:07:55 +11:00 committed by GitHub
commit 351078e8aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 129 additions and 65 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 20 - name: Setup Node 18
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '20' node-version: '18'
- 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 version: '8.12.1'
- 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,13 +1,15 @@
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:
release: build-and-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:
@ -15,19 +17,43 @@ 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 sources - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: install deps - name: Setup Node 18
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: '8.12.1'
- name: Install frontend dependencies
run: pnpm install --prefer-frozen-lockfile
working-directory: invokeai/frontend/web
- name: Build frontend
run: pnpm run build
working-directory: invokeai/frontend/web
- name: Install python dependencies
run: pip install --upgrade build twine run: pip install --upgrade build twine
- name: build package - name: Build python package
run: python3 -m build run: python3 -m build
- name: check distribution - name: Upload build as workflow artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: dist
- name: Check distribution
run: twine check dist/* run: twine check dist/*
- name: check PyPI versions - name: Check PyPI versions
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
run: | run: |
pip install --upgrade requests pip install --upgrade requests
@ -36,6 +62,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: upload package - name: Publish build on PyPi
if: env.PACKAGE_EXISTS == 'False' && env.TWINE_PASSWORD != '' if: env.PACKAGE_EXISTS == 'False' && env.TWINE_PASSWORD != '' && github.event.inputs.publish_package == 'true'
run: twine upload dist/* run: twine upload dist/*

View File

@ -0,0 +1,10 @@
document.addEventListener("DOMContentLoaded", function () {
var script = document.createElement("script");
script.src = "https://widget.kapa.ai/kapa-widget.bundle.js";
script.setAttribute("data-website-id", "b5973bb1-476b-451e-8cf4-98de86745a10");
script.setAttribute("data-project-name", "Invoke.AI");
script.setAttribute("data-project-color", "#11213C");
script.setAttribute("data-project-logo", "https://avatars.githubusercontent.com/u/113954515?s=280&v=4");
script.async = true;
document.head.appendChild(script);
});

View File

@ -91,9 +91,11 @@ rm -rf InvokeAI-Installer
# copy content # copy content
mkdir InvokeAI-Installer mkdir InvokeAI-Installer
for f in templates lib *.txt *.reg; do for f in templates *.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/
@ -111,6 +113,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 rm -rf InvokeAI-Installer tmp dist ../invokeai/frontend/web/dist/
exit 0 exit 0

View File

@ -45,6 +45,9 @@ async def list_model_records(
base_models: Optional[List[BaseModelType]] = Query(default=None, description="Base models to include"), base_models: Optional[List[BaseModelType]] = Query(default=None, description="Base models to include"),
model_type: Optional[ModelType] = Query(default=None, description="The type of model to get"), model_type: Optional[ModelType] = Query(default=None, description="The type of model to get"),
model_name: Optional[str] = Query(default=None, description="Exact match on the name of the model"), model_name: Optional[str] = Query(default=None, description="Exact match on the name of the model"),
model_format: Optional[str] = Query(
default=None, description="Exact match on the format of the model (e.g. 'diffusers')"
),
) -> ModelsList: ) -> ModelsList:
"""Get a list of models.""" """Get a list of models."""
record_store = ApiDependencies.invoker.services.model_records record_store = ApiDependencies.invoker.services.model_records
@ -52,10 +55,14 @@ async def list_model_records(
if base_models: if base_models:
for base_model in base_models: for base_model in base_models:
found_models.extend( found_models.extend(
record_store.search_by_attr(base_model=base_model, model_type=model_type, model_name=model_name) record_store.search_by_attr(
base_model=base_model, model_type=model_type, model_name=model_name, model_format=model_format
)
) )
else: else:
found_models.extend(record_store.search_by_attr(model_type=model_type, model_name=model_name)) found_models.extend(
record_store.search_by_attr(model_type=model_type, model_name=model_name, model_format=model_format)
)
return ModelsList(models=found_models) return ModelsList(models=found_models)

View File

@ -7,7 +7,7 @@ from abc import ABC, abstractmethod
from pathlib import Path from pathlib import Path
from typing import List, Optional, Union from typing import List, Optional, Union
from invokeai.backend.model_manager.config import AnyModelConfig, BaseModelType, ModelType from invokeai.backend.model_manager.config import AnyModelConfig, BaseModelType, ModelFormat, ModelType
class DuplicateModelException(Exception): class DuplicateModelException(Exception):
@ -106,6 +106,7 @@ class ModelRecordServiceBase(ABC):
model_name: Optional[str] = None, model_name: Optional[str] = None,
base_model: Optional[BaseModelType] = None, base_model: Optional[BaseModelType] = None,
model_type: Optional[ModelType] = None, model_type: Optional[ModelType] = None,
model_format: Optional[ModelFormat] = None,
) -> List[AnyModelConfig]: ) -> List[AnyModelConfig]:
""" """
Return models matching name, base and/or type. Return models matching name, base and/or type.
@ -113,6 +114,7 @@ class ModelRecordServiceBase(ABC):
:param model_name: Filter by name of model (optional) :param model_name: Filter by name of model (optional)
:param base_model: Filter by base model (optional) :param base_model: Filter by base model (optional)
:param model_type: Filter by type of model (optional) :param model_type: Filter by type of model (optional)
:param model_format: Filter by model format (e.g. "diffusers") (optional)
If none of the optional filters are passed, will return all If none of the optional filters are passed, will return all
models in the database. models in the database.

View File

@ -49,6 +49,7 @@ from invokeai.backend.model_manager.config import (
AnyModelConfig, AnyModelConfig,
BaseModelType, BaseModelType,
ModelConfigFactory, ModelConfigFactory,
ModelFormat,
ModelType, ModelType,
) )
@ -225,6 +226,7 @@ class ModelRecordServiceSQL(ModelRecordServiceBase):
model_name: Optional[str] = None, model_name: Optional[str] = None,
base_model: Optional[BaseModelType] = None, base_model: Optional[BaseModelType] = None,
model_type: Optional[ModelType] = None, model_type: Optional[ModelType] = None,
model_format: Optional[ModelFormat] = None,
) -> List[AnyModelConfig]: ) -> List[AnyModelConfig]:
""" """
Return models matching name, base and/or type. Return models matching name, base and/or type.
@ -232,6 +234,7 @@ class ModelRecordServiceSQL(ModelRecordServiceBase):
:param model_name: Filter by name of model (optional) :param model_name: Filter by name of model (optional)
:param base_model: Filter by base model (optional) :param base_model: Filter by base model (optional)
:param model_type: Filter by type of model (optional) :param model_type: Filter by type of model (optional)
:param model_format: Filter by model format (e.g. "diffusers") (optional)
If none of the optional filters are passed, will return all If none of the optional filters are passed, will return all
models in the database. models in the database.
@ -248,6 +251,9 @@ class ModelRecordServiceSQL(ModelRecordServiceBase):
if model_type: if model_type:
where_clause.append("type=?") where_clause.append("type=?")
bindings.append(model_type) bindings.append(model_type)
if model_format:
where_clause.append("format=?")
bindings.append(model_format)
where = f"WHERE {' AND '.join(where_clause)}" if where_clause else "" where = f"WHERE {' AND '.join(where_clause)}" if where_clause else ""
with self._db.lock: with self._db.lock:
self._cursor.execute( self._cursor.execute(

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, tensor, checkpoint): def _get_shape_1(key: str, tensor, checkpoint) -> int:
lora_token_vector_length = None lora_token_vector_length = None
if "." not in key: if "." not in key:
@ -57,6 +57,10 @@ 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,6 +400,8 @@ 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

@ -950,9 +950,9 @@
"problemSettingTitle": "Problem Setting Title", "problemSettingTitle": "Problem Setting Title",
"reloadNodeTemplates": "Reload Node Templates", "reloadNodeTemplates": "Reload Node Templates",
"removeLinearView": "Remove from Linear View", "removeLinearView": "Remove from Linear View",
"resetWorkflow": "Reset Workflow Editor", "newWorkflow": "New Workflow",
"resetWorkflowDesc": "Are you sure you want to reset the Workflow Editor?", "newWorkflowDesc": "Create a new workflow?",
"resetWorkflowDesc2": "Resetting the Workflow Editor will clear all nodes, edges and workflow details. Saved workflows will not be affected.", "newWorkflowDesc2": "Your current workflow has unsaved changes.",
"scheduler": "Scheduler", "scheduler": "Scheduler",
"schedulerDescription": "TODO", "schedulerDescription": "TODO",
"sDXLMainModelField": "SDXL Model", "sDXLMainModelField": "SDXL Model",
@ -1634,10 +1634,10 @@
"userWorkflows": "My Workflows", "userWorkflows": "My Workflows",
"defaultWorkflows": "Default Workflows", "defaultWorkflows": "Default Workflows",
"openWorkflow": "Open Workflow", "openWorkflow": "Open Workflow",
"uploadWorkflow": "Upload Workflow", "uploadWorkflow": "Load from File",
"deleteWorkflow": "Delete Workflow", "deleteWorkflow": "Delete Workflow",
"unnamedWorkflow": "Unnamed Workflow", "unnamedWorkflow": "Unnamed Workflow",
"downloadWorkflow": "Download Workflow", "downloadWorkflow": "Save to File",
"saveWorkflow": "Save Workflow", "saveWorkflow": "Save Workflow",
"saveWorkflowAs": "Save Workflow As", "saveWorkflowAs": "Save Workflow As",
"savingWorkflow": "Saving Workflow...", "savingWorkflow": "Saving Workflow...",
@ -1652,7 +1652,7 @@
"searchWorkflows": "Search Workflows", "searchWorkflows": "Search Workflows",
"clearWorkflowSearchFilter": "Clear Workflow Search Filter", "clearWorkflowSearchFilter": "Clear Workflow Search Filter",
"workflowName": "Workflow Name", "workflowName": "Workflow Name",
"workflowEditorReset": "Workflow Editor Reset", "newWorkflowCreated": "New Workflow Created",
"workflowEditorMenu": "Workflow Editor Menu", "workflowEditorMenu": "Workflow Editor Menu",
"workflowIsOpen": "Workflow is Open" "workflowIsOpen": "Workflow is Open"
}, },

View File

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

View File

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

View File

@ -144,6 +144,7 @@ export const buildCanvasImageToImageGraph = (
type: 'l2i', type: 'l2i',
id: CANVAS_OUTPUT, id: CANVAS_OUTPUT,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [
@ -255,6 +256,7 @@ export const buildCanvasImageToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -295,6 +297,7 @@ 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,6 +191,7 @@ 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,6 +199,7 @@ 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,6 +266,7 @@ export const buildCanvasSDXLImageToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -306,6 +307,7 @@ 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,6 +196,7 @@ 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,6 +204,7 @@ 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,6 +258,7 @@ export const buildCanvasSDXLTextToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -288,6 +289,7 @@ 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,6 +246,7 @@ export const buildCanvasTextToImageGraph = (
is_intermediate, is_intermediate,
width: width, width: width,
height: height, height: height,
use_cache: false,
}; };
graph.edges.push( graph.edges.push(
@ -276,6 +277,7 @@ 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,6 +143,7 @@ export const buildLinearImageToImageGraph = (
// }, // },
fp32, fp32,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

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

View File

@ -127,6 +127,7 @@ 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,6 +146,7 @@ export const buildLinearTextToImageGraph = (
id: LATENTS_TO_IMAGE, id: LATENTS_TO_IMAGE,
fp32, fp32,
is_intermediate, is_intermediate,
use_cache: false,
}, },
}, },
edges: [ edges: [

View File

@ -11,44 +11,48 @@ import {
Text, Text,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { nodeEditorReset } from 'features/nodes/store/nodesSlice'; import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast'; import { makeToast } from 'features/system/util/makeToast';
import { memo, useCallback, useRef } from 'react'; import { memo, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FaTrash } from 'react-icons/fa'; import { FaCircleNodes } from 'react-icons/fa6';
const ResetWorkflowEditorMenuItem = () => { const NewWorkflowMenuItem = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const cancelRef = useRef<HTMLButtonElement | null>(null); const cancelRef = useRef<HTMLButtonElement | null>(null);
const isTouched = useAppSelector((state) => state.workflow.isTouched);
const handleConfirmClear = useCallback(() => { const handleNewWorkflow = useCallback(() => {
dispatch(nodeEditorReset()); dispatch(nodeEditorReset());
dispatch( dispatch(
addToast( addToast(
makeToast({ makeToast({
title: t('workflows.workflowEditorReset'), title: t('workflows.newWorkflowCreated'),
status: 'success', status: 'success',
}) })
) )
); );
onClose(); onClose();
}, [dispatch, t, onClose]); }, [dispatch, onClose, t]);
const onClick = useCallback(() => {
if (!isTouched) {
handleNewWorkflow();
return;
}
onOpen();
}, [handleNewWorkflow, isTouched, onOpen]);
return ( return (
<> <>
<MenuItem <MenuItem as="button" icon={<FaCircleNodes />} onClick={onClick}>
as="button" {t('nodes.newWorkflow')}
icon={<FaTrash />}
sx={{ color: 'error.600', _dark: { color: 'error.300' } }}
onClick={onOpen}
>
{t('nodes.resetWorkflow')}
</MenuItem> </MenuItem>
<AlertDialog <AlertDialog
@ -61,13 +65,13 @@ const ResetWorkflowEditorMenuItem = () => {
<AlertDialogContent> <AlertDialogContent>
<AlertDialogHeader fontSize="lg" fontWeight="bold"> <AlertDialogHeader fontSize="lg" fontWeight="bold">
{t('nodes.resetWorkflow')} {t('nodes.newWorkflow')}
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogBody py={4}> <AlertDialogBody py={4}>
<Flex flexDir="column" gap={2}> <Flex flexDir="column" gap={2}>
<Text>{t('nodes.resetWorkflowDesc')}</Text> <Text>{t('nodes.newWorkflowDesc')}</Text>
<Text variant="subtext">{t('nodes.resetWorkflowDesc2')}</Text> <Text variant="subtext">{t('nodes.newWorkflowDesc2')}</Text>
</Flex> </Flex>
</AlertDialogBody> </AlertDialogBody>
@ -75,7 +79,7 @@ const ResetWorkflowEditorMenuItem = () => {
<Button ref={cancelRef} onClick={onClose}> <Button ref={cancelRef} onClick={onClose}>
{t('common.cancel')} {t('common.cancel')}
</Button> </Button>
<Button colorScheme="error" ml={3} onClick={handleConfirmClear}> <Button colorScheme="error" ml={3} onClick={handleNewWorkflow}>
{t('common.accept')} {t('common.accept')}
</Button> </Button>
</AlertDialogFooter> </AlertDialogFooter>
@ -85,4 +89,4 @@ const ResetWorkflowEditorMenuItem = () => {
); );
}; };
export default memo(ResetWorkflowEditorMenuItem); export default memo(NewWorkflowMenuItem);

View File

@ -9,7 +9,7 @@ import IAIIconButton from 'common/components/IAIIconButton';
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger'; import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import DownloadWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/DownloadWorkflowMenuItem'; import DownloadWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/DownloadWorkflowMenuItem';
import ResetWorkflowEditorMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/ResetWorkflowEditorMenuItem'; import NewWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/NewWorkflowMenuItem';
import SaveWorkflowAsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowAsMenuItem'; import SaveWorkflowAsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowAsMenuItem';
import SaveWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowMenuItem'; import SaveWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowMenuItem';
import SettingsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SettingsMenuItem'; import SettingsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SettingsMenuItem';
@ -39,7 +39,7 @@ const WorkflowLibraryMenu = () => {
{isWorkflowLibraryEnabled && <SaveWorkflowAsMenuItem />} {isWorkflowLibraryEnabled && <SaveWorkflowAsMenuItem />}
<DownloadWorkflowMenuItem /> <DownloadWorkflowMenuItem />
<UploadWorkflowMenuItem /> <UploadWorkflowMenuItem />
<ResetWorkflowEditorMenuItem /> <NewWorkflowMenuItem />
<MenuDivider /> <MenuDivider />
<SettingsMenuItem /> <SettingsMenuItem />
</MenuList> </MenuList>

View File

@ -101,6 +101,8 @@ plugins:
extra_javascript: extra_javascript:
- https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js - https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js
- javascripts/tablesort.js - javascripts/tablesort.js
- https://widget.kapa.ai/kapa-widget.bundle.js
- javascript/init_kapa_widget.js
extra: extra:
analytics: analytics: