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 ee879a8915..05076960fb 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
@@ -10,6 +10,7 @@ import { zMainModel } from 'features/parameters/types/parameterSchemas';
import { addToast } from 'features/system/store/systemSlice';
import { forEach } from 'lodash-es';
import { startAppListening } from '..';
+import { controlNetRemoved } from 'features/controlNet/store/controlNetSlice';
const moduleLog = log.child({ module: 'models' });
@@ -51,7 +52,14 @@ export const addModelSelectedListener = () => {
modelsCleared += 1;
}
- // TODO: handle incompatible controlnet; pending model manager support
+ const { controlNets } = state.controlNet;
+ forEach(controlNets, (controlNet, controlNetId) => {
+ if (controlNet.model?.base_model !== base_model) {
+ dispatch(controlNetRemoved({ controlNetId }));
+ modelsCleared += 1;
+ }
+ });
+
if (modelsCleared > 0) {
dispatch(
addToast(
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts
index f8abcfa758..5e3caa7c99 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts
@@ -11,6 +11,7 @@ import {
import { forEach, some } from 'lodash-es';
import { modelsApi } from 'services/api/endpoints/models';
import { startAppListening } from '..';
+import { controlNetRemoved } from 'features/controlNet/store/controlNetSlice';
const moduleLog = log.child({ module: 'models' });
@@ -127,7 +128,22 @@ export const addModelsLoadedListener = () => {
matcher: modelsApi.endpoints.getControlNetModels.matchFulfilled,
effect: async (action, { getState, dispatch }) => {
// ControlNet models loaded - need to remove missing ControlNets from state
- // TODO: pending model manager controlnet support
+ const controlNets = getState().controlNet.controlNets;
+
+ forEach(controlNets, (controlNet, controlNetId) => {
+ const isControlNetAvailable = some(
+ action.payload.entities,
+ (m) =>
+ m?.model_name === controlNet?.model?.model_name &&
+ m?.base_model === controlNet?.model?.base_model
+ );
+
+ if (isControlNetAvailable) {
+ return;
+ }
+
+ dispatch(controlNetRemoved({ controlNetId }));
+ });
},
});
};
diff --git a/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts b/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts
index 3b1476fb1f..580206266d 100644
--- a/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts
+++ b/invokeai/frontend/web/src/common/hooks/useIsReadyToInvoke.ts
@@ -5,6 +5,7 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { validateSeedWeights } from 'common/util/seedWeightPairs';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { modelsApi } from '../../services/api/endpoints/models';
+import { forEach } from 'lodash-es';
const readinessSelector = createSelector(
[stateSelector, activeTabNameSelector],
@@ -52,6 +53,13 @@ const readinessSelector = createSelector(
reasonsWhyNotReady.push('Seed-Weights badly formatted.');
}
+ forEach(state.controlNet.controlNets, (controlNet, id) => {
+ if (!controlNet.model) {
+ isReady = false;
+ reasonsWhyNotReady.push('ControlNet ${id} has no model selected.');
+ }
+ });
+
// All good
return { isReady, reasonsWhyNotReady };
},
diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx
index e25c320cd6..cd3cafa12a 100644
--- a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx
+++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx
@@ -90,7 +90,7 @@ const ControlNet = (props: ControlNetProps) => {
transitionDuration: '0.1s',
}}
>
-
+
{
- const { controlNetId, isControlImageProcessed } = props;
- const dispatch = useAppDispatch();
-
- const handleIsControlImageProcessedToggled = useCallback(() => {
- dispatch(
- isControlNetImagePreprocessedToggled({
- controlNetId,
- })
- );
- }, [controlNetId, dispatch]);
-
- return (
-
- );
-};
-
-export default memo(ParamControlNetIsEnabled);
diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetModel.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetModel.tsx
index eda3cde5d2..548acfaea7 100644
--- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetModel.tsx
+++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetModel.tsx
@@ -1,39 +1,45 @@
import { SelectItem } from '@mantine/core';
-import { RootState } from 'app/store/store';
+import { createSelector } from '@reduxjs/toolkit';
+import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
import IAIMantineSelectItemWithTooltip from 'common/components/IAIMantineSelectItemWithTooltip';
-import { useIsReadyToInvoke } from 'common/hooks/useIsReadyToInvoke';
import { controlNetModelChanged } from 'features/controlNet/store/controlNetSlice';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
+import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam';
+import { selectIsBusy } from 'features/system/store/systemSelectors';
import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react';
import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
type ParamControlNetModelProps = {
controlNetId: string;
- model: string;
};
const ParamControlNetModel = (props: ParamControlNetModelProps) => {
- const { controlNetId, model } = props;
+ const { controlNetId } = props;
const dispatch = useAppDispatch();
- const isReady = useIsReadyToInvoke();
+ const isBusy = useAppSelector(selectIsBusy);
- const currentMainModel = useAppSelector(
- (state: RootState) => state.generation.model
+ const selector = useMemo(
+ () =>
+ createSelector(
+ stateSelector,
+ ({ generation, controlNet }) => {
+ const { model } = generation;
+ const controlNetModel = controlNet.controlNets[controlNetId]?.model;
+ return { mainModel: model, controlNetModel };
+ },
+ defaultSelectorOptions
+ ),
+ [controlNetId]
);
+ const { mainModel, controlNetModel } = useAppSelector(selector);
+
const { data: controlNetModels } = useGetControlNetModelsQuery();
- const handleModelChanged = useCallback(
- (val: string | null) => {
- if (!val) return;
- dispatch(controlNetModelChanged({ controlNetId, model: val }));
- },
- [controlNetId, dispatch]
- );
-
const data = useMemo(() => {
if (!controlNetModels) {
return [];
@@ -46,7 +52,7 @@ const ParamControlNetModel = (props: ParamControlNetModelProps) => {
return;
}
- const disabled = currentMainModel?.base_model !== model.base_model;
+ const disabled = model?.base_model !== mainModel?.base_model;
data.push({
value: id,
@@ -60,16 +66,52 @@ const ParamControlNetModel = (props: ParamControlNetModelProps) => {
});
return data;
- }, [controlNetModels, currentMainModel?.base_model]);
+ }, [controlNetModels, mainModel?.base_model]);
+
+ // grab the full model entity from the RTK Query cache
+ const selectedModel = useMemo(
+ () =>
+ controlNetModels?.entities[
+ `${controlNetModel?.base_model}/controlnet/${controlNetModel?.model_name}`
+ ] ?? null,
+ [
+ controlNetModel?.base_model,
+ controlNetModel?.model_name,
+ controlNetModels?.entities,
+ ]
+ );
+
+ const handleModelChanged = useCallback(
+ (v: string | null) => {
+ if (!v) {
+ return;
+ }
+
+ const newControlNetModel = modelIdToControlNetModelParam(v);
+
+ if (!newControlNetModel) {
+ return;
+ }
+
+ dispatch(
+ controlNetModelChanged({ controlNetId, model: newControlNetModel })
+ );
+ },
+ [controlNetId, dispatch]
+ );
return (
);
};
diff --git a/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts b/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts
index 39a321b282..c735a47510 100644
--- a/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts
+++ b/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts
@@ -1,23 +1,20 @@
-import { PayloadAction } from '@reduxjs/toolkit';
-import { createSlice } from '@reduxjs/toolkit';
+import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store';
-import { ImageDTO } from 'services/api/types';
+import { ControlNetModelParam } from 'features/parameters/types/parameterSchemas';
+import { forEach } from 'lodash-es';
+import { imageDeleted } from 'services/api/thunks/image';
+import { isAnySessionRejected } from 'services/api/thunks/session';
+import { appSocketInvocationError } from 'services/events/actions';
+import { controlNetImageProcessed } from './actions';
+import {
+ CONTROLNET_MODEL_DEFAULT_PROCESSORS,
+ CONTROLNET_PROCESSORS,
+} from './constants';
import {
ControlNetProcessorType,
RequiredCannyImageProcessorInvocation,
RequiredControlNetProcessorNode,
} from './types';
-import {
- CONTROLNET_MODEL_DEFAULT_PROCESSORS,
- // CONTROLNET_MODELS,
- CONTROLNET_PROCESSORS,
- // ControlNetModelName,
-} from './constants';
-import { controlNetImageProcessed } from './actions';
-import { imageDeleted, imageUrlsReceived } from 'services/api/thunks/image';
-import { forEach } from 'lodash-es';
-import { isAnySessionRejected } from 'services/api/thunks/session';
-import { appSocketInvocationError } from 'services/events/actions';
export type ControlModes =
| 'balanced'
@@ -27,7 +24,7 @@ export type ControlModes =
export const initialControlNet: Omit = {
isEnabled: true,
- model: '',
+ model: null,
weight: 1,
beginStepPct: 0,
endStepPct: 1,
@@ -43,7 +40,7 @@ export const initialControlNet: Omit = {
export type ControlNetConfig = {
controlNetId: string;
isEnabled: boolean;
- model: string;
+ model: ControlNetModelParam | null;
weight: number;
beginStepPct: number;
endStepPct: number;
@@ -148,7 +145,7 @@ export const controlNetSlice = createSlice({
state,
action: PayloadAction<{
controlNetId: string;
- model: string;
+ model: ControlNetModelParam;
}>
) => {
const { controlNetId, model } = action.payload;
@@ -159,7 +156,7 @@ export const controlNetSlice = createSlice({
let processorType: ControlNetProcessorType | undefined = undefined;
for (const modelSubstring in CONTROLNET_MODEL_DEFAULT_PROCESSORS) {
- if (model.includes(modelSubstring)) {
+ if (model.model_name.includes(modelSubstring)) {
processorType = CONTROLNET_MODEL_DEFAULT_PROCESSORS[modelSubstring];
break;
}
@@ -253,7 +250,11 @@ export const controlNetSlice = createSlice({
let processorType: ControlNetProcessorType | undefined = undefined;
for (const modelSubstring in CONTROLNET_MODEL_DEFAULT_PROCESSORS) {
- if (state.controlNets[controlNetId].model.includes(modelSubstring)) {
+ if (
+ state.controlNets[controlNetId].model?.model_name.includes(
+ modelSubstring
+ )
+ ) {
processorType = CONTROLNET_MODEL_DEFAULT_PROCESSORS[modelSubstring];
break;
}
@@ -287,7 +288,8 @@ export const controlNetSlice = createSlice({
});
builder.addCase(imageDeleted.pending, (state, action) => {
- // Preemptively remove the image from the gallery
+ // Preemptively remove the image from all controlnets
+ // TODO: doesn't the imageusage stuff do this for us?
const { image_name } = action.meta.arg;
forEach(state.controlNets, (c) => {
if (c.controlImage === image_name) {
@@ -300,21 +302,6 @@ export const controlNetSlice = createSlice({
});
});
- // builder.addCase(imageUrlsReceived.fulfilled, (state, action) => {
- // const { image_name, image_url, thumbnail_url } = action.payload;
-
- // forEach(state.controlNets, (c) => {
- // if (c.controlImage?.image_name === image_name) {
- // c.controlImage.image_url = image_url;
- // c.controlImage.thumbnail_url = thumbnail_url;
- // }
- // if (c.processedControlImage?.image_name === image_name) {
- // c.processedControlImage.image_url = image_url;
- // c.processedControlImage.thumbnail_url = thumbnail_url;
- // }
- // });
- // });
-
builder.addCase(appSocketInvocationError, (state, action) => {
state.pendingControlImages = [];
});
diff --git a/invokeai/frontend/web/src/features/nodes/components/fields/ControlNetModelInputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/fields/ControlNetModelInputFieldComponent.tsx
index f8c42de60e..b5d9fef312 100644
--- a/invokeai/frontend/web/src/features/nodes/components/fields/ControlNetModelInputFieldComponent.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/fields/ControlNetModelInputFieldComponent.tsx
@@ -6,9 +6,10 @@ import {
ControlNetModelInputFieldTemplate,
ControlNetModelInputFieldValue,
} from 'features/nodes/types/types';
-import { MODEL_TYPE_MAP as BASE_MODEL_NAME_MAP } from 'features/system/components/ModelSelect';
-import { forEach, isString } from 'lodash-es';
-import { memo, useCallback, useEffect, useMemo } from 'react';
+import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
+import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam';
+import { forEach } from 'lodash-es';
+import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types';
@@ -20,15 +21,23 @@ const ControlNetModelInputFieldComponent = (
>
) => {
const { nodeId, field } = props;
-
+ const controlNetModel = field.value;
const dispatch = useAppDispatch();
const { t } = useTranslation();
const { data: controlNetModels } = useGetControlNetModelsQuery();
+ // grab the full model entity from the RTK Query cache
const selectedModel = useMemo(
- () => controlNetModels?.entities[field.value ?? controlNetModels.ids[0]],
- [controlNetModels?.entities, controlNetModels?.ids, field.value]
+ () =>
+ controlNetModels?.entities[
+ `${controlNetModel?.base_model}/controlnet/${controlNetModel?.model_name}`
+ ] ?? null,
+ [
+ controlNetModel?.base_model,
+ controlNetModel?.model_name,
+ controlNetModels?.entities,
+ ]
);
const data = useMemo(() => {
@@ -45,8 +54,8 @@ const ControlNetModelInputFieldComponent = (
data.push({
value: id,
- label: model.name,
- group: BASE_MODEL_NAME_MAP[model.base_model],
+ label: model.model_name,
+ group: MODEL_TYPE_MAP[model.base_model],
});
});
@@ -59,40 +68,32 @@ const ControlNetModelInputFieldComponent = (
return;
}
+ const newControlNetModel = modelIdToControlNetModelParam(v);
+
+ if (!newControlNetModel) {
+ return;
+ }
+
dispatch(
fieldValueChanged({
nodeId,
fieldName: field.name,
- value: v,
+ value: newControlNetModel,
})
);
},
[dispatch, field.name, nodeId]
);
- useEffect(() => {
- if (field.value && controlNetModels?.ids.includes(field.value)) {
- return;
- }
-
- const firstLora = controlNetModels?.ids[0];
-
- if (!isString(firstLora)) {
- return;
- }
-
- handleValueChanged(firstLora);
- }, [field.value, handleValueChanged, controlNetModels?.ids]);
-
return (
diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
index 8255c65045..eac272ea01 100644
--- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
+++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
@@ -1,6 +1,7 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store';
import {
+ ControlNetModelParam,
LoRAModelParam,
MainModelParam,
VaeModelParam,
@@ -81,7 +82,8 @@ const nodesSlice = createSlice({
| ImageField[]
| MainModelParam
| VaeModelParam
- | LoRAModelParam;
+ | LoRAModelParam
+ | ControlNetModelParam;
}>
) => {
const { nodeId, fieldName, value } = action.payload;
diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts
index 18b837a98e..f111155a39 100644
--- a/invokeai/frontend/web/src/features/nodes/types/types.ts
+++ b/invokeai/frontend/web/src/features/nodes/types/types.ts
@@ -1,4 +1,5 @@
import {
+ ControlNetModelParam,
LoRAModelParam,
MainModelParam,
VaeModelParam,
@@ -254,7 +255,7 @@ export type LoRAModelInputFieldValue = FieldValueBase & {
export type ControlNetModelInputFieldValue = FieldValueBase & {
type: 'controlnet_model';
- value?: string;
+ value?: ControlNetModelParam;
};
export type ArrayInputFieldValue = FieldValueBase & {
diff --git a/invokeai/frontend/web/src/features/nodes/util/modelIdToControlNetModelField.ts b/invokeai/frontend/web/src/features/nodes/util/modelIdToControlNetModelField.ts
deleted file mode 100644
index 655d5cd5df..0000000000
--- a/invokeai/frontend/web/src/features/nodes/util/modelIdToControlNetModelField.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { BaseModelType, ControlNetModelField } from 'services/api/types';
-
-export const modelIdToControlNetModelField = (
- controlNetModelId: string
-): ControlNetModelField => {
- const [base_model, model_type, model_name] = controlNetModelId.split('/');
-
- const field: ControlNetModelField = {
- base_model: base_model as BaseModelType,
- model_name,
- };
-
- return field;
-};
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEModelSelect.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEModelSelect.tsx
index ee9f7a87bb..f82b02b5af 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEModelSelect.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/VAEModel/ParamVAEModelSelect.tsx
@@ -37,6 +37,7 @@ const ParamVAEModelSelect = () => {
return [];
}
+ // add a "default" option, this means use the main model's included VAE
const data: SelectItem[] = [
{
value: 'default',
diff --git a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts
index aa2c60f3a8..9a4b71ce40 100644
--- a/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts
+++ b/invokeai/frontend/web/src/features/parameters/types/parameterSchemas.ts
@@ -180,6 +180,23 @@ export type LoRAModelParam = z.infer;
*/
export const isValidLoRAModel = (val: unknown): val is LoRAModelParam =>
zLoRAModel.safeParse(val).success;
+/**
+ * Zod schema for ControlNet models
+ */
+export const zControlNetModel = z.object({
+ model_name: z.string().min(1),
+ base_model: zBaseModel,
+});
+/**
+ * Type alias for model parameter, inferred from its zod schema
+ */
+export type ControlNetModelParam = z.infer;
+/**
+ * Validates/type-guards a value as a model parameter
+ */
+export const isValidControlNetModel = (
+ val: unknown
+): val is ControlNetModelParam => zControlNetModel.safeParse(val).success;
/**
* Zod schema for l2l strength parameter
diff --git a/invokeai/frontend/web/src/features/parameters/util/modelIdToControlNetModelParam.ts b/invokeai/frontend/web/src/features/parameters/util/modelIdToControlNetModelParam.ts
new file mode 100644
index 0000000000..c08bca0bbc
--- /dev/null
+++ b/invokeai/frontend/web/src/features/parameters/util/modelIdToControlNetModelParam.ts
@@ -0,0 +1,30 @@
+import { log } from 'app/logging/useLogger';
+import { zControlNetModel } from 'features/parameters/types/parameterSchemas';
+import { ControlNetModelField } from 'services/api/types';
+
+const moduleLog = log.child({ module: 'models' });
+
+export const modelIdToControlNetModelParam = (
+ controlNetModelId: string
+): ControlNetModelField | undefined => {
+ const [base_model, model_type, model_name] = controlNetModelId.split('/');
+
+ const result = zControlNetModel.safeParse({
+ base_model,
+ model_name,
+ });
+
+ if (!result.success) {
+ moduleLog.error(
+ {
+ controlNetModelId,
+ errors: result.error.format(),
+ },
+ 'Failed to parse ControlNet model id'
+ );
+
+ return;
+ }
+
+ return result.data;
+};
diff --git a/invokeai/frontend/web/src/features/parameters/util/modelIdToLoRAModelParam.ts b/invokeai/frontend/web/src/features/parameters/util/modelIdToLoRAModelParam.ts
index 2ea7cacb5d..206246c79e 100644
--- a/invokeai/frontend/web/src/features/parameters/util/modelIdToLoRAModelParam.ts
+++ b/invokeai/frontend/web/src/features/parameters/util/modelIdToLoRAModelParam.ts
@@ -1,9 +1,12 @@
import { LoRAModelParam, zLoRAModel } from '../types/parameterSchemas';
+import { log } from 'app/logging/useLogger';
+
+const moduleLog = log.child({ module: 'models' });
export const modelIdToLoRAModelParam = (
- loraId: string
+ loraModelId: string
): LoRAModelParam | undefined => {
- const [base_model, model_type, model_name] = loraId.split('/');
+ const [base_model, model_type, model_name] = loraModelId.split('/');
const result = zLoRAModel.safeParse({
base_model,
@@ -11,6 +14,13 @@ export const modelIdToLoRAModelParam = (
});
if (!result.success) {
+ moduleLog.error(
+ {
+ loraModelId,
+ errors: result.error.format(),
+ },
+ 'Failed to parse LoRA model id'
+ );
return;
}
diff --git a/invokeai/frontend/web/src/features/parameters/util/modelIdToMainModelParam.ts b/invokeai/frontend/web/src/features/parameters/util/modelIdToMainModelParam.ts
index b73d3c5f0d..70fb219bed 100644
--- a/invokeai/frontend/web/src/features/parameters/util/modelIdToMainModelParam.ts
+++ b/invokeai/frontend/web/src/features/parameters/util/modelIdToMainModelParam.ts
@@ -2,11 +2,14 @@ import {
MainModelParam,
zMainModel,
} from 'features/parameters/types/parameterSchemas';
+import { log } from 'app/logging/useLogger';
+
+const moduleLog = log.child({ module: 'models' });
export const modelIdToMainModelParam = (
- modelId: string
+ mainModelId: string
): MainModelParam | undefined => {
- const [base_model, model_type, model_name] = modelId.split('/');
+ const [base_model, model_type, model_name] = mainModelId.split('/');
const result = zMainModel.safeParse({
base_model,
@@ -14,6 +17,13 @@ export const modelIdToMainModelParam = (
});
if (!result.success) {
+ moduleLog.error(
+ {
+ mainModelId,
+ errors: result.error.format(),
+ },
+ 'Failed to parse main model id'
+ );
return;
}
diff --git a/invokeai/frontend/web/src/features/parameters/util/modelIdToVAEModelParam.ts b/invokeai/frontend/web/src/features/parameters/util/modelIdToVAEModelParam.ts
index 49856531d6..eb57d07f0e 100644
--- a/invokeai/frontend/web/src/features/parameters/util/modelIdToVAEModelParam.ts
+++ b/invokeai/frontend/web/src/features/parameters/util/modelIdToVAEModelParam.ts
@@ -1,9 +1,12 @@
import { VaeModelParam, zVaeModel } from '../types/parameterSchemas';
+import { log } from 'app/logging/useLogger';
+
+const moduleLog = log.child({ module: 'models' });
export const modelIdToVAEModelParam = (
- modelId: string
+ vaeModelId: string
): VaeModelParam | undefined => {
- const [base_model, model_type, model_name] = modelId.split('/');
+ const [base_model, model_type, model_name] = vaeModelId.split('/');
const result = zVaeModel.safeParse({
base_model,
@@ -11,6 +14,13 @@ export const modelIdToVAEModelParam = (
});
if (!result.success) {
+ moduleLog.error(
+ {
+ vaeModelId,
+ errors: result.error.format(),
+ },
+ 'Failed to parse VAE model id'
+ );
return;
}
diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts
index 2a9275de73..dc68200408 100644
--- a/invokeai/frontend/web/src/services/api/schema.d.ts
+++ b/invokeai/frontend/web/src/services/api/schema.d.ts
@@ -1935,12 +1935,12 @@ export type components = {
* Width
* @description The width to resize to (px)
*/
- width: number;
+ width?: number;
/**
* Height
* @description The height to resize to (px)
*/
- height: number;
+ height?: number;
/**
* Resample Mode
* @description The resampling mode
@@ -3302,7 +3302,7 @@ export type components = {
/** ModelsList */
ModelsList: {
/** Models */
- models: (components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"])[];
+ models: (components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"])[];
};
/**
* MultiplyInvocation
@@ -3922,14 +3922,16 @@ export type components = {
latents?: components["schemas"]["LatentsField"];
/**
* Width
- * @description The width to resize to (px)
+ * @description The width to resize to (px)
+ * @default 512
*/
- width: number;
+ width?: number;
/**
* Height
- * @description The height to resize to (px)
+ * @description The height to resize to (px)
+ * @default 512
*/
- height: number;
+ height?: number;
/**
* Mode
* @description The interpolation mode
@@ -5009,7 +5011,7 @@ export type operations = {
/** @description The model imported successfully */
201: {
content: {
- "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
+ "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"];
};
};
/** @description The model could not be found */
@@ -5077,14 +5079,14 @@ export type operations = {
};
requestBody: {
content: {
- "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
+ "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"];
};
};
responses: {
/** @description The model was updated successfully */
200: {
content: {
- "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
+ "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"];
};
};
/** @description Bad request */
@@ -5118,7 +5120,7 @@ export type operations = {
/** @description Model converted successfully */
200: {
content: {
- "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
+ "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"];
};
};
/** @description Bad request */
@@ -5153,7 +5155,7 @@ export type operations = {
/** @description Model converted successfully */
200: {
content: {
- "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
+ "application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"];
};
};
/** @description Incompatible models */