@@ -9,10 +9,11 @@ import type { AppConfig } from 'app/types/invokeai';
9
9
import { useAssertSingleton } from 'common/hooks/useAssertSingleton' ;
10
10
import { debounce , groupBy , upperFirst } from 'es-toolkit/compat' ;
11
11
import { useCanvasManagerSafe } from 'features/controlLayers/contexts/CanvasManagerProviderGate' ;
12
+ import { selectAddedLoRAs } from 'features/controlLayers/store/lorasSlice' ;
12
13
import { selectMainModelConfig , selectParamsSlice } from 'features/controlLayers/store/paramsSlice' ;
13
14
import { selectRefImagesSlice } from 'features/controlLayers/store/refImagesSlice' ;
14
15
import { selectCanvasSlice } from 'features/controlLayers/store/selectors' ;
15
- import type { CanvasState , ParamsState , RefImagesState } from 'features/controlLayers/store/types' ;
16
+ import type { CanvasState , LoRA , ParamsState , RefImagesState } from 'features/controlLayers/store/types' ;
16
17
import {
17
18
getControlLayerWarnings ,
18
19
getGlobalReferenceImageWarnings ,
@@ -73,96 +74,124 @@ export type Reason = { prefix?: string; content: string };
73
74
export const $reasonsWhyCannotEnqueue = atom < Reason [ ] > ( [ ] ) ;
74
75
export const $isReadyToEnqueue = computed ( $reasonsWhyCannotEnqueue , ( reasons ) => reasons . length === 0 ) ;
75
76
76
- const debouncedUpdateReasons = debounce (
77
- async (
78
- tab : TabName ,
79
- isConnected : boolean ,
80
- canvas : CanvasState ,
81
- params : ParamsState ,
82
- refImages : RefImagesState ,
83
- dynamicPrompts : DynamicPromptsState ,
84
- canvasIsFiltering : boolean ,
85
- canvasIsTransforming : boolean ,
86
- canvasIsRasterizing : boolean ,
87
- canvasIsCompositing : boolean ,
88
- canvasIsSelectingObject : boolean ,
89
- nodes : NodesState ,
90
- workflowSettings : WorkflowSettingsState ,
91
- templates : Templates ,
92
- upscale : UpscaleState ,
93
- config : AppConfig ,
94
- store : AppStore ,
95
- isInPublishFlow : boolean ,
96
- isChatGPT4oHighModelDisabled : ( model : ParameterModel ) => boolean ,
97
- isVideoEnabled : boolean ,
98
- promptExpansionRequest : PromptExpansionRequestState ,
99
- video : VideoState
100
- ) => {
101
- if ( tab === 'generate' ) {
102
- const model = selectMainModelConfig ( store . getState ( ) ) ;
103
- const reasons = await getReasonsWhyCannotEnqueueGenerateTab ( {
104
- isConnected,
105
- model,
106
- params,
107
- refImages,
108
- dynamicPrompts,
109
- isChatGPT4oHighModelDisabled,
110
- promptExpansionRequest,
111
- } ) ;
112
- $reasonsWhyCannotEnqueue . set ( reasons ) ;
113
- } else if ( tab === 'canvas' ) {
114
- const model = selectMainModelConfig ( store . getState ( ) ) ;
115
- const reasons = await getReasonsWhyCannotEnqueueCanvasTab ( {
116
- isConnected,
117
- model,
118
- canvas,
119
- params,
120
- refImages,
121
- dynamicPrompts,
122
- canvasIsFiltering,
123
- canvasIsTransforming,
124
- canvasIsRasterizing,
125
- canvasIsCompositing,
126
- canvasIsSelectingObject,
127
- isChatGPT4oHighModelDisabled,
128
- promptExpansionRequest,
129
- } ) ;
130
- $reasonsWhyCannotEnqueue . set ( reasons ) ;
131
- } else if ( tab === 'workflows' ) {
132
- const reasons = await getReasonsWhyCannotEnqueueWorkflowsTab ( {
133
- dispatch : store . dispatch ,
134
- nodesState : nodes ,
135
- workflowSettingsState : workflowSettings ,
136
- isConnected,
137
- templates,
138
- isInPublishFlow,
139
- } ) ;
140
- $reasonsWhyCannotEnqueue . set ( reasons ) ;
141
- } else if ( tab === 'upscaling' ) {
142
- const reasons = getReasonsWhyCannotEnqueueUpscaleTab ( {
143
- isConnected,
144
- upscale,
145
- config,
146
- params,
147
- promptExpansionRequest,
148
- } ) ;
149
- $reasonsWhyCannotEnqueue . set ( reasons ) ;
150
- } else if ( tab === 'video' ) {
151
- const reasons = getReasonsWhyCannotEnqueueVideoTab ( {
152
- isConnected,
153
- video,
154
- params,
155
- promptExpansionRequest,
156
- dynamicPrompts,
157
- isVideoEnabled,
158
- } ) ;
159
- $reasonsWhyCannotEnqueue . set ( reasons ) ;
160
- } else {
161
- $reasonsWhyCannotEnqueue . set ( EMPTY_ARRAY ) ;
162
- }
163
- } ,
164
- 300
165
- ) ;
77
+ type UpdateReasonsArg = {
78
+ tab : TabName ;
79
+ isConnected : boolean ;
80
+ canvas : CanvasState ;
81
+ params : ParamsState ;
82
+ refImages : RefImagesState ;
83
+ dynamicPrompts : DynamicPromptsState ;
84
+ canvasIsFiltering : boolean ;
85
+ canvasIsTransforming : boolean ;
86
+ canvasIsRasterizing : boolean ;
87
+ canvasIsCompositing : boolean ;
88
+ canvasIsSelectingObject : boolean ;
89
+ nodes : NodesState ;
90
+ workflowSettings : WorkflowSettingsState ;
91
+ templates : Templates ;
92
+ upscale : UpscaleState ;
93
+ config : AppConfig ;
94
+ loras : LoRA [ ] ;
95
+ store : AppStore ;
96
+ isInPublishFlow : boolean ;
97
+ isChatGPT4oHighModelDisabled : ( model : ParameterModel ) => boolean ;
98
+ isVideoEnabled : boolean ;
99
+ promptExpansionRequest : PromptExpansionRequestState ;
100
+ video : VideoState ;
101
+ } ;
102
+
103
+ const debouncedUpdateReasons = debounce ( async ( arg : UpdateReasonsArg ) => {
104
+ const {
105
+ tab,
106
+ isConnected,
107
+ canvas,
108
+ params,
109
+ refImages,
110
+ dynamicPrompts,
111
+ canvasIsFiltering,
112
+ canvasIsTransforming,
113
+ canvasIsRasterizing,
114
+ canvasIsCompositing,
115
+ canvasIsSelectingObject,
116
+ nodes,
117
+ workflowSettings,
118
+ templates,
119
+ upscale,
120
+ config,
121
+ loras,
122
+ store,
123
+ isInPublishFlow,
124
+ isChatGPT4oHighModelDisabled,
125
+ isVideoEnabled,
126
+ promptExpansionRequest,
127
+ video,
128
+ } = arg ;
129
+ if ( tab === 'generate' ) {
130
+ const model = selectMainModelConfig ( store . getState ( ) ) ;
131
+ const reasons = await getReasonsWhyCannotEnqueueGenerateTab ( {
132
+ isConnected,
133
+ model,
134
+ params,
135
+ refImages,
136
+ dynamicPrompts,
137
+ isChatGPT4oHighModelDisabled,
138
+ promptExpansionRequest,
139
+ loras,
140
+ } ) ;
141
+ $reasonsWhyCannotEnqueue . set ( reasons ) ;
142
+ } else if ( tab === 'canvas' ) {
143
+ const model = selectMainModelConfig ( store . getState ( ) ) ;
144
+ const reasons = await getReasonsWhyCannotEnqueueCanvasTab ( {
145
+ isConnected,
146
+ model,
147
+ canvas,
148
+ params,
149
+ refImages,
150
+ dynamicPrompts,
151
+ canvasIsFiltering,
152
+ canvasIsTransforming,
153
+ canvasIsRasterizing,
154
+ canvasIsCompositing,
155
+ canvasIsSelectingObject,
156
+ isChatGPT4oHighModelDisabled,
157
+ promptExpansionRequest,
158
+ loras,
159
+ } ) ;
160
+ $reasonsWhyCannotEnqueue . set ( reasons ) ;
161
+ } else if ( tab === 'workflows' ) {
162
+ const reasons = await getReasonsWhyCannotEnqueueWorkflowsTab ( {
163
+ dispatch : store . dispatch ,
164
+ nodesState : nodes ,
165
+ workflowSettingsState : workflowSettings ,
166
+ isConnected,
167
+ templates,
168
+ isInPublishFlow,
169
+ } ) ;
170
+ $reasonsWhyCannotEnqueue . set ( reasons ) ;
171
+ } else if ( tab === 'upscaling' ) {
172
+ const reasons = getReasonsWhyCannotEnqueueUpscaleTab ( {
173
+ isConnected,
174
+ upscale,
175
+ config,
176
+ params,
177
+ promptExpansionRequest,
178
+ loras,
179
+ } ) ;
180
+ $reasonsWhyCannotEnqueue . set ( reasons ) ;
181
+ } else if ( tab === 'video' ) {
182
+ const reasons = getReasonsWhyCannotEnqueueVideoTab ( {
183
+ isConnected,
184
+ video,
185
+ params,
186
+ promptExpansionRequest,
187
+ dynamicPrompts,
188
+ isVideoEnabled,
189
+ } ) ;
190
+ $reasonsWhyCannotEnqueue . set ( reasons ) ;
191
+ } else {
192
+ $reasonsWhyCannotEnqueue . set ( EMPTY_ARRAY ) ;
193
+ }
194
+ } , 300 ) ;
166
195
167
196
export const useReadinessWatcher = ( ) => {
168
197
useAssertSingleton ( 'useReadinessWatcher' ) ;
@@ -177,6 +206,7 @@ export const useReadinessWatcher = () => {
177
206
const workflowSettings = useAppSelector ( selectWorkflowSettingsSlice ) ;
178
207
const upscale = useAppSelector ( selectUpscaleSlice ) ;
179
208
const config = useAppSelector ( selectConfigSlice ) ;
209
+ const loras = useAppSelector ( selectAddedLoRAs ) ;
180
210
const templates = useStore ( $templates ) ;
181
211
const isConnected = useStore ( $isConnected ) ;
182
212
const canvasIsFiltering = useStore ( canvasManager ?. stateApi . $isFiltering ?? $false ) ;
@@ -190,7 +220,7 @@ export const useReadinessWatcher = () => {
190
220
const promptExpansionRequest = useStore ( promptExpansionApi . $state ) ;
191
221
const video = useAppSelector ( selectVideoSlice ) ;
192
222
useEffect ( ( ) => {
193
- debouncedUpdateReasons (
223
+ debouncedUpdateReasons ( {
194
224
tab,
195
225
isConnected,
196
226
canvas,
@@ -207,13 +237,14 @@ export const useReadinessWatcher = () => {
207
237
templates,
208
238
upscale,
209
239
config,
240
+ loras,
210
241
store,
211
242
isInPublishFlow,
212
243
isChatGPT4oHighModelDisabled,
213
244
isVideoEnabled,
214
245
promptExpansionRequest,
215
- video
216
- ) ;
246
+ video,
247
+ } ) ;
217
248
} , [
218
249
store ,
219
250
canvas ,
@@ -232,6 +263,7 @@ export const useReadinessWatcher = () => {
232
263
templates ,
233
264
upscale ,
234
265
workflowSettings ,
266
+ loras ,
235
267
isInPublishFlow ,
236
268
isChatGPT4oHighModelDisabled ,
237
269
isVideoEnabled ,
@@ -289,6 +321,7 @@ const getReasonsWhyCannotEnqueueGenerateTab = (arg: {
289
321
model : MainModelConfig | null | undefined ;
290
322
params : ParamsState ;
291
323
refImages : RefImagesState ;
324
+ loras : LoRA [ ] ;
292
325
dynamicPrompts : DynamicPromptsState ;
293
326
isChatGPT4oHighModelDisabled : ( model : ParameterModel ) => boolean ;
294
327
promptExpansionRequest : PromptExpansionRequestState ;
@@ -298,6 +331,7 @@ const getReasonsWhyCannotEnqueueGenerateTab = (arg: {
298
331
model,
299
332
params,
300
333
refImages,
334
+ loras,
301
335
dynamicPrompts,
302
336
isChatGPT4oHighModelDisabled,
303
337
promptExpansionRequest,
@@ -333,6 +367,16 @@ const getReasonsWhyCannotEnqueueGenerateTab = (arg: {
333
367
reasons . push ( { content : i18n . t ( 'parameters.invoke.modelDisabledForTrial' , { modelName : model . name } ) } ) ;
334
368
}
335
369
370
+ if ( model ) {
371
+ for ( const lora of loras . filter ( ( { isEnabled } ) => isEnabled === true ) ) {
372
+ if ( model . base !== lora . model . base ) {
373
+ reasons . push ( { content : i18n . t ( 'parameters.invoke.incompatibleLoRAs' ) } ) ;
374
+ // Just add the warning once.
375
+ break ;
376
+ }
377
+ }
378
+ }
379
+
336
380
if ( promptExpansionRequest . isPending ) {
337
381
reasons . push ( { content : i18n . t ( 'parameters.invoke.promptExpansionPending' ) } ) ;
338
382
} else if ( promptExpansionRequest . isSuccess ) {
@@ -447,9 +491,10 @@ const getReasonsWhyCannotEnqueueUpscaleTab = (arg: {
447
491
upscale : UpscaleState ;
448
492
config : AppConfig ;
449
493
params : ParamsState ;
494
+ loras : LoRA [ ] ;
450
495
promptExpansionRequest : PromptExpansionRequestState ;
451
496
} ) => {
452
- const { isConnected, upscale, config, params, promptExpansionRequest } = arg ;
497
+ const { isConnected, upscale, config, params, loras , promptExpansionRequest } = arg ;
453
498
const reasons : Reason [ ] = [ ] ;
454
499
455
500
if ( ! isConnected ) {
@@ -484,6 +529,15 @@ const getReasonsWhyCannotEnqueueUpscaleTab = (arg: {
484
529
if ( ! upscale . tileControlnetModel ) {
485
530
reasons . push ( { content : i18n . t ( 'upscaling.missingTileControlNetModel' ) } ) ;
486
531
}
532
+ if ( model ) {
533
+ for ( const lora of loras . filter ( ( { isEnabled } ) => isEnabled === true ) ) {
534
+ if ( model . base !== lora . model . base ) {
535
+ reasons . push ( { content : i18n . t ( 'parameters.invoke.incompatibleLoRAs' ) } ) ;
536
+ // Just add the warning once.
537
+ break ;
538
+ }
539
+ }
540
+ }
487
541
}
488
542
489
543
if ( promptExpansionRequest . isPending ) {
@@ -501,6 +555,7 @@ const getReasonsWhyCannotEnqueueCanvasTab = (arg: {
501
555
canvas : CanvasState ;
502
556
params : ParamsState ;
503
557
refImages : RefImagesState ;
558
+ loras : LoRA [ ] ;
504
559
dynamicPrompts : DynamicPromptsState ;
505
560
canvasIsFiltering : boolean ;
506
561
canvasIsTransforming : boolean ;
@@ -516,6 +571,7 @@ const getReasonsWhyCannotEnqueueCanvasTab = (arg: {
516
571
canvas,
517
572
params,
518
573
refImages,
574
+ loras,
519
575
dynamicPrompts,
520
576
canvasIsFiltering,
521
577
canvasIsTransforming,
@@ -656,6 +712,16 @@ const getReasonsWhyCannotEnqueueCanvasTab = (arg: {
656
712
}
657
713
}
658
714
715
+ if ( model ) {
716
+ for ( const lora of loras . filter ( ( { isEnabled } ) => isEnabled === true ) ) {
717
+ if ( model . base !== lora . model . base ) {
718
+ reasons . push ( { content : i18n . t ( 'parameters.invoke.incompatibleLoRAs' ) } ) ;
719
+ // Just add the warning once.
720
+ break ;
721
+ }
722
+ }
723
+ }
724
+
659
725
if ( model && isChatGPT4oHighModelDisabled ( model ) ) {
660
726
reasons . push ( { content : i18n . t ( 'parameters.invoke.modelDisabledForTrial' , { modelName : model . name } ) } ) ;
661
727
}
0 commit comments