mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): do not optimize size when changing between models with same base model
There's a challenge to accomplish this due to our slice structure - the model is stored in `generationSlice`, but `canvasSlice` also needs to have awareness of it. For example, when the model changes, the canvas slice doesn't know what the previous model was, so it doesn't know whether or not to optimize the size. This means we need to lift the "should we optimize size" information up. To do this, the `modelChanged` action creator accepts the previous model as an optional second arg. Now the canvas has access to both the previous model and new model selection, and can decide whether or not it should optimize its size setting in the same way that the generation slice does. Closes #5452
This commit is contained in:
parent
63d74b4ba6
commit
4082f25062
@ -37,8 +37,10 @@ export const addModelSelectedListener = () => {
|
||||
const newModel = result.data;
|
||||
|
||||
const { base_model } = newModel;
|
||||
const didBaseModelChange =
|
||||
state.generation.model?.base_model !== base_model;
|
||||
|
||||
if (state.generation.model?.base_model !== base_model) {
|
||||
if (didBaseModelChange) {
|
||||
// we may need to reset some incompatible submodels
|
||||
let modelsCleared = 0;
|
||||
|
||||
@ -81,7 +83,7 @@ export const addModelSelectedListener = () => {
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(modelChanged(newModel));
|
||||
dispatch(modelChanged(newModel, state.generation.model));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -74,7 +74,7 @@ export const addModelsLoadedListener = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(modelChanged(result.data));
|
||||
dispatch(modelChanged(result.data, currentModel));
|
||||
},
|
||||
});
|
||||
startAppListening({
|
||||
@ -149,7 +149,7 @@ export const addModelsLoadedListener = () => {
|
||||
|
||||
if (!firstModel) {
|
||||
// No custom VAEs loaded at all; use the default
|
||||
dispatch(modelChanged(null));
|
||||
dispatch(vaeSelected(null));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ export const addModelsLoadedListener = () => {
|
||||
const log = logger('models');
|
||||
log.info(
|
||||
{ models: action.payload.entities },
|
||||
`ControlNet models loaded (${action.payload.ids.length})`
|
||||
`T2I Adapter models loaded (${action.payload.ids.length})`
|
||||
);
|
||||
|
||||
selectAllT2IAdapters(getState().controlAdapters).forEach((ca) => {
|
||||
|
@ -682,6 +682,12 @@ export const canvasSlice = createSlice({
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(modelChanged, (state, action) => {
|
||||
if (
|
||||
action.meta.previousModel?.base_model === action.payload?.base_model
|
||||
) {
|
||||
// The base model hasn't changed, we don't need to optimize the size
|
||||
return;
|
||||
}
|
||||
const optimalDimension = getOptimalDimension(action.payload);
|
||||
const { width, height } = state.boundingBoxDimensions;
|
||||
if (getIsSizeOptimal(width, height, optimalDimension)) {
|
||||
|
@ -158,27 +158,51 @@ export const generationSlice = createSlice({
|
||||
const { image_name, width, height } = action.payload;
|
||||
state.initialImage = { imageName: image_name, width, height };
|
||||
},
|
||||
modelChanged: (state, action: PayloadAction<ParameterModel | null>) => {
|
||||
const newModel = action.payload;
|
||||
state.model = newModel;
|
||||
modelChanged: {
|
||||
reducer: (
|
||||
state,
|
||||
action: PayloadAction<
|
||||
ParameterModel | null,
|
||||
string,
|
||||
{ previousModel?: ParameterModel | null }
|
||||
>
|
||||
) => {
|
||||
const newModel = action.payload;
|
||||
state.model = newModel;
|
||||
|
||||
if (newModel === null) {
|
||||
return;
|
||||
}
|
||||
if (newModel === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clamp ClipSkip Based On Selected Model
|
||||
const { maxClip } = CLIP_SKIP_MAP[newModel.base_model];
|
||||
state.clipSkip = clamp(state.clipSkip, 0, maxClip);
|
||||
const optimalDimension = getOptimalDimension(newModel);
|
||||
if (getIsSizeOptimal(state.width, state.height, optimalDimension)) {
|
||||
return;
|
||||
}
|
||||
const { width, height } = calculateNewSize(
|
||||
state.aspectRatio.value,
|
||||
optimalDimension * optimalDimension
|
||||
);
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
// Clamp ClipSkip Based On Selected Model
|
||||
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
|
||||
return;
|
||||
}
|
||||
|
||||
const optimalDimension = getOptimalDimension(newModel);
|
||||
if (getIsSizeOptimal(state.width, state.height, optimalDimension)) {
|
||||
return;
|
||||
}
|
||||
const { width, height } = calculateNewSize(
|
||||
state.aspectRatio.value,
|
||||
optimalDimension * optimalDimension
|
||||
);
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
},
|
||||
prepare: (
|
||||
payload: ParameterModel | null,
|
||||
previousModel?: ParameterModel | null
|
||||
) => ({
|
||||
payload,
|
||||
meta: {
|
||||
previousModel,
|
||||
},
|
||||
}),
|
||||
},
|
||||
vaeSelected: (state, action: PayloadAction<ParameterVAEModel | null>) => {
|
||||
// null is a valid VAE!
|
||||
|
Loading…
Reference in New Issue
Block a user