mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into simplify-docker-compose-setup
This commit is contained in:
commit
351078e8aa
6
.github/workflows/lint-frontend.yml
vendored
6
.github/workflows/lint-frontend.yml
vendored
@ -21,16 +21,16 @@ jobs:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Setup Node 20
|
||||
- name: Setup Node 18
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
node-version: '18'
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
version: '8.12.1'
|
||||
- name: Install dependencies
|
||||
run: 'pnpm install --prefer-frozen-lockfile'
|
||||
- name: Typescript
|
||||
|
50
.github/workflows/pypi-release.yml
vendored
50
.github/workflows/pypi-release.yml
vendored
@ -1,13 +1,15 @@
|
||||
name: PyPI Release
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'invokeai/version/invokeai_version.py'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
publish_package:
|
||||
description: 'Publish build on PyPi? [true/false]'
|
||||
required: true
|
||||
default: 'false'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
build-and-release:
|
||||
if: github.repository == 'invoke-ai/InvokeAI'
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
@ -15,19 +17,43 @@ jobs:
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
||||
TWINE_NON_INTERACTIVE: 1
|
||||
steps:
|
||||
- name: checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
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
|
||||
|
||||
- name: build package
|
||||
- name: Build python package
|
||||
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/*
|
||||
|
||||
- name: check PyPI versions
|
||||
- name: Check PyPI versions
|
||||
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
|
||||
run: |
|
||||
pip install --upgrade requests
|
||||
@ -36,6 +62,6 @@ jobs:
|
||||
EXISTS=scripts.pypi_helper.local_on_pypi(); \
|
||||
print(f'PACKAGE_EXISTS={EXISTS}')" >> $GITHUB_ENV
|
||||
|
||||
- name: upload package
|
||||
if: env.PACKAGE_EXISTS == 'False' && env.TWINE_PASSWORD != ''
|
||||
- name: Publish build on PyPi
|
||||
if: env.PACKAGE_EXISTS == 'False' && env.TWINE_PASSWORD != '' && github.event.inputs.publish_package == 'true'
|
||||
run: twine upload dist/*
|
||||
|
10
docs/javascripts/init_kapa_widget.js
Normal file
10
docs/javascripts/init_kapa_widget.js
Normal 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);
|
||||
});
|
@ -91,9 +91,11 @@ rm -rf InvokeAI-Installer
|
||||
|
||||
# copy content
|
||||
mkdir InvokeAI-Installer
|
||||
for f in templates lib *.txt *.reg; do
|
||||
for f in templates *.txt *.reg; do
|
||||
cp -r ${f} InvokeAI-Installer/
|
||||
done
|
||||
mkdir InvokeAI-Installer/lib
|
||||
cp lib/*.py InvokeAI-Installer/lib
|
||||
|
||||
# Move the wheel
|
||||
mv dist/*.whl InvokeAI-Installer/lib/
|
||||
@ -111,6 +113,6 @@ cp WinLongPathsEnabled.reg InvokeAI-Installer/
|
||||
zip -r InvokeAI-installer-$VERSION.zip InvokeAI-Installer
|
||||
|
||||
# clean up
|
||||
rm -rf InvokeAI-Installer tmp dist
|
||||
rm -rf InvokeAI-Installer tmp dist ../invokeai/frontend/web/dist/
|
||||
|
||||
exit 0
|
||||
|
@ -45,6 +45,9 @@ async def list_model_records(
|
||||
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_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:
|
||||
"""Get a list of models."""
|
||||
record_store = ApiDependencies.invoker.services.model_records
|
||||
@ -52,10 +55,14 @@ async def list_model_records(
|
||||
if base_models:
|
||||
for base_model in base_models:
|
||||
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:
|
||||
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)
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@ from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
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):
|
||||
@ -106,6 +106,7 @@ class ModelRecordServiceBase(ABC):
|
||||
model_name: Optional[str] = None,
|
||||
base_model: Optional[BaseModelType] = None,
|
||||
model_type: Optional[ModelType] = None,
|
||||
model_format: Optional[ModelFormat] = None,
|
||||
) -> List[AnyModelConfig]:
|
||||
"""
|
||||
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 base_model: Filter by base 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
|
||||
models in the database.
|
||||
|
@ -49,6 +49,7 @@ from invokeai.backend.model_manager.config import (
|
||||
AnyModelConfig,
|
||||
BaseModelType,
|
||||
ModelConfigFactory,
|
||||
ModelFormat,
|
||||
ModelType,
|
||||
)
|
||||
|
||||
@ -225,6 +226,7 @@ class ModelRecordServiceSQL(ModelRecordServiceBase):
|
||||
model_name: Optional[str] = None,
|
||||
base_model: Optional[BaseModelType] = None,
|
||||
model_type: Optional[ModelType] = None,
|
||||
model_format: Optional[ModelFormat] = None,
|
||||
) -> List[AnyModelConfig]:
|
||||
"""
|
||||
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 base_model: Filter by base 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
|
||||
models in the database.
|
||||
@ -248,6 +251,9 @@ class ModelRecordServiceSQL(ModelRecordServiceBase):
|
||||
if model_type:
|
||||
where_clause.append("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 ""
|
||||
with self._db.lock:
|
||||
self._cursor.execute(
|
||||
|
@ -9,7 +9,7 @@ def lora_token_vector_length(checkpoint: dict) -> int:
|
||||
: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
|
||||
|
||||
if "." not in key:
|
||||
@ -57,6 +57,10 @@ def lora_token_vector_length(checkpoint: dict) -> int:
|
||||
for key, tensor in checkpoint.items():
|
||||
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)
|
||||
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:
|
||||
tmp_length = _get_shape_1(key, tensor, checkpoint)
|
||||
if key.startswith("lora_te_"):
|
||||
|
@ -400,6 +400,8 @@ class LoRACheckpointProbe(CheckpointProbeBase):
|
||||
return BaseModelType.StableDiffusion1
|
||||
elif token_vector_length == 1024:
|
||||
return BaseModelType.StableDiffusion2
|
||||
elif token_vector_length == 1280:
|
||||
return BaseModelType.StableDiffusionXL # recognizes format at https://civitai.com/models/224641
|
||||
elif token_vector_length == 2048:
|
||||
return BaseModelType.StableDiffusionXL
|
||||
else:
|
||||
|
@ -950,9 +950,9 @@
|
||||
"problemSettingTitle": "Problem Setting Title",
|
||||
"reloadNodeTemplates": "Reload Node Templates",
|
||||
"removeLinearView": "Remove from Linear View",
|
||||
"resetWorkflow": "Reset Workflow Editor",
|
||||
"resetWorkflowDesc": "Are you sure you want to reset the Workflow Editor?",
|
||||
"resetWorkflowDesc2": "Resetting the Workflow Editor will clear all nodes, edges and workflow details. Saved workflows will not be affected.",
|
||||
"newWorkflow": "New Workflow",
|
||||
"newWorkflowDesc": "Create a new workflow?",
|
||||
"newWorkflowDesc2": "Your current workflow has unsaved changes.",
|
||||
"scheduler": "Scheduler",
|
||||
"schedulerDescription": "TODO",
|
||||
"sDXLMainModelField": "SDXL Model",
|
||||
@ -1634,10 +1634,10 @@
|
||||
"userWorkflows": "My Workflows",
|
||||
"defaultWorkflows": "Default Workflows",
|
||||
"openWorkflow": "Open Workflow",
|
||||
"uploadWorkflow": "Upload Workflow",
|
||||
"uploadWorkflow": "Load from File",
|
||||
"deleteWorkflow": "Delete Workflow",
|
||||
"unnamedWorkflow": "Unnamed Workflow",
|
||||
"downloadWorkflow": "Download Workflow",
|
||||
"downloadWorkflow": "Save to File",
|
||||
"saveWorkflow": "Save Workflow",
|
||||
"saveWorkflowAs": "Save Workflow As",
|
||||
"savingWorkflow": "Saving Workflow...",
|
||||
@ -1652,7 +1652,7 @@
|
||||
"searchWorkflows": "Search Workflows",
|
||||
"clearWorkflowSearchFilter": "Clear Workflow Search Filter",
|
||||
"workflowName": "Workflow Name",
|
||||
"workflowEditorReset": "Workflow Editor Reset",
|
||||
"newWorkflowCreated": "New Workflow Created",
|
||||
"workflowEditorMenu": "Workflow Editor Menu",
|
||||
"workflowIsOpen": "Workflow is Open"
|
||||
},
|
||||
|
@ -727,9 +727,6 @@
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
@ -898,11 +898,8 @@
|
||||
"zoomInNodes": "Ingrandire",
|
||||
"fitViewportNodes": "Adatta vista",
|
||||
"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",
|
||||
"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",
|
||||
"scheduler": "Campionatore",
|
||||
"addNode": "Aggiungi nodo",
|
||||
@ -1619,7 +1616,6 @@
|
||||
"saveWorkflow": "Salva flusso di lavoro",
|
||||
"openWorkflow": "Apri flusso di lavoro",
|
||||
"clearWorkflowSearchFilter": "Cancella il filtro di ricerca del flusso di lavoro",
|
||||
"workflowEditorReset": "Reimpostazione dell'editor del flusso di lavoro",
|
||||
"workflowLibrary": "Libreria",
|
||||
"noRecentWorkflows": "Nessun flusso di lavoro recente",
|
||||
"workflowSaved": "Flusso di lavoro salvato",
|
||||
|
@ -844,9 +844,6 @@
|
||||
"hideLegendNodes": "Typelegende veld verbergen",
|
||||
"reloadNodeTemplates": "Herlaad knooppuntsjablonen",
|
||||
"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",
|
||||
"booleanPolymorphicDescription": "Een verzameling Booleanse waarden.",
|
||||
"scheduler": "Planner",
|
||||
|
@ -909,9 +909,6 @@
|
||||
"hideLegendNodes": "Скрыть тип поля",
|
||||
"showMinimapnodes": "Показать миникарту",
|
||||
"loadWorkflow": "Загрузить рабочий процесс",
|
||||
"resetWorkflowDesc2": "Сброс рабочего процесса очистит все узлы, ребра и детали рабочего процесса.",
|
||||
"resetWorkflow": "Сбросить рабочий процесс",
|
||||
"resetWorkflowDesc": "Вы уверены, что хотите сбросить этот рабочий процесс?",
|
||||
"reloadNodeTemplates": "Перезагрузить шаблоны узлов",
|
||||
"downloadWorkflow": "Скачать JSON рабочего процесса",
|
||||
"booleanPolymorphicDescription": "Коллекция логических значений.",
|
||||
@ -1599,7 +1596,6 @@
|
||||
"saveWorkflow": "Сохранить рабочий процесс",
|
||||
"openWorkflow": "Открытый рабочий процесс",
|
||||
"clearWorkflowSearchFilter": "Очистить фильтр поиска рабочих процессов",
|
||||
"workflowEditorReset": "Сброс редактора рабочих процессов",
|
||||
"workflowLibrary": "Библиотека",
|
||||
"downloadWorkflow": "Скачать рабочий процесс",
|
||||
"noRecentWorkflows": "Нет недавних рабочих процессов",
|
||||
|
@ -892,11 +892,8 @@
|
||||
},
|
||||
"nodes": {
|
||||
"zoomInNodes": "放大",
|
||||
"resetWorkflowDesc": "是否确定要重置工作流编辑器?",
|
||||
"resetWorkflow": "重置工作流编辑器",
|
||||
"loadWorkflow": "加载工作流",
|
||||
"zoomOutNodes": "缩小",
|
||||
"resetWorkflowDesc2": "重置工作流编辑器将清除所有节点、边际和节点图详情。不影响已保存的工作流。",
|
||||
"reloadNodeTemplates": "重载节点模板",
|
||||
"hideGraphNodes": "隐藏节点图信息",
|
||||
"fitViewportNodes": "自适应视图",
|
||||
@ -1637,7 +1634,6 @@
|
||||
"saveWorkflow": "保存工作流",
|
||||
"openWorkflow": "打开工作流",
|
||||
"clearWorkflowSearchFilter": "清除工作流检索过滤器",
|
||||
"workflowEditorReset": "工作流编辑器重置",
|
||||
"workflowLibrary": "工作流库",
|
||||
"downloadWorkflow": "下载工作流",
|
||||
"noRecentWorkflows": "无最近工作流",
|
||||
|
@ -144,6 +144,7 @@ export const buildCanvasImageToImageGraph = (
|
||||
type: 'l2i',
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
@ -255,6 +256,7 @@ export const buildCanvasImageToImageGraph = (
|
||||
is_intermediate,
|
||||
width: width,
|
||||
height: height,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
graph.edges.push(
|
||||
@ -295,6 +297,7 @@ export const buildCanvasImageToImageGraph = (
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
fp32,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image =
|
||||
|
@ -191,6 +191,7 @@ export const buildCanvasInpaintGraph = (
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
reference: canvasInitImage,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -199,6 +199,7 @@ export const buildCanvasOutpaintGraph = (
|
||||
type: 'color_correct',
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -266,6 +266,7 @@ export const buildCanvasSDXLImageToImageGraph = (
|
||||
is_intermediate,
|
||||
width: width,
|
||||
height: height,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
graph.edges.push(
|
||||
@ -306,6 +307,7 @@ export const buildCanvasSDXLImageToImageGraph = (
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
fp32,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
(graph.nodes[IMAGE_TO_LATENTS] as ImageToLatentsInvocation).image =
|
||||
|
@ -196,6 +196,7 @@ export const buildCanvasSDXLInpaintGraph = (
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
reference: canvasInitImage,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -204,6 +204,7 @@ export const buildCanvasSDXLOutpaintGraph = (
|
||||
type: 'color_correct',
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -258,6 +258,7 @@ export const buildCanvasSDXLTextToImageGraph = (
|
||||
is_intermediate,
|
||||
width: width,
|
||||
height: height,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
graph.edges.push(
|
||||
@ -288,6 +289,7 @@ export const buildCanvasSDXLTextToImageGraph = (
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
fp32,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
graph.edges.push({
|
||||
|
@ -246,6 +246,7 @@ export const buildCanvasTextToImageGraph = (
|
||||
is_intermediate,
|
||||
width: width,
|
||||
height: height,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
graph.edges.push(
|
||||
@ -276,6 +277,7 @@ export const buildCanvasTextToImageGraph = (
|
||||
id: CANVAS_OUTPUT,
|
||||
is_intermediate,
|
||||
fp32,
|
||||
use_cache: false,
|
||||
};
|
||||
|
||||
graph.edges.push({
|
||||
|
@ -143,6 +143,7 @@ export const buildLinearImageToImageGraph = (
|
||||
// },
|
||||
fp32,
|
||||
is_intermediate,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -154,6 +154,7 @@ export const buildLinearSDXLImageToImageGraph = (
|
||||
// },
|
||||
fp32,
|
||||
is_intermediate,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -127,6 +127,7 @@ export const buildLinearSDXLTextToImageGraph = (
|
||||
id: LATENTS_TO_IMAGE,
|
||||
fp32,
|
||||
is_intermediate,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -146,6 +146,7 @@ export const buildLinearTextToImageGraph = (
|
||||
id: LATENTS_TO_IMAGE,
|
||||
fp32,
|
||||
is_intermediate,
|
||||
use_cache: false,
|
||||
},
|
||||
},
|
||||
edges: [
|
||||
|
@ -11,44 +11,48 @@ import {
|
||||
Text,
|
||||
useDisclosure,
|
||||
} 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 { addToast } from 'features/system/store/systemSlice';
|
||||
import { makeToast } from 'features/system/util/makeToast';
|
||||
import { memo, useCallback, useRef } from 'react';
|
||||
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 dispatch = useAppDispatch();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const cancelRef = useRef<HTMLButtonElement | null>(null);
|
||||
const isTouched = useAppSelector((state) => state.workflow.isTouched);
|
||||
|
||||
const handleConfirmClear = useCallback(() => {
|
||||
const handleNewWorkflow = useCallback(() => {
|
||||
dispatch(nodeEditorReset());
|
||||
|
||||
dispatch(
|
||||
addToast(
|
||||
makeToast({
|
||||
title: t('workflows.workflowEditorReset'),
|
||||
title: t('workflows.newWorkflowCreated'),
|
||||
status: 'success',
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
onClose();
|
||||
}, [dispatch, t, onClose]);
|
||||
}, [dispatch, onClose, t]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
if (!isTouched) {
|
||||
handleNewWorkflow();
|
||||
return;
|
||||
}
|
||||
onOpen();
|
||||
}, [handleNewWorkflow, isTouched, onOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem
|
||||
as="button"
|
||||
icon={<FaTrash />}
|
||||
sx={{ color: 'error.600', _dark: { color: 'error.300' } }}
|
||||
onClick={onOpen}
|
||||
>
|
||||
{t('nodes.resetWorkflow')}
|
||||
<MenuItem as="button" icon={<FaCircleNodes />} onClick={onClick}>
|
||||
{t('nodes.newWorkflow')}
|
||||
</MenuItem>
|
||||
|
||||
<AlertDialog
|
||||
@ -61,13 +65,13 @@ const ResetWorkflowEditorMenuItem = () => {
|
||||
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
||||
{t('nodes.resetWorkflow')}
|
||||
{t('nodes.newWorkflow')}
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogBody py={4}>
|
||||
<Flex flexDir="column" gap={2}>
|
||||
<Text>{t('nodes.resetWorkflowDesc')}</Text>
|
||||
<Text variant="subtext">{t('nodes.resetWorkflowDesc2')}</Text>
|
||||
<Text>{t('nodes.newWorkflowDesc')}</Text>
|
||||
<Text variant="subtext">{t('nodes.newWorkflowDesc2')}</Text>
|
||||
</Flex>
|
||||
</AlertDialogBody>
|
||||
|
||||
@ -75,7 +79,7 @@ const ResetWorkflowEditorMenuItem = () => {
|
||||
<Button ref={cancelRef} onClick={onClose}>
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button colorScheme="error" ml={3} onClick={handleConfirmClear}>
|
||||
<Button colorScheme="error" ml={3} onClick={handleNewWorkflow}>
|
||||
{t('common.accept')}
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
@ -85,4 +89,4 @@ const ResetWorkflowEditorMenuItem = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ResetWorkflowEditorMenuItem);
|
||||
export default memo(NewWorkflowMenuItem);
|
@ -9,7 +9,7 @@ import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
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 SaveWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowMenuItem';
|
||||
import SettingsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SettingsMenuItem';
|
||||
@ -39,7 +39,7 @@ const WorkflowLibraryMenu = () => {
|
||||
{isWorkflowLibraryEnabled && <SaveWorkflowAsMenuItem />}
|
||||
<DownloadWorkflowMenuItem />
|
||||
<UploadWorkflowMenuItem />
|
||||
<ResetWorkflowEditorMenuItem />
|
||||
<NewWorkflowMenuItem />
|
||||
<MenuDivider />
|
||||
<SettingsMenuItem />
|
||||
</MenuList>
|
||||
|
@ -101,6 +101,8 @@ plugins:
|
||||
extra_javascript:
|
||||
- https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js
|
||||
- javascripts/tablesort.js
|
||||
- https://widget.kapa.ai/kapa-widget.bundle.js
|
||||
- javascript/init_kapa_widget.js
|
||||
|
||||
extra:
|
||||
analytics:
|
||||
|
Loading…
Reference in New Issue
Block a user