Skip to content

Commit 4082f25

Browse files
psychedelicioushipsterusername
authored andcommitted
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
1 parent 63d74b4 commit 4082f25

File tree

4 files changed

+56
-24
lines changed

4 files changed

+56
-24
lines changed

invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelSelected.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ export const addModelSelectedListener = () => {
3737
const newModel = result.data;
3838

3939
const { base_model } = newModel;
40+
const didBaseModelChange =
41+
state.generation.model?.base_model !== base_model;
4042

41-
if (state.generation.model?.base_model !== base_model) {
43+
if (didBaseModelChange) {
4244
// we may need to reset some incompatible submodels
4345
let modelsCleared = 0;
4446

@@ -81,7 +83,7 @@ export const addModelSelectedListener = () => {
8183
}
8284
}
8385

84-
dispatch(modelChanged(newModel));
86+
dispatch(modelChanged(newModel, state.generation.model));
8587
},
8688
});
8789
};

invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/modelsLoaded.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const addModelsLoadedListener = () => {
7474
return;
7575
}
7676

77-
dispatch(modelChanged(result.data));
77+
dispatch(modelChanged(result.data, currentModel));
7878
},
7979
});
8080
startAppListening({
@@ -149,7 +149,7 @@ export const addModelsLoadedListener = () => {
149149

150150
if (!firstModel) {
151151
// No custom VAEs loaded at all; use the default
152-
dispatch(modelChanged(null));
152+
dispatch(vaeSelected(null));
153153
return;
154154
}
155155

@@ -227,7 +227,7 @@ export const addModelsLoadedListener = () => {
227227
const log = logger('models');
228228
log.info(
229229
{ models: action.payload.entities },
230-
`ControlNet models loaded (${action.payload.ids.length})`
230+
`T2I Adapter models loaded (${action.payload.ids.length})`
231231
);
232232

233233
selectAllT2IAdapters(getState().controlAdapters).forEach((ca) => {

invokeai/frontend/web/src/features/canvas/store/canvasSlice.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,12 @@ export const canvasSlice = createSlice({
682682
},
683683
extraReducers: (builder) => {
684684
builder.addCase(modelChanged, (state, action) => {
685+
if (
686+
action.meta.previousModel?.base_model === action.payload?.base_model
687+
) {
688+
// The base model hasn't changed, we don't need to optimize the size
689+
return;
690+
}
685691
const optimalDimension = getOptimalDimension(action.payload);
686692
const { width, height } = state.boundingBoxDimensions;
687693
if (getIsSizeOptimal(width, height, optimalDimension)) {

invokeai/frontend/web/src/features/parameters/store/generationSlice.ts

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -158,27 +158,51 @@ export const generationSlice = createSlice({
158158
const { image_name, width, height } = action.payload;
159159
state.initialImage = { imageName: image_name, width, height };
160160
},
161-
modelChanged: (state, action: PayloadAction<ParameterModel | null>) => {
162-
const newModel = action.payload;
163-
state.model = newModel;
161+
modelChanged: {
162+
reducer: (
163+
state,
164+
action: PayloadAction<
165+
ParameterModel | null,
166+
string,
167+
{ previousModel?: ParameterModel | null }
168+
>
169+
) => {
170+
const newModel = action.payload;
171+
state.model = newModel;
164172

165-
if (newModel === null) {
166-
return;
167-
}
173+
if (newModel === null) {
174+
return;
175+
}
168176

169-
// Clamp ClipSkip Based On Selected Model
170-
const { maxClip } = CLIP_SKIP_MAP[newModel.base_model];
171-
state.clipSkip = clamp(state.clipSkip, 0, maxClip);
172-
const optimalDimension = getOptimalDimension(newModel);
173-
if (getIsSizeOptimal(state.width, state.height, optimalDimension)) {
174-
return;
175-
}
176-
const { width, height } = calculateNewSize(
177-
state.aspectRatio.value,
178-
optimalDimension * optimalDimension
179-
);
180-
state.width = width;
181-
state.height = height;
177+
// Clamp ClipSkip Based On Selected Model
178+
const { maxClip } = CLIP_SKIP_MAP[newModel.base_model];
179+
state.clipSkip = clamp(state.clipSkip, 0, maxClip);
180+
181+
if (action.meta.previousModel?.base_model === newModel.base_model) {
182+
// The base model hasn't changed, we don't need to optimize the size
183+
return;
184+
}
185+
186+
const optimalDimension = getOptimalDimension(newModel);
187+
if (getIsSizeOptimal(state.width, state.height, optimalDimension)) {
188+
return;
189+
}
190+
const { width, height } = calculateNewSize(
191+
state.aspectRatio.value,
192+
optimalDimension * optimalDimension
193+
);
194+
state.width = width;
195+
state.height = height;
196+
},
197+
prepare: (
198+
payload: ParameterModel | null,
199+
previousModel?: ParameterModel | null
200+
) => ({
201+
payload,
202+
meta: {
203+
previousModel,
204+
},
205+
}),
182206
},
183207
vaeSelected: (state, action: PayloadAction<ParameterVAEModel | null>) => {
184208
// null is a valid VAE!

0 commit comments

Comments
 (0)