From 653b820da1fec697fb1edb12fa8574942e0e709b Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:40:26 +1100 Subject: [PATCH 01/34] tidy(ui): clearer variable names in modelSelected listener --- .../listenerMiddleware/listeners/modelSelected.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts index 67a85cdc14..fae6925ad5 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts @@ -36,9 +36,9 @@ export const addModelSelectedListener = () => { const newModel = result.data; - const { base_model } = newModel; + const newBaseModel = newModel.base_model; const didBaseModelChange = - state.generation.model?.base_model !== base_model; + state.generation.model?.base_model !== newBaseModel; if (didBaseModelChange) { // we may need to reset some incompatible submodels @@ -46,7 +46,7 @@ export const addModelSelectedListener = () => { // handle incompatible loras forEach(state.lora.loras, (lora, id) => { - if (lora.base_model !== base_model) { + if (lora.base_model !== newBaseModel) { dispatch(loraRemoved(id)); modelsCleared += 1; } @@ -54,14 +54,14 @@ export const addModelSelectedListener = () => { // handle incompatible vae const { vae } = state.generation; - if (vae && vae.base_model !== base_model) { + if (vae && vae.base_model !== newBaseModel) { dispatch(vaeSelected(null)); modelsCleared += 1; } // handle incompatible controlnets selectControlAdapterAll(state.controlAdapters).forEach((ca) => { - if (ca.model?.base_model !== base_model) { + if (ca.model?.base_model !== newBaseModel) { dispatch( controlAdapterIsEnabledChanged({ id: ca.id, isEnabled: false }) ); From 022b32c7249ed7d09ac6956b5d33d203dd66f80f Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:41:14 +1100 Subject: [PATCH 02/34] fix(ui): reset clip skip to 0 if new model is sdxl Clip skip wasn't actually used in SDXL graphs so enabling it didn't do anything, just a UI quirk. Closes #5508 --- .../src/features/parameters/store/generationSlice.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 1a27aa2fd7..f9f61c074f 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -175,8 +175,15 @@ export const generationSlice = createSlice({ } // Clamp ClipSkip Based On Selected Model - const { maxClip } = CLIP_SKIP_MAP[newModel.base_model]; - state.clipSkip = clamp(state.clipSkip, 0, maxClip); + // TODO(psyche): remove this special handling when https://github.com/invoke-ai/InvokeAI/issues/4583 is resolved + // WIP PR here: https://github.com/invoke-ai/InvokeAI/pull/4624 + if (newModel.base_model === 'sdxl') { + // We don't support clip skip for SDXL yet - it's not in the graphs + state.clipSkip = 0; + } else { + const { maxClip } = CLIP_SKIP_MAP[newModel.base_model]; + state.clipSkip = clamp(state.clipSkip, 0, maxClip); + } if (action.meta.previousModel?.base_model === newModel.base_model) { // The base model hasn't changed, we don't need to optimize the size From b76d2cd7160ea97213c204eb61d20845117a88f8 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:58:30 +1100 Subject: [PATCH 03/34] fix(ui): handle base model compat when recalling parameters We had a one-behind issue with recalling metadata items that had a model. For example, when recalling LoRAs, we check against the current main model to decide whether or not the requested LoRA is compatible and may be recalled. When recalling all params, we are often also recalling the main model, but the compat logic didn't compare against this new main model. The logic is updated to check against the new main model, if one is being set. Closes #5512 --- .../parameters/hooks/useRecallParameters.ts | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts b/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts index b55ff546f1..d25c3aea77 100644 --- a/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts +++ b/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts @@ -47,6 +47,7 @@ import { vaeSelected, widthChanged, } from 'features/parameters/store/generationSlice'; +import type { ParameterModel } from 'features/parameters/types/parameterSchemas'; import { isParameterCFGRescaleMultiplier, isParameterCFGScale, @@ -480,7 +481,7 @@ export const useRecallParameters = () => { const { data: loraModels } = useGetLoRAModelsQuery(undefined); const prepareLoRAMetadataItem = useCallback( - (loraMetadataItem: LoRAMetadataItem) => { + (loraMetadataItem: LoRAMetadataItem, newModel?: ParameterModel) => { if (!isParameterLoRAModel(loraMetadataItem.lora)) { return { lora: null, error: 'Invalid LoRA model' }; } @@ -499,7 +500,7 @@ export const useRecallParameters = () => { } const isCompatibleBaseModel = - matchingLoRA?.base_model === model?.base_model; + matchingLoRA?.base_model === (newModel ?? model)?.base_model; if (!isCompatibleBaseModel) { return { @@ -510,7 +511,7 @@ export const useRecallParameters = () => { return { lora: matchingLoRA, error: null }; }, - [loraModels, model?.base_model] + [loraModels, model] ); const recallLoRA = useCallback( @@ -538,7 +539,10 @@ export const useRecallParameters = () => { const { data: controlNetModels } = useGetControlNetModelsQuery(undefined); const prepareControlNetMetadataItem = useCallback( - (controlnetMetadataItem: ControlNetMetadataItem) => { + ( + controlnetMetadataItem: ControlNetMetadataItem, + newModel?: ParameterModel + ) => { if (!isParameterControlNetModel(controlnetMetadataItem.control_model)) { return { controlnet: null, error: 'Invalid ControlNet model' }; } @@ -565,7 +569,7 @@ export const useRecallParameters = () => { } const isCompatibleBaseModel = - matchingControlNetModel?.base_model === model?.base_model; + matchingControlNetModel?.base_model === (newModel ?? model)?.base_model; if (!isCompatibleBaseModel) { return { @@ -600,7 +604,7 @@ export const useRecallParameters = () => { return { controlnet, error: null }; }, - [controlNetModels, model?.base_model] + [controlNetModels, model] ); const recallControlNet = useCallback( @@ -631,7 +635,10 @@ export const useRecallParameters = () => { const { data: t2iAdapterModels } = useGetT2IAdapterModelsQuery(undefined); const prepareT2IAdapterMetadataItem = useCallback( - (t2iAdapterMetadataItem: T2IAdapterMetadataItem) => { + ( + t2iAdapterMetadataItem: T2IAdapterMetadataItem, + newModel?: ParameterModel + ) => { if ( !isParameterControlNetModel(t2iAdapterMetadataItem.t2i_adapter_model) ) { @@ -659,7 +666,7 @@ export const useRecallParameters = () => { } const isCompatibleBaseModel = - matchingT2IAdapterModel?.base_model === model?.base_model; + matchingT2IAdapterModel?.base_model === (newModel ?? model)?.base_model; if (!isCompatibleBaseModel) { return { @@ -690,7 +697,7 @@ export const useRecallParameters = () => { return { t2iAdapter, error: null }; }, - [model?.base_model, t2iAdapterModels] + [model, t2iAdapterModels] ); const recallT2IAdapter = useCallback( @@ -721,7 +728,10 @@ export const useRecallParameters = () => { const { data: ipAdapterModels } = useGetIPAdapterModelsQuery(undefined); const prepareIPAdapterMetadataItem = useCallback( - (ipAdapterMetadataItem: IPAdapterMetadataItem) => { + ( + ipAdapterMetadataItem: IPAdapterMetadataItem, + newModel?: ParameterModel + ) => { if (!isParameterIPAdapterModel(ipAdapterMetadataItem?.ip_adapter_model)) { return { ipAdapter: null, error: 'Invalid IP Adapter model' }; } @@ -746,7 +756,7 @@ export const useRecallParameters = () => { } const isCompatibleBaseModel = - matchingIPAdapterModel?.base_model === model?.base_model; + matchingIPAdapterModel?.base_model === (newModel ?? model)?.base_model; if (!isCompatibleBaseModel) { return { @@ -768,7 +778,7 @@ export const useRecallParameters = () => { return { ipAdapter, error: null }; }, - [ipAdapterModels, model?.base_model] + [ipAdapterModels, model] ); const recallIPAdapter = useCallback( @@ -840,6 +850,13 @@ export const useRecallParameters = () => { t2iAdapters, } = metadata; + let newModel: ParameterModel | undefined = undefined; + + if (isParameterModel(model)) { + newModel = model; + dispatch(modelSelected(model)); + } + if (isParameterCFGScale(cfg_scale)) { dispatch(setCfgScale(cfg_scale)); } @@ -848,10 +865,6 @@ export const useRecallParameters = () => { dispatch(setCfgRescaleMultiplier(cfg_rescale_multiplier)); } - if (isParameterModel(model)) { - dispatch(modelSelected(model)); - } - if (isParameterPositivePrompt(positive_prompt)) { dispatch(setPositivePrompt(positive_prompt)); } @@ -953,7 +966,7 @@ export const useRecallParameters = () => { dispatch(lorasCleared()); loras?.forEach((lora) => { - const result = prepareLoRAMetadataItem(lora); + const result = prepareLoRAMetadataItem(lora, newModel); if (result.lora) { dispatch(loraRecalled({ ...result.lora, weight: lora.weight })); } @@ -961,21 +974,21 @@ export const useRecallParameters = () => { dispatch(controlAdaptersReset()); controlnets?.forEach((controlnet) => { - const result = prepareControlNetMetadataItem(controlnet); + const result = prepareControlNetMetadataItem(controlnet, newModel); if (result.controlnet) { dispatch(controlAdapterRecalled(result.controlnet)); } }); ipAdapters?.forEach((ipAdapter) => { - const result = prepareIPAdapterMetadataItem(ipAdapter); + const result = prepareIPAdapterMetadataItem(ipAdapter, newModel); if (result.ipAdapter) { dispatch(controlAdapterRecalled(result.ipAdapter)); } }); t2iAdapters?.forEach((t2iAdapter) => { - const result = prepareT2IAdapterMetadataItem(t2iAdapter); + const result = prepareT2IAdapterMetadataItem(t2iAdapter, newModel); if (result.t2iAdapter) { dispatch(controlAdapterRecalled(result.t2iAdapter)); } From 504bdac14a8a42b325a574cebaa316889fc614ec Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:26:05 +1100 Subject: [PATCH 04/34] tidy(ui): remove unused state from uiSlice --- invokeai/frontend/web/src/features/ui/store/uiSlice.ts | 8 -------- invokeai/frontend/web/src/features/ui/store/uiTypes.ts | 1 - 2 files changed, 9 deletions(-) diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index f39dbd4758..57b725ed06 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -10,7 +10,6 @@ export const initialUIState: UIState = { _version: 1, activeTab: 'txt2img', shouldShowImageDetails: false, - shouldShowExistingModelsInSearch: false, shouldHidePreview: false, shouldShowProgressInViewer: true, panels: {}, @@ -29,12 +28,6 @@ export const uiSlice = createSlice({ setShouldHidePreview: (state, action: PayloadAction) => { state.shouldHidePreview = action.payload; }, - setShouldShowExistingModelsInSearch: ( - state, - action: PayloadAction - ) => { - state.shouldShowExistingModelsInSearch = action.payload; - }, setShouldShowProgressInViewer: (state, action: PayloadAction) => { state.shouldShowProgressInViewer = action.payload; }, @@ -55,7 +48,6 @@ export const uiSlice = createSlice({ export const { setActiveTab, setShouldShowImageDetails, - setShouldShowExistingModelsInSearch, setShouldHidePreview, setShouldShowProgressInViewer, panelsChanged, diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts index b0800c456e..60a96142e4 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -4,7 +4,6 @@ export interface UIState { _version: 1; activeTab: InvokeTabName; shouldShowImageDetails: boolean; - shouldShowExistingModelsInSearch: boolean; shouldHidePreview: boolean; shouldShowProgressInViewer: boolean; panels: Record; From e7e7793896f1b1d048374aced819d6847267c684 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:31:20 +1100 Subject: [PATCH 05/34] feat(ui): remember open/closed state of accordions/expanders --- .../hooks/useExpanderToggle.ts | 28 ++++++++-------- .../hooks/useStandaloneAccordionToggle.ts | 32 +++++++++++-------- .../settingsAccordions/store/actions.ts | 10 ------ .../web/src/features/ui/store/uiSlice.ts | 18 +++++++++++ .../web/src/features/ui/store/uiTypes.ts | 26 +++++++++++++++ 5 files changed, 78 insertions(+), 36 deletions(-) delete mode 100644 invokeai/frontend/web/src/features/settingsAccordions/store/actions.ts diff --git a/invokeai/frontend/web/src/features/settingsAccordions/hooks/useExpanderToggle.ts b/invokeai/frontend/web/src/features/settingsAccordions/hooks/useExpanderToggle.ts index 19aad55220..d065d7d8f9 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/hooks/useExpanderToggle.ts +++ b/invokeai/frontend/web/src/features/settingsAccordions/hooks/useExpanderToggle.ts @@ -1,23 +1,25 @@ -import { useDisclosure } from '@invoke-ai/ui'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { expanderToggled } from 'features/settingsAccordions/store/actions'; -import { useCallback } from 'react'; +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { + expanderStateChanged, + selectUiSlice, +} from 'features/ui/store/uiSlice'; +import { useCallback, useMemo } from 'react'; type UseExpanderToggleArg = { defaultIsOpen: boolean; - id?: string; + id: string; }; export const useExpanderToggle = (arg: UseExpanderToggleArg) => { const dispatch = useAppDispatch(); - const { isOpen, onToggle: _onToggle } = useDisclosure({ - defaultIsOpen: arg.defaultIsOpen, - }); + const selectIsOpen = useMemo( + () => createSelector(selectUiSlice, (ui) => ui.expanders[arg.id] ?? arg.defaultIsOpen), + [arg] + ); + const isOpen = useAppSelector(selectIsOpen); const onToggle = useCallback(() => { - if (arg.id) { - dispatch(expanderToggled({ id: arg.id, isOpen })); - } - _onToggle(); - }, [_onToggle, dispatch, arg.id, isOpen]); + dispatch(expanderStateChanged({ id: arg.id, isOpen: !isOpen })); + }, [dispatch, arg.id, isOpen]); return { isOpen, onToggle }; }; diff --git a/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts b/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts index 94a4aaefe3..d7a7ea0dc8 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts +++ b/invokeai/frontend/web/src/features/settingsAccordions/hooks/useStandaloneAccordionToggle.ts @@ -1,25 +1,31 @@ -import { useDisclosure } from '@invoke-ai/ui'; -import { useAppDispatch } from 'app/store/storeHooks'; -import { standaloneAccordionToggled } from 'features/settingsAccordions/store/actions'; -import { useCallback } from 'react'; +import { createSelector } from '@reduxjs/toolkit'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { + accordionStateChanged, + selectUiSlice, +} from 'features/ui/store/uiSlice'; +import { useCallback, useMemo } from 'react'; type UseStandaloneAccordionToggleArg = { defaultIsOpen: boolean; - id?: string; + id: string; }; export const useStandaloneAccordionToggle = ( arg: UseStandaloneAccordionToggleArg ) => { const dispatch = useAppDispatch(); - const { isOpen, onToggle: _onToggle } = useDisclosure({ - defaultIsOpen: arg.defaultIsOpen, - }); + const selectIsOpen = useMemo( + () => + createSelector( + selectUiSlice, + (ui) => ui.accordions[arg.id] ?? arg.defaultIsOpen + ), + [arg] + ); + const isOpen = useAppSelector(selectIsOpen); const onToggle = useCallback(() => { - if (arg.id) { - dispatch(standaloneAccordionToggled({ id: arg.id, isOpen })); - } - _onToggle(); - }, [_onToggle, arg.id, dispatch, isOpen]); + dispatch(accordionStateChanged({ id: arg.id, isOpen: !isOpen })); + }, [arg.id, dispatch, isOpen]); return { isOpen, onToggle }; }; diff --git a/invokeai/frontend/web/src/features/settingsAccordions/store/actions.ts b/invokeai/frontend/web/src/features/settingsAccordions/store/actions.ts deleted file mode 100644 index 8ce987168d..0000000000 --- a/invokeai/frontend/web/src/features/settingsAccordions/store/actions.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createAction } from '@reduxjs/toolkit'; - -export const expanderToggled = createAction<{ id: string; isOpen: boolean }>( - 'parameters/expanderToggled' -); - -export const standaloneAccordionToggled = createAction<{ - id: string; - isOpen: boolean; -}>('parameters/standaloneAccordionToggled'); diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index 57b725ed06..71a26cb1f0 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -13,6 +13,8 @@ export const initialUIState: UIState = { shouldHidePreview: false, shouldShowProgressInViewer: true, panels: {}, + accordions: {}, + expanders: {}, }; export const uiSlice = createSlice({ @@ -37,6 +39,20 @@ export const uiSlice = createSlice({ ) => { state.panels[action.payload.name] = action.payload.value; }, + accordionStateChanged: ( + state, + action: PayloadAction<{ id: string; isOpen: boolean }> + ) => { + const { id, isOpen } = action.payload; + state.accordions[id] = isOpen; + }, + expanderStateChanged: ( + state, + action: PayloadAction<{ id: string; isOpen: boolean }> + ) => { + const { id, isOpen } = action.payload; + state.expanders[id] = isOpen; + }, }, extraReducers(builder) { builder.addCase(initialImageChanged, (state) => { @@ -51,6 +67,8 @@ export const { setShouldHidePreview, setShouldShowProgressInViewer, panelsChanged, + accordionStateChanged, + expanderStateChanged, } = uiSlice.actions; export default uiSlice.reducer; diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts index 60a96142e4..4e371090cf 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -1,10 +1,36 @@ import type { InvokeTabName } from './tabMap'; export interface UIState { + /** + * Slice schema version. + */ _version: 1; + /** + * The currently active tab. + */ activeTab: InvokeTabName; + /** + * Whether or not to show image details, e.g. metadata, workflow, etc. + */ shouldShowImageDetails: boolean; + /** + * Whether or not to hide the preview. + */ shouldHidePreview: boolean; + /** + * Whether or not to show progress in the viewer. + */ shouldShowProgressInViewer: boolean; + /** + * The react-resizable-panels state. The shape is managed by react-resizable-panels. + */ panels: Record; + /** + * The state of accordions. The key is the id of the accordion, and the value is a boolean representing the open state. + */ + accordions: Record; + /** + * The state of expanders. The key is the id of the expander, and the value is a boolean representing the open state. + */ + expanders: Record; } From b74e0de74a6dce1db3f319aa93180962ac473b47 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:31:57 +1100 Subject: [PATCH 06/34] tidy(ui): remove unused state from uiSlice --- invokeai/frontend/web/src/features/ui/store/uiSlice.ts | 7 +------ invokeai/frontend/web/src/features/ui/store/uiTypes.ts | 4 ---- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index 71a26cb1f0..51262b9b90 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -10,7 +10,6 @@ export const initialUIState: UIState = { _version: 1, activeTab: 'txt2img', shouldShowImageDetails: false, - shouldHidePreview: false, shouldShowProgressInViewer: true, panels: {}, accordions: {}, @@ -27,9 +26,6 @@ export const uiSlice = createSlice({ setShouldShowImageDetails: (state, action: PayloadAction) => { state.shouldShowImageDetails = action.payload; }, - setShouldHidePreview: (state, action: PayloadAction) => { - state.shouldHidePreview = action.payload; - }, setShouldShowProgressInViewer: (state, action: PayloadAction) => { state.shouldShowProgressInViewer = action.payload; }, @@ -43,7 +39,7 @@ export const uiSlice = createSlice({ state, action: PayloadAction<{ id: string; isOpen: boolean }> ) => { - const { id, isOpen } = action.payload; + const { id, isOpen } = action.payload; state.accordions[id] = isOpen; }, expanderStateChanged: ( @@ -64,7 +60,6 @@ export const uiSlice = createSlice({ export const { setActiveTab, setShouldShowImageDetails, - setShouldHidePreview, setShouldShowProgressInViewer, panelsChanged, accordionStateChanged, diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts index 4e371090cf..2cf9fd8aa6 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -13,10 +13,6 @@ export interface UIState { * Whether or not to show image details, e.g. metadata, workflow, etc. */ shouldShowImageDetails: boolean; - /** - * Whether or not to hide the preview. - */ - shouldHidePreview: boolean; /** * Whether or not to show progress in the viewer. */ From 3cbb1a7671ba37458eb850c333c1bbb32f3a3043 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:50:07 +1100 Subject: [PATCH 07/34] chore(ui): bump @invoke-ai/ui This includes a minor enhancement, increasing the contrast on tabs. --- invokeai/frontend/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index 28dfd84fcf..641e13407e 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -66,7 +66,7 @@ "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@fontsource-variable/inter": "^5.0.16", - "@invoke-ai/ui": "0.0.10", + "@invoke-ai/ui": "0.0.11", "@mantine/form": "6.0.21", "@nanostores/react": "^0.7.1", "@reduxjs/toolkit": "2.0.1", From 8bbdfc45fa403044cad951c3a65099f31da425a6 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:51:19 +1100 Subject: [PATCH 08/34] fix(ui): increase size of control adapters advanced toggle button --- .../features/controlAdapters/components/ControlAdapterConfig.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx index a878c19856..8496bde318 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx @@ -131,6 +131,7 @@ const ControlAdapterConfig = (props: { id: string; number: number }) => { variant="ghost" icon={ Date: Tue, 23 Jan 2024 20:07:35 +1100 Subject: [PATCH 09/34] feat(ui): scollable areas support x-axis scrolling Closes #5490 --- .../OverlayScrollbars/ScrollableContent.tsx | 19 +++++++++++++++---- .../components/OverlayScrollbars/constants.ts | 10 ++++++++++ .../ImageMetadataViewer/DataViewer.tsx | 11 +++++++++-- .../components/QueueList/QueueItemDetail.tsx | 5 +---- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/invokeai/frontend/web/src/common/components/OverlayScrollbars/ScrollableContent.tsx b/invokeai/frontend/web/src/common/components/OverlayScrollbars/ScrollableContent.tsx index 2e4b61a0a5..b78fd3d3a6 100644 --- a/invokeai/frontend/web/src/common/components/OverlayScrollbars/ScrollableContent.tsx +++ b/invokeai/frontend/web/src/common/components/OverlayScrollbars/ScrollableContent.tsx @@ -1,24 +1,35 @@ import type { ChakraProps } from '@invoke-ai/ui'; import { Box, Flex } from '@invoke-ai/ui'; -import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants'; +import { getOverlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; import type { CSSProperties, PropsWithChildren } from 'react'; -import { memo } from 'react'; +import { memo, useMemo } from 'react'; type Props = PropsWithChildren & { maxHeight?: ChakraProps['maxHeight']; + overflowX?: 'hidden' | 'scroll'; + overflowY?: 'hidden' | 'scroll'; }; const styles: CSSProperties = { height: '100%', width: '100%' }; -const ScrollableContent = ({ children, maxHeight }: Props) => { +const ScrollableContent = ({ + children, + maxHeight, + overflowX = 'hidden', + overflowY = 'scroll', +}: Props) => { + const overlayscrollbarsOptions = useMemo( + () => getOverlayScrollbarsParams(overflowX, overflowY).options, + [overflowX, overflowY] + ); return ( {children} diff --git a/invokeai/frontend/web/src/common/components/OverlayScrollbars/constants.ts b/invokeai/frontend/web/src/common/components/OverlayScrollbars/constants.ts index fa6969b2ed..4ec4b5620d 100644 --- a/invokeai/frontend/web/src/common/components/OverlayScrollbars/constants.ts +++ b/invokeai/frontend/web/src/common/components/OverlayScrollbars/constants.ts @@ -1,3 +1,4 @@ +import { cloneDeep, merge } from 'lodash-es'; import { ClickScrollPlugin, OverlayScrollbars } from 'overlayscrollbars'; import type { UseOverlayScrollbarsParams } from 'overlayscrollbars-react'; @@ -16,3 +17,12 @@ export const overlayScrollbarsParams: UseOverlayScrollbarsParams = { overflow: { x: 'hidden' }, }, }; + +export const getOverlayScrollbarsParams = ( + overflowX: 'hidden' | 'scroll' = 'hidden', + overflowY: 'hidden' | 'scroll' = 'scroll' +) => { + const params = cloneDeep(overlayScrollbarsParams); + merge(params, { options: { overflow: { y: overflowY, x: overflowX } } }); + return params; +}; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx index 23c59f3af4..b8268c9676 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/DataViewer.tsx @@ -1,5 +1,7 @@ import { Box, Flex, IconButton, Tooltip } from '@invoke-ai/ui'; -import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants'; +import { + getOverlayScrollbarsParams, +} from 'common/components/OverlayScrollbars/constants'; import { isString } from 'lodash-es'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; import type { CSSProperties } from 'react'; @@ -15,6 +17,11 @@ type Props = { withCopy?: boolean; }; +const overlayscrollbarsOptions = getOverlayScrollbarsParams( + 'scroll', + 'scroll' +).options; + const DataViewer = (props: Props) => { const { label, data, fileName, withDownload = true, withCopy = true } = props; const dataString = useMemo( @@ -60,7 +67,7 @@ const DataViewer = (props: Props) => {
{dataString}
diff --git a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx index 0af1948c55..2401962e98 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemDetail.tsx @@ -6,7 +6,6 @@ import { Spinner, Text, } from '@invoke-ai/ui'; -import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer'; import { useCancelBatch } from 'features/queue/hooks/useCancelBatch'; import { useCancelQueueItem } from 'features/queue/hooks/useCancelQueueItem'; @@ -127,9 +126,7 @@ const QueueItemComponent = ({ queueItemDTO }: Props) => { justifyContent="center" > {queueItem ? ( - - - + ) : ( )} From 2f656cc3573ac8e8af24b2dd68b1783659c80f6d Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 21:40:18 +1100 Subject: [PATCH 10/34] fix(ui): fix field context menu jank Closes #5551 --- .../nodes/Invocation/fields/InputField.tsx | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputField.tsx index 65ffbccb6f..0de87b8f58 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputField.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputField.tsx @@ -109,28 +109,28 @@ const InputField = ({ nodeId, fieldName }: Props) => { return ( - - {(ref) => ( - - + + + + {(ref) => ( - - - - )} - + )} + + +
+ {fieldTemplate.input !== 'direct' && ( Date: Tue, 23 Jan 2024 22:39:01 +1100 Subject: [PATCH 11/34] fix(ui): remove unused import in storybook --- invokeai/frontend/web/.storybook/preview.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/invokeai/frontend/web/.storybook/preview.tsx b/invokeai/frontend/web/.storybook/preview.tsx index 3d5c8d8493..791a48ab9e 100644 --- a/invokeai/frontend/web/.storybook/preview.tsx +++ b/invokeai/frontend/web/.storybook/preview.tsx @@ -6,7 +6,6 @@ import { Provider } from 'react-redux'; import ThemeLocaleProvider from '../src/app/components/ThemeLocaleProvider'; import { $baseUrl } from '../src/app/store/nanostores/baseUrl'; import { createStore } from '../src/app/store/store'; -import { Container } from '@chakra-ui/react'; // TODO: Disabled for IDE performance issues with our translation JSON // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore From 1178fd8bd3bf35421cc69abc680b741041c62c9e Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 22:40:05 +1100 Subject: [PATCH 12/34] fix(ui): fix styling of some form elements --- .../IAICanvasToolbar/IAICanvasMaskOptions.tsx | 67 +++++---- .../IAICanvasSettingsButtonPopover.tsx | 136 ++++++++++-------- .../IAICanvasToolChooserOptions.tsx | 2 +- .../components/GallerySettingsPopover.tsx | 36 +++-- 4 files changed, 135 insertions(+), 106 deletions(-) diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx index 23cffc05a2..2e4fcccd85 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasMaskOptions.tsx @@ -1,9 +1,12 @@ +import type { FormLabelProps } from '@invoke-ai/ui'; import { Box, Button, + ButtonGroup, Checkbox, Flex, FormControl, + FormControlGroup, FormLabel, IconButton, Popover, @@ -33,6 +36,10 @@ import { PiTrashSimpleFill, } from 'react-icons/pi'; +const formLabelProps: FormLabelProps = { + flexGrow: 1, +}; + const IAICanvasMaskOptions = () => { const dispatch = useAppDispatch(); const { t } = useTranslation(); @@ -124,40 +131,44 @@ const IAICanvasMaskOptions = () => { - - {`${t('unifiedCanvas.enableMask')} (H)`} - - - - {t('unifiedCanvas.preserveMaskedArea')} - - + + + {`${t('unifiedCanvas.enableMask')} (H)`} + + + + {t('unifiedCanvas.preserveMaskedArea')} + + + - - + + + + diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx index 6b2f2eddb0..bbdff781bf 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasSettingsButtonPopover.tsx @@ -1,7 +1,9 @@ +import type { FormLabelProps } from '@invoke-ai/ui'; import { Checkbox, Flex, FormControl, + FormControlGroup, FormLabel, IconButton, Popover, @@ -28,6 +30,10 @@ import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; import { PiGearSixBold } from 'react-icons/pi'; +const formLabelProps: FormLabelProps = { + flexGrow: 1, +}; + const IAICanvasSettingsButtonPopover = () => { const dispatch = useAppDispatch(); const { t } = useTranslation(); @@ -122,69 +128,73 @@ const IAICanvasSettingsButtonPopover = () => { - - {t('unifiedCanvas.showIntermediates')} - - - - {t('unifiedCanvas.showGrid')} - - - - {t('unifiedCanvas.snapToGrid')} - - - - {t('unifiedCanvas.darkenOutsideSelection')} - - - - {t('unifiedCanvas.autoSaveToGallery')} - - - - {t('unifiedCanvas.saveBoxRegionOnly')} - - - - {t('unifiedCanvas.limitStrokesToBox')} - - - - {t('unifiedCanvas.showCanvasDebugInfo')} - - - - {t('unifiedCanvas.antialiasing')} - - + + + {t('unifiedCanvas.showIntermediates')} + + + + {t('unifiedCanvas.showGrid')} + + + + {t('unifiedCanvas.snapToGrid')} + + + + + {t('unifiedCanvas.darkenOutsideSelection')} + + + + + {t('unifiedCanvas.autoSaveToGallery')} + + + + {t('unifiedCanvas.saveBoxRegionOnly')} + + + + {t('unifiedCanvas.limitStrokesToBox')} + + + + {t('unifiedCanvas.showCanvasDebugInfo')} + + + + {t('unifiedCanvas.antialiasing')} + + + diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx index 59a0ae2619..5584be9ed1 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx @@ -276,9 +276,9 @@ const IAICanvasToolChooserOptions = () => { diff --git a/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx b/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx index 8056a34f9c..bc5720e9fc 100644 --- a/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/GallerySettingsPopover.tsx @@ -1,8 +1,10 @@ +import type { FormLabelProps } from '@invoke-ai/ui'; import { Checkbox, CompositeSlider, Flex, FormControl, + FormControlGroup, FormLabel, IconButton, Popover, @@ -24,6 +26,10 @@ import { RiSettings4Fill } from 'react-icons/ri'; import BoardAutoAddSelect from './Boards/BoardAutoAddSelect'; +const formLabelProps: FormLabelProps = { + flexGrow: 1, +}; + const GallerySettingsPopover = () => { const dispatch = useAppDispatch(); const { t } = useTranslation(); @@ -78,20 +84,22 @@ const GallerySettingsPopover = () => { defaultValue={90} /> - - {t('gallery.autoSwitchNewImages')} - - - - {t('gallery.autoAssignBoardOnClick')} - - + + + {t('gallery.autoSwitchNewImages')} + + + + {t('gallery.autoAssignBoardOnClick')} + + + From 52b24e01e2edd3d67dcdb9335b60dfe583f83cd4 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 22:56:11 +1100 Subject: [PATCH 13/34] feat(ui): remove chakra as direct dependency Moved a number of things to `@invoke-ai/ui` to support this. Unfortunately, the bundle size has increased a bit. I will work on that later. --- invokeai/frontend/web/package.json | 11 +- invokeai/frontend/web/pnpm-lock.yaml | 732 ++++++++++++++++-- .../components/ControlAdapterConfig.tsx | 9 +- .../Boards/BoardsList/BoardsSearch.tsx | 2 +- .../gallery/components/GalleryBoardName.tsx | 8 +- .../ImageMetadataViewer/DataViewer.tsx | 4 +- .../ImageMetadataViewer/ImageMetadataItem.tsx | 7 +- .../ImageMetadataViewer.tsx | 12 +- .../flow/nodes/common/NodeCollapseButton.tsx | 7 +- .../hooks/useExpanderToggle.ts | 11 +- .../components/AboutModal/AboutModal.tsx | 23 +- .../components/HotkeysModal/HotkeysModal.tsx | 5 +- .../FloatingParametersPanelButtons.tsx | 6 +- .../components/WorkflowLibraryList.tsx | 11 +- 14 files changed, 730 insertions(+), 118 deletions(-) diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index 641e13407e..f989a98b4e 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -52,21 +52,12 @@ } }, "dependencies": { - "@chakra-ui/anatomy": "^2.2.2", - "@chakra-ui/icons": "^2.1.1", - "@chakra-ui/layout": "^2.3.1", - "@chakra-ui/portal": "^2.1.0", - "@chakra-ui/react": "^2.8.2", "@chakra-ui/react-use-size": "^2.1.0", - "@chakra-ui/styled-system": "^2.9.2", - "@chakra-ui/theme-tools": "^2.1.2", "@dagrejs/graphlib": "^2.1.13", "@dnd-kit/core": "^6.1.0", "@dnd-kit/utilities": "^3.2.2", - "@emotion/react": "^11.11.3", - "@emotion/styled": "^11.11.0", "@fontsource-variable/inter": "^5.0.16", - "@invoke-ai/ui": "0.0.11", + "@invoke-ai/ui": "0.0.12", "@mantine/form": "6.0.21", "@nanostores/react": "^0.7.1", "@reduxjs/toolkit": "2.0.1", diff --git a/invokeai/frontend/web/pnpm-lock.yaml b/invokeai/frontend/web/pnpm-lock.yaml index a6b710c628..bdd7ab844c 100644 --- a/invokeai/frontend/web/pnpm-lock.yaml +++ b/invokeai/frontend/web/pnpm-lock.yaml @@ -10,30 +10,12 @@ patchedDependencies: path: patches/reselect@5.0.1.patch dependencies: - '@chakra-ui/anatomy': - specifier: ^2.2.2 - version: 2.2.2 - '@chakra-ui/icons': - specifier: ^2.1.1 - version: 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0) - '@chakra-ui/layout': - specifier: ^2.3.1 - version: 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0) - '@chakra-ui/portal': - specifier: ^2.1.0 - version: 2.1.0(react-dom@18.2.0)(react@18.2.0) '@chakra-ui/react': specifier: ^2.8.2 version: 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@10.18.0)(react-dom@18.2.0)(react@18.2.0) '@chakra-ui/react-use-size': specifier: ^2.1.0 version: 2.1.0(react@18.2.0) - '@chakra-ui/styled-system': - specifier: ^2.9.2 - version: 2.9.2 - '@chakra-ui/theme-tools': - specifier: ^2.1.2 - version: 2.1.2(@chakra-ui/styled-system@2.9.2) '@dagrejs/graphlib': specifier: ^2.1.13 version: 2.1.13 @@ -43,18 +25,12 @@ dependencies: '@dnd-kit/utilities': specifier: ^3.2.2 version: 3.2.2(react@18.2.0) - '@emotion/react': - specifier: ^11.11.3 - version: 11.11.3(@types/react@18.2.48)(react@18.2.0) - '@emotion/styled': - specifier: ^11.11.0 - version: 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.48)(react@18.2.0) '@fontsource-variable/inter': specifier: ^5.0.16 version: 5.0.16 '@invoke-ai/ui': - specifier: 0.0.10 - version: 0.0.10(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0) + specifier: 0.0.12 + version: 0.0.12(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0) '@mantine/form': specifier: 6.0.21 version: 6.0.21(react@18.2.0) @@ -356,6 +332,92 @@ packages: '@jridgewell/trace-mapping': 0.3.21 dev: true + /@ark-ui/anatomy@1.3.0(@internationalized/date@3.5.1): + resolution: {integrity: sha512-1yG2MrzUlix6KthjQMCNiHnkXrWwEdFAX6D+HqGJaNu0XvaGul2J+wDNtjsdX+gxiWu1nXXEEOAWlFVYMUf65w==} + dependencies: + '@zag-js/accordion': 0.32.1 + '@zag-js/anatomy': 0.32.1 + '@zag-js/avatar': 0.32.1 + '@zag-js/carousel': 0.32.1 + '@zag-js/checkbox': 0.32.1 + '@zag-js/color-picker': 0.32.1 + '@zag-js/color-utils': 0.32.1 + '@zag-js/combobox': 0.32.1 + '@zag-js/date-picker': 0.32.1 + '@zag-js/date-utils': 0.32.1(@internationalized/date@3.5.1) + '@zag-js/dialog': 0.32.1 + '@zag-js/editable': 0.32.1 + '@zag-js/file-upload': 0.32.1 + '@zag-js/hover-card': 0.32.1 + '@zag-js/menu': 0.32.1 + '@zag-js/number-input': 0.32.1 + '@zag-js/pagination': 0.32.1 + '@zag-js/pin-input': 0.32.1 + '@zag-js/popover': 0.32.1 + '@zag-js/presence': 0.32.1 + '@zag-js/progress': 0.32.1 + '@zag-js/radio-group': 0.32.1 + '@zag-js/rating-group': 0.32.1 + '@zag-js/select': 0.32.1 + '@zag-js/slider': 0.32.1 + '@zag-js/splitter': 0.32.1 + '@zag-js/switch': 0.32.1 + '@zag-js/tabs': 0.32.1 + '@zag-js/tags-input': 0.32.1 + '@zag-js/toast': 0.32.1 + '@zag-js/toggle-group': 0.32.1 + '@zag-js/tooltip': 0.32.1 + transitivePeerDependencies: + - '@internationalized/date' + dev: false + + /@ark-ui/react@1.3.0(@internationalized/date@3.5.1)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-JHjNoIX50+mUCTaEGMjfGQWGGi31pKsV646jZJlR/1xohpYJigzg8BvO97cTsVk8fwtur+cm11gz3Nf7f5QUnA==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + dependencies: + '@ark-ui/anatomy': 1.3.0(@internationalized/date@3.5.1) + '@zag-js/accordion': 0.32.1 + '@zag-js/avatar': 0.32.1 + '@zag-js/carousel': 0.32.1 + '@zag-js/checkbox': 0.32.1 + '@zag-js/color-picker': 0.32.1 + '@zag-js/color-utils': 0.32.1 + '@zag-js/combobox': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/date-picker': 0.32.1 + '@zag-js/date-utils': 0.32.1(@internationalized/date@3.5.1) + '@zag-js/dialog': 0.32.1 + '@zag-js/editable': 0.32.1 + '@zag-js/file-upload': 0.32.1 + '@zag-js/hover-card': 0.32.1 + '@zag-js/menu': 0.32.1 + '@zag-js/number-input': 0.32.1 + '@zag-js/pagination': 0.32.1 + '@zag-js/pin-input': 0.32.1 + '@zag-js/popover': 0.32.1 + '@zag-js/presence': 0.32.1 + '@zag-js/progress': 0.32.1 + '@zag-js/radio-group': 0.32.1 + '@zag-js/rating-group': 0.32.1 + '@zag-js/react': 0.32.1(react-dom@18.2.0)(react@18.2.0) + '@zag-js/select': 0.32.1 + '@zag-js/slider': 0.32.1 + '@zag-js/splitter': 0.32.1 + '@zag-js/switch': 0.32.1 + '@zag-js/tabs': 0.32.1 + '@zag-js/tags-input': 0.32.1 + '@zag-js/toast': 0.32.1 + '@zag-js/toggle-group': 0.32.1 + '@zag-js/tooltip': 0.32.1 + '@zag-js/types': 0.32.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - '@internationalized/date' + dev: false + /@arthurgeron/eslint-plugin-react-usememo@2.2.3: resolution: {integrity: sha512-YJG+8hULmhHAxztaANswpa9hWNqEOSvbZcbd6R/JQzyNlEZ49Xh97kqZGuJGZ74rrmULckEO1m3Jh5ctqrGA2A==} dependencies: @@ -2940,7 +3002,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.8 '@emotion/babel-plugin': 11.11.0 '@emotion/is-prop-valid': 1.2.1 '@emotion/react': 11.11.3(@types/react@18.2.48)(react@18.2.0) @@ -3629,7 +3691,6 @@ packages: resolution: {integrity: sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==} dependencies: '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/dom@1.5.3: resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} @@ -3643,7 +3704,6 @@ packages: dependencies: '@floating-ui/core': 1.5.3 '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/react-dom@2.0.6(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-IB8aCRFxr8nFkdYZgH+Otd9EVQPJoynxeFRGTB8voPoZMRWo8XjYuCRgpI1btvuKY69XMiLnW+ym7zoBHM90Rw==} @@ -3662,7 +3722,6 @@ packages: /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - dev: true /@fontsource-variable/inter@5.0.16: resolution: {integrity: sha512-k+BUNqksTL+AN+o+OV7ILeiE9B5M5X+/jA7LWvCwjbV9ovXTqZyKRhA/x7uYv/ml8WQ0XNLBM7cRFIx4jW0/hg==} @@ -3688,31 +3747,26 @@ packages: resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: true - /@invoke-ai/ui@0.0.10(@chakra-ui/anatomy@2.2.2)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/portal@2.1.0)(@chakra-ui/react@2.8.2)(@chakra-ui/styled-system@2.9.2)(@chakra-ui/theme-tools@2.1.2)(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@fontsource-variable/inter@5.0.16)(@nanostores/react@0.7.1)(chakra-react-select@4.7.6)(framer-motion@10.18.0)(lodash-es@4.17.21)(nanostores@0.9.5)(overlayscrollbars-react@0.5.3)(overlayscrollbars@2.4.6)(react-dom@18.2.0)(react-i18next@14.0.0)(react-select@5.8.0)(react@18.2.0): - resolution: {integrity: sha512-e3cX3g1xap57mkMfjsNznN6V9YS8qUTpSiyjSSr80HEsD3NjXxCoL+Ik6y/Na/KwXgcK00jM6H+xF6ahJFobvw==} + /@internationalized/date@3.5.1: + resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==} + dependencies: + '@swc/helpers': 0.5.3 + dev: false + + /@internationalized/number@3.5.0: + resolution: {integrity: sha512-ZY1BW8HT9WKYvaubbuqXbbDdHhOUMfE2zHHFJeTppid0S+pc8HtdIxFxaYMsGjCb4UsF+MEJ4n2TfU7iHnUK8w==} + dependencies: + '@swc/helpers': 0.5.3 + dev: false + + /@invoke-ai/ui@0.0.12(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-G0iPzGx1Nu7mHOZtwUYtqNWAqo2KnYGvs883w4WJwUpoCEbnaZd9Pi876UvOh9aNyjO93t/5ctIffkcYlDKGNg==} peerDependencies: - '@chakra-ui/anatomy': ^2.2.2 - '@chakra-ui/icons': ^2.1.1 - '@chakra-ui/layout': ^2.3.1 - '@chakra-ui/portal': ^2.1.0 - '@chakra-ui/react': ^2.8.2 - '@chakra-ui/styled-system': ^2.9.2 - '@chakra-ui/theme-tools': ^2.1.2 - '@emotion/react': ^11.11.3 - '@emotion/styled': ^11.11.0 '@fontsource-variable/inter': ^5.0.16 - '@nanostores/react': ^0.7.1 - chakra-react-select: ^4.7.6 - framer-motion: ^10.18.0 - lodash-es: ^4.17.21 - nanostores: ^0.9.5 - overlayscrollbars: ^2.4.6 - overlayscrollbars-react: ^0.5.3 react: ^18.2.0 react-dom: ^18.2.0 - react-i18next: ^14.0.0 - react-select: ^5.8.0 dependencies: + '@ark-ui/react': 1.3.0(@internationalized/date@3.5.1)(react-dom@18.2.0)(react@18.2.0) '@chakra-ui/anatomy': 2.2.2 '@chakra-ui/icons': 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/layout': 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0) @@ -3734,6 +3788,17 @@ packages: react-dom: 18.2.0(react@18.2.0) react-i18next: 14.0.0(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0) react-select: 5.8.0(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + transitivePeerDependencies: + - '@chakra-ui/form-control' + - '@chakra-ui/icon' + - '@chakra-ui/media-query' + - '@chakra-ui/menu' + - '@chakra-ui/spinner' + - '@chakra-ui/system' + - '@internationalized/date' + - '@types/react' + - i18next + - react-native dev: false /@isaacs/cliui@8.0.2: @@ -5719,6 +5784,12 @@ packages: resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==} dev: true + /@swc/helpers@0.5.3: + resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==} + dependencies: + tslib: 2.6.2 + dev: false + /@swc/types@0.1.5: resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==} dev: true @@ -6679,20 +6750,567 @@ packages: tslib: 1.14.1 dev: true + /@zag-js/accordion@0.32.1: + resolution: {integrity: sha512-16beDVpEhXFQsQRMZLmHFruhGphSprJ5XrRu6+OM2U7aTulo1w3ENUd9uI+mIs4oTVO66lYI4Lp+dFcT2UUIYA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/anatomy@0.32.1: + resolution: {integrity: sha512-bR+tfFfkbxwhBzGGjEQG+RUnbeCjMx7tWJxykGnGdVLwAh0wKTQBEfHEOCOQh5qU8RhKUieqemAdvc7oP3Tp4w==} + dev: false + + /@zag-js/aria-hidden@0.32.1: + resolution: {integrity: sha512-kznwxvUUHDax8Kd7YNVVCzQcwGARTRaZNOcIkw7MTLE8g/pU+C4pYkwR9iqA7/8imGfjYrZfSsQqZRTb4bkS0g==} + dependencies: + '@zag-js/dom-query': 0.32.1 + dev: false + + /@zag-js/auto-resize@0.32.1: + resolution: {integrity: sha512-MO6N5gPs2xDKbFgrakn6LDWv1GgN8uhfwpsqchLJX+EaZVvLIz8cXFD+jDv3RjK+5GRWV4mIF+26SXuHRSt9Ug==} + dependencies: + '@zag-js/dom-query': 0.32.1 + dev: false + + /@zag-js/avatar@0.32.1: + resolution: {integrity: sha512-5P+95pkMX2Na4yljN1etdgYyA+3HPORjWKn0Y3JamkYIAqJwRFO+taEdSm/xcRkuT6aGA3luheUowjt8wZssyA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/mutation-observer': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/carousel@0.32.1: + resolution: {integrity: sha512-S7dUrPtiLr42Fa+S3O18kqKVqSu2yuk67bqGDtppIZSaFOugYHK4feBkZqjKw+eF12NVRRVO2j+A40d3MvxbSA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/checkbox@0.32.1: + resolution: {integrity: sha512-5reRreGyDZ5IlBNd5m1QrYXCehVIl/pmfKMEcAfad5DcgCaHGv5j76eahxbKln/8TEdwz4eWzBrqNtwSkKL5+w==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/collection@0.32.1: + resolution: {integrity: sha512-dAzcVQ/n+xAYoxWB/65/CQinv66RNVuq5ig0fEYszBqP+HjFnOpeGkIrEvP+bFI38hFEViiGtfr6oGAsVByOVQ==} + dev: false + + /@zag-js/color-picker@0.32.1: + resolution: {integrity: sha512-ov3FC+c2WBYmEGRXWFVb2jih2Ecejj5JqBjDL9iMLBs2KNY9jnpvtH7WnZbijNY+RMDBj+C/DNI7K2NVaamSIA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/color-utils': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/tabbable': 0.32.1 + '@zag-js/text-selection': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/color-utils@0.32.1: + resolution: {integrity: sha512-AzupfOD7oD0mE+H9roTzwnLqtw1wYiJGOQKLPAwdwPQdznJUQD6sMOpxR/6RBuITVTm8Bl12Mr4+7s29LVJruw==} + dependencies: + '@zag-js/numeric-range': 0.32.1 + dev: false + + /@zag-js/combobox@0.32.1: + resolution: {integrity: sha512-skz2C5UxLD5JoYNP4hcPaQJu2cW7vycKqjDNI9ZtygSkZHOHx+JxpYiACBnr1vqzXatIOuDQm/HUuWW9yOT4eA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/aria-hidden': 0.32.1 + '@zag-js/collection': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/mutation-observer': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/core@0.32.1: + resolution: {integrity: sha512-F9F7920/CisoLWALQACIhqbMvemgbv86qBULJ+UEe+a/9XgGwPh9UGn/H/q5EWkNpgEapz2b3pl3ONgKmXsK1A==} + dependencies: + '@zag-js/store': 0.32.1 + klona: 2.0.6 + dev: false + + /@zag-js/date-picker@0.32.1: + resolution: {integrity: sha512-n/hYmF+/R4+NuyfPRzCgeuLT6LJihKSuKzK29STPWy3sC/tBBHiqhNv1/4UKbatHUJXdBW2XF+N8Rw08RffcFQ==} + dependencies: + '@internationalized/date': 3.5.1 + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/date-utils': 0.32.1(@internationalized/date@3.5.1) + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/live-region': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/text-selection': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/date-utils@0.32.1(@internationalized/date@3.5.1): + resolution: {integrity: sha512-dbBDRSVr5pRUw3rXndyGuSshZiWqQI5JQO4D2KIFGkXzorj6WzoOpcO910Z7AdM/9cCAMpCjUrka8d8o9BpJBg==} + peerDependencies: + '@internationalized/date': '>=3.0.0' + dependencies: + '@internationalized/date': 3.5.1 + dev: false + + /@zag-js/dialog@0.32.1: + resolution: {integrity: sha512-czp+qXcdAOM70SrvDo4gBpYZx6gS6HXyrpiptW3+EHa2eiCfc/Z2w+Nu+ZadOTEQGgNWlKlCLW7Ery0i9mMDsw==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/aria-hidden': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/remove-scroll': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + focus-trap: 7.5.4 + dev: false + + /@zag-js/dismissable@0.32.1: + resolution: {integrity: sha512-UIkG+9Eb5wrus2F2Dy4zqk0pwCV53sdnMYBxk9dpvDzBJHzW+InhVeg3UeKmPL8ELcYlhH/Bap99XCRJvxsXow==} + dependencies: + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/interact-outside': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/dom-event@0.32.1: + resolution: {integrity: sha512-wN6f5Kkf7C/YFN3wbEG3gUockSebyy1fPNL2BuL4C8PIP8vOD14hnHTzZWg5yYfO+veybIAL38r8I46C+bOVBQ==} + dependencies: + '@zag-js/text-selection': 0.32.1 + '@zag-js/types': 0.32.1 + dev: false + /@zag-js/dom-query@0.16.0: resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==} dev: false + /@zag-js/dom-query@0.32.1: + resolution: {integrity: sha512-u6hrQHQ0/dcUi6xJn8d2Mu1ClN4KZpPqOKrJFSaxadWjSy+x0qp48WY2CBQ6gZ3j8IwR/XjzU9bu9wY5jJfHgA==} + dev: false + + /@zag-js/editable@0.32.1: + resolution: {integrity: sha512-QEGnfp2P9nWVp9vGNWtszspvQcF3KtBRToZrv5/DT30Mpo/uPDKtqijLs0SnB/W60ELzcIRhK4J9taGoK8O8uw==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/interact-outside': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/element-rect@0.32.1: + resolution: {integrity: sha512-tAmxgxU2LsByK8PIs/Cj6cBJ8xZCVXE9RoStxthhuPL7xKYUfZvFGuhHVOHTHd6sDKEqbj6K1ds/TGPuglIh4w==} + dev: false + /@zag-js/element-size@0.10.5: resolution: {integrity: sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w==} dev: false + /@zag-js/element-size@0.32.1: + resolution: {integrity: sha512-ACklufmJQpah2UqwZUlYFaKi6uWfZBeTghtbfYHcDfzRbg2Hni612v8L1JeS4vAgjeDpcdHQpXXR4AZSpGZgNw==} + dev: false + + /@zag-js/file-upload@0.32.1: + resolution: {integrity: sha512-cD0NRIDof9Vv2DemmnYe9ZPZxOZ6b8XZl8eq4G0e8+WLYtnRXyEURl8Dw0QJpfdDPQaHnnD4CNxPTQcLgP+9Sg==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/file-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/file-utils@0.32.1: + resolution: {integrity: sha512-0PxTrljW51Lf9OCuYNlZuaLgF0v1NoVRzXa/osZ9HGceQjfo77R5G9u+/TP3u53W2PTxajEZ4eNzTibgpzNXFg==} + dev: false + /@zag-js/focus-visible@0.16.0: resolution: {integrity: sha512-a7U/HSopvQbrDU4GLerpqiMcHKEkQkNPeDZJWz38cw/6Upunh41GjHetq5TB84hxyCaDzJ6q2nEdNoBQfC0FKA==} dependencies: '@zag-js/dom-query': 0.16.0 dev: false + /@zag-js/form-utils@0.32.1: + resolution: {integrity: sha512-OemLBlHCHHm7t8wNcf78FRudRA7FegSgsNEzAjrRTyx+lJztDyHRLaoyI1gCEIg+0Kzl2nMxjOl4MStGsDj8iw==} + dependencies: + '@zag-js/mutation-observer': 0.32.1 + dev: false + + /@zag-js/hover-card@0.32.1: + resolution: {integrity: sha512-k66YK0z0P4LuK78+jnRoUPxJiM9GA0sbEEz3oPlvcFVXMMwnRTPNIw1OjksfAPI+Nvgg7H6D3A+7HCdRI/oBjw==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/interact-outside@0.32.1: + resolution: {integrity: sha512-8zHuswfTAgfMCaQnp3N4WStvnL32VyxURafb21+mE4neAF/DaKfJHWnJpeUMG1Qh/eXsrMRBxVoX+nBMhHj9bg==} + dependencies: + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/tabbable': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/live-region@0.32.1: + resolution: {integrity: sha512-6/9QMLVZbTRh/G6MoJc/auN8r5vjdY9vUgNT680C2LOa2vnRR5/y0DkIpVgttNh1rSenQ/eLEYxp8hQF1rIYNw==} + dependencies: + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/menu@0.32.1: + resolution: {integrity: sha512-IPsTljVF0N9xTwub1cpGl3GAG5ttAq3h38PdZERREzT3qRgw4v3K/I1TG2vIiDXgJz8UZzUKox6ZYdU7UIAkRA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/mutation-observer': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/rect-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/mutation-observer@0.32.1: + resolution: {integrity: sha512-/hlObxGnhAaYYVnwRJC227md0M3kSE6mO24vkqVGwq2GglS+u4zbVcBBUuWgHdMML+ZjIQrZuVycCBMfVlHq0g==} + dev: false + + /@zag-js/number-input@0.32.1: + resolution: {integrity: sha512-atyIOvoMITb4hZtQym7yD6I7grvPW83UeMFO8hCQg3HWwd2zR4+63mouWuyMoWb4QrzVFRVQBaU8OG5xGlknEw==} + dependencies: + '@internationalized/number': 3.5.0 + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/mutation-observer': 0.32.1 + '@zag-js/number-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/number-utils@0.32.1: + resolution: {integrity: sha512-x/nttU31TtFVTqFBM8e3ZH/0MCc+u15WAfk0rT6ESkoZcdb80rTzZVMokCKCUdpi/JdB1vjEeCLSnj+ig8oAIQ==} + dev: false + + /@zag-js/numeric-range@0.32.1: + resolution: {integrity: sha512-1Qe2URTenlrdsWuArlnQ+v5bBH2mHZD3XsK6jYV+C2lgatVzdcoN4GCSNTiF7w+So6J+NTeLMkVHMGCW1Kzx1g==} + dev: false + + /@zag-js/pagination@0.32.1: + resolution: {integrity: sha512-lhogzKxJnx5D2Xoni/xm5rkOuy15KWSxqBHVwe8+j5aSNqMy7+aRtEN2F2VQCDVL/v1fdciQvOCA9udm37kZ4w==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/pin-input@0.32.1: + resolution: {integrity: sha512-d18cCXKUr7INL0Xm5KyIoiTRSNsPXfIlIEMl2HrAvM3r70wtEag0PmiDNA5NS2tB4LnnX0XowchGB4HsdFS/ng==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/popover@0.32.1: + resolution: {integrity: sha512-B01if49v3crCjkvtSvIX4CBdT/475nj3DttOObc36s0YOxCEt3UihMITBD5JvIKwEqjZ6oU5t0sLcUYOqQ4f2A==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/aria-hidden': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/remove-scroll': 0.32.1 + '@zag-js/tabbable': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + focus-trap: 7.5.4 + dev: false + + /@zag-js/popper@0.32.1: + resolution: {integrity: sha512-aQgogW1N4VreNACSQhXQoZeXtQQtB//FXUvt1CBnW2DtmZ6YkNnaAfn186Q2lkw2/T0chITRy3eYeviwMmMrqg==} + dependencies: + '@floating-ui/dom': 1.5.4 + '@zag-js/dom-query': 0.32.1 + '@zag-js/element-rect': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/presence@0.32.1: + resolution: {integrity: sha512-8189QMUf/L1dztAZdurx18ZwPyWlq58Mrd+GdATSaf8JstgrI1ovzVs606inQghWptKHMsH7dUIaV9UkhbSx3Q==} + dependencies: + '@zag-js/core': 0.32.1 + '@zag-js/types': 0.32.1 + dev: false + + /@zag-js/progress@0.32.1: + resolution: {integrity: sha512-ClkQvNYnuIpKfAPUceZXY5E2m/3NnIm21cvHe4gAoJ88YdqEHd5rIRoHP63g8ET8Ct/2KkBRkgR+LrQnGQOomA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/radio-group@0.32.1: + resolution: {integrity: sha512-NvdSjwRF38qIh0oM68jERf71uiwV2JFTrGeQEs3EIqONzULwL6jR2p4P1wm3JJNBAkSYBKZMER5cVUUcqM3kjQ==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/element-rect': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/rating-group@0.32.1: + resolution: {integrity: sha512-RBaFRCw7P00bgTrEjUHT3h/OGRO8XmXKkQYqqhm1tsVbeTsT47iwHoc6XnMEiGBonaJDwN/J0oFasw7GNg5sow==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/react@0.32.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-b1SB7hXXv1K6CmXkcy5Y7mb0YRWkyvulyhK8VW5O5hIAPuGxOTx70psmVeZbmVzhjdORCiro9jKx8Ec0LfolFg==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + dependencies: + '@zag-js/core': 0.32.1 + '@zag-js/store': 0.32.1 + '@zag-js/types': 0.32.1 + proxy-compare: 2.5.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@zag-js/rect-utils@0.32.1: + resolution: {integrity: sha512-cI07kgldjUZP+SLhXeG9VSl47nrENlC96Fs7jWcTfHj62rhdY8WsBJ0tiTztvwar9m1chwxXZwJowHN+nPIgDQ==} + dev: false + + /@zag-js/remove-scroll@0.32.1: + resolution: {integrity: sha512-LyXt2rNMSKb9MKeJRyKTgpk4R7jdA+9kEQTSG5qyA94jo1og7FVgA1W/E+pNkdxDEk1VplL768VU6y7E/L3DHg==} + dependencies: + '@zag-js/dom-query': 0.32.1 + dev: false + + /@zag-js/select@0.32.1: + resolution: {integrity: sha512-jSzmTKCN1Fk/ZDDWM8TVGOtwgpYUDgyceegjYT+hW1mmEetu4tQcEvAr0557NOzh8akqLvcVFbg/kMj0IriKAA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/collection': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dismissable': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/mutation-observer': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/tabbable': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/slider@0.32.1: + resolution: {integrity: sha512-iZSB3Y8/Maakxem0Ha3rBRa8AyAplhN5K50Bgz+wsv0VEzNNUmK4QgaTWReWd6SfeTRpnC5ftKCcfM2aQrLm6g==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/element-size': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/numeric-range': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/splitter@0.32.1: + resolution: {integrity: sha512-NdHLUXtQAlnz6QpdPwcqZCqYul7LaVqsp0hgtXR2PN4HbH+VAaDfY76pUk6LBerUcykChGZvtM9U0A5FCo1x4A==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/number-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/store@0.32.1: + resolution: {integrity: sha512-hKwzpqAPljw06oOI+eO+Is2udpmY9GsGfmdoqvZVYoK4f5sawpZY9EC/84tbK9QKWUDTbFS+0Ujc254GUThmDA==} + dependencies: + proxy-compare: 2.5.1 + dev: false + + /@zag-js/switch@0.32.1: + resolution: {integrity: sha512-+5w/AtINA+jpORX1cuUrnyIFXrfjhqV7667EKK/zbPi0Pf1E10+TEihpfFjY6bgms9CSNWZVEb6w2f2C0PNBDA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + '@zag-js/visually-hidden': 0.32.1 + dev: false + + /@zag-js/tabbable@0.32.1: + resolution: {integrity: sha512-fMXtVgBiX7z3Qmdv+McrfihiSkqsDbNX2nn3e63L7jdy9ZpgnR3jG9BwUZvv7hvzkuOAFhhdKgBYYT+fkBavGg==} + dependencies: + '@zag-js/dom-query': 0.32.1 + dev: false + + /@zag-js/tabs@0.32.1: + resolution: {integrity: sha512-5l8/k2Pw9Kbfsvvx6HWcVqK7Ns7ca+nyPGLSZtZLMp/Zn2q3xSG32C1U3oDaYtQVIQSiEHdnMjw0C2v+CxGDMA==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/element-rect': 0.32.1 + '@zag-js/tabbable': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/tags-input@0.32.1: + resolution: {integrity: sha512-oliLhiMpRNbWFixHF+Oe7hySQBp7NKtL/s8rN5dLT1G1GFRMzuuht/QnmL1h8EoGGpTwaaokMo4zl4uVzHbwyw==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/auto-resize': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/form-utils': 0.32.1 + '@zag-js/interact-outside': 0.32.1 + '@zag-js/live-region': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/text-selection@0.32.1: + resolution: {integrity: sha512-aK1uswWYF76PFoxGL+3HW/kth9uldFWSW4lOh89NfEcc6Ym7qS5B+P0HKJVM9DuQbihvQX9dyc9PvM7/LJTSRA==} + dependencies: + '@zag-js/dom-query': 0.32.1 + dev: false + + /@zag-js/toast@0.32.1: + resolution: {integrity: sha512-HrfVzFX7ANS9qOewCr8qOCbgko635bZxYKMv+ojjo4U/TtwkGb43+lVU7/qwZj0z18/OtXBH5YQjFwQZXg5x8g==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/toggle-group@0.32.1: + resolution: {integrity: sha512-MM1XI4J45rRCZiDHcMtZWud0+bWMu6IcMnrbd9oig330YAF3RzcjTlxX93YRY35F04OUMBq5el9qe3qc2vyMuw==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/tooltip@0.32.1: + resolution: {integrity: sha512-+rsmDYTELFBHoYKg5iKShGfRD3H9FJDaZRq915Uc9YnyePMXCnWRgnVp+lk3zI+FDgysQm67SDLRJsR24Iioqg==} + dependencies: + '@zag-js/anatomy': 0.32.1 + '@zag-js/core': 0.32.1 + '@zag-js/dom-event': 0.32.1 + '@zag-js/dom-query': 0.32.1 + '@zag-js/popper': 0.32.1 + '@zag-js/types': 0.32.1 + '@zag-js/utils': 0.32.1 + dev: false + + /@zag-js/types@0.32.1: + resolution: {integrity: sha512-BLfqb+im4vtXXJqhd2ZUg/4LquEd1qPt9XN56XVjudGDTftN8n3EDpuail7VKxdL59W4jR7wW8lvl4sSgrQKWw==} + dependencies: + csstype: 3.1.3 + dev: false + + /@zag-js/utils@0.32.1: + resolution: {integrity: sha512-jrcmWYcA3L6TO4fZbPFvpSGEy2Z/mbWt6bPQbmcVgq/BltSS0YxxfPl+eD+S/rZI9aneszwsr04Z5TpladFiVA==} + dev: false + + /@zag-js/visually-hidden@0.32.1: + resolution: {integrity: sha512-Vzieo4vNulzY/0zqmVfeYW/LcFJp5xtEoyUgR1FBctH8uBPBRhTIEXxKtoMablW6/vccOVo7zcu0UrR5Vx+eYQ==} + dev: false + /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -9074,6 +9692,12 @@ packages: tslib: 2.6.2 dev: false + /focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + dependencies: + tabbable: 6.2.0 + dev: false + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: @@ -11307,6 +11931,10 @@ packages: ipaddr.js: 1.9.1 dev: true + /proxy-compare@2.5.1: + resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} + dev: false + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true @@ -12777,6 +13405,10 @@ packages: resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} dev: true + /tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + dev: false + /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx index 8496bde318..8c40777714 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterConfig.tsx @@ -1,9 +1,9 @@ -import { ChevronUpIcon } from '@chakra-ui/icons'; import { Box, Flex, FormControl, FormLabel, + Icon, IconButton, Switch, } from '@invoke-ai/ui'; @@ -19,7 +19,7 @@ import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import type { ChangeEvent } from 'react'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { PiCopyBold, PiTrashSimpleBold } from 'react-icons/pi'; +import { PiCaretUpBold, PiCopyBold, PiTrashSimpleBold } from 'react-icons/pi'; import { useToggle } from 'react-use'; import ControlAdapterImagePreview from './ControlAdapterImagePreview'; @@ -130,8 +130,9 @@ const ControlAdapterConfig = (props: { id: string; number: number }) => { onClick={toggleIsExpanded} variant="ghost" icon={ - { } /> diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx index 97e8f740ef..04a4ae8078 100644 --- a/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx @@ -1,7 +1,7 @@ -import { ChevronUpIcon } from '@chakra-ui/icons'; -import { Button, Flex, Spacer } from '@invoke-ai/ui'; +import { Button, Flex, Icon, Spacer } from '@invoke-ai/ui'; import { useAppSelector } from 'app/store/storeHooks'; import { memo, useMemo } from 'react'; +import { PiCaretUpBold } from 'react-icons/pi'; import { useBoardName } from 'services/api/hooks/useBoardName'; type Props = { @@ -36,7 +36,9 @@ const GalleryBoardName = (props: Props) => { {formattedBoardName} - {isLink ? ( - - {value.toString()} - + ) : ( {value.toString()} diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx index 52770458f7..58c04e483b 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageMetadataViewer/ImageMetadataViewer.tsx @@ -1,13 +1,11 @@ -import { ExternalLinkIcon } from '@chakra-ui/icons'; import { + ExternalLink, Flex, - Link, Tab, TabList, TabPanel, TabPanels, Tabs, - Text, } from '@invoke-ai/ui'; import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; @@ -46,13 +44,7 @@ const ImageMetadataViewer = ({ image }: ImageMetadataViewerProps) => { position="absolute" overflow="hidden" > - - {t('common.file')}: - - {image.image_name} - - - + { h={8} variant="link" icon={ - { const dispatch = useAppDispatch(); const selectIsOpen = useMemo( - () => createSelector(selectUiSlice, (ui) => ui.expanders[arg.id] ?? arg.defaultIsOpen), + () => + createSelector( + selectUiSlice, + (ui) => ui.expanders[arg.id] ?? arg.defaultIsOpen + ), [arg] ); const isOpen = useAppSelector(selectIsOpen); diff --git a/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx b/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx index 9f7f295ed2..9ff0389e26 100644 --- a/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx @@ -1,11 +1,10 @@ -import { ExternalLinkIcon } from '@chakra-ui/icons'; import { + ExternalLink, Flex, Grid, GridItem, Heading, Image, - Link, Modal, ModalBody, ModalCloseButton, @@ -103,23 +102,21 @@ const AboutModal = ({ children }: AboutModalProps) => { {appVersion && {`v${appVersion?.version}`}} - - {t('common.githubLabel')} - - + - - {t('common.discordLabel')} - - + {t('common.aboutHeading')} {t('common.aboutDesc')} - - {websiteLink} - + diff --git a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx index 9b54784101..36d24ba5eb 100644 --- a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx @@ -1,4 +1,3 @@ -import { CloseIcon } from '@chakra-ui/icons'; import { Divider, Flex, @@ -30,6 +29,7 @@ import { useState, } from 'react'; import { useTranslation } from 'react-i18next'; +import { PiXBold } from 'react-icons/pi'; import HotkeyListItem from './HotkeyListItem'; @@ -103,7 +103,8 @@ const HotkeysModal = ({ children }: HotkeysModalProps) => { size="sm" variant="ghost" aria-label={t('hotkeys.clearSearch')} - icon={} + boxSize={4} + icon={} /> )} diff --git a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx index 3faaa683ee..6e1278c665 100644 --- a/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx +++ b/invokeai/frontend/web/src/features/ui/components/FloatingParametersPanelButtons.tsx @@ -1,8 +1,8 @@ -import { SpinnerIcon } from '@chakra-ui/icons'; import type { SystemStyleObject } from '@invoke-ai/ui'; import { ButtonGroup, Flex, + Icon, IconButton, Portal, spinAnimation, @@ -14,7 +14,7 @@ import { useQueueBack } from 'features/queue/hooks/useQueueBack'; import type { UsePanelReturn } from 'features/ui/hooks/usePanel'; import { memo, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { PiSlidersHorizontalBold } from 'react-icons/pi'; +import { PiCircleNotchBold, PiSlidersHorizontalBold } from 'react-icons/pi'; import { RiSparklingFill } from 'react-icons/ri'; import { useGetQueueStatusQuery } from 'services/api/endpoints/queue'; @@ -35,7 +35,7 @@ const FloatingSidePanelButtons = (props: Props) => { const queueButtonIcon = useMemo( () => !isDisabled && queueStatus?.processor.is_processing ? ( - + ) : ( ), diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx index 2c5b6fa1e7..9d5087d059 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx +++ b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx @@ -1,4 +1,3 @@ -import { CloseIcon } from '@chakra-ui/icons'; import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui'; import { Button, @@ -25,6 +24,7 @@ import WorkflowLibraryPagination from 'features/workflowLibrary/components/Workf import type { ChangeEvent, KeyboardEvent } from 'react'; import { memo, useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { PiXBold } from 'react-icons/pi'; import { useListWorkflowsQuery } from 'services/api/endpoints/workflows'; import type { SQLiteDirection, @@ -202,14 +202,13 @@ const WorkflowLibraryList = () => { minW={64} /> {query.trim().length && ( - + } + icon={} /> )} From 52b51a608864477f52b0eccce3ee07f65ad56210 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 23:05:29 +1100 Subject: [PATCH 14/34] fix(ui): recall/use size sets aspect ratio correctly Added a new action that resets the aspect ratio when dispatched. Closes #5456 --- .../parameters/hooks/useRecallParameters.ts | 16 ++++++++-------- .../features/parameters/store/generationSlice.ts | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts b/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts index d25c3aea77..126b700fde 100644 --- a/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts +++ b/invokeai/frontend/web/src/features/parameters/hooks/useRecallParameters.ts @@ -34,7 +34,7 @@ import { modelSelected, } from 'features/parameters/store/actions'; import { - heightChanged, + heightRecalled, selectGenerationSlice, setCfgRescaleMultiplier, setCfgScale, @@ -45,7 +45,7 @@ import { setSeed, setSteps, vaeSelected, - widthChanged, + widthRecalled, } from 'features/parameters/store/generationSlice'; import type { ParameterModel } from 'features/parameters/types/parameterSchemas'; import { @@ -373,7 +373,7 @@ export const useRecallParameters = () => { parameterNotSetToast(); return; } - dispatch(widthChanged(width)); + dispatch(widthRecalled(width)); parameterSetToast(); }, [dispatch, parameterSetToast, parameterNotSetToast] @@ -388,7 +388,7 @@ export const useRecallParameters = () => { parameterNotSetToast(); return; } - dispatch(heightChanged(height)); + dispatch(heightRecalled(height)); parameterSetToast(); }, [dispatch, parameterSetToast, parameterNotSetToast] @@ -407,8 +407,8 @@ export const useRecallParameters = () => { allParameterNotSetToast(); return; } - dispatch(heightChanged(height)); - dispatch(widthChanged(width)); + dispatch(heightRecalled(height)); + dispatch(widthRecalled(width)); allParameterSetToast(); }, [dispatch, allParameterSetToast, allParameterNotSetToast] @@ -893,11 +893,11 @@ export const useRecallParameters = () => { } if (isParameterWidth(width)) { - dispatch(widthChanged(width)); + dispatch(widthRecalled(width)); } if (isParameterHeight(height)) { - dispatch(heightChanged(height)); + dispatch(heightRecalled(height)); } if (isParameterStrength(strength)) { diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index f9f61c074f..baa4852697 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -230,6 +230,18 @@ export const generationSlice = createSlice({ heightChanged: (state, action: PayloadAction) => { state.height = action.payload; }, + widthRecalled: (state, action: PayloadAction) => { + state.width = action.payload; + state.aspectRatio.value = action.payload / state.height; + state.aspectRatio.id = 'Free'; + state.aspectRatio.isLocked = false; + }, + heightRecalled: (state, action: PayloadAction) => { + state.height = action.payload; + state.aspectRatio.value = state.width / action.payload; + state.aspectRatio.id = 'Free'; + state.aspectRatio.isLocked = false; + }, aspectRatioChanged: (state, action: PayloadAction) => { state.aspectRatio = action.payload; }, @@ -306,6 +318,8 @@ export const { aspectRatioChanged, widthChanged, heightChanged, + widthRecalled, + heightRecalled, } = generationSlice.actions; export const { selectOptimalDimension } = generationSlice.selectors; From 2aed6e2dbae00871eb867e7acedd8e4207056c19 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 23 Jan 2024 23:08:36 +1100 Subject: [PATCH 15/34] fix(ui): duplicate "base model" in merge UI closes #5505 --- .../AddModelsPanel/AdvancedAddDiffusers.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/invokeai/frontend/web/src/features/modelManager/subpanels/AddModelsPanel/AdvancedAddDiffusers.tsx b/invokeai/frontend/web/src/features/modelManager/subpanels/AddModelsPanel/AdvancedAddDiffusers.tsx index 18e55ff686..090b65f8d7 100644 --- a/invokeai/frontend/web/src/features/modelManager/subpanels/AddModelsPanel/AdvancedAddDiffusers.tsx +++ b/invokeai/frontend/web/src/features/modelManager/subpanels/AddModelsPanel/AdvancedAddDiffusers.tsx @@ -122,13 +122,10 @@ const AdvancedAddDiffusers = (props: AdvancedAddDiffusersProps) => { {errors.model_name?.message} )} - - {t('modelManager.baseModel')} - - control={control} - name="base_model" - /> - + + control={control} + name="base_model" + /> {t('modelManager.modelLocation')} { value.trim().length > 0 || 'Must provide a path', onBlur, })} - />{' '} + /> {errors.path?.message && ( {errors.path?.message} )} From 8f5e2cbcc7f75f1427bfa94da55d50524d9d52ff Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 23 Jan 2024 02:30:56 +0530 Subject: [PATCH 16/34] feat: Add Depth Anything PreProcessor --- .../controlnet_image_processors.py | 30 +++ .../image_util/depth_anything/__init__.py | 107 +++++++++ .../image_util/depth_anything/model/blocks.py | 145 +++++++++++ .../image_util/depth_anything/model/dpt.py | 186 ++++++++++++++ .../depth_anything/utilities/util.py | 227 ++++++++++++++++++ 5 files changed, 695 insertions(+) create mode 100644 invokeai/backend/image_util/depth_anything/__init__.py create mode 100644 invokeai/backend/image_util/depth_anything/model/blocks.py create mode 100644 invokeai/backend/image_util/depth_anything/model/dpt.py create mode 100644 invokeai/backend/image_util/depth_anything/utilities/util.py diff --git a/invokeai/app/invocations/controlnet_image_processors.py b/invokeai/app/invocations/controlnet_image_processors.py index f16a8e36ae..967e0c6f40 100644 --- a/invokeai/app/invocations/controlnet_image_processors.py +++ b/invokeai/app/invocations/controlnet_image_processors.py @@ -30,6 +30,7 @@ from invokeai.app.invocations.primitives import ImageField, ImageOutput from invokeai.app.invocations.util import validate_begin_end_step, validate_weights from invokeai.app.services.image_records.image_records_common import ImageCategory, ResourceOrigin from invokeai.app.shared.fields import FieldDescriptions +from invokeai.backend.image_util.depth_anything import DepthAnythingDetector from ...backend.model_management import BaseModelType from .baseinvocation import ( @@ -602,3 +603,32 @@ class ColorMapImageProcessorInvocation(ImageProcessorInvocation): color_map = cv2.resize(color_map, (width, height), interpolation=cv2.INTER_NEAREST) color_map = Image.fromarray(color_map) return color_map + + +DEPTH_ANYTHING_MODEL_SIZES = Literal["large", "base", "small"] + + +@invocation( + "depth_anything_image_processor", + title="Depth Anything Processor", + tags=["controlnet", "depth", "depth anything"], + category="controlnet", + version="1.0.0", +) +class DepthAnythingImageProcessorInvocation(ImageProcessorInvocation): + """Generates a depth map based on the Depth Anything algorithm""" + + model_size: DEPTH_ANYTHING_MODEL_SIZES = InputField( + default="large", description="The size of the depth model to use" + ) + offload: bool = InputField(default=False) + + def run_processor(self, image): + depth_anything_detector = DepthAnythingDetector() + depth_anything_detector.load_model(model_size=self.model_size) + + if image.mode == "RGBA": + image = image.convert("RGB") + + processed_image = depth_anything_detector(image=image, offload=self.offload) + return processed_image diff --git a/invokeai/backend/image_util/depth_anything/__init__.py b/invokeai/backend/image_util/depth_anything/__init__.py new file mode 100644 index 0000000000..626e48a87a --- /dev/null +++ b/invokeai/backend/image_util/depth_anything/__init__.py @@ -0,0 +1,107 @@ +import pathlib +from typing import Literal, Union + +import cv2 +import numpy as np +import torch +import torch.nn.functional as F +from einops import repeat +from PIL import Image +from torchvision.transforms import Compose + +from invokeai.app.services.config.config_default import InvokeAIAppConfig +from invokeai.backend.image_util.depth_anything.model.dpt import DPT_DINOv2 +from invokeai.backend.image_util.depth_anything.utilities.util import NormalizeImage, PrepareForNet, Resize +from invokeai.backend.util.devices import choose_torch_device +from invokeai.backend.util.util import download_with_progress_bar + +config = InvokeAIAppConfig.get_config() + +DEPTH_ANYTHING_MODELS = { + "large": { + "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitl14.pth?download=true", + "local": "sd-1/controlnet/annotator/depth_anything/depth_anything_vitl14.pth", + }, + "base": { + "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitb14.pth?download=true", + "local": "sd-1/controlnet/annotator/depth_anything/depth_anything_vitb14.pth", + }, + "small": { + "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vits14.pth?download=true", + "local": "sd-1/controlnet/annotator/depth_anything/depth_anything_vits14.pth", + }, +} + + +transform = Compose( + [ + Resize( + width=518, + height=518, + resize_target=False, + keep_aspect_ratio=True, + ensure_multiple_of=14, + resize_method="lower_bound", + image_interpolation_method=cv2.INTER_CUBIC, + ), + NormalizeImage(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), + PrepareForNet(), + ] +) + + +class DepthAnythingDetector: + def __init__(self) -> None: + self.model = None + self.model_size: Union[Literal["large", "base", "small"], None] = None + + def load_model(self, model_size=Literal["large", "base", "small"]): + DEPTH_ANYTHING_MODEL_PATH = pathlib.Path(config.models_path / DEPTH_ANYTHING_MODELS[model_size]["local"]) + if not DEPTH_ANYTHING_MODEL_PATH.exists(): + download_with_progress_bar(DEPTH_ANYTHING_MODELS[model_size]["url"], DEPTH_ANYTHING_MODEL_PATH) + + if not self.model or model_size != self.model_size: + del self.model + self.model_size = model_size + + if self.model_size == "small": + self.model = DPT_DINOv2(encoder="vits", features=64, out_channels=[48, 96, 192, 384], localhub=True) + if self.model_size == "base": + self.model = DPT_DINOv2(encoder="vitb", features=128, out_channels=[96, 192, 384, 768], localhub=True) + if self.model_size == "large": + self.model = DPT_DINOv2( + encoder="vitl", features=256, out_channels=[256, 512, 1024, 1024], localhub=True + ) + + self.model.load_state_dict(torch.load(DEPTH_ANYTHING_MODEL_PATH.as_posix(), map_location="cpu")) + self.model.eval() + + self.model.to(choose_torch_device()) + return self.model + + def to(self, device): + self.model.to(device) + return self + + def __call__(self, image, offload=False): + image = np.array(image, dtype=np.uint8) + original_width, original_height = image.shape[:2] + image = image[:, :, ::-1] / 255.0 + + image_width, image_height = image.shape[:2] + image = transform({"image": image})["image"] + image = torch.from_numpy(image).unsqueeze(0).to(choose_torch_device()) + + with torch.no_grad(): + depth = self.model(image) + depth = F.interpolate(depth[None], (image_height, image_width), mode="bilinear", align_corners=False)[0, 0] + depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255.0 + + depth_map = repeat(depth, "h w -> h w 3").cpu().numpy().astype(np.uint8) + depth_map = Image.fromarray(depth_map) + depth_map = depth_map.resize((original_height, original_width)) + + if offload: + del self.model + + return depth_map diff --git a/invokeai/backend/image_util/depth_anything/model/blocks.py b/invokeai/backend/image_util/depth_anything/model/blocks.py new file mode 100644 index 0000000000..4534f52237 --- /dev/null +++ b/invokeai/backend/image_util/depth_anything/model/blocks.py @@ -0,0 +1,145 @@ +import torch.nn as nn + + +def _make_scratch(in_shape, out_shape, groups=1, expand=False): + scratch = nn.Module() + + out_shape1 = out_shape + out_shape2 = out_shape + out_shape3 = out_shape + if len(in_shape) >= 4: + out_shape4 = out_shape + + if expand: + out_shape1 = out_shape + out_shape2 = out_shape * 2 + out_shape3 = out_shape * 4 + if len(in_shape) >= 4: + out_shape4 = out_shape * 8 + + scratch.layer1_rn = nn.Conv2d( + in_shape[0], out_shape1, kernel_size=3, stride=1, padding=1, bias=False, groups=groups + ) + scratch.layer2_rn = nn.Conv2d( + in_shape[1], out_shape2, kernel_size=3, stride=1, padding=1, bias=False, groups=groups + ) + scratch.layer3_rn = nn.Conv2d( + in_shape[2], out_shape3, kernel_size=3, stride=1, padding=1, bias=False, groups=groups + ) + if len(in_shape) >= 4: + scratch.layer4_rn = nn.Conv2d( + in_shape[3], out_shape4, kernel_size=3, stride=1, padding=1, bias=False, groups=groups + ) + + return scratch + + +class ResidualConvUnit(nn.Module): + """Residual convolution module.""" + + def __init__(self, features, activation, bn): + """Init. + + Args: + features (int): number of features + """ + super().__init__() + + self.bn = bn + + self.groups = 1 + + self.conv1 = nn.Conv2d(features, features, kernel_size=3, stride=1, padding=1, bias=True, groups=self.groups) + + self.conv2 = nn.Conv2d(features, features, kernel_size=3, stride=1, padding=1, bias=True, groups=self.groups) + + if self.bn: + self.bn1 = nn.BatchNorm2d(features) + self.bn2 = nn.BatchNorm2d(features) + + self.activation = activation + + self.skip_add = nn.quantized.FloatFunctional() + + def forward(self, x): + """Forward pass. + + Args: + x (tensor): input + + Returns: + tensor: output + """ + + out = self.activation(x) + out = self.conv1(out) + if self.bn: + out = self.bn1(out) + + out = self.activation(out) + out = self.conv2(out) + if self.bn: + out = self.bn2(out) + + if self.groups > 1: + out = self.conv_merge(out) + + return self.skip_add.add(out, x) + + +class FeatureFusionBlock(nn.Module): + """Feature fusion block.""" + + def __init__(self, features, activation, deconv=False, bn=False, expand=False, align_corners=True, size=None): + """Init. + + Args: + features (int): number of features + """ + super(FeatureFusionBlock, self).__init__() + + self.deconv = deconv + self.align_corners = align_corners + + self.groups = 1 + + self.expand = expand + out_features = features + if self.expand: + out_features = features // 2 + + self.out_conv = nn.Conv2d(features, out_features, kernel_size=1, stride=1, padding=0, bias=True, groups=1) + + self.resConfUnit1 = ResidualConvUnit(features, activation, bn) + self.resConfUnit2 = ResidualConvUnit(features, activation, bn) + + self.skip_add = nn.quantized.FloatFunctional() + + self.size = size + + def forward(self, *xs, size=None): + """Forward pass. + + Returns: + tensor: output + """ + output = xs[0] + + if len(xs) == 2: + res = self.resConfUnit1(xs[1]) + output = self.skip_add.add(output, res) + + output = self.resConfUnit2(output) + + if (size is None) and (self.size is None): + modifier = {"scale_factor": 2} + elif size is None: + modifier = {"size": self.size} + else: + modifier = {"size": size} + + output = nn.functional.interpolate(output, **modifier, mode="bilinear", align_corners=self.align_corners) + + output = self.out_conv(output) + + return output diff --git a/invokeai/backend/image_util/depth_anything/model/dpt.py b/invokeai/backend/image_util/depth_anything/model/dpt.py new file mode 100644 index 0000000000..3be6f97fc4 --- /dev/null +++ b/invokeai/backend/image_util/depth_anything/model/dpt.py @@ -0,0 +1,186 @@ +from pathlib import Path + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from .blocks import FeatureFusionBlock, _make_scratch + +torchhub_path = Path(__file__).parent.parent / "torchhub" + + +def _make_fusion_block(features, use_bn, size=None): + return FeatureFusionBlock( + features, + nn.ReLU(False), + deconv=False, + bn=use_bn, + expand=False, + align_corners=True, + size=size, + ) + + +class DPTHead(nn.Module): + def __init__( + self, nclass, in_channels, features=256, use_bn=False, out_channels=[256, 512, 1024, 1024], use_clstoken=False + ): + super(DPTHead, self).__init__() + + self.nclass = nclass + self.use_clstoken = use_clstoken + + self.projects = nn.ModuleList( + [ + nn.Conv2d( + in_channels=in_channels, + out_channels=out_channel, + kernel_size=1, + stride=1, + padding=0, + ) + for out_channel in out_channels + ] + ) + + self.resize_layers = nn.ModuleList( + [ + nn.ConvTranspose2d( + in_channels=out_channels[0], out_channels=out_channels[0], kernel_size=4, stride=4, padding=0 + ), + nn.ConvTranspose2d( + in_channels=out_channels[1], out_channels=out_channels[1], kernel_size=2, stride=2, padding=0 + ), + nn.Identity(), + nn.Conv2d( + in_channels=out_channels[3], out_channels=out_channels[3], kernel_size=3, stride=2, padding=1 + ), + ] + ) + + if use_clstoken: + self.readout_projects = nn.ModuleList() + for _ in range(len(self.projects)): + self.readout_projects.append(nn.Sequential(nn.Linear(2 * in_channels, in_channels), nn.GELU())) + + self.scratch = _make_scratch( + out_channels, + features, + groups=1, + expand=False, + ) + + self.scratch.stem_transpose = None + + self.scratch.refinenet1 = _make_fusion_block(features, use_bn) + self.scratch.refinenet2 = _make_fusion_block(features, use_bn) + self.scratch.refinenet3 = _make_fusion_block(features, use_bn) + self.scratch.refinenet4 = _make_fusion_block(features, use_bn) + + head_features_1 = features + head_features_2 = 32 + + if nclass > 1: + self.scratch.output_conv = nn.Sequential( + nn.Conv2d(head_features_1, head_features_1, kernel_size=3, stride=1, padding=1), + nn.ReLU(True), + nn.Conv2d(head_features_1, nclass, kernel_size=1, stride=1, padding=0), + ) + else: + self.scratch.output_conv1 = nn.Conv2d( + head_features_1, head_features_1 // 2, kernel_size=3, stride=1, padding=1 + ) + + self.scratch.output_conv2 = nn.Sequential( + nn.Conv2d(head_features_1 // 2, head_features_2, kernel_size=3, stride=1, padding=1), + nn.ReLU(True), + nn.Conv2d(head_features_2, 1, kernel_size=1, stride=1, padding=0), + nn.ReLU(True), + nn.Identity(), + ) + + def forward(self, out_features, patch_h, patch_w): + out = [] + for i, x in enumerate(out_features): + if self.use_clstoken: + x, cls_token = x[0], x[1] + readout = cls_token.unsqueeze(1).expand_as(x) + x = self.readout_projects[i](torch.cat((x, readout), -1)) + else: + x = x[0] + + x = x.permute(0, 2, 1).reshape((x.shape[0], x.shape[-1], patch_h, patch_w)) + + x = self.projects[i](x) + x = self.resize_layers[i](x) + + out.append(x) + + layer_1, layer_2, layer_3, layer_4 = out + + layer_1_rn = self.scratch.layer1_rn(layer_1) + layer_2_rn = self.scratch.layer2_rn(layer_2) + layer_3_rn = self.scratch.layer3_rn(layer_3) + layer_4_rn = self.scratch.layer4_rn(layer_4) + + path_4 = self.scratch.refinenet4(layer_4_rn, size=layer_3_rn.shape[2:]) + path_3 = self.scratch.refinenet3(path_4, layer_3_rn, size=layer_2_rn.shape[2:]) + path_2 = self.scratch.refinenet2(path_3, layer_2_rn, size=layer_1_rn.shape[2:]) + path_1 = self.scratch.refinenet1(path_2, layer_1_rn) + + out = self.scratch.output_conv1(path_1) + out = F.interpolate(out, (int(patch_h * 14), int(patch_w * 14)), mode="bilinear", align_corners=True) + out = self.scratch.output_conv2(out) + + return out + + +class DPT_DINOv2(nn.Module): + def __init__( + self, + encoder="vitl", + features=256, + out_channels=[256, 512, 1024, 1024], + use_bn=False, + use_clstoken=False, + localhub=True, + ): + super(DPT_DINOv2, self).__init__() + + assert encoder in ["vits", "vitb", "vitl"] + + # # in case the Internet connection is not stable, please load the DINOv2 locally + # if localhub: + # self.pretrained = torch.hub.load( + # torchhub_path / "facebookresearch_dinov2_main", + # "dinov2_{:}14".format(encoder), + # source="local", + # pretrained=False, + # ) + # else: + # self.pretrained = torch.hub.load( + # "facebookresearch/dinov2", + # "dinov2_{:}14".format(encoder), + # ) + + self.pretrained = torch.hub.load( + "facebookresearch/dinov2", + "dinov2_{:}14".format(encoder), + ) + + dim = self.pretrained.blocks[0].attn.qkv.in_features + + self.depth_head = DPTHead(1, dim, features, use_bn, out_channels=out_channels, use_clstoken=use_clstoken) + + def forward(self, x): + h, w = x.shape[-2:] + + features = self.pretrained.get_intermediate_layers(x, 4, return_class_token=True) + + patch_h, patch_w = h // 14, w // 14 + + depth = self.depth_head(features, patch_h, patch_w) + depth = F.interpolate(depth, size=(h, w), mode="bilinear", align_corners=True) + depth = F.relu(depth) + + return depth.squeeze(1) diff --git a/invokeai/backend/image_util/depth_anything/utilities/util.py b/invokeai/backend/image_util/depth_anything/utilities/util.py new file mode 100644 index 0000000000..5362ef6c3e --- /dev/null +++ b/invokeai/backend/image_util/depth_anything/utilities/util.py @@ -0,0 +1,227 @@ +import math + +import cv2 +import numpy as np +import torch +import torch.nn.functional as F + + +def apply_min_size(sample, size, image_interpolation_method=cv2.INTER_AREA): + """Rezise the sample to ensure the given size. Keeps aspect ratio. + + Args: + sample (dict): sample + size (tuple): image size + + Returns: + tuple: new size + """ + shape = list(sample["disparity"].shape) + + if shape[0] >= size[0] and shape[1] >= size[1]: + return sample + + scale = [0, 0] + scale[0] = size[0] / shape[0] + scale[1] = size[1] / shape[1] + + scale = max(scale) + + shape[0] = math.ceil(scale * shape[0]) + shape[1] = math.ceil(scale * shape[1]) + + # resize + sample["image"] = cv2.resize(sample["image"], tuple(shape[::-1]), interpolation=image_interpolation_method) + + sample["disparity"] = cv2.resize(sample["disparity"], tuple(shape[::-1]), interpolation=cv2.INTER_NEAREST) + sample["mask"] = cv2.resize( + sample["mask"].astype(np.float32), + tuple(shape[::-1]), + interpolation=cv2.INTER_NEAREST, + ) + sample["mask"] = sample["mask"].astype(bool) + + return tuple(shape) + + +class Resize(object): + """Resize sample to given size (width, height).""" + + def __init__( + self, + width, + height, + resize_target=True, + keep_aspect_ratio=False, + ensure_multiple_of=1, + resize_method="lower_bound", + image_interpolation_method=cv2.INTER_AREA, + ): + """Init. + + Args: + width (int): desired output width + height (int): desired output height + resize_target (bool, optional): + True: Resize the full sample (image, mask, target). + False: Resize image only. + Defaults to True. + keep_aspect_ratio (bool, optional): + True: Keep the aspect ratio of the input sample. + Output sample might not have the given width and height, and + resize behaviour depends on the parameter 'resize_method'. + Defaults to False. + ensure_multiple_of (int, optional): + Output width and height is constrained to be multiple of this parameter. + Defaults to 1. + resize_method (str, optional): + "lower_bound": Output will be at least as large as the given size. + "upper_bound": Output will be at max as large as the given size. (Output size might be smaller + than given size.) + "minimal": Scale as least as possible. (Output size might be smaller than given size.) + Defaults to "lower_bound". + """ + self.__width = width + self.__height = height + + self.__resize_target = resize_target + self.__keep_aspect_ratio = keep_aspect_ratio + self.__multiple_of = ensure_multiple_of + self.__resize_method = resize_method + self.__image_interpolation_method = image_interpolation_method + + def constrain_to_multiple_of(self, x, min_val=0, max_val=None): + y = (np.round(x / self.__multiple_of) * self.__multiple_of).astype(int) + + if max_val is not None and y > max_val: + y = (np.floor(x / self.__multiple_of) * self.__multiple_of).astype(int) + + if y < min_val: + y = (np.ceil(x / self.__multiple_of) * self.__multiple_of).astype(int) + + return y + + def get_size(self, width, height): + # determine new height and width + scale_height = self.__height / height + scale_width = self.__width / width + + if self.__keep_aspect_ratio: + if self.__resize_method == "lower_bound": + # scale such that output size is lower bound + if scale_width > scale_height: + # fit width + scale_height = scale_width + else: + # fit height + scale_width = scale_height + elif self.__resize_method == "upper_bound": + # scale such that output size is upper bound + if scale_width < scale_height: + # fit width + scale_height = scale_width + else: + # fit height + scale_width = scale_height + elif self.__resize_method == "minimal": + # scale as least as possbile + if abs(1 - scale_width) < abs(1 - scale_height): + # fit width + scale_height = scale_width + else: + # fit height + scale_width = scale_height + else: + raise ValueError(f"resize_method {self.__resize_method} not implemented") + + if self.__resize_method == "lower_bound": + new_height = self.constrain_to_multiple_of(scale_height * height, min_val=self.__height) + new_width = self.constrain_to_multiple_of(scale_width * width, min_val=self.__width) + elif self.__resize_method == "upper_bound": + new_height = self.constrain_to_multiple_of(scale_height * height, max_val=self.__height) + new_width = self.constrain_to_multiple_of(scale_width * width, max_val=self.__width) + elif self.__resize_method == "minimal": + new_height = self.constrain_to_multiple_of(scale_height * height) + new_width = self.constrain_to_multiple_of(scale_width * width) + else: + raise ValueError(f"resize_method {self.__resize_method} not implemented") + + return (new_width, new_height) + + def __call__(self, sample): + width, height = self.get_size(sample["image"].shape[1], sample["image"].shape[0]) + + # resize sample + sample["image"] = cv2.resize( + sample["image"], + (width, height), + interpolation=self.__image_interpolation_method, + ) + + if self.__resize_target: + if "disparity" in sample: + sample["disparity"] = cv2.resize( + sample["disparity"], + (width, height), + interpolation=cv2.INTER_NEAREST, + ) + + if "depth" in sample: + sample["depth"] = cv2.resize(sample["depth"], (width, height), interpolation=cv2.INTER_NEAREST) + + if "semseg_mask" in sample: + # sample["semseg_mask"] = cv2.resize( + # sample["semseg_mask"], (width, height), interpolation=cv2.INTER_NEAREST + # ) + sample["semseg_mask"] = F.interpolate( + torch.from_numpy(sample["semseg_mask"]).float()[None, None, ...], (height, width), mode="nearest" + ).numpy()[0, 0] + + if "mask" in sample: + sample["mask"] = cv2.resize( + sample["mask"].astype(np.float32), + (width, height), + interpolation=cv2.INTER_NEAREST, + ) + # sample["mask"] = sample["mask"].astype(bool) + + # print(sample['image'].shape, sample['depth'].shape) + return sample + + +class NormalizeImage(object): + """Normlize image by given mean and std.""" + + def __init__(self, mean, std): + self.__mean = mean + self.__std = std + + def __call__(self, sample): + sample["image"] = (sample["image"] - self.__mean) / self.__std + + return sample + + +class PrepareForNet(object): + """Prepare sample for usage as network input.""" + + def __init__(self): + pass + + def __call__(self, sample): + image = np.transpose(sample["image"], (2, 0, 1)) + sample["image"] = np.ascontiguousarray(image).astype(np.float32) + + if "mask" in sample: + sample["mask"] = sample["mask"].astype(np.float32) + sample["mask"] = np.ascontiguousarray(sample["mask"]) + + if "depth" in sample: + depth = sample["depth"].astype(np.float32) + sample["depth"] = np.ascontiguousarray(depth) + + if "semseg_mask" in sample: + sample["semseg_mask"] = sample["semseg_mask"].astype(np.float32) + sample["semseg_mask"] = np.ascontiguousarray(sample["semseg_mask"]) + + return sample From c859eb865e4aa93a8ce71c6a1b1e1b42888e1007 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 23 Jan 2024 02:50:20 +0530 Subject: [PATCH 17/34] fix: lint & other minor issues --- .../backend/image_util/depth_anything/__init__.py | 8 +++----- .../backend/image_util/depth_anything/model/dpt.py | 13 +++++-------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/invokeai/backend/image_util/depth_anything/__init__.py b/invokeai/backend/image_util/depth_anything/__init__.py index 626e48a87a..37adaa3004 100644 --- a/invokeai/backend/image_util/depth_anything/__init__.py +++ b/invokeai/backend/image_util/depth_anything/__init__.py @@ -65,13 +65,11 @@ class DepthAnythingDetector: self.model_size = model_size if self.model_size == "small": - self.model = DPT_DINOv2(encoder="vits", features=64, out_channels=[48, 96, 192, 384], localhub=True) + self.model = DPT_DINOv2(encoder="vits", features=64, out_channels=[48, 96, 192, 384]) if self.model_size == "base": - self.model = DPT_DINOv2(encoder="vitb", features=128, out_channels=[96, 192, 384, 768], localhub=True) + self.model = DPT_DINOv2(encoder="vitb", features=128, out_channels=[96, 192, 384, 768]) if self.model_size == "large": - self.model = DPT_DINOv2( - encoder="vitl", features=256, out_channels=[256, 512, 1024, 1024], localhub=True - ) + self.model = DPT_DINOv2(encoder="vitl", features=256, out_channels=[256, 512, 1024, 1024]) self.model.load_state_dict(torch.load(DEPTH_ANYTHING_MODEL_PATH.as_posix(), map_location="cpu")) self.model.eval() diff --git a/invokeai/backend/image_util/depth_anything/model/dpt.py b/invokeai/backend/image_util/depth_anything/model/dpt.py index 3be6f97fc4..e1101b3c39 100644 --- a/invokeai/backend/image_util/depth_anything/model/dpt.py +++ b/invokeai/backend/image_util/depth_anything/model/dpt.py @@ -22,9 +22,7 @@ def _make_fusion_block(features, use_bn, size=None): class DPTHead(nn.Module): - def __init__( - self, nclass, in_channels, features=256, use_bn=False, out_channels=[256, 512, 1024, 1024], use_clstoken=False - ): + def __init__(self, nclass, in_channels, features, out_channels, use_bn=False, use_clstoken=False): super(DPTHead, self).__init__() self.nclass = nclass @@ -138,19 +136,18 @@ class DPTHead(nn.Module): class DPT_DINOv2(nn.Module): def __init__( self, + features, + out_channels, encoder="vitl", - features=256, - out_channels=[256, 512, 1024, 1024], use_bn=False, use_clstoken=False, - localhub=True, ): super(DPT_DINOv2, self).__init__() assert encoder in ["vits", "vitb", "vitl"] # # in case the Internet connection is not stable, please load the DINOv2 locally - # if localhub: + # if use_local: # self.pretrained = torch.hub.load( # torchhub_path / "facebookresearch_dinov2_main", # "dinov2_{:}14".format(encoder), @@ -170,7 +167,7 @@ class DPT_DINOv2(nn.Module): dim = self.pretrained.blocks[0].attn.qkv.in_features - self.depth_head = DPTHead(1, dim, features, use_bn, out_channels=out_channels, use_clstoken=use_clstoken) + self.depth_head = DPTHead(1, dim, features, out_channels=out_channels, use_bn=use_bn, use_clstoken=use_clstoken) def forward(self, x): h, w = x.shape[-2:] From 13123daa3f863ce73c4a952e6122418e5ab9f3b8 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 23 Jan 2024 03:58:24 +0530 Subject: [PATCH 18/34] feat: Add DepthAnything to Linear UI --- invokeai/frontend/web/public/locales/en.json | 6 + .../ControlAdapterProcessorComponent.tsx | 11 + .../processors/DepthAnyThingProcessor.tsx | 72 ++ .../controlAdapters/store/constants.ts | 15 + .../features/controlAdapters/store/types.ts | 33 + .../frontend/web/src/services/api/schema.ts | 852 ++++++++++++++++-- .../frontend/web/src/services/api/types.ts | 2 + 7 files changed, 893 insertions(+), 98 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 4aa31ede8a..be231684b4 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -224,6 +224,7 @@ "amult": "a_mult", "autoConfigure": "Auto configure processor", "balanced": "Balanced", + "base": "Base", "beginEndStepPercent": "Begin / End Step Percentage", "bgth": "bg_th", "canny": "Canny", @@ -237,6 +238,8 @@ "controlMode": "Control Mode", "crop": "Crop", "delete": "Delete", + "depthAnything": "Depth Anything", + "depthAnythingDescription": "Depth map generation using the Depth Anything technique", "depthMidas": "Depth (Midas)", "depthMidasDescription": "Depth map generation using Midas", "depthZoe": "Depth (Zoe)", @@ -256,6 +259,7 @@ "colorMapTileSize": "Tile Size", "importImageFromCanvas": "Import Image From Canvas", "importMaskFromCanvas": "Import Mask From Canvas", + "large": "Large", "lineart": "Lineart", "lineartAnime": "Lineart Anime", "lineartAnimeDescription": "Anime-style lineart processing", @@ -268,6 +272,7 @@ "minConfidence": "Min Confidence", "mlsd": "M-LSD", "mlsdDescription": "Minimalist Line Segment Detector", + "modelSize": "Model Size", "none": "None", "noneDescription": "No processing applied", "normalBae": "Normal BAE", @@ -288,6 +293,7 @@ "selectModel": "Select a model", "setControlImageDimensions": "Set Control Image Dimensions To W/H", "showAdvanced": "Show Advanced", + "small": "Small", "toggleControlNet": "Toggle this ControlNet", "w": "W", "weight": "Weight", diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx index 79ef4c0a0a..45c4b7fac9 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/ControlAdapterProcessorComponent.tsx @@ -5,6 +5,7 @@ import { memo } from 'react'; import CannyProcessor from './processors/CannyProcessor'; import ColorMapProcessor from './processors/ColorMapProcessor'; import ContentShuffleProcessor from './processors/ContentShuffleProcessor'; +import DepthAnyThingProcessor from './processors/DepthAnyThingProcessor'; import HedProcessor from './processors/HedProcessor'; import LineartAnimeProcessor from './processors/LineartAnimeProcessor'; import LineartProcessor from './processors/LineartProcessor'; @@ -48,6 +49,16 @@ const ControlAdapterProcessorComponent = ({ id }: Props) => { ); } + if (processorNode.type === 'depth_anything_image_processor') { + return ( + + ); + } + if (processorNode.type === 'hed_image_processor') { return ( { + const { controlNetId, processorNode, isEnabled } = props; + const { model_size } = processorNode; + const processorChanged = useProcessorNodeChanged(); + + const { t } = useTranslation(); + + const handleModelSizeChange = useCallback( + (v) => { + if (!isDepthAnythingModelSize(v?.value)) { + return; + } + processorChanged(controlNetId, { + model_size: v.value, + }); + }, + [controlNetId, processorChanged] + ); + + const options: { label: string; value: DepthAnythingModelSize }[] = useMemo( + () => [ + { label: t('controlnet.large'), value: 'large' }, + { label: t('controlnet.base'), value: 'base' }, + { label: t('controlnet.small'), value: 'small' }, + ], + [t] + ); + + const value = useMemo( + () => options.filter((o) => o.value === model_size)[0], + [options, model_size] + ); + + return ( + + + {t('controlnet.modelSize')} + + + + ); +}; + +export default memo(DepthAnythingProcessor); diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts index b7647c9f0d..2b4124cbb1 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts @@ -83,6 +83,21 @@ export const CONTROLNET_PROCESSORS: ControlNetProcessorsDict = { f: 256, }, }, + depth_anything_image_processor: { + type: 'depth_anything_image_processor', + get label() { + return i18n.t('controlnet.depthAnything'); + }, + get description() { + return i18n.t('controlnet.depthAnythingDescription'); + }, + default: { + id: 'depth_anything_image_processor', + type: 'depth_anything_image_processor', + model_size: 'large', + offload: false, + }, + }, hed_image_processor: { type: 'hed_image_processor', get label() { diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts index 8d391a9c08..0cd6c9b5c6 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts @@ -10,6 +10,7 @@ import type { CannyImageProcessorInvocation, ColorMapImageProcessorInvocation, ContentShuffleImageProcessorInvocation, + DepthAnythingImageProcessorInvocation, HedImageProcessorInvocation, LineartAnimeImageProcessorInvocation, LineartImageProcessorInvocation, @@ -31,6 +32,7 @@ export type ControlAdapterProcessorNode = | CannyImageProcessorInvocation | ColorMapImageProcessorInvocation | ContentShuffleImageProcessorInvocation + | DepthAnythingImageProcessorInvocation | HedImageProcessorInvocation | LineartAnimeImageProcessorInvocation | LineartImageProcessorInvocation @@ -73,6 +75,20 @@ export type RequiredContentShuffleImageProcessorInvocation = O.Required< 'type' | 'detect_resolution' | 'image_resolution' | 'w' | 'h' | 'f' >; +/** + * The DepthAnything processor node, with parameters flagged as required + */ +export type RequiredDepthAnythingImageProcessorInvocation = O.Required< + DepthAnythingImageProcessorInvocation, + 'type' | 'model_size' | 'offload' +>; + +export const zDepthAnythingModelSize = z.enum(['large', 'base', 'small']); +export type DepthAnythingModelSize = z.infer; +export const isDepthAnythingModelSize = ( + v: unknown +): v is DepthAnythingModelSize => zDepthAnythingModelSize.safeParse(v).success; + /** * The HED processor node, with parameters flagged as required */ @@ -161,6 +177,7 @@ export type RequiredControlAdapterProcessorNode = | RequiredCannyImageProcessorInvocation | RequiredColorMapImageProcessorInvocation | RequiredContentShuffleImageProcessorInvocation + | RequiredDepthAnythingImageProcessorInvocation | RequiredHedImageProcessorInvocation | RequiredLineartAnimeImageProcessorInvocation | RequiredLineartImageProcessorInvocation @@ -219,6 +236,22 @@ export const isContentShuffleImageProcessorInvocation = ( return false; }; +/** + * Type guard for DepthAnythingImageProcessorInvocation + */ +export const isDepthAnythingImageProcessorInvocation = ( + obj: unknown +): obj is DepthAnythingImageProcessorInvocation => { + if ( + isObject(obj) && + 'type' in obj && + obj.type === 'depth_anything_image_processor' + ) { + return true; + } + return false; +}; + /** * Type guard for HedImageprocessorInvocation */ diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 92987c2a05..bade77e5bf 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -112,6 +112,34 @@ export type paths = { */ patch: operations["update_model_record"]; }; + "/api/v1/model/record/meta": { + /** + * List Model Summary + * @description Gets a page of model summary data. + */ + get: operations["list_model_summary"]; + }; + "/api/v1/model/record/meta/i/{key}": { + /** + * Get Model Metadata + * @description Get a model metadata object. + */ + get: operations["get_model_metadata"]; + }; + "/api/v1/model/record/tags": { + /** + * List Tags + * @description Get a unique set of all the model tags. + */ + get: operations["list_tags"]; + }; + "/api/v1/model/record/tags/search": { + /** + * Search By Metadata Tags + * @description Get a list of models. + */ + get: operations["search_by_metadata_tags"]; + }; "/api/v1/model/record/i/": { /** * Add Model Record @@ -123,9 +151,6 @@ export type paths = { /** * List Model Install Jobs * @description Return list of model install jobs. - * - * If the optional 'source' argument is provided, then the list will be filtered - * for partial string matches against the install source. */ get: operations["list_model_install_jobs"]; /** @@ -175,7 +200,7 @@ export type paths = { * Installation occurs in the background. Either use list_model_install_jobs() * to poll for completion, or listen on the event bus for the following events: * - * "model_install_started" + * "model_install_running" * "model_install_completed" * "model_install_error" * @@ -191,10 +216,24 @@ export type paths = { */ patch: operations["prune_model_install_jobs"]; }; + "/api/v1/model/record/import/{id}": { + /** + * Get Model Install Job + * @description Return model install job corresponding to the given source. + */ + get: operations["get_model_install_job"]; + /** + * Cancel Model Install Job + * @description Cancel the model install job(s) corresponding to the given job ID. + */ + delete: operations["cancel_model_install_job"]; + }; "/api/v1/model/record/sync": { /** * Sync Models To Config - * @description Traverse the models and autoimport directories. Model files without a corresponding + * @description Traverse the models and autoimport directories. + * + * Model files without a corresponding * record in the database are added. Orphan records without a models file are deleted. */ patch: operations["sync_models_to_config"]; @@ -736,46 +775,31 @@ export type components = { version: string; }; /** - * Average Images - * @description Average images + * BaseMetadata + * @description Adds typing data for discriminated union. */ - AverageImagesInvocation: { - /** @description Optional metadata to be saved with the image */ - metadata?: components["schemas"]["MetadataField"] | null; + BaseMetadata: { /** - * Id - * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + * Name + * @description model's name */ - id: string; + name: string; /** - * Is Intermediate - * @description Whether or not this is an intermediate invocation. - * @default false + * Author + * @description model's author */ - is_intermediate?: boolean; + author: string; /** - * Use Cache - * @description Whether or not to use the cache - * @default true + * Tags + * @description tags provided by model source */ - use_cache?: boolean; + tags: string[]; /** - * Images - * @description The collection of images to average - */ - images?: components["schemas"]["ImageField"][]; - /** - * Gamma - * @description Gamma for color correcting before/after blending - * @default 2.2 - */ - gamma?: number; - /** - * type - * @default average_images + * Type + * @default basemetadata * @constant */ - type: "average_images"; + type?: "basemetadata"; }; /** Batch */ Batch: { @@ -1137,7 +1161,7 @@ export type components = { /** Body_import_model_record */ Body_import_model_record: { /** Source */ - source: components["schemas"]["LocalModelSource"] | components["schemas"]["HFModelSource"] | components["schemas"]["URLModelSource"]; + source: components["schemas"]["LocalModelSource"] | components["schemas"]["HFModelSource"] | components["schemas"]["CivitaiModelSource"] | components["schemas"]["URLModelSource"]; /** * Config * @description Dict of fields that override auto-probed values in the model config record, such as name, description and prediction_type @@ -1747,6 +1771,136 @@ export type components = { */ type: "img_pad_crop"; }; + /** + * CivitaiMetadata + * @description Extended metadata fields provided by Civitai. + */ + CivitaiMetadata: { + /** + * Name + * @description model's name + */ + name: string; + /** + * Author + * @description model's author + */ + author: string; + /** + * Tags + * @description tags provided by model source + */ + tags: string[]; + /** + * Files + * @description model files and their sizes + */ + files?: components["schemas"]["RemoteModelFile"][]; + /** + * Type + * @default civitai + * @constant + */ + type?: "civitai"; + /** + * Id + * @description Civitai version identifier + */ + id: number; + /** + * Version Name + * @description Version identifier, such as 'V2-alpha' + */ + version_name: string; + /** + * Version Id + * @description Civitai model version identifier + */ + version_id: number; + /** + * Created + * Format: date-time + * @description date the model was created + */ + created: string; + /** + * Updated + * Format: date-time + * @description date the model was last modified + */ + updated: string; + /** + * Published + * Format: date-time + * @description date the model was published to Civitai + */ + published: string; + /** + * Description + * @description text description of model; may contain HTML + */ + description: string; + /** + * Version Description + * @description text description of the model's reversion; usually change history; may contain HTML + */ + version_description: string; + /** + * Nsfw + * @description whether the model tends to generate NSFW content + * @default false + */ + nsfw?: boolean; + /** @description license terms */ + restrictions?: components["schemas"]["LicenseRestrictions"]; + /** + * Trained Words + * @description words to trigger the model + */ + trained_words?: string[]; + /** + * Download Url + * Format: uri + * @description download URL for this model + */ + download_url: string; + /** + * Base Model Trained On + * @description base model on which this model was trained (currently not an enum) + */ + base_model_trained_on: string; + /** + * Thumbnail Url + * @description a thumbnail image for this model + */ + thumbnail_url?: string | null; + /** + * Weight Minmax + * @description minimum and maximum slider values for a LoRA or other secondary model + * @default [ + * -1, + * 2 + * ] + */ + weight_minmax?: [number, number]; + }; + /** + * CivitaiModelSource + * @description A Civitai version id, with optional variant and access token. + */ + CivitaiModelSource: { + /** Version Id */ + version_id: number; + variant?: components["schemas"]["ModelRepoVariant"] | null; + /** Access Token */ + access_token?: string | null; + /** + * Type + * @default civitai + * @constant + */ + type?: "civitai"; + }; /** * ClearResult * @description Result of clearing the session queue @@ -2065,6 +2219,12 @@ export type components = { */ type: "color_output"; }; + /** + * CommercialUsage + * @description Type of commercial usage allowed. + * @enum {string} + */ + CommercialUsage: "None" | "Image" | "Rent" | "RentCivit" | "Sell"; /** * Prompt * @description Parse prompt using compel package to conditioning. @@ -2993,7 +3153,7 @@ export type components = { */ t2i_adapter?: components["schemas"]["T2IAdapterField"] | components["schemas"]["T2IAdapterField"][] | null; /** - * Cfg Rescale Multiplier + * CFG Rescale Multiplier * @description Rescale multiplier for CFG guidance, used for models trained with zero-terminal SNR * @default 0 */ @@ -3039,6 +3199,51 @@ export type components = { */ type: "denoise_mask_output"; }; + /** + * Depth Anything Processor + * @description Generates a depth map based on the Depth Anything algorithm + */ + DepthAnythingImageProcessorInvocation: { + /** @description Optional metadata to be saved with the image */ + metadata?: components["schemas"]["MetadataField"] | null; + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** @description The image to process */ + image?: components["schemas"]["ImageField"]; + /** + * Model Size + * @description The size of the depth model to use + * @default large + * @enum {string} + */ + model_size?: "large" | "base" | "small"; + /** + * Offload + * @default false + */ + offload?: boolean; + /** + * type + * @default depth_anything_image_processor + * @constant + */ + type: "depth_anything_image_processor"; + }; /** * Divide Integers * @description Divides two numbers @@ -3134,6 +3339,11 @@ export type components = { * @description Timestamp for when the download job ende1d (completed or errored) */ job_ended?: string | null; + /** + * Content Type + * @description Content type of downloaded file + */ + content_type?: string | null; /** * Bytes * @description Bytes downloaded so far @@ -3908,7 +4118,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["LinearUIOutputInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["AverageImagesInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["InfillTileInvocation"]; + [key: string]: components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["LinearUIOutputInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["LatentConsistencyInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"]; }; /** * Edges @@ -3945,7 +4155,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["CollectInvocationOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["String2Output"] | components["schemas"]["NoiseOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["IntegerCollectionOutput"]; + [key: string]: components["schemas"]["UNetOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["String2Output"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"]; }; /** * Errors @@ -4011,13 +4221,15 @@ export type components = { }; /** * HFModelSource - * @description A HuggingFace repo_id, with optional variant and sub-folder. + * @description A HuggingFace repo_id with optional variant, sub-folder and access token. + * Note that the variant option, if not provided to the constructor, will default to fp16, which is + * what people (almost) always want. */ HFModelSource: { /** Repo Id */ repo_id: string; - /** Variant */ - variant?: string | null; + /** @default fp16 */ + variant?: components["schemas"]["ModelRepoVariant"] | null; /** Subfolder */ subfolder?: string | null; /** Access Token */ @@ -4085,6 +4297,51 @@ export type components = { */ type: "hed_image_processor"; }; + /** + * HuggingFaceMetadata + * @description Extended metadata fields provided by HuggingFace. + */ + HuggingFaceMetadata: { + /** + * Name + * @description model's name + */ + name: string; + /** + * Author + * @description model's author + */ + author: string; + /** + * Tags + * @description tags provided by model source + */ + tags: string[]; + /** + * Files + * @description model files and their sizes + */ + files?: components["schemas"]["RemoteModelFile"][]; + /** + * Type + * @default huggingface + * @constant + */ + type?: "huggingface"; + /** + * Id + * @description huggingface model id + */ + id: string; + /** Tag Dict */ + tag_dict: Record; + /** + * Last Modified + * Format: date-time + * @description date of last commit to repo + */ + last_modified: string; + }; /** * IPAdapterConfig * @description Model config for IP Adaptor format models. @@ -4312,23 +4569,21 @@ export type components = { use_cache?: boolean; /** * Width - * @description Target width + * @description Final image width * @default 1024 */ width?: number; /** * Height - * @description Target height + * @description Final image height * @default 576 */ height?: number; - /** @description UNet submodel */ + /** @description UNet (scheduler, LoRAs) */ unet?: components["schemas"]["UNetField"]; - /** @description Vae submodel */ - vae?: components["schemas"]["VaeField"]; /** * Multiplier - * @description Dimensional multiplier + * @description Amount to multiply the model's dimensions by when calculating the ideal size (may result in initial generation artifacts if too large) * @default 1 */ multiplier?: number; @@ -4346,12 +4601,12 @@ export type components = { IdealSizeOutput: { /** * Width - * @description The ideal width of the image in pixels + * @description The ideal width of the image (in pixels) */ width: number; /** * Height - * @description The ideal height of the image in pixels + * @description The ideal height of the image (in pixels) */ height: number; /** @@ -5489,7 +5744,7 @@ export type components = { * @description State of an install job running in the background. * @enum {string} */ - InstallStatus: "waiting" | "running" | "completed" | "error"; + InstallStatus: "waiting" | "downloading" | "running" | "completed" | "error" | "cancelled"; /** * Integer Collection Primitive * @description A collection of integer primitive values @@ -5772,6 +6027,96 @@ export type components = { */ type: "infill_lama"; }; + /** + * Latent Consistency MonoNode + * @description Wrapper node around diffusers LatentConsistencyTxt2ImgPipeline + */ + LatentConsistencyInvocation: { + /** + * Id + * @description The id of this instance of an invocation. Must be unique among all instances of invocations. + */ + id: string; + /** + * Is Intermediate + * @description Whether or not this is an intermediate invocation. + * @default false + */ + is_intermediate?: boolean; + /** + * Use Cache + * @description Whether or not to use the cache + * @default true + */ + use_cache?: boolean; + /** + * Prompt + * @description The prompt to use + */ + prompt?: string; + /** + * Num Inference Steps + * @description The number of inference steps to use, 4-8 recommended + * @default 8 + */ + num_inference_steps?: number; + /** + * Guidance Scale + * @description The guidance scale to use + * @default 8 + */ + guidance_scale?: number; + /** + * Batches + * @description The number of batches to use + * @default 1 + */ + batches?: number; + /** + * Images Per Batch + * @description The number of images per batch to use + * @default 1 + */ + images_per_batch?: number; + /** + * Seeds + * @description List of noise seeds to use + */ + seeds?: number[]; + /** + * Lcm Origin Steps + * @description The lcm origin steps to use + * @default 50 + */ + lcm_origin_steps?: number; + /** + * Width + * @description The width to use + * @default 512 + */ + width?: number; + /** + * Height + * @description The height to use + * @default 512 + */ + height?: number; + /** + * Precision + * @description floating point precision + * @default fp16 + * @enum {string} + */ + precision?: "fp16" | "fp32"; + /** @description The board to save the image to */ + board?: components["schemas"]["BoardField"]; + /** + * type + * @default latent_consistency_mononode + * @constant + */ + type: "latent_consistency_mononode"; + }; /** * Latents Collection Primitive * @description A collection of latents tensor primitive values @@ -6004,6 +6349,32 @@ export type components = { */ type: "leres_image_processor"; }; + /** + * LicenseRestrictions + * @description Broad categories of licensing restrictions. + */ + LicenseRestrictions: { + /** + * Allownocredit + * @description if true, model can be redistributed without crediting author + * @default false + */ + AllowNoCredit?: boolean; + /** + * Allowderivatives + * @description if true, derivatives of this model can be redistributed + * @default false + */ + AllowDerivatives?: boolean; + /** + * Allowdifferentlicense + * @description if true, derivatives of this model be redistributed under a different license + * @default false + */ + AllowDifferentLicense?: boolean; + /** @description Type of commercial use allowed or 'No' if no commercial use is allowed. */ + AllowCommercialUse?: components["schemas"]["CommercialUsage"]; + }; /** * Linear UI Image Output * @description Handles Linear UI Image Outputting tasks. @@ -7028,6 +7399,12 @@ export type components = { * @constant */ ModelError: "not_found"; + /** + * ModelFormat + * @description Storage format of model. + * @enum {string} + */ + ModelFormat: "diffusers" | "checkpoint" | "lycoris" | "onnx" | "olive" | "embedding_file" | "embedding_folder" | "invokeai"; /** ModelInfo */ ModelInfo: { /** @@ -7047,6 +7424,11 @@ export type components = { * @description Object that tracks the current status of an install request. */ ModelInstallJob: { + /** + * Id + * @description Unique ID for this job + */ + id: number; /** * @description Current status of install process * @default waiting @@ -7072,7 +7454,7 @@ export type components = { * Source * @description Source (URL, repo_id, or local path) of model */ - source: components["schemas"]["LocalModelSource"] | components["schemas"]["HFModelSource"] | components["schemas"]["URLModelSource"]; + source: components["schemas"]["LocalModelSource"] | components["schemas"]["HFModelSource"] | components["schemas"]["CivitaiModelSource"] | components["schemas"]["URLModelSource"]; /** * Local Path * Format: path @@ -7080,15 +7462,26 @@ export type components = { */ local_path: string; /** - * Error Type - * @description Class name of the exception that led to status==ERROR + * Bytes + * @description For a remote model, the number of bytes downloaded so far (may not be available) */ - error_type?: string | null; + bytes?: number | null; /** - * Error - * @description Error traceback + * Total Bytes + * @description Total size of the model to be installed + * @default 0 */ - error?: string | null; + total_bytes?: number; + /** + * Source Metadata + * @description Metadata provided by the model source + */ + source_metadata?: (components["schemas"]["BaseMetadata"] | components["schemas"]["HuggingFaceMetadata"] | components["schemas"]["CivitaiMetadata"]) | null; + /** + * Download Parts + * @description Download jobs contributing to this install + */ + download_parts?: components["schemas"]["DownloadJob"][]; }; /** * ModelLoaderOutput @@ -7117,6 +7510,50 @@ export type components = { */ unet: components["schemas"]["UNetField"]; }; + /** + * ModelRecordOrderBy + * @description The order in which to return model summaries. + * @enum {string} + */ + ModelRecordOrderBy: "default" | "type" | "base" | "name" | "format"; + /** + * ModelRepoVariant + * @description Various hugging face variants on the diffusers format. + * @enum {string} + */ + ModelRepoVariant: "default" | "fp16" | "fp32" | "onnx" | "openvino" | "flax"; + /** + * ModelSummary + * @description A short summary of models for UI listing purposes. + */ + ModelSummary: { + /** + * Key + * @description model key + */ + key: string; + /** @description model type */ + type: components["schemas"]["invokeai__backend__model_manager__config__ModelType"]; + /** @description base model */ + base: components["schemas"]["invokeai__backend__model_manager__config__BaseModelType"]; + /** @description model format */ + format: components["schemas"]["ModelFormat"]; + /** + * Name + * @description model name + */ + name: string; + /** + * Description + * @description short description of model + */ + description: string; + /** + * Tags + * @description tags associated with model + */ + tags: string[]; + }; /** * Multiply Integers * @description Multiplies two numbers @@ -7791,6 +8228,34 @@ export type components = { */ type: "openpose_image_processor"; }; + /** PaginatedResults[ModelSummary] */ + PaginatedResults_ModelSummary_: { + /** + * Page + * @description Current Page + */ + page: number; + /** + * Pages + * @description Total number of pages + */ + pages: number; + /** + * Per Page + * @description Number of items per page + */ + per_page: number; + /** + * Total + * @description Total number of items in result + */ + total: number; + /** + * Items + * @description Items + */ + items: components["schemas"]["ModelSummary"][]; + }; /** PaginatedResults[WorkflowRecordListItemDTO] */ PaginatedResults_WorkflowRecordListItemDTO_: { /** @@ -8222,6 +8687,34 @@ export type components = { */ type: "range_of_size"; }; + /** + * RemoteModelFile + * @description Information about a downloadable file that forms part of a model. + */ + RemoteModelFile: { + /** + * Url + * Format: uri + * @description The url to download this model file + */ + url: string; + /** + * Path + * Format: path + * @description The path to the file, relative to the model root + */ + path: string; + /** + * Size + * @description The size of this file, in bytes + */ + size: number; + /** + * Sha256 + * @description SHA256 hash of this model (not always available) + */ + sha256?: string | null; + }; /** RemoveImagesFromBoardResult */ RemoveImagesFromBoardResult: { /** @@ -10274,10 +10767,10 @@ export type components = { access_token?: string | null; /** * Type - * @default generic_url + * @default url * @constant */ - type?: "generic_url"; + type?: "url"; }; /** * Unsharp Mask @@ -11004,53 +11497,53 @@ export type components = { */ UIType: "SDXLMainModelField" | "SDXLRefinerModelField" | "ONNXModelField" | "VAEModelField" | "LoRAModelField" | "ControlNetModelField" | "IPAdapterModelField" | "SchedulerField" | "AnyField" | "CollectionField" | "CollectionItemField" | "DEPRECATED_Boolean" | "DEPRECATED_Color" | "DEPRECATED_Conditioning" | "DEPRECATED_Control" | "DEPRECATED_Float" | "DEPRECATED_Image" | "DEPRECATED_Integer" | "DEPRECATED_Latents" | "DEPRECATED_String" | "DEPRECATED_BooleanCollection" | "DEPRECATED_ColorCollection" | "DEPRECATED_ConditioningCollection" | "DEPRECATED_ControlCollection" | "DEPRECATED_FloatCollection" | "DEPRECATED_ImageCollection" | "DEPRECATED_IntegerCollection" | "DEPRECATED_LatentsCollection" | "DEPRECATED_StringCollection" | "DEPRECATED_BooleanPolymorphic" | "DEPRECATED_ColorPolymorphic" | "DEPRECATED_ConditioningPolymorphic" | "DEPRECATED_ControlPolymorphic" | "DEPRECATED_FloatPolymorphic" | "DEPRECATED_ImagePolymorphic" | "DEPRECATED_IntegerPolymorphic" | "DEPRECATED_LatentsPolymorphic" | "DEPRECATED_StringPolymorphic" | "DEPRECATED_MainModel" | "DEPRECATED_UNet" | "DEPRECATED_Vae" | "DEPRECATED_CLIP" | "DEPRECATED_Collection" | "DEPRECATED_CollectionItem" | "DEPRECATED_Enum" | "DEPRECATED_WorkflowField" | "DEPRECATED_IsIntermediate" | "DEPRECATED_BoardField" | "DEPRECATED_MetadataItem" | "DEPRECATED_MetadataItemCollection" | "DEPRECATED_MetadataItemPolymorphic" | "DEPRECATED_MetadataDict"; /** - * ControlNetModelFormat + * StableDiffusion1ModelFormat * @description An enumeration. * @enum {string} */ - ControlNetModelFormat: "checkpoint" | "diffusers"; - /** - * IPAdapterModelFormat - * @description An enumeration. - * @enum {string} - */ - IPAdapterModelFormat: "invokeai"; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; - /** - * T2IAdapterModelFormat - * @description An enumeration. - * @enum {string} - */ - T2IAdapterModelFormat: "diffusers"; - /** - * CLIPVisionModelFormat - * @description An enumeration. - * @enum {string} - */ - CLIPVisionModelFormat: "diffusers"; + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + /** + * CLIPVisionModelFormat + * @description An enumeration. + * @enum {string} + */ + CLIPVisionModelFormat: "diffusers"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; + /** + * T2IAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + T2IAdapterModelFormat: "diffusers"; + /** + * IPAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + IPAdapterModelFormat: "invokeai"; /** * StableDiffusionOnnxModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionOnnxModelFormat: "olive" | "onnx"; - /** - * StableDiffusion1ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; @@ -11456,7 +11949,7 @@ export type operations = { /** @description Exact match on the name of the model */ model_name?: string | null; /** @description Exact match on the format of the model (e.g. 'diffusers') */ - model_format?: string | null; + model_format?: components["schemas"]["ModelFormat"] | null; }; }; responses: { @@ -11582,6 +12075,110 @@ export type operations = { }; }; }; + /** + * List Model Summary + * @description Gets a page of model summary data. + */ + list_model_summary: { + parameters: { + query?: { + /** @description The page to get */ + page?: number; + /** @description The number of models per page */ + per_page?: number; + /** @description The attribute to order by */ + order_by?: components["schemas"]["ModelRecordOrderBy"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["PaginatedResults_ModelSummary_"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + /** + * Get Model Metadata + * @description Get a model metadata object. + */ + get_model_metadata: { + parameters: { + path: { + /** @description Key of the model repo metadata to fetch. */ + key: string; + }; + }; + responses: { + /** @description Success */ + 200: { + content: { + "application/json": (components["schemas"]["BaseMetadata"] | components["schemas"]["HuggingFaceMetadata"] | components["schemas"]["CivitaiMetadata"]) | null; + }; + }; + /** @description Bad request */ + 400: { + content: never; + }; + /** @description No metadata available */ + 404: { + content: never; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + /** + * List Tags + * @description Get a unique set of all the model tags. + */ + list_tags: { + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": string[]; + }; + }; + }; + }; + /** + * Search By Metadata Tags + * @description Get a list of models. + */ + search_by_metadata_tags: { + parameters: { + query?: { + /** @description Tags to search for */ + tags?: string[]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["invokeai__app__api__routers__model_records__ModelsList"]; + }; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; /** * Add Model Record * @description Add a model using the configuration information appropriate for its type. @@ -11618,9 +12215,6 @@ export type operations = { /** * List Model Install Jobs * @description Return list of model install jobs. - * - * If the optional 'source' argument is provided, then the list will be filtered - * for partial string matches against the install source. */ list_model_install_jobs: { responses: { @@ -11679,7 +12273,7 @@ export type operations = { * Installation occurs in the background. Either use list_model_install_jobs() * to poll for completion, or listen on the event bus for the following events: * - * "model_install_started" + * "model_install_running" * "model_install_completed" * "model_install_error" * @@ -11743,9 +12337,71 @@ export type operations = { }; }; }; + /** + * Get Model Install Job + * @description Return model install job corresponding to the given source. + */ + get_model_install_job: { + parameters: { + path: { + /** @description Model install id */ + id: number; + }; + }; + responses: { + /** @description Success */ + 200: { + content: { + "application/json": components["schemas"]["ModelInstallJob"]; + }; + }; + /** @description No such job */ + 404: { + content: never; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + /** + * Cancel Model Install Job + * @description Cancel the model install job(s) corresponding to the given job ID. + */ + cancel_model_install_job: { + parameters: { + path: { + /** @description Model install job ID */ + id: number; + }; + }; + responses: { + /** @description The job was cancelled successfully */ + 201: { + content: { + "application/json": unknown; + }; + }; + /** @description No such job */ + 415: { + content: never; + }; + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; /** * Sync Models To Config - * @description Traverse the models and autoimport directories. Model files without a corresponding + * @description Traverse the models and autoimport directories. + * + * Model files without a corresponding * record in the database are added. Orphan records without a models file are deleted. */ sync_models_to_config: { diff --git a/invokeai/frontend/web/src/services/api/types.ts b/invokeai/frontend/web/src/services/api/types.ts index 03d9153361..871a7f5a2e 100644 --- a/invokeai/frontend/web/src/services/api/types.ts +++ b/invokeai/frontend/web/src/services/api/types.ts @@ -164,6 +164,8 @@ export type ColorMapImageProcessorInvocation = s['ColorMapImageProcessorInvocation']; export type ContentShuffleImageProcessorInvocation = s['ContentShuffleImageProcessorInvocation']; +export type DepthAnythingImageProcessorInvocation = + s['DepthAnythingImageProcessorInvocation']; export type HedImageProcessorInvocation = s['HedImageProcessorInvocation']; export type LineartAnimeImageProcessorInvocation = s['LineartAnimeImageProcessorInvocation']; From 6a2eb1d2e4374ca1b5e01b4cdf53c56e9934dfe7 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 23 Jan 2024 04:56:59 +0530 Subject: [PATCH 19/34] fix: Change the path of the annotator folder to annotators Just making this change in case there are other models added to the folder in the future --- invokeai/backend/image_util/depth_anything/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/image_util/depth_anything/__init__.py b/invokeai/backend/image_util/depth_anything/__init__.py index 37adaa3004..0fca75c741 100644 --- a/invokeai/backend/image_util/depth_anything/__init__.py +++ b/invokeai/backend/image_util/depth_anything/__init__.py @@ -20,15 +20,15 @@ config = InvokeAIAppConfig.get_config() DEPTH_ANYTHING_MODELS = { "large": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitl14.pth?download=true", - "local": "sd-1/controlnet/annotator/depth_anything/depth_anything_vitl14.pth", + "local": "sd-1/controlnet/annotators/depth_anything/depth_anything_vitl14.pth", }, "base": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitb14.pth?download=true", - "local": "sd-1/controlnet/annotator/depth_anything/depth_anything_vitb14.pth", + "local": "sd-1/controlnet/annotators/depth_anything/depth_anything_vitb14.pth", }, "small": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vits14.pth?download=true", - "local": "sd-1/controlnet/annotator/depth_anything/depth_anything_vits14.pth", + "local": "sd-1/controlnet/annotators/depth_anything/depth_anything_vits14.pth", }, } From f36a6912199582845818d4973c602aa580771e78 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 23 Jan 2024 09:14:47 +0530 Subject: [PATCH 20/34] feat: Make the depth anything small model the default --- invokeai/app/invocations/controlnet_image_processors.py | 2 +- .../components/processors/DepthAnyThingProcessor.tsx | 4 ++-- .../web/src/features/controlAdapters/store/constants.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/invokeai/app/invocations/controlnet_image_processors.py b/invokeai/app/invocations/controlnet_image_processors.py index 967e0c6f40..f16ff55351 100644 --- a/invokeai/app/invocations/controlnet_image_processors.py +++ b/invokeai/app/invocations/controlnet_image_processors.py @@ -619,7 +619,7 @@ class DepthAnythingImageProcessorInvocation(ImageProcessorInvocation): """Generates a depth map based on the Depth Anything algorithm""" model_size: DEPTH_ANYTHING_MODEL_SIZES = InputField( - default="large", description="The size of the depth model to use" + default="small", description="The size of the depth model to use" ) offload: bool = InputField(default=False) diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx index c0e69950c1..4897cf50c5 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx @@ -42,9 +42,9 @@ const DepthAnythingProcessor = (props: Props) => { const options: { label: string; value: DepthAnythingModelSize }[] = useMemo( () => [ - { label: t('controlnet.large'), value: 'large' }, - { label: t('controlnet.base'), value: 'base' }, { label: t('controlnet.small'), value: 'small' }, + { label: t('controlnet.base'), value: 'base' }, + { label: t('controlnet.large'), value: 'large' }, ], [t] ); diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts index 2b4124cbb1..1bdfabd0ab 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts @@ -94,7 +94,7 @@ export const CONTROLNET_PROCESSORS: ControlNetProcessorsDict = { default: { id: 'depth_anything_image_processor', type: 'depth_anything_image_processor', - model_size: 'large', + model_size: 'small', offload: false, }, }, From 39fedb090bb71890776d2f5570f6626e3691c86d Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 23 Jan 2024 09:15:04 +0530 Subject: [PATCH 21/34] feat: Make depth anything the default processor for depth controlnet --- .../web/src/features/controlAdapters/store/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts index 1bdfabd0ab..dc7444c3e7 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts @@ -260,7 +260,7 @@ export const CONTROLNET_MODEL_DEFAULT_PROCESSORS: { } = { canny: 'canny_image_processor', mlsd: 'mlsd_image_processor', - depth: 'midas_depth_image_processor', + depth: 'depth_anything_image_processor', bae: 'normalbae_image_processor', sketch: 'pidi_image_processor', scribble: 'lineart_image_processor', From 7cb49e65bdf3ebd8c749c8c131cec40798811641 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:13:03 +0530 Subject: [PATCH 22/34] feat: Add Resolution to DepthAnything --- .../controlnet_image_processors.py | 3 +- .../image_util/depth_anything/__init__.py | 24 +++++---- .../processors/DepthAnyThingProcessor.tsx | 42 ++++++++++++++- .../controlAdapters/store/constants.ts | 1 + .../features/controlAdapters/store/types.ts | 2 +- .../frontend/web/src/services/api/schema.ts | 52 +++++++++++-------- 6 files changed, 87 insertions(+), 37 deletions(-) diff --git a/invokeai/app/invocations/controlnet_image_processors.py b/invokeai/app/invocations/controlnet_image_processors.py index f16ff55351..00c3fa74f6 100644 --- a/invokeai/app/invocations/controlnet_image_processors.py +++ b/invokeai/app/invocations/controlnet_image_processors.py @@ -621,6 +621,7 @@ class DepthAnythingImageProcessorInvocation(ImageProcessorInvocation): model_size: DEPTH_ANYTHING_MODEL_SIZES = InputField( default="small", description="The size of the depth model to use" ) + resolution: int = InputField(default=512, ge=64, multiple_of=64, description=FieldDescriptions.image_res) offload: bool = InputField(default=False) def run_processor(self, image): @@ -630,5 +631,5 @@ class DepthAnythingImageProcessorInvocation(ImageProcessorInvocation): if image.mode == "RGBA": image = image.convert("RGB") - processed_image = depth_anything_detector(image=image, offload=self.offload) + processed_image = depth_anything_detector(image=image, resolution=self.resolution, offload=self.offload) return processed_image diff --git a/invokeai/backend/image_util/depth_anything/__init__.py b/invokeai/backend/image_util/depth_anything/__init__.py index 0fca75c741..64eeb3d12f 100644 --- a/invokeai/backend/image_util/depth_anything/__init__.py +++ b/invokeai/backend/image_util/depth_anything/__init__.py @@ -64,12 +64,15 @@ class DepthAnythingDetector: del self.model self.model_size = model_size - if self.model_size == "small": - self.model = DPT_DINOv2(encoder="vits", features=64, out_channels=[48, 96, 192, 384]) - if self.model_size == "base": - self.model = DPT_DINOv2(encoder="vitb", features=128, out_channels=[96, 192, 384, 768]) - if self.model_size == "large": - self.model = DPT_DINOv2(encoder="vitl", features=256, out_channels=[256, 512, 1024, 1024]) + match self.model_size: + case "small": + self.model = DPT_DINOv2(encoder="vits", features=64, out_channels=[48, 96, 192, 384]) + case "base": + self.model = DPT_DINOv2(encoder="vitb", features=128, out_channels=[96, 192, 384, 768]) + case "large": + self.model = DPT_DINOv2(encoder="vitl", features=256, out_channels=[256, 512, 1024, 1024]) + case _: + raise TypeError("Not a supported model") self.model.load_state_dict(torch.load(DEPTH_ANYTHING_MODEL_PATH.as_posix(), map_location="cpu")) self.model.eval() @@ -81,12 +84,11 @@ class DepthAnythingDetector: self.model.to(device) return self - def __call__(self, image, offload=False): + def __call__(self, image, resolution=512, offload=False): image = np.array(image, dtype=np.uint8) - original_width, original_height = image.shape[:2] image = image[:, :, ::-1] / 255.0 - image_width, image_height = image.shape[:2] + image_height, image_width = image.shape[:2] image = transform({"image": image})["image"] image = torch.from_numpy(image).unsqueeze(0).to(choose_torch_device()) @@ -97,7 +99,9 @@ class DepthAnythingDetector: depth_map = repeat(depth, "h w -> h w 3").cpu().numpy().astype(np.uint8) depth_map = Image.fromarray(depth_map) - depth_map = depth_map.resize((original_height, original_width)) + + new_height = int(image_height * (resolution / image_width)) + depth_map = depth_map.resize((resolution, new_height)) if offload: del self.model diff --git a/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx b/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx index 4897cf50c5..025c53743e 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx +++ b/invokeai/frontend/web/src/features/controlAdapters/components/processors/DepthAnyThingProcessor.tsx @@ -1,5 +1,11 @@ import type { ComboboxOnChange } from '@invoke-ai/ui'; -import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui'; +import { + Combobox, + CompositeNumberInput, + CompositeSlider, + FormControl, + FormLabel, +} from '@invoke-ai/ui'; import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged'; import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants'; import type { @@ -23,7 +29,7 @@ type Props = { const DepthAnythingProcessor = (props: Props) => { const { controlNetId, processorNode, isEnabled } = props; - const { model_size } = processorNode; + const { model_size, resolution } = processorNode; const processorChanged = useProcessorNodeChanged(); const { t } = useTranslation(); @@ -54,6 +60,17 @@ const DepthAnythingProcessor = (props: Props) => { [options, model_size] ); + const handleResolutionChange = useCallback( + (v: number) => { + processorChanged(controlNetId, { resolution: v }); + }, + [controlNetId, processorChanged] + ); + + const handleResolutionDefaultChange = useCallback(() => { + processorChanged(controlNetId, { resolution: 512 }); + }, [controlNetId, processorChanged]); + return ( @@ -65,6 +82,27 @@ const DepthAnythingProcessor = (props: Props) => { onChange={handleModelSizeChange} /> + + {t('controlnet.imageResolution')} + + + ); }; diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts index dc7444c3e7..ddebffcfde 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/constants.ts @@ -95,6 +95,7 @@ export const CONTROLNET_PROCESSORS: ControlNetProcessorsDict = { id: 'depth_anything_image_processor', type: 'depth_anything_image_processor', model_size: 'small', + resolution: 512, offload: false, }, }, diff --git a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts index 0cd6c9b5c6..87366a443d 100644 --- a/invokeai/frontend/web/src/features/controlAdapters/store/types.ts +++ b/invokeai/frontend/web/src/features/controlAdapters/store/types.ts @@ -80,7 +80,7 @@ export type RequiredContentShuffleImageProcessorInvocation = O.Required< */ export type RequiredDepthAnythingImageProcessorInvocation = O.Required< DepthAnythingImageProcessorInvocation, - 'type' | 'model_size' | 'offload' + 'type' | 'model_size' | 'resolution' | 'offload' >; export const zDepthAnythingModelSize = z.enum(['large', 'base', 'small']); diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index bade77e5bf..87f4718b1b 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -3228,10 +3228,16 @@ export type components = { /** * Model Size * @description The size of the depth model to use - * @default large + * @default small * @enum {string} */ model_size?: "large" | "base" | "small"; + /** + * Resolution + * @description Pixel resolution for output image + * @default 512 + */ + resolution?: number; /** * Offload * @default false @@ -4118,7 +4124,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["LinearUIOutputInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["LatentConsistencyInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"]; + [key: string]: components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["CalculateImageTilesInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["CenterPadCropInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["LinearUIOutputInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["TileToPropertiesInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["UnsharpMaskInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["CropLatentsCoreInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["MergeTilesToImageInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["IdealSizeInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["PairTileImageInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["LatentConsistencyInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["CalculateImageTilesMinimumOverlapInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["CalculateImageTilesEvenSplitInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["DepthAnythingImageProcessorInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"]; }; /** * Edges @@ -4155,7 +4161,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["UNetOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["String2Output"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"]; + [key: string]: components["schemas"]["StringCollectionOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["PairTileImageOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["TileToPropertiesOutput"] | components["schemas"]["SchedulerOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["CalculateImageTilesOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["String2Output"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["IdealSizeOutput"] | components["schemas"]["MetadataOutput"]; }; /** * Errors @@ -11502,30 +11508,12 @@ export type components = { * @enum {string} */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusionXLModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; /** * CLIPVisionModelFormat * @description An enumeration. * @enum {string} */ CLIPVisionModelFormat: "diffusers"; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; /** * T2IAdapterModelFormat * @description An enumeration. @@ -11533,17 +11521,35 @@ export type components = { */ T2IAdapterModelFormat: "diffusers"; /** - * IPAdapterModelFormat + * ControlNetModelFormat * @description An enumeration. * @enum {string} */ - IPAdapterModelFormat: "invokeai"; + ControlNetModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionOnnxModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionOnnxModelFormat: "olive" | "onnx"; + /** + * IPAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + IPAdapterModelFormat: "invokeai"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusionXLModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never; From a0e68705dd80fceda5cdd1d3aa35dbb2cfa7ff59 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 24 Jan 2024 07:59:29 +1100 Subject: [PATCH 23/34] feat(ui): improved dynamic prompts behaviour - Bump `@invoke-ai/ui` for updated styles - Update regex to parse prompts with newlines - Update styling of overlay button when prompt has an error - Fix bug where loading and error state sometimes weren't cleared --- invokeai/frontend/web/package.json | 2 +- invokeai/frontend/web/pnpm-lock.yaml | 12 ++++++------ .../listenerMiddleware/listeners/promptChanged.ts | 7 +++---- .../components/ParamDynamicPromptsPreview.tsx | 7 ++++++- .../components/ShowDynamicPromptsPreviewButton.tsx | 5 +++++ .../dynamicPrompts/store/dynamicPromptsSlice.ts | 1 + .../dynamicPrompts/util/getShouldProcessPrompt.ts | 2 +- 7 files changed, 23 insertions(+), 13 deletions(-) diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index f989a98b4e..db43fd2f71 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -57,7 +57,7 @@ "@dnd-kit/core": "^6.1.0", "@dnd-kit/utilities": "^3.2.2", "@fontsource-variable/inter": "^5.0.16", - "@invoke-ai/ui": "0.0.12", + "@invoke-ai/ui": "0.0.13", "@mantine/form": "6.0.21", "@nanostores/react": "^0.7.1", "@reduxjs/toolkit": "2.0.1", diff --git a/invokeai/frontend/web/pnpm-lock.yaml b/invokeai/frontend/web/pnpm-lock.yaml index bdd7ab844c..958c3f6350 100644 --- a/invokeai/frontend/web/pnpm-lock.yaml +++ b/invokeai/frontend/web/pnpm-lock.yaml @@ -29,8 +29,8 @@ dependencies: specifier: ^5.0.16 version: 5.0.16 '@invoke-ai/ui': - specifier: 0.0.12 - version: 0.0.12(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0) + specifier: 0.0.13 + version: 0.0.13(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0) '@mantine/form': specifier: 6.0.21 version: 6.0.21(react@18.2.0) @@ -3759,8 +3759,8 @@ packages: '@swc/helpers': 0.5.3 dev: false - /@invoke-ai/ui@0.0.12(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-G0iPzGx1Nu7mHOZtwUYtqNWAqo2KnYGvs883w4WJwUpoCEbnaZd9Pi876UvOh9aNyjO93t/5ctIffkcYlDKGNg==} + /@invoke-ai/ui@0.0.13(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@fontsource-variable/inter@5.0.16)(@internationalized/date@3.5.1)(@types/react@18.2.48)(i18next@23.7.16)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-X4Txij2dMnzPUXTPhorBHezByJQ/ceyHxCM+zZ0gpFsSyXUieOFWjaSu+dAVpghS9y0dxFQGayHvNyX6VsX/PA==} peerDependencies: '@fontsource-variable/inter': ^5.0.16 react: ^18.2.0 @@ -12063,7 +12063,7 @@ packages: peerDependencies: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 react: 18.2.0 dev: false @@ -12158,7 +12158,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.23.7 + '@babel/runtime': 7.23.8 '@types/react': 18.2.48 focus-lock: 1.0.0 prop-types: 15.8.1 diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts index 7b24220e98..2dd36690a0 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts @@ -46,14 +46,14 @@ export const addDynamicPromptsListener = () => { if (cachedPrompts) { dispatch(promptsChanged(cachedPrompts.prompts)); + dispatch(parsingErrorChanged(cachedPrompts.error)); return; } if (!getShouldProcessPrompt(state.generation.positivePrompt)) { - if (state.dynamicPrompts.isLoading) { - dispatch(isLoadingChanged(false)); - } dispatch(promptsChanged([state.generation.positivePrompt])); + dispatch(parsingErrorChanged(undefined)); + dispatch(isErrorChanged(false)); return; } @@ -78,7 +78,6 @@ export const addDynamicPromptsListener = () => { dispatch(promptsChanged(res.prompts)); dispatch(parsingErrorChanged(res.error)); dispatch(isErrorChanged(false)); - dispatch(isLoadingChanged(false)); } catch { dispatch(isErrorChanged(true)); dispatch(isLoadingChanged(false)); diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsPreview.tsx b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsPreview.tsx index 4b5de0cb85..48cfd9a8d4 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsPreview.tsx +++ b/invokeai/frontend/web/src/features/dynamicPrompts/components/ParamDynamicPromptsPreview.tsx @@ -61,7 +61,12 @@ const ParamDynamicPromptsPreview = () => { } return ( - + {label} diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton.tsx b/invokeai/frontend/web/src/features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton.tsx index 7dceb6acfc..b590767868 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton.tsx +++ b/invokeai/frontend/web/src/features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton.tsx @@ -13,7 +13,11 @@ const loadingStyles: SystemStyleObject = { export const ShowDynamicPromptsPreviewButton = memo(() => { const { t } = useTranslation(); const isLoading = useAppSelector((s) => s.dynamicPrompts.isLoading); + const isError = useAppSelector((s) => + Boolean(s.dynamicPrompts.isError || s.dynamicPrompts.parsingError) + ); const { isOpen, onOpen } = useDynamicPromptsModal(); + return ( { icon={} onClick={onOpen} sx={isLoading ? loadingStyles : undefined} + colorScheme={isError && !isLoading ? 'error' : 'base'} /> ); diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts index 845f72306e..603faa5535 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts +++ b/invokeai/frontend/web/src/features/dynamicPrompts/store/dynamicPromptsSlice.ts @@ -47,6 +47,7 @@ export const dynamicPromptsSlice = createSlice({ }, promptsChanged: (state, action: PayloadAction) => { state.prompts = action.payload; + state.isLoading = false; }, parsingErrorChanged: ( state, diff --git a/invokeai/frontend/web/src/features/dynamicPrompts/util/getShouldProcessPrompt.ts b/invokeai/frontend/web/src/features/dynamicPrompts/util/getShouldProcessPrompt.ts index 56fa32fb67..1d2a5e715e 100644 --- a/invokeai/frontend/web/src/features/dynamicPrompts/util/getShouldProcessPrompt.ts +++ b/invokeai/frontend/web/src/features/dynamicPrompts/util/getShouldProcessPrompt.ts @@ -1,3 +1,3 @@ -const hasOpenCloseCurlyBracesRegex = /.*\{.*\}.*/; +const hasOpenCloseCurlyBracesRegex = /.*\{[\s\S]*\}.*/; export const getShouldProcessPrompt = (prompt: string): boolean => hasOpenCloseCurlyBracesRegex.test(prompt); From b4cf5496b6fcdafb894bad7fd73a7c7ac40ec757 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 24 Jan 2024 08:39:23 +1100 Subject: [PATCH 24/34] fix(ui): handle model names with spaces Remove `trim()` from model identifier schema, which prevented parsed model identifiers from matching. The root issue here is that model names are identifiers. This will be resolved in the model manager refactor. Closes #5556 --- invokeai/frontend/web/src/features/nodes/types/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/frontend/web/src/features/nodes/types/common.ts b/invokeai/frontend/web/src/features/nodes/types/common.ts index 81334078fd..c3cb758c87 100644 --- a/invokeai/frontend/web/src/features/nodes/types/common.ts +++ b/invokeai/frontend/web/src/features/nodes/types/common.ts @@ -65,7 +65,7 @@ export const zModelType = z.enum([ 'controlnet', 'embedding', ]); -export const zModelName = z.string().trim().min(1); +export const zModelName = z.string().min(3); export const zModelIdentifier = z.object({ model_name: zModelName, base_model: zBaseModel, From 92fb09c4df4728ac43ff3a44aa43b968732cbd98 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Wed, 24 Jan 2024 03:35:37 +0530 Subject: [PATCH 25/34] fix: Move the models to any folder to avoid boot warnings --- invokeai/backend/image_util/depth_anything/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/invokeai/backend/image_util/depth_anything/__init__.py b/invokeai/backend/image_util/depth_anything/__init__.py index 64eeb3d12f..af94b3bdef 100644 --- a/invokeai/backend/image_util/depth_anything/__init__.py +++ b/invokeai/backend/image_util/depth_anything/__init__.py @@ -20,15 +20,15 @@ config = InvokeAIAppConfig.get_config() DEPTH_ANYTHING_MODELS = { "large": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitl14.pth?download=true", - "local": "sd-1/controlnet/annotators/depth_anything/depth_anything_vitl14.pth", + "local": "any/annotators/depth_anything/depth_anything_vitl14.pth", }, "base": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitb14.pth?download=true", - "local": "sd-1/controlnet/annotators/depth_anything/depth_anything_vitb14.pth", + "local": "any/annotators/depth_anything/depth_anything/depth_anything_vitb14.pth", }, "small": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vits14.pth?download=true", - "local": "sd-1/controlnet/annotators/depth_anything/depth_anything_vits14.pth", + "local": "any/annotators/depth_anything/depth_anything/depth_anything_vits14.pth", }, } From 35184dbd86d8f299071a2e865395f8845891bc5c Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Wed, 24 Jan 2024 03:37:16 +0530 Subject: [PATCH 26/34] fix: incorrect local file path --- invokeai/backend/image_util/depth_anything/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/backend/image_util/depth_anything/__init__.py b/invokeai/backend/image_util/depth_anything/__init__.py index af94b3bdef..fcd600b99e 100644 --- a/invokeai/backend/image_util/depth_anything/__init__.py +++ b/invokeai/backend/image_util/depth_anything/__init__.py @@ -24,11 +24,11 @@ DEPTH_ANYTHING_MODELS = { }, "base": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vitb14.pth?download=true", - "local": "any/annotators/depth_anything/depth_anything/depth_anything_vitb14.pth", + "local": "any/annotators/depth_anything/depth_anything_vitb14.pth", }, "small": { "url": "https://huggingface.co/spaces/LiheYoung/Depth-Anything/resolve/main/checkpoints/depth_anything_vits14.pth?download=true", - "local": "any/annotators/depth_anything/depth_anything/depth_anything_vits14.pth", + "local": "any/annotators/depth_anything/depth_anything_vits14.pth", }, } From 3dc13221d87498572c17d5388149ac8110b15a49 Mon Sep 17 00:00:00 2001 From: Mary Hipp Date: Tue, 23 Jan 2024 09:49:50 -0500 Subject: [PATCH 27/34] add project as a workflow category in the front-end --- invokeai/frontend/web/public/locales/en.json | 2 + .../web/src/features/nodes/types/workflow.ts | 2 +- .../components/WorkflowLibraryList.tsx | 42 +- .../components/WorkflowLibraryListItem.tsx | 6 +- .../frontend/web/src/services/api/schema.ts | 748 ++++++++++++++---- 5 files changed, 630 insertions(+), 170 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 4aa31ede8a..54c259efbf 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1697,6 +1697,7 @@ "workflowLibrary": "Library", "userWorkflows": "My Workflows", "defaultWorkflows": "Default Workflows", + "projectWorkflows": "Project Workflows", "openWorkflow": "Open Workflow", "uploadWorkflow": "Load from File", "deleteWorkflow": "Delete Workflow", @@ -1709,6 +1710,7 @@ "workflowSaved": "Workflow Saved", "noRecentWorkflows": "No Recent Workflows", "noUserWorkflows": "No User Workflows", + "noWorkflows": "No Workflows", "noSystemWorkflows": "No System Workflows", "problemLoading": "Problem Loading Workflows", "loading": "Loading Workflows", diff --git a/invokeai/frontend/web/src/features/nodes/types/workflow.ts b/invokeai/frontend/web/src/features/nodes/types/workflow.ts index f7ada635e5..8919e597dc 100644 --- a/invokeai/frontend/web/src/features/nodes/types/workflow.ts +++ b/invokeai/frontend/web/src/features/nodes/types/workflow.ts @@ -15,7 +15,7 @@ export type XYPosition = z.infer; export const zDimension = z.number().gt(0).nullish(); export type Dimension = z.infer; -export const zWorkflowCategory = z.enum(['user', 'default']); +export const zWorkflowCategory = z.enum(['user', 'default', 'project']); export type WorkflowCategory = z.infer; // #endregion diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx index 9d5087d059..3ff519f672 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx +++ b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryList.tsx @@ -13,6 +13,8 @@ import { InputRightElement, Spacer, } from '@invoke-ai/ui'; +import { useStore } from '@nanostores/react'; +import { $projectId } from 'app/store/nanostores/projectId'; import { IAINoContentFallback, IAINoContentFallbackWithSpinner, @@ -62,6 +64,7 @@ const WorkflowLibraryList = () => { const [order_by, setOrderBy] = useState('opened_at'); const [direction, setDirection] = useState('ASC'); const [debouncedQuery] = useDebounce(query, 500); + const projectId = useStore($projectId); const queryArg = useMemo[0]>(() => { if (category === 'user') { @@ -142,13 +145,8 @@ const WorkflowLibraryList = () => { [] ); - const handleSetUserCategory = useCallback(() => { - setCategory('user'); - setPage(0); - }, []); - - const handleSetDefaultCategory = useCallback(() => { - setCategory('default'); + const handleSetCategory = useCallback((category: WorkflowCategory) => { + setCategory(category); setPage(0); }, []); @@ -158,21 +156,31 @@ const WorkflowLibraryList = () => { - + {projectId ? ( + + ) : ( + + )} - {category === 'user' && ( + {category !== 'default' && ( <> {t('common.orderBy')} @@ -228,7 +236,7 @@ const WorkflowLibraryList = () => { ) : ( - + )} {data && ( diff --git a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryListItem.tsx b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryListItem.tsx index 59fd8983de..da122c39e0 100644 --- a/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryListItem.tsx +++ b/invokeai/frontend/web/src/features/workflowLibrary/components/WorkflowLibraryListItem.tsx @@ -52,7 +52,7 @@ const WorkflowLibraryListItem = ({ workflowDTO }: Props) => { {workflowDTO.name || t('workflows.unnamedWorkflow')} - {workflowDTO.category === 'user' && ( + {workflowDTO.category !== 'default' && ( { )} - {workflowDTO.category === 'user' && ( + {workflowDTO.category !== 'default' && ( { > {t('common.load')} - {workflowDTO.category === 'user' && ( + {workflowDTO.category !== 'default' && (