Merge branch 'main' into depth_anything_v2

This commit is contained in:
Kent Keirsey
2024-08-07 10:45:56 -04:00
committed by GitHub
21 changed files with 646 additions and 137 deletions

View File

@ -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;

View File

@ -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') });

View File

@ -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>

View File

@ -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>

View File

@ -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);
};

View File

@ -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>

View File

@ -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>

View File

@ -24,7 +24,6 @@ const initialConfigState: AppConfig = {
disabledSDFeatures: ['variation', 'symmetry', 'hires', 'perlinNoise', 'noiseThreshold'],
nodesAllowlist: undefined,
nodesDenylist: undefined,
canRestoreDeletedImagesFromBin: true,
sd: {
disabledControlNetModels: [],
disabledControlNetProcessors: [],