mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
removed upscale button, created spandrel model dropdown, created upscale initial image that works with dnd
This commit is contained in:
parent
43b3e242b0
commit
a0a54348e8
@ -24,6 +24,7 @@ import {
|
|||||||
import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
|
import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
|
||||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
import { upscaleInitialImageChanged } from '../../../../../features/parameters/store/upscaleSlice';
|
||||||
|
|
||||||
export const dndDropped = createAction<{
|
export const dndDropped = createAction<{
|
||||||
overData: TypesafeDroppableData;
|
overData: TypesafeDroppableData;
|
||||||
@ -243,6 +244,20 @@ export const addImageDroppedListener = (startAppListening: AppStartListening) =>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image dropped on upscale initial image
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
overData.actionType === 'SET_UPSCALE_INITIAL_IMAGE' &&
|
||||||
|
activeData.payloadType === 'IMAGE_DTO' &&
|
||||||
|
activeData.payload.imageDTO
|
||||||
|
) {
|
||||||
|
const { imageDTO } = activeData.payload;
|
||||||
|
|
||||||
|
dispatch(upscaleInitialImageChanged(imageDTO));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiple images dropped on user board
|
* Multiple images dropped on user board
|
||||||
*/
|
*/
|
||||||
|
@ -19,6 +19,7 @@ import { t } from 'i18next';
|
|||||||
import { omit } from 'lodash-es';
|
import { omit } from 'lodash-es';
|
||||||
import { boardsApi } from 'services/api/endpoints/boards';
|
import { boardsApi } from 'services/api/endpoints/boards';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
|
import { upscaleInitialImageChanged } from '../../../../../features/parameters/store/upscaleSlice';
|
||||||
|
|
||||||
export const addImageUploadedFulfilledListener = (startAppListening: AppStartListening) => {
|
export const addImageUploadedFulfilledListener = (startAppListening: AppStartListening) => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
@ -89,6 +90,15 @@ export const addImageUploadedFulfilledListener = (startAppListening: AppStartLis
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (postUploadAction?.type === 'SET_UPSCALE_INITIAL_IMAGE') {
|
||||||
|
dispatch(upscaleInitialImageChanged(imageDTO));
|
||||||
|
toast({
|
||||||
|
...DEFAULT_UPLOADED_TOAST,
|
||||||
|
description: "set as upscale initial image",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (postUploadAction?.type === 'SET_CONTROL_ADAPTER_IMAGE') {
|
if (postUploadAction?.type === 'SET_CONTROL_ADAPTER_IMAGE') {
|
||||||
const { id } = postUploadAction;
|
const { id } = postUploadAction;
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -17,7 +17,8 @@ import { forEach } from 'lodash-es';
|
|||||||
import type { Logger } from 'roarr';
|
import type { Logger } from 'roarr';
|
||||||
import { modelConfigsAdapterSelectors, modelsApi } from 'services/api/endpoints/models';
|
import { modelConfigsAdapterSelectors, modelsApi } from 'services/api/endpoints/models';
|
||||||
import type { AnyModelConfig } from 'services/api/types';
|
import type { AnyModelConfig } from 'services/api/types';
|
||||||
import { isNonRefinerMainModelConfig, isRefinerMainModelModelConfig, isVAEModelConfig } from 'services/api/types';
|
import { isNonRefinerMainModelConfig, isRefinerMainModelModelConfig, isSpandrelImageToImageModelConfig, isVAEModelConfig } from 'services/api/types';
|
||||||
|
import { upscaleModelChanged } from '../../../../../features/parameters/store/upscaleSlice';
|
||||||
|
|
||||||
export const addModelsLoadedListener = (startAppListening: AppStartListening) => {
|
export const addModelsLoadedListener = (startAppListening: AppStartListening) => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
@ -36,6 +37,7 @@ export const addModelsLoadedListener = (startAppListening: AppStartListening) =>
|
|||||||
handleVAEModels(models, state, dispatch, log);
|
handleVAEModels(models, state, dispatch, log);
|
||||||
handleLoRAModels(models, state, dispatch, log);
|
handleLoRAModels(models, state, dispatch, log);
|
||||||
handleControlAdapterModels(models, state, dispatch, log);
|
handleControlAdapterModels(models, state, dispatch, log);
|
||||||
|
handleSpandrelImageToImageModels(models, state, dispatch, log);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -177,3 +179,24 @@ const handleControlAdapterModels: ModelHandler = (models, state, dispatch, _log)
|
|||||||
dispatch(controlAdapterModelCleared({ id: ca.id }));
|
dispatch(controlAdapterModelCleared({ id: ca.id }));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSpandrelImageToImageModels: ModelHandler = (models, state, dispatch, _log) => {
|
||||||
|
const currentUpscaleModel = state.upscale.upscaleModel;
|
||||||
|
const upscaleModels = models.filter(isSpandrelImageToImageModelConfig);
|
||||||
|
|
||||||
|
if (currentUpscaleModel) {
|
||||||
|
const isCurrentUpscaleModelAvailable = upscaleModels.some((m) => m.key === currentUpscaleModel.key);
|
||||||
|
if (isCurrentUpscaleModelAvailable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstModel = upscaleModels[0];
|
||||||
|
if (firstModel) {
|
||||||
|
dispatch(upscaleModelChanged(firstModel))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(upscaleModelChanged(null))
|
||||||
|
|
||||||
|
};
|
||||||
|
@ -46,6 +46,7 @@ import { actionSanitizer } from './middleware/devtools/actionSanitizer';
|
|||||||
import { actionsDenylist } from './middleware/devtools/actionsDenylist';
|
import { actionsDenylist } from './middleware/devtools/actionsDenylist';
|
||||||
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
||||||
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
||||||
|
import { upscalePersistConfig, upscaleSlice } from '../../features/parameters/store/upscaleSlice';
|
||||||
|
|
||||||
const allReducers = {
|
const allReducers = {
|
||||||
[canvasSlice.name]: canvasSlice.reducer,
|
[canvasSlice.name]: canvasSlice.reducer,
|
||||||
@ -69,6 +70,7 @@ const allReducers = {
|
|||||||
[controlLayersSlice.name]: undoable(controlLayersSlice.reducer, controlLayersUndoableConfig),
|
[controlLayersSlice.name]: undoable(controlLayersSlice.reducer, controlLayersUndoableConfig),
|
||||||
[workflowSettingsSlice.name]: workflowSettingsSlice.reducer,
|
[workflowSettingsSlice.name]: workflowSettingsSlice.reducer,
|
||||||
[api.reducerPath]: api.reducer,
|
[api.reducerPath]: api.reducer,
|
||||||
|
[upscaleSlice.name]: upscaleSlice.reducer
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootReducer = combineReducers(allReducers);
|
const rootReducer = combineReducers(allReducers);
|
||||||
@ -114,6 +116,7 @@ const persistConfigs: { [key in keyof typeof allReducers]?: PersistConfig } = {
|
|||||||
[hrfPersistConfig.name]: hrfPersistConfig,
|
[hrfPersistConfig.name]: hrfPersistConfig,
|
||||||
[controlLayersPersistConfig.name]: controlLayersPersistConfig,
|
[controlLayersPersistConfig.name]: controlLayersPersistConfig,
|
||||||
[workflowSettingsPersistConfig.name]: workflowSettingsPersistConfig,
|
[workflowSettingsPersistConfig.name]: workflowSettingsPersistConfig,
|
||||||
|
[upscalePersistConfig.name]: upscalePersistConfig
|
||||||
};
|
};
|
||||||
|
|
||||||
const unserialize: UnserializeFunction = (data, key) => {
|
const unserialize: UnserializeFunction = (data, key) => {
|
||||||
|
@ -21,6 +21,10 @@ const selectPostUploadAction = createMemoizedSelector(activeTabNameSelector, (ac
|
|||||||
postUploadAction = { type: 'SET_CANVAS_INITIAL_IMAGE' };
|
postUploadAction = { type: 'SET_CANVAS_INITIAL_IMAGE' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (activeTabName === 'upscaling') {
|
||||||
|
postUploadAction = { type: 'SET_UPSCALE_INITIAL_IMAGE' };
|
||||||
|
}
|
||||||
|
|
||||||
return postUploadAction;
|
return postUploadAction;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -62,6 +62,10 @@ export type CanvasInitialImageDropData = BaseDropData & {
|
|||||||
actionType: 'SET_CANVAS_INITIAL_IMAGE';
|
actionType: 'SET_CANVAS_INITIAL_IMAGE';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UpscaleInitialImageDropData = BaseDropData & {
|
||||||
|
actionType: 'SET_UPSCALE_INITIAL_IMAGE';
|
||||||
|
};
|
||||||
|
|
||||||
type NodesImageDropData = BaseDropData & {
|
type NodesImageDropData = BaseDropData & {
|
||||||
actionType: 'SET_NODES_IMAGE';
|
actionType: 'SET_NODES_IMAGE';
|
||||||
context: {
|
context: {
|
||||||
@ -87,6 +91,8 @@ export type SelectForCompareDropData = BaseDropData & {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type TypesafeDroppableData =
|
export type TypesafeDroppableData =
|
||||||
| CurrentImageDropData
|
| CurrentImageDropData
|
||||||
| ControlAdapterDropData
|
| ControlAdapterDropData
|
||||||
@ -98,7 +104,8 @@ export type TypesafeDroppableData =
|
|||||||
| IPALayerImageDropData
|
| IPALayerImageDropData
|
||||||
| RGLayerIPAdapterImageDropData
|
| RGLayerIPAdapterImageDropData
|
||||||
| IILayerImageDropData
|
| IILayerImageDropData
|
||||||
| SelectForCompareDropData;
|
| SelectForCompareDropData
|
||||||
|
| UpscaleInitialImageDropData;
|
||||||
|
|
||||||
type BaseDragData = {
|
type BaseDragData = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -159,11 +166,11 @@ interface DragEvent {
|
|||||||
over: TypesafeOver | null;
|
over: TypesafeOver | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DragStartEvent extends Pick<DragEvent, 'active'> {}
|
export interface DragStartEvent extends Pick<DragEvent, 'active'> { }
|
||||||
interface DragMoveEvent extends DragEvent {}
|
interface DragMoveEvent extends DragEvent { }
|
||||||
interface DragOverEvent extends DragMoveEvent {}
|
interface DragOverEvent extends DragMoveEvent { }
|
||||||
export interface DragEndEvent extends DragEvent {}
|
export interface DragEndEvent extends DragEvent { }
|
||||||
interface DragCancelEvent extends DragEndEvent {}
|
interface DragCancelEvent extends DragEndEvent { }
|
||||||
|
|
||||||
export interface DndContextTypesafeProps
|
export interface DndContextTypesafeProps
|
||||||
extends Omit<DndContextProps, 'onDragStart' | 'onDragMove' | 'onDragOver' | 'onDragEnd' | 'onDragCancel'> {
|
extends Omit<DndContextProps, 'onDragStart' | 'onDragMove' | 'onDragOver' | 'onDragEnd' | 'onDragCancel'> {
|
||||||
|
@ -27,6 +27,8 @@ export const isValidDrop = (overData?: TypesafeDroppableData | null, activeData?
|
|||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'SET_CANVAS_INITIAL_IMAGE':
|
case 'SET_CANVAS_INITIAL_IMAGE':
|
||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
|
case 'SET_UPSCALE_INITIAL_IMAGE':
|
||||||
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'SET_NODES_IMAGE':
|
case 'SET_NODES_IMAGE':
|
||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'SELECT_FOR_COMPARE':
|
case 'SELECT_FOR_COMPARE':
|
||||||
|
@ -11,12 +11,8 @@ import SingleSelectionMenuItems from 'features/gallery/components/ImageContextMe
|
|||||||
import { useImageActions } from 'features/gallery/hooks/useImageActions';
|
import { useImageActions } from 'features/gallery/hooks/useImageActions';
|
||||||
import { sentImageToImg2Img } from 'features/gallery/store/actions';
|
import { sentImageToImg2Img } from 'features/gallery/store/actions';
|
||||||
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
|
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
|
||||||
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
|
|
||||||
import { parseAndRecallImageDimensions } from 'features/metadata/util/handlers';
|
import { parseAndRecallImageDimensions } from 'features/metadata/util/handlers';
|
||||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||||
import ParamUpscalePopover from 'features/parameters/components/Upscale/ParamUpscaleSettings';
|
|
||||||
import { useIsQueueMutationInProgress } from 'features/queue/hooks/useIsQueueMutationInProgress';
|
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
|
||||||
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
||||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||||
import { useGetAndLoadEmbeddedWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadEmbeddedWorkflow';
|
import { useGetAndLoadEmbeddedWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadEmbeddedWorkflow';
|
||||||
@ -37,9 +33,8 @@ import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
|||||||
|
|
||||||
const selectShouldDisableToolbarButtons = createSelector(
|
const selectShouldDisableToolbarButtons = createSelector(
|
||||||
selectSystemSlice,
|
selectSystemSlice,
|
||||||
selectGallerySlice,
|
|
||||||
selectLastSelectedImage,
|
selectLastSelectedImage,
|
||||||
(system, gallery, lastSelectedImage) => {
|
(system, lastSelectedImage) => {
|
||||||
const hasProgressImage = Boolean(system.denoiseProgress?.progress_image);
|
const hasProgressImage = Boolean(system.denoiseProgress?.progress_image);
|
||||||
return hasProgressImage || !lastSelectedImage;
|
return hasProgressImage || !lastSelectedImage;
|
||||||
}
|
}
|
||||||
@ -47,13 +42,10 @@ const selectShouldDisableToolbarButtons = createSelector(
|
|||||||
|
|
||||||
const CurrentImageButtons = () => {
|
const CurrentImageButtons = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const isConnected = useAppSelector((s) => s.system.isConnected);
|
|
||||||
const lastSelectedImage = useAppSelector(selectLastSelectedImage);
|
const lastSelectedImage = useAppSelector(selectLastSelectedImage);
|
||||||
const selection = useAppSelector((s) => s.gallery.selection);
|
const selection = useAppSelector((s) => s.gallery.selection);
|
||||||
const shouldDisableToolbarButtons = useAppSelector(selectShouldDisableToolbarButtons);
|
const shouldDisableToolbarButtons = useAppSelector(selectShouldDisableToolbarButtons);
|
||||||
const templates = useStore($templates);
|
const templates = useStore($templates);
|
||||||
const isUpscalingEnabled = useFeatureStatus('upscaling');
|
|
||||||
const isQueueMutationInProgress = useIsQueueMutationInProgress();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { currentData: imageDTO } = useGetImageDTOQuery(lastSelectedImage?.image_name ?? skipToken);
|
const { currentData: imageDTO } = useGetImageDTOQuery(lastSelectedImage?.image_name ?? skipToken);
|
||||||
@ -107,17 +99,6 @@ const CurrentImageButtons = () => {
|
|||||||
dispatch(imagesToDeleteSelected(selection));
|
dispatch(imagesToDeleteSelected(selection));
|
||||||
}, [dispatch, imageDTO, selection]);
|
}, [dispatch, imageDTO, selection]);
|
||||||
|
|
||||||
useHotkeys(
|
|
||||||
'Shift+U',
|
|
||||||
() => {
|
|
||||||
handleClickUpscale();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: () => Boolean(isUpscalingEnabled && !shouldDisableToolbarButtons && isConnected),
|
|
||||||
},
|
|
||||||
[isUpscalingEnabled, imageDTO, shouldDisableToolbarButtons, isConnected]
|
|
||||||
);
|
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
'delete',
|
'delete',
|
||||||
() => {
|
() => {
|
||||||
@ -191,12 +172,6 @@ const CurrentImageButtons = () => {
|
|||||||
/>
|
/>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
{isUpscalingEnabled && (
|
|
||||||
<ButtonGroup isDisabled={isQueueMutationInProgress}>
|
|
||||||
{isUpscalingEnabled && <ParamUpscalePopover imageDTO={imageDTO} />}
|
|
||||||
</ButtonGroup>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<DeleteImageButton onClick={handleDelete} />
|
<DeleteImageButton onClick={handleDelete} />
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
@ -63,7 +63,7 @@ const ParamESRGANModel = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl orientation="vertical">
|
<FormControl orientation="vertical">
|
||||||
<FormLabel>{t('models.esrganModel')} </FormLabel>
|
<FormLabel>{t('models.esrganModel')}</FormLabel>
|
||||||
<Combobox value={value} onChange={onChange} options={options} />
|
<Combobox value={value} onChange={onChange} options={options} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useSpandrelImageToImageModels } from '../../../../services/api/hooks/modelsByType';
|
||||||
|
import { useModelCombobox } from '../../../../common/hooks/useModelCombobox';
|
||||||
|
import { SpandrelImageToImageModelConfig } from '../../../../services/api/types';
|
||||||
|
import { upscaleModelChanged } from '../../store/upscaleSlice';
|
||||||
|
|
||||||
|
const ParamSpandrelModel = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [modelConfigs, { isLoading }] = useSpandrelImageToImageModels();
|
||||||
|
|
||||||
|
const model = useAppSelector((s) => s.upscale.upscaleModel);
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const _onChange = useCallback(
|
||||||
|
(v: SpandrelImageToImageModelConfig | null) => {
|
||||||
|
dispatch(upscaleModelChanged(v));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
const { options, value, onChange, placeholder, noOptionsMessage } = useModelCombobox({
|
||||||
|
modelConfigs,
|
||||||
|
onChange: _onChange,
|
||||||
|
selectedModel: model,
|
||||||
|
isLoading,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl orientation="vertical">
|
||||||
|
<FormLabel>Upscale Model</FormLabel>
|
||||||
|
<Combobox
|
||||||
|
value={value}
|
||||||
|
placeholder={placeholder}
|
||||||
|
options={options}
|
||||||
|
onChange={onChange}
|
||||||
|
noOptionsMessage={noOptionsMessage}
|
||||||
|
isClearable
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ParamSpandrelModel);
|
@ -17,7 +17,8 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { PiFrameCornersBold } from 'react-icons/pi';
|
import { PiFrameCornersBold } from 'react-icons/pi';
|
||||||
import type { ImageDTO } from 'services/api/types';
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
import ParamESRGANModel from './ParamRealESRGANModel';
|
import ParamSpandrelModel from './ParamSpandrelModel';
|
||||||
|
import { useSpandrelImageToImageModels } from '../../../../services/api/hooks/modelsByType';
|
||||||
|
|
||||||
type Props = { imageDTO?: ImageDTO };
|
type Props = { imageDTO?: ImageDTO };
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ const ParamUpscalePopover = (props: Props) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const { isAllowedToUpscale, detail } = useIsAllowedToUpscale(imageDTO);
|
const { isAllowedToUpscale, detail } = useIsAllowedToUpscale(imageDTO);
|
||||||
|
const [modelConfigs] = useSpandrelImageToImageModels();
|
||||||
|
|
||||||
const handleClickUpscale = useCallback(() => {
|
const handleClickUpscale = useCallback(() => {
|
||||||
onClose();
|
onClose();
|
||||||
@ -45,16 +47,17 @@ const ParamUpscalePopover = (props: Props) => {
|
|||||||
onClick={onOpen}
|
onClick={onOpen}
|
||||||
icon={<PiFrameCornersBold />}
|
icon={<PiFrameCornersBold />}
|
||||||
aria-label={t('parameters.upscale')}
|
aria-label={t('parameters.upscale')}
|
||||||
|
isDisabled={!modelConfigs.length}
|
||||||
/>
|
/>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent>
|
<PopoverContent>
|
||||||
<PopoverBody minW={96}>
|
<PopoverBody minW={96}>
|
||||||
<Flex flexDirection="column" gap={4}>
|
<Flex flexDirection="column" gap={4}>
|
||||||
<ParamESRGANModel />
|
<ParamSpandrelModel />
|
||||||
<Button
|
<Button
|
||||||
tooltip={detail}
|
tooltip={detail}
|
||||||
size="sm"
|
size="sm"
|
||||||
isDisabled={!imageDTO || inProgress || !isAllowedToUpscale}
|
isDisabled={!imageDTO || inProgress || !isAllowedToUpscale || !modelConfigs.length}
|
||||||
onClick={handleClickUpscale}
|
onClick={handleClickUpscale}
|
||||||
>
|
>
|
||||||
{t('parameters.upscaleImage')}
|
{t('parameters.upscaleImage')}
|
||||||
|
@ -5,6 +5,7 @@ import { selectConfigSlice } from 'features/system/store/configSlice';
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { ImageDTO } from 'services/api/types';
|
import type { ImageDTO } from 'services/api/types';
|
||||||
|
import { useSpandrelImageToImageModels } from '../../../services/api/hooks/modelsByType';
|
||||||
|
|
||||||
const getUpscaledPixels = (imageDTO?: ImageDTO, maxUpscalePixels?: number) => {
|
const getUpscaledPixels = (imageDTO?: ImageDTO, maxUpscalePixels?: number) => {
|
||||||
if (!imageDTO) {
|
if (!imageDTO) {
|
||||||
|
@ -10,7 +10,7 @@ import type {
|
|||||||
ParameterSeed,
|
ParameterSeed,
|
||||||
ParameterSteps,
|
ParameterSteps,
|
||||||
ParameterStrength,
|
ParameterStrength,
|
||||||
ParameterVAEModel,
|
ParameterVAEModel
|
||||||
} from 'features/parameters/types/parameterSchemas';
|
} from 'features/parameters/types/parameterSchemas';
|
||||||
import type { RgbaColor } from 'react-colorful';
|
import type { RgbaColor } from 'react-colorful';
|
||||||
|
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
import type { PersistConfig, RootState } from 'app/store/store';
|
||||||
|
import { ParameterSpandrelImageToImageModel } from '../types/parameterSchemas';
|
||||||
|
import { ImageDTO } from '../../../services/api/types';
|
||||||
|
|
||||||
|
|
||||||
|
interface UpscaleState {
|
||||||
|
_version: 1;
|
||||||
|
upscaleModel: ParameterSpandrelImageToImageModel | null;
|
||||||
|
upscaleInitialImage: ImageDTO | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialUpscaleState: UpscaleState = {
|
||||||
|
_version: 1,
|
||||||
|
upscaleModel: null,
|
||||||
|
upscaleInitialImage: null
|
||||||
|
};
|
||||||
|
|
||||||
|
export const upscaleSlice = createSlice({
|
||||||
|
name: 'upscale',
|
||||||
|
initialState: initialUpscaleState,
|
||||||
|
reducers: {
|
||||||
|
upscaleModelChanged: (state, action: PayloadAction<ParameterSpandrelImageToImageModel | null>) => {
|
||||||
|
state.upscaleModel = action.payload;
|
||||||
|
},
|
||||||
|
upscaleInitialImageChanged: (state, action: PayloadAction<ImageDTO | null>) => {
|
||||||
|
state.upscaleInitialImage = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { upscaleModelChanged, upscaleInitialImageChanged } = upscaleSlice.actions;
|
||||||
|
|
||||||
|
export const selectUpscalelice = (state: RootState) => state.upscale;
|
||||||
|
|
||||||
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||||
|
const migrateUpscaleState = (state: any): any => {
|
||||||
|
if (!('_version' in state)) {
|
||||||
|
state._version = 1;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const upscalePersistConfig: PersistConfig<UpscaleState> = {
|
||||||
|
name: upscaleSlice.name,
|
||||||
|
initialState: initialUpscaleState,
|
||||||
|
migrate: migrateUpscaleState,
|
||||||
|
persistDenylist: [],
|
||||||
|
};
|
@ -126,6 +126,11 @@ const zParameterT2IAdapterModel = zModelIdentifierField;
|
|||||||
export type ParameterT2IAdapterModel = z.infer<typeof zParameterT2IAdapterModel>;
|
export type ParameterT2IAdapterModel = z.infer<typeof zParameterT2IAdapterModel>;
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
// #region VAE Model
|
||||||
|
export const zParameterSpandrelImageToImageModel = zModelIdentifierField;
|
||||||
|
export type ParameterSpandrelImageToImageModel = z.infer<typeof zParameterSpandrelImageToImageModel>;
|
||||||
|
// #endregion
|
||||||
|
|
||||||
// #region Strength (l2l strength)
|
// #region Strength (l2l strength)
|
||||||
export const zParameterStrength = z.number().min(0).max(1);
|
export const zParameterStrength = z.number().min(0).max(1);
|
||||||
export type ParameterStrength = z.infer<typeof zParameterStrength>;
|
export type ParameterStrength = z.infer<typeof zParameterStrength>;
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
import { Flex } from '@invoke-ai/ui-library';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import IAIDndImage from '../../../../common/components/IAIDndImage';
|
||||||
|
import { PostUploadAction } from '../../../../services/api/types';
|
||||||
|
import { TypesafeDroppableData } from '../../../dnd/types';
|
||||||
|
import { useAppDispatch, useAppSelector } from '../../../../app/store/storeHooks';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
import { PiArrowCounterClockwiseBold } from 'react-icons/pi';
|
||||||
|
import IAIDndImageIcon from '../../../../common/components/IAIDndImageIcon';
|
||||||
|
import { upscaleInitialImageChanged } from '../../../parameters/store/upscaleSlice';
|
||||||
|
|
||||||
|
export const UpscaleInitialImage = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const imageDTO = useAppSelector((s) => s.upscale.upscaleInitialImage);
|
||||||
|
|
||||||
|
const droppableData = useMemo<TypesafeDroppableData | undefined>(
|
||||||
|
() => ({
|
||||||
|
actionType: 'SET_UPSCALE_INITIAL_IMAGE',
|
||||||
|
id: 'upscale-intial-image',
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const postUploadAction = useMemo<PostUploadAction>(
|
||||||
|
() => ({
|
||||||
|
type: 'SET_UPSCALE_INITIAL_IMAGE',
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onReset = useCallback(() => {
|
||||||
|
dispatch(upscaleInitialImageChanged(null));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex justifyContent="flex-start">
|
||||||
|
<Flex position="relative" w={36} h={36} alignItems="center" justifyContent="center">
|
||||||
|
<IAIDndImage
|
||||||
|
droppableData={droppableData}
|
||||||
|
imageDTO={imageDTO || undefined}
|
||||||
|
postUploadAction={postUploadAction}
|
||||||
|
/>
|
||||||
|
{imageDTO && (
|
||||||
|
<Flex position="absolute" flexDir="column" top={1} insetInlineEnd={1} gap={1}>
|
||||||
|
<IAIDndImageIcon
|
||||||
|
onClick={onReset}
|
||||||
|
icon={<PiArrowCounterClockwiseBold size={16} />}
|
||||||
|
tooltip={t('controlnet.resetControlImage')}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,27 @@
|
|||||||
|
import { Flex, StandaloneAccordion } from '@invoke-ai/ui-library';
|
||||||
|
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import ParamSpandrelModel from '../../../parameters/components/Upscale/ParamSpandrelModel';
|
||||||
|
import { UpscaleInitialImage } from './UpscaleInitialImage';
|
||||||
|
|
||||||
|
export const UpscaleSettingsAccordion = memo(() => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { isOpen: isOpenAccordion, onToggle: onToggleAccordion } = useStandaloneAccordionToggle({
|
||||||
|
id: 'upscale-settings',
|
||||||
|
defaultIsOpen: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StandaloneAccordion label="Upscale" isOpen={isOpenAccordion} onToggle={onToggleAccordion}>
|
||||||
|
<Flex p={4} w="full" h="full" flexDir="column" data-testid="image-settings-accordion">
|
||||||
|
<Flex gap={4}>
|
||||||
|
<UpscaleInitialImage />
|
||||||
|
<ParamSpandrelModel />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</StandaloneAccordion>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
UpscaleSettingsAccordion.displayName = 'UpscaleSettingsAccordion';
|
@ -37,6 +37,7 @@ import { Panel, PanelGroup } from 'react-resizable-panels';
|
|||||||
import ParametersPanelCanvas from './ParametersPanels/ParametersPanelCanvas';
|
import ParametersPanelCanvas from './ParametersPanels/ParametersPanelCanvas';
|
||||||
import ResizeHandle from './tabs/ResizeHandle';
|
import ResizeHandle from './tabs/ResizeHandle';
|
||||||
import UpscalingTab from './tabs/UpscalingTab';
|
import UpscalingTab from './tabs/UpscalingTab';
|
||||||
|
import ParametersPanelUpscale from './ParametersPanels/ParametersPanelUpscale';
|
||||||
|
|
||||||
type TabData = {
|
type TabData = {
|
||||||
id: InvokeTabName;
|
id: InvokeTabName;
|
||||||
@ -66,6 +67,7 @@ const TAB_DATA: Record<InvokeTabName, TabData> = {
|
|||||||
translationKey: 'ui.tabs.upscaling',
|
translationKey: 'ui.tabs.upscaling',
|
||||||
icon: <MdZoomOutMap />,
|
icon: <MdZoomOutMap />,
|
||||||
content: <UpscalingTab />,
|
content: <UpscalingTab />,
|
||||||
|
parametersPanel: <ParametersPanelUpscale />,
|
||||||
},
|
},
|
||||||
workflows: {
|
workflows: {
|
||||||
id: 'workflows',
|
id: 'workflows',
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
import { Box, Flex, Switch } from '@invoke-ai/ui-library';
|
||||||
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
|
||||||
|
import { Prompts } from 'features/parameters/components/Prompts/Prompts';
|
||||||
|
import QueueControls from 'features/queue/components/QueueControls';
|
||||||
|
import { SDXLPrompts } from 'features/sdxl/components/SDXLPrompts/SDXLPrompts';
|
||||||
|
import { AdvancedSettingsAccordion } from 'features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion';
|
||||||
|
import { GenerationSettingsAccordion } from 'features/settingsAccordions/components/GenerationSettingsAccordion/GenerationSettingsAccordion';
|
||||||
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||||
|
import type { CSSProperties } from 'react';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { UpscaleSettingsAccordion } from '../../../settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion';
|
||||||
|
|
||||||
|
const overlayScrollbarsStyles: CSSProperties = {
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
};
|
||||||
|
|
||||||
|
const ParametersPanelUpscale = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const isSDXL = useAppSelector((s) => s.generation.model?.base === 'sdxl');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex w="full" h="full" flexDir="column" gap={2}>
|
||||||
|
<QueueControls />
|
||||||
|
<Flex w="full" h="full" position="relative">
|
||||||
|
<Box position="absolute" top={0} left={0} right={0} bottom={0}>
|
||||||
|
<OverlayScrollbarsComponent defer style={overlayScrollbarsStyles} options={overlayScrollbarsParams.options}>
|
||||||
|
<Flex gap={2} flexDirection="column" h="full" w="full">
|
||||||
|
<UpscaleSettingsAccordion />
|
||||||
|
{isSDXL ? <SDXLPrompts /> : <Prompts />}
|
||||||
|
<GenerationSettingsAccordion />
|
||||||
|
<AdvancedSettingsAccordion />
|
||||||
|
</Flex>
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ParametersPanelUpscale);
|
@ -205,6 +205,10 @@ type CanvasInitialImageAction = {
|
|||||||
type: 'SET_CANVAS_INITIAL_IMAGE';
|
type: 'SET_CANVAS_INITIAL_IMAGE';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type UpscaleInitialImageAction = {
|
||||||
|
type: 'SET_UPSCALE_INITIAL_IMAGE';
|
||||||
|
};
|
||||||
|
|
||||||
type ToastAction = {
|
type ToastAction = {
|
||||||
type: 'TOAST';
|
type: 'TOAST';
|
||||||
title?: string;
|
title?: string;
|
||||||
@ -223,4 +227,5 @@ export type PostUploadAction =
|
|||||||
| CALayerImagePostUploadAction
|
| CALayerImagePostUploadAction
|
||||||
| IPALayerImagePostUploadAction
|
| IPALayerImagePostUploadAction
|
||||||
| RGLayerIPAdapterImagePostUploadAction
|
| RGLayerIPAdapterImagePostUploadAction
|
||||||
| IILayerImagePostUploadAction;
|
| IILayerImagePostUploadAction
|
||||||
|
| UpscaleInitialImageAction;
|
||||||
|
Loading…
Reference in New Issue
Block a user