mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into depth_anything_v2
This commit is contained in:
@ -65,11 +65,15 @@ export type AppConfig = {
|
||||
*/
|
||||
shouldUpdateImagesOnConnect: boolean;
|
||||
shouldFetchMetadataFromApi: boolean;
|
||||
/**
|
||||
* Sets a size limit for outputs on the upscaling tab. This is a maximum dimension, so the actual max number of pixels
|
||||
* will be the square of this value.
|
||||
*/
|
||||
maxUpscaleDimension?: number;
|
||||
allowPrivateBoards: boolean;
|
||||
disabledTabs: InvokeTabName[];
|
||||
disabledFeatures: AppFeature[];
|
||||
disabledSDFeatures: SDFeature[];
|
||||
canRestoreDeletedImagesFromBin: boolean;
|
||||
nodesAllowlist: string[] | undefined;
|
||||
nodesDenylist: string[] | undefined;
|
||||
metadataFetchDebounce?: number;
|
||||
|
@ -16,6 +16,7 @@ import { selectWorkflowSettingsSlice } from 'features/nodes/store/workflowSettin
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import { selectUpscalelice } from 'features/parameters/store/upscaleSlice';
|
||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
||||
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import i18n from 'i18next';
|
||||
@ -42,6 +43,7 @@ const createSelector = (templates: Templates) =>
|
||||
selectControlLayersSlice,
|
||||
activeTabNameSelector,
|
||||
selectUpscalelice,
|
||||
selectConfigSlice,
|
||||
],
|
||||
(
|
||||
controlAdapters,
|
||||
@ -52,7 +54,8 @@ const createSelector = (templates: Templates) =>
|
||||
dynamicPrompts,
|
||||
controlLayers,
|
||||
activeTabName,
|
||||
upscale
|
||||
upscale,
|
||||
config
|
||||
) => {
|
||||
const { model } = generation;
|
||||
const { size } = controlLayers.present;
|
||||
@ -209,6 +212,16 @@ const createSelector = (templates: Templates) =>
|
||||
} else if (activeTabName === 'upscaling') {
|
||||
if (!upscale.upscaleInitialImage) {
|
||||
reasons.push({ content: i18n.t('upscaling.missingUpscaleInitialImage') });
|
||||
} else if (config.maxUpscaleDimension) {
|
||||
const { width, height } = upscale.upscaleInitialImage;
|
||||
const { scale } = upscale;
|
||||
|
||||
const maxPixels = config.maxUpscaleDimension ** 2;
|
||||
const upscaledPixels = width * scale * height * scale;
|
||||
|
||||
if (upscaledPixels > maxPixels) {
|
||||
reasons.push({ content: i18n.t('upscaling.exceedsMaxSize') });
|
||||
}
|
||||
}
|
||||
if (!upscale.upscaleModel) {
|
||||
reasons.push({ content: i18n.t('upscaling.missingUpscaleModel') });
|
||||
|
@ -56,7 +56,6 @@ const DeleteImageModal = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const shouldConfirmOnDelete = useAppSelector((s) => s.system.shouldConfirmOnDelete);
|
||||
const canRestoreDeletedImagesFromBin = useAppSelector((s) => s.config.canRestoreDeletedImagesFromBin);
|
||||
const isModalOpen = useAppSelector((s) => s.deleteImageModal.isModalOpen);
|
||||
const { imagesToDelete, imagesUsage, imageUsageSummary } = useAppSelector(selectImageUsages);
|
||||
|
||||
@ -90,7 +89,7 @@ const DeleteImageModal = () => {
|
||||
<Flex direction="column" gap={3}>
|
||||
<ImageUsageMessage imageUsage={imageUsageSummary} />
|
||||
<Divider />
|
||||
<Text>{canRestoreDeletedImagesFromBin ? t('gallery.deleteImageBin') : t('gallery.deleteImagePermanent')}</Text>
|
||||
<Text>{t('gallery.deleteImagePermanent')}</Text>
|
||||
<Text>{t('common.areYouSure')}</Text>
|
||||
<FormControl>
|
||||
<FormLabel>{t('common.dontAskMeAgain')}</FormLabel>
|
||||
|
@ -35,7 +35,6 @@ type Props = {
|
||||
const DeleteBoardModal = (props: Props) => {
|
||||
const { boardToDelete, setBoardToDelete } = props;
|
||||
const { t } = useTranslation();
|
||||
const canRestoreDeletedImagesFromBin = useAppSelector((s) => s.config.canRestoreDeletedImagesFromBin);
|
||||
const { currentData: boardImageNames, isFetching: isFetchingBoardNames } = useListAllImageNamesForBoardQuery(
|
||||
boardToDelete?.board_id ?? skipToken
|
||||
);
|
||||
@ -125,9 +124,7 @@ const DeleteBoardModal = (props: Props) => {
|
||||
? t('boards.deletedPrivateBoardsCannotbeRestored')
|
||||
: t('boards.deletedBoardsCannotbeRestored')}
|
||||
</Text>
|
||||
<Text>
|
||||
{canRestoreDeletedImagesFromBin ? t('gallery.deleteImageBin') : t('gallery.deleteImagePermanent')}
|
||||
</Text>
|
||||
<Text>{t('gallery.deleteImagePermanent')}</Text>
|
||||
</Flex>
|
||||
</AlertDialogBody>
|
||||
<AlertDialogFooter>
|
||||
|
@ -0,0 +1,29 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectUpscalelice } from 'features/parameters/store/upscaleSlice';
|
||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
||||
import { useMemo } from 'react';
|
||||
import type { ImageDTO } from 'services/api/types';
|
||||
|
||||
const createIsTooLargeToUpscaleSelector = (imageDTO?: ImageDTO) =>
|
||||
createMemoizedSelector(selectUpscalelice, selectConfigSlice, (upscale, config) => {
|
||||
const { upscaleModel, scale } = upscale;
|
||||
const { maxUpscaleDimension } = config;
|
||||
|
||||
if (!maxUpscaleDimension || !upscaleModel || !imageDTO) {
|
||||
// When these are missing, another warning will be shown
|
||||
return false;
|
||||
}
|
||||
|
||||
const { width, height } = imageDTO;
|
||||
|
||||
const maxPixels = maxUpscaleDimension ** 2;
|
||||
const upscaledPixels = width * scale * height * scale;
|
||||
|
||||
return upscaledPixels > maxPixels;
|
||||
});
|
||||
|
||||
export const useIsTooLargeToUpscale = (imageDTO?: ImageDTO) => {
|
||||
const selectIsTooLargeToUpscale = useMemo(() => createIsTooLargeToUpscaleSelector(imageDTO), [imageDTO]);
|
||||
return useAppSelector(selectIsTooLargeToUpscale);
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { Flex, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||
@ -41,13 +41,30 @@ export const UpscaleInitialImage = () => {
|
||||
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 position="absolute" flexDir="column" top={1} insetInlineEnd={1} gap={1}>
|
||||
<IAIDndImageIcon
|
||||
onClick={onReset}
|
||||
icon={<PiArrowCounterClockwiseBold size={16} />}
|
||||
tooltip={t('controlnet.resetControlImage')}
|
||||
/>
|
||||
</Flex>
|
||||
<Text
|
||||
position="absolute"
|
||||
background="base.900"
|
||||
color="base.50"
|
||||
fontSize="sm"
|
||||
fontWeight="semibold"
|
||||
bottom={0}
|
||||
left={0}
|
||||
opacity={0.7}
|
||||
px={2}
|
||||
lineHeight={1.25}
|
||||
borderTopEndRadius="base"
|
||||
borderBottomStartRadius="base"
|
||||
pointerEvents="none"
|
||||
>{`${imageDTO.width}x${imageDTO.height}`}</Text>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Button, Flex, ListItem, Text, UnorderedList } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { $installModelsTab } from 'features/modelManagerV2/subpanels/InstallModels';
|
||||
import { useIsTooLargeToUpscale } from 'features/parameters/hooks/useIsTooLargeToUpscale';
|
||||
import { tileControlnetModelChanged } from 'features/parameters/store/upscaleSlice';
|
||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
@ -12,10 +13,13 @@ export const UpscaleWarning = () => {
|
||||
const model = useAppSelector((s) => s.generation.model);
|
||||
const upscaleModel = useAppSelector((s) => s.upscale.upscaleModel);
|
||||
const tileControlnetModel = useAppSelector((s) => s.upscale.tileControlnetModel);
|
||||
const upscaleInitialImage = useAppSelector((s) => s.upscale.upscaleInitialImage);
|
||||
const dispatch = useAppDispatch();
|
||||
const [modelConfigs, { isLoading }] = useControlNetModels();
|
||||
const disabledTabs = useAppSelector((s) => s.config.disabledTabs);
|
||||
const shouldShowButton = useMemo(() => !disabledTabs.includes('models'), [disabledTabs]);
|
||||
const maxUpscaleDimension = useAppSelector((s) => s.config.maxUpscaleDimension);
|
||||
const isTooLargeToUpscale = useIsTooLargeToUpscale(upscaleInitialImage || undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const validModel = modelConfigs.find((cnetModel) => {
|
||||
@ -24,7 +28,7 @@ export const UpscaleWarning = () => {
|
||||
dispatch(tileControlnetModelChanged(validModel || null));
|
||||
}, [model?.base, modelConfigs, dispatch]);
|
||||
|
||||
const warnings = useMemo(() => {
|
||||
const modelWarnings = useMemo(() => {
|
||||
const _warnings: string[] = [];
|
||||
if (!model) {
|
||||
_warnings.push(t('upscaling.mainModelDesc'));
|
||||
@ -35,33 +39,44 @@ export const UpscaleWarning = () => {
|
||||
if (!upscaleModel) {
|
||||
_warnings.push(t('upscaling.upscaleModelDesc'));
|
||||
}
|
||||
|
||||
return _warnings;
|
||||
}, [model, tileControlnetModel, upscaleModel, t]);
|
||||
|
||||
const otherWarnings = useMemo(() => {
|
||||
const _warnings: string[] = [];
|
||||
if (isTooLargeToUpscale && maxUpscaleDimension) {
|
||||
_warnings.push(
|
||||
t('upscaling.exceedsMaxSizeDetails', { maxUpscaleDimension: maxUpscaleDimension.toLocaleString() })
|
||||
);
|
||||
}
|
||||
return _warnings;
|
||||
}, [isTooLargeToUpscale, t, maxUpscaleDimension]);
|
||||
|
||||
const handleGoToModelManager = useCallback(() => {
|
||||
dispatch(setActiveTab('models'));
|
||||
$installModelsTab.set(3);
|
||||
}, [dispatch]);
|
||||
|
||||
if (!warnings.length || isLoading || !shouldShowButton) {
|
||||
if ((!modelWarnings.length && !otherWarnings.length) || isLoading || !shouldShowButton) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex bg="error.500" borderRadius="base" padding={4} direction="column" fontSize="sm" gap={2}>
|
||||
<Text>
|
||||
<Trans
|
||||
i18nKey="upscaling.missingModelsWarning"
|
||||
components={{
|
||||
LinkComponent: (
|
||||
<Button size="sm" flexGrow={0} variant="link" color="base.50" onClick={handleGoToModelManager} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
{!!modelWarnings.length && (
|
||||
<Text>
|
||||
<Trans
|
||||
i18nKey="upscaling.missingModelsWarning"
|
||||
components={{
|
||||
LinkComponent: (
|
||||
<Button size="sm" flexGrow={0} variant="link" color="base.50" onClick={handleGoToModelManager} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
)}
|
||||
<UnorderedList>
|
||||
{warnings.map((warning) => (
|
||||
{[...modelWarnings, ...otherWarnings].map((warning) => (
|
||||
<ListItem key={warning}>{warning}</ListItem>
|
||||
))}
|
||||
</UnorderedList>
|
||||
|
@ -24,7 +24,6 @@ const initialConfigState: AppConfig = {
|
||||
disabledSDFeatures: ['variation', 'symmetry', 'hires', 'perlinNoise', 'noiseThreshold'],
|
||||
nodesAllowlist: undefined,
|
||||
nodesDenylist: undefined,
|
||||
canRestoreDeletedImagesFromBin: true,
|
||||
sd: {
|
||||
disabledControlNetModels: [],
|
||||
disabledControlNetProcessors: [],
|
||||
|
Reference in New Issue
Block a user