Add tile ControlNet model selection to upscale settings

Co-authored-by: kent <kent@invoke.ai>
This commit is contained in:
Cursor Agent
2025-06-29 20:04:55 +00:00
committed by psychedelicious
parent 8bfbea5ed3
commit 264cc5ef46
3 changed files with 83 additions and 1 deletions

View File

@@ -15,7 +15,7 @@ import { refImageModelChanged, selectRefImagesSlice } from 'features/controlLaye
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
import { getEntityIdentifier, isFLUXReduxConfig, isIPAdapterConfig } from 'features/controlLayers/store/types';
import { modelSelected } from 'features/parameters/store/actions';
import { postProcessingModelChanged, upscaleModelChanged } from 'features/parameters/store/upscaleSlice';
import { postProcessingModelChanged, tileControlnetModelChanged, upscaleModelChanged } from 'features/parameters/store/upscaleSlice';
import {
zParameterCLIPEmbedModel,
zParameterSpandrelImageToImageModel,
@@ -28,6 +28,7 @@ import type { AnyModelConfig } from 'services/api/types';
import {
isCLIPEmbedModelConfig,
isControlLayerModelConfig,
isControlNetModelConfig,
isFluxReduxModelConfig,
isFluxVAEModelConfig,
isIPAdapterModelConfig,
@@ -71,6 +72,7 @@ export const addModelsLoadedListener = (startAppListening: AppStartListening) =>
handleControlAdapterModels(models, state, dispatch, log);
handlePostProcessingModel(models, state, dispatch, log);
handleUpscaleModel(models, state, dispatch, log);
handleTileControlNetModel(models, state, dispatch, log);
handleIPAdapterModels(models, state, dispatch, log);
handleT5EncoderModels(models, state, dispatch, log);
handleCLIPEmbedModels(models, state, dispatch, log);
@@ -345,6 +347,46 @@ const handleUpscaleModel: ModelHandler = (models, state, dispatch, log) => {
}
};
const handleTileControlNetModel: ModelHandler = (models, state, dispatch, log) => {
const selectedTileControlNetModel = state.upscale.tileControlnetModel;
const controlNetModels = models.filter(isControlNetModelConfig);
// If the currently selected model is available, we don't need to do anything
if (selectedTileControlNetModel && controlNetModels.some((m) => m.key === selectedTileControlNetModel.key)) {
return;
}
// Find a model with "Tile" in the name, case-insensitive
const tileModel = controlNetModels.find((m) => m.name.toLowerCase().includes('tile'));
// If we have a tile model, select it
if (tileModel) {
log.debug(
{ selectedTileControlNetModel, tileModel },
'No selected tile ControlNet model or selected model is not available, selecting tile model'
);
dispatch(tileControlnetModelChanged(tileModel));
return;
}
// Otherwise, select the first available ControlNet model
const firstModel = controlNetModels[0] || null;
if (firstModel) {
log.debug(
{ selectedTileControlNetModel, firstModel },
'No tile ControlNet model found, selecting first available ControlNet model'
);
dispatch(tileControlnetModelChanged(firstModel));
return;
}
// No available models, we should clear the selected model - but only if we have one selected
if (selectedTileControlNetModel) {
log.debug({ selectedTileControlNetModel }, 'Selected tile ControlNet model is not available, clearing');
dispatch(tileControlnetModelChanged(null));
}
};
const handleT5EncoderModels: ModelHandler = (models, state, dispatch, log) => {
const selectedT5EncoderModel = state.params.t5EncoderModel;
const t5EncoderModels = models.filter((m) => isT5EncoderModelConfig(m));

View File

@@ -0,0 +1,38 @@
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useModelCombobox } from 'common/hooks/useModelCombobox';
import { selectTileControlNetModel, tileControlnetModelChanged } from 'features/parameters/store/upscaleSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useControlNetModels } from 'services/api/hooks/modelsByType';
import type { ControlNetModelConfig } from 'services/api/types';
const ParamTileControlNetModel = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const tileControlNetModel = useAppSelector(selectTileControlNetModel);
const [modelConfigs, { isLoading }] = useControlNetModels();
const _onChange = useCallback(
(controlNetModel: ControlNetModelConfig | null) => {
dispatch(tileControlnetModelChanged(controlNetModel));
},
[dispatch]
);
const { options, value, onChange, noOptionsMessage } = useModelCombobox({
modelConfigs,
onChange: _onChange,
selectedModel: tileControlNetModel,
isLoading,
});
return (
<FormControl isDisabled={!options.length} isInvalid={!options.length} minW={0} flexGrow={1} gap={2}>
<FormLabel m={0}>{t('controlLayers.controlNet')}</FormLabel>
<Combobox value={value} options={options} onChange={onChange} noOptionsMessage={noOptionsMessage} />
</FormControl>
);
};
export default memo(ParamTileControlNetModel);

View File

@@ -5,6 +5,7 @@ import { roundDownToMultiple } from 'common/util/roundDownToMultiple';
import ParamCreativity from 'features/parameters/components/Upscale/ParamCreativity';
import ParamSpandrelModel from 'features/parameters/components/Upscale/ParamSpandrelModel';
import ParamStructure from 'features/parameters/components/Upscale/ParamStructure';
import ParamTileControlNetModel from 'features/parameters/components/Upscale/ParamTileControlNetModel';
import { selectUpscaleSlice } from 'features/parameters/store/upscaleSlice';
import { getGridSize } from 'features/parameters/util/optimalDimension';
import { UpscaleScaleSlider } from 'features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleScaleSlider';
@@ -70,6 +71,7 @@ export const UpscaleSettingsAccordion = memo(() => {
</Flex>
<Expander label={t('accordions.advanced.options')} isOpen={isOpenExpander} onToggle={onToggleExpander}>
<Flex gap={4} pb={4} flexDir="column">
<ParamTileControlNetModel />
<ParamCreativity />
<ParamStructure />
</Flex>