From 569ae7c482a6d8889d49ba8be93f759454edf574 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Wed, 13 Dec 2023 15:59:21 -0500 Subject: [PATCH 01/14] add ability to filter model listings by format --- invokeai/app/api/routers/model_records.py | 5 +++-- invokeai/app/services/model_records/model_records_base.py | 4 +++- invokeai/app/services/model_records/model_records_sql.py | 6 ++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/invokeai/app/api/routers/model_records.py b/invokeai/app/api/routers/model_records.py index 997f76a185..8d029db422 100644 --- a/invokeai/app/api/routers/model_records.py +++ b/invokeai/app/api/routers/model_records.py @@ -45,6 +45,7 @@ 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 +53,10 @@ 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) diff --git a/invokeai/app/services/model_records/model_records_base.py b/invokeai/app/services/model_records/model_records_base.py index 679d05fccd..ae0e633990 100644 --- a/invokeai/app/services/model_records/model_records_base.py +++ b/invokeai/app/services/model_records/model_records_base.py @@ -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. diff --git a/invokeai/app/services/model_records/model_records_sql.py b/invokeai/app/services/model_records/model_records_sql.py index 08956a960f..a8e777cf64 100644 --- a/invokeai/app/services/model_records/model_records_sql.py +++ b/invokeai/app/services/model_records/model_records_sql.py @@ -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( From b935768eeb4ab524e03b97ac29757d815e59ba73 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:28:47 -0500 Subject: [PATCH 02/14] Update mkdocs.yml --- mkdocs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index d030e3d6fc..7c67a2777a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -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: From 42c04db1675ef7339596aa50e4af4cbe53485b05 Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Wed, 13 Dec 2023 22:33:50 -0500 Subject: [PATCH 03/14] adding kapa widget to docs --- docs/javascripts/init_kapa_widget.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 docs/javascripts/init_kapa_widget.js diff --git a/docs/javascripts/init_kapa_widget.js b/docs/javascripts/init_kapa_widget.js new file mode 100644 index 0000000000..f22e276b5a --- /dev/null +++ b/docs/javascripts/init_kapa_widget.js @@ -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); +}); From 6ea09ba0b6101b5c0be09d4129c253c8d44f464e Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Thu, 14 Dec 2023 19:55:47 +1100 Subject: [PATCH 04/14] feat(ui): workflow menu tweaks - "Reset Workflow Editor" -> "New Workflow" - "New Workflow" gets nodes icon & is no longer danger coloured - When creating a new workflow, if the current workflow has unsaved changes, you get a dialog asking for confirmation. If the current workflow is saved, it immediately creates a new workflow. - "Download Workflow" -> "Save to File" - "Upload Workflow" -> "Load from File" - Moved "Load from File" up 1 in the menu --- invokeai/frontend/web/public/locales/en.json | 12 +++--- ...orMenuItem.tsx => NewWorkflowMenuItem.tsx} | 40 ++++++++++--------- .../WorkflowLibraryMenu.tsx | 4 +- 3 files changed, 30 insertions(+), 26 deletions(-) rename invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/{ResetWorkflowEditorMenuItem.tsx => NewWorkflowMenuItem.tsx} (63%) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index ec257ee044..f5f3f434f5 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -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" }, diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/ResetWorkflowEditorMenuItem.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/NewWorkflowMenuItem.tsx similarity index 63% rename from invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/ResetWorkflowEditorMenuItem.tsx rename to invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/NewWorkflowMenuItem.tsx index 5d7e58e198..c4497c5ddb 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/ResetWorkflowEditorMenuItem.tsx +++ b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/NewWorkflowMenuItem.tsx @@ -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(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 ( <> - } - sx={{ color: 'error.600', _dark: { color: 'error.300' } }} - onClick={onOpen} - > - {t('nodes.resetWorkflow')} + } onClick={onClick}> + {t('nodes.newWorkflow')} { - {t('nodes.resetWorkflow')} + {t('nodes.newWorkflow')} - {t('nodes.resetWorkflowDesc')} - {t('nodes.resetWorkflowDesc2')} + {t('nodes.newWorkflowDesc')} + {t('nodes.newWorkflowDesc2')} @@ -75,7 +79,7 @@ const ResetWorkflowEditorMenuItem = () => { - @@ -85,4 +89,4 @@ const ResetWorkflowEditorMenuItem = () => { ); }; -export default memo(ResetWorkflowEditorMenuItem); +export default memo(NewWorkflowMenuItem); diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx index a19b9cd6b5..c07bb8f5cd 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx +++ b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu.tsx @@ -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 && } - + From 264ea6d94d3593bd9a67f9b30ab313e293e17319 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 14 Dec 2023 23:54:59 -0500 Subject: [PATCH 05/14] fix ruff errors --- invokeai/app/api/routers/model_records.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/invokeai/app/api/routers/model_records.py b/invokeai/app/api/routers/model_records.py index 8d029db422..934a7d15b3 100644 --- a/invokeai/app/api/routers/model_records.py +++ b/invokeai/app/api/routers/model_records.py @@ -45,7 +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')"), + 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 @@ -53,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, model_format=model_format) + 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, model_format=model_format)) + 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) From ac3cf48d7fb6d762d8b42e2b34c0d29e2fa48c6f Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 14 Dec 2023 22:52:50 -0500 Subject: [PATCH 06/14] make probe recognize lora format at https://civitai.com/models/224641 --- invokeai/backend/model_management/util.py | 6 +++++- invokeai/backend/model_manager/probe.py | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/invokeai/backend/model_management/util.py b/invokeai/backend/model_management/util.py index 6d70107c93..441467a4c7 100644 --- a/invokeai/backend/model_management/util.py +++ b/invokeai/backend/model_management/util.py @@ -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 work + 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_"): diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 3ba62fa6ff..25120e2e33 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -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 work elif token_vector_length == 2048: return BaseModelType.StableDiffusionXL else: From 212dbaf9a2b3b3cf6d5bbf7204feeafacb40c56f Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 14 Dec 2023 23:04:13 -0500 Subject: [PATCH 07/14] fix comment --- invokeai/backend/model_management/util.py | 2 +- invokeai/backend/model_manager/probe.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/backend/model_management/util.py b/invokeai/backend/model_management/util.py index 441467a4c7..f4737d9f0b 100644 --- a/invokeai/backend/model_management/util.py +++ b/invokeai/backend/model_management/util.py @@ -59,7 +59,7 @@ def lora_token_vector_length(checkpoint: dict) -> int: 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 work + ): # 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) diff --git a/invokeai/backend/model_manager/probe.py b/invokeai/backend/model_manager/probe.py index 25120e2e33..64eefb774e 100644 --- a/invokeai/backend/model_manager/probe.py +++ b/invokeai/backend/model_manager/probe.py @@ -401,7 +401,7 @@ class LoRACheckpointProbe(CheckpointProbeBase): elif token_vector_length == 1024: return BaseModelType.StableDiffusion2 elif token_vector_length == 1280: - return BaseModelType.StableDiffusionXL # recognizes format at https://civitai.com/models/224641 work + return BaseModelType.StableDiffusionXL # recognizes format at https://civitai.com/models/224641 elif token_vector_length == 2048: return BaseModelType.StableDiffusionXL else: From b2a8c45553639650eeccd212042eae6178cd6e7a Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 15 Dec 2023 23:56:31 +1100 Subject: [PATCH 08/14] fix: build frontend in pypi-release workflow This was missing, resulting in the 3.5.0rc1 having no frontend. --- .github/workflows/pypi-release.yml | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 5b7d2cd2fa..452454b072 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -15,19 +15,35 @@ 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 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: Install frontend dependencies + run: pnpm install --prefer-frozen-lockfile + + - name: Build frontend + run: pnpm run build + + - name: Install python dependencies run: pip install --upgrade build twine - - name: build package + - name: Build package run: python3 -m build - - name: check distribution + - 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 +52,6 @@ jobs: EXISTS=scripts.pypi_helper.local_on_pypi(); \ print(f'PACKAGE_EXISTS={EXISTS}')" >> $GITHUB_ENV - - name: upload package + - name: Upload package if: env.PACKAGE_EXISTS == 'False' && env.TWINE_PASSWORD != '' run: twine upload dist/* From 1615df3aa160296d0ba6e54d8082efe3a7582622 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 16 Dec 2023 00:32:31 +1100 Subject: [PATCH 09/14] fix: use node 18, set working directory - Node 20 has a problem with `pnpm`; set it to Node 18 - Set the working directory for the frontend commands --- .github/workflows/lint-frontend.yml | 6 +++--- .github/workflows/pypi-release.yml | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lint-frontend.yml b/.github/workflows/lint-frontend.yml index 3b354d1003..a4e1bba428 100644 --- a/.github/workflows/lint-frontend.yml +++ b/.github/workflows/lint-frontend.yml @@ -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 diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 452454b072..32648cfc57 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -18,21 +18,23 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node 20 + - name: Setup Node 18 uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '18' - name: Setup pnpm uses: pnpm/action-setup@v2 with: - version: 8 + 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 From 3f970c8326244d653a0b0acaf9c351a969593f9f Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Fri, 15 Dec 2023 11:27:21 -0500 Subject: [PATCH 10/14] Don't copy extraneous paths into installer .zip --- installer/create_installer.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/installer/create_installer.sh b/installer/create_installer.sh index ed8cbb0d0a..722fe5771a 100755 --- a/installer/create_installer.sh +++ b/installer/create_installer.sh @@ -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/ From df9a903a509e7a9d3243f983e3645d673095ef39 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 16 Dec 2023 11:51:34 +1100 Subject: [PATCH 11/14] fix(ui): do not cache VAE decode on linear The VAE decode on linear graphs was getting cached. This caused some unexpected behaviour around image outputs. For example, say you ran the exact same graph twice. The first time, you get an image written to disk and added to gallery. The second time, the VAE decode is cached and no image file is created. But, the UI still gets the graph complete event and selects the first image in the gallery. The second run does not add an image to the gallery. There are probbably edge cases related to this - the UI does not expect this to happen. I'm not sure how to handle it any better in the UI. The solution is to not cache VAE decode on the linear graphs, ever. If you run a graph twice in linear, you expect two images. This simple change disables the node cache for terminal VAE decode nodes in all linear graphs, ensuring you always get images. If they graph was fully cached, all images after the first will be created very quickly of course. --- .../features/nodes/util/graph/buildCanvasImageToImageGraph.ts | 3 +++ .../src/features/nodes/util/graph/buildCanvasInpaintGraph.ts | 1 + .../src/features/nodes/util/graph/buildCanvasOutpaintGraph.ts | 1 + .../nodes/util/graph/buildCanvasSDXLImageToImageGraph.ts | 2 ++ .../features/nodes/util/graph/buildCanvasSDXLInpaintGraph.ts | 1 + .../features/nodes/util/graph/buildCanvasSDXLOutpaintGraph.ts | 1 + .../nodes/util/graph/buildCanvasSDXLTextToImageGraph.ts | 2 ++ .../features/nodes/util/graph/buildCanvasTextToImageGraph.ts | 2 ++ .../features/nodes/util/graph/buildLinearImageToImageGraph.ts | 1 + .../nodes/util/graph/buildLinearSDXLImageToImageGraph.ts | 1 + .../nodes/util/graph/buildLinearSDXLTextToImageGraph.ts | 1 + .../features/nodes/util/graph/buildLinearTextToImageGraph.ts | 1 + 12 files changed, 17 insertions(+) diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasImageToImageGraph.ts index 978e6bfaaa..f8d29ffa1d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasImageToImageGraph.ts @@ -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 = diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasInpaintGraph.ts index 6253ce1f18..a05c46ad09 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasInpaintGraph.ts @@ -191,6 +191,7 @@ export const buildCanvasInpaintGraph = ( id: CANVAS_OUTPUT, is_intermediate, reference: canvasInitImage, + use_cache: false, }, }, edges: [ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasOutpaintGraph.ts index 11573c21c2..dcbf563cf9 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasOutpaintGraph.ts @@ -199,6 +199,7 @@ export const buildCanvasOutpaintGraph = ( type: 'color_correct', id: CANVAS_OUTPUT, is_intermediate, + use_cache: false, }, }, edges: [ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLImageToImageGraph.ts index 73c03ee98f..b023295646 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLImageToImageGraph.ts @@ -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 = diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLInpaintGraph.ts index de1dd0dfd2..10eecde0d9 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLInpaintGraph.ts @@ -196,6 +196,7 @@ export const buildCanvasSDXLInpaintGraph = ( id: CANVAS_OUTPUT, is_intermediate, reference: canvasInitImage, + use_cache: false, }, }, edges: [ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLOutpaintGraph.ts index 2f8b4fd653..7c75bea2be 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLOutpaintGraph.ts @@ -204,6 +204,7 @@ export const buildCanvasSDXLOutpaintGraph = ( type: 'color_correct', id: CANVAS_OUTPUT, is_intermediate, + use_cache: false, }, }, edges: [ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLTextToImageGraph.ts index 3ddff5a9a1..e91d556476 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasSDXLTextToImageGraph.ts @@ -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({ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasTextToImageGraph.ts index 95e5763449..933365ce23 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildCanvasTextToImageGraph.ts @@ -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({ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearImageToImageGraph.ts index 454c9f31a0..6b7b8f05c6 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearImageToImageGraph.ts @@ -143,6 +143,7 @@ export const buildLinearImageToImageGraph = ( // }, fp32, is_intermediate, + use_cache: false, }, }, edges: [ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLImageToImageGraph.ts index 6b1a55f7d0..d589116c17 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLImageToImageGraph.ts @@ -154,6 +154,7 @@ export const buildLinearSDXLImageToImageGraph = ( // }, fp32, is_intermediate, + use_cache: false, }, }, edges: [ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLTextToImageGraph.ts index bf01facf64..238a9054b1 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearSDXLTextToImageGraph.ts @@ -127,6 +127,7 @@ export const buildLinearSDXLTextToImageGraph = ( id: LATENTS_TO_IMAGE, fp32, is_intermediate, + use_cache: false, }, }, edges: [ diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearTextToImageGraph.ts index aea14c2fe4..487157c869 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildLinearTextToImageGraph.ts @@ -146,6 +146,7 @@ export const buildLinearTextToImageGraph = ( id: LATENTS_TO_IMAGE, fp32, is_intermediate, + use_cache: false, }, }, edges: [ From 4af1695c601d2d06da967c3f501969d062715895 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 14 Dec 2023 14:31:09 +0100 Subject: [PATCH 12/14] translationBot(ui): update translation files Updated by "Cleanup translation files" hook in Weblate. Co-authored-by: Hosted Weblate Translate-URL: https://hosted.weblate.org/projects/invokeai/web-ui/ Translation: InvokeAI/Web UI --- invokeai/frontend/web/public/locales/es.json | 3 --- invokeai/frontend/web/public/locales/it.json | 4 ---- invokeai/frontend/web/public/locales/nl.json | 3 --- invokeai/frontend/web/public/locales/ru.json | 4 ---- invokeai/frontend/web/public/locales/zh_CN.json | 4 ---- 5 files changed, 18 deletions(-) diff --git a/invokeai/frontend/web/public/locales/es.json b/invokeai/frontend/web/public/locales/es.json index 20c15f2698..4ce0072517 100644 --- a/invokeai/frontend/web/public/locales/es.json +++ b/invokeai/frontend/web/public/locales/es.json @@ -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" } } diff --git a/invokeai/frontend/web/public/locales/it.json b/invokeai/frontend/web/public/locales/it.json index c2eebedf77..b816858bd8 100644 --- a/invokeai/frontend/web/public/locales/it.json +++ b/invokeai/frontend/web/public/locales/it.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", diff --git a/invokeai/frontend/web/public/locales/nl.json b/invokeai/frontend/web/public/locales/nl.json index dfdfb54bd0..6be48de918 100644 --- a/invokeai/frontend/web/public/locales/nl.json +++ b/invokeai/frontend/web/public/locales/nl.json @@ -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", diff --git a/invokeai/frontend/web/public/locales/ru.json b/invokeai/frontend/web/public/locales/ru.json index 901d0520d5..665a821eb1 100644 --- a/invokeai/frontend/web/public/locales/ru.json +++ b/invokeai/frontend/web/public/locales/ru.json @@ -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": "Нет недавних рабочих процессов", diff --git a/invokeai/frontend/web/public/locales/zh_CN.json b/invokeai/frontend/web/public/locales/zh_CN.json index b29cf037d3..b0151b8e76 100644 --- a/invokeai/frontend/web/public/locales/zh_CN.json +++ b/invokeai/frontend/web/public/locales/zh_CN.json @@ -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": "无最近工作流", From 0f1c5f382a681552d7903d016bcddb9a5f15e26c Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 16 Dec 2023 19:39:29 +1100 Subject: [PATCH 13/14] feat(installer): delete frontend build after creating installer This prevents an empty `dist/` from breaking the app on startup. --- installer/create_installer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/create_installer.sh b/installer/create_installer.sh index 722fe5771a..b32f65d9bf 100755 --- a/installer/create_installer.sh +++ b/installer/create_installer.sh @@ -113,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 From 5bf61382a40923cc013edb1d4b94518517b25715 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 16 Dec 2023 20:02:09 +1100 Subject: [PATCH 14/14] feat: add python dist as release artifact, as input to enable publish to pypi - The release workflow never runs automatically. It must be manually kicked off. - The release workflow has an input. When running it from the GH actions UI, you will see a "Publish build on PyPi" prompt. If this value is "true", the workflow will upload the build to PyPi, releasing it. If this is anything else (e.g. "false", the default), the workflow will build but not upload to PyPi. - The `dist/` folder (where the python package is built) is uploaded as a workflow artifact as a zip file. This can be downloaded and inspected. This allows "dry" runs of the workflow. - The workflow job and some steps have been renamed to clarify what they do --- .github/workflows/pypi-release.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml index 32648cfc57..162cbe3427 100644 --- a/.github/workflows/pypi-release.yml +++ b/.github/workflows/pypi-release.yml @@ -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: @@ -39,9 +41,15 @@ jobs: - name: Install python dependencies run: pip install --upgrade build twine - - name: Build package + - name: Build python package run: python3 -m build + - name: Upload build as workflow artifact + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist + - name: Check distribution run: twine check dist/* @@ -54,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/*