From fe8b5193de73fc2809d4b8922dbf1652b66e4d93 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 9 May 2023 21:39:50 +1000 Subject: [PATCH] feat(ui): half-baked use all parameters until we have a better system for metadata, this will remain half-baked --- .../components/CurrentImageButtons.tsx | 39 ++--- .../gallery/components/HoverableImage.tsx | 18 +-- .../parameters/hooks/useParameters.ts | 42 +++++- .../parameters/store/generationSlice.ts | 134 +----------------- .../store/setAllParametersReducer.ts | 61 ++++++++ 5 files changed, 118 insertions(+), 176 deletions(-) create mode 100644 invokeai/frontend/web/src/features/parameters/store/setAllParametersReducer.ts diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx index a0ff83b8c6..32e631005d 100644 --- a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx @@ -61,6 +61,7 @@ import { initialImageSelected } from 'features/parameters/store/actions'; import { requestedImageDeletion } from '../store/actions'; import FaceRestoreSettings from 'features/parameters/components/Parameters/FaceRestore/FaceRestoreSettings'; import UpscaleSettings from 'features/parameters/components/Parameters/Upscale/UpscaleSettings'; +import { allParametersSet } from 'features/parameters/store/generationSlice'; const currentImageButtonsSelector = createSelector( [ @@ -157,7 +158,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { const toast = useToast(); const { t } = useTranslation(); - const { recallPrompt, recallSeed } = useParameters(); + const { recallPrompt, recallSeed, recallAllParameters } = useParameters(); // const handleCopyImage = useCallback(async () => { // if (!image?.url) { @@ -228,39 +229,15 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { }, [dispatch, shouldHidePreview]); const handleClickUseAllParameters = useCallback(() => { - if (!image) return; - // selectedImage.metadata && - // dispatch(setAllParameters(selectedImage.metadata)); - // if (selectedImage.metadata?.image.type === 'img2img') { - // dispatch(setActiveTab('img2img')); - // } else if (selectedImage.metadata?.image.type === 'txt2img') { - // dispatch(setActiveTab('txt2img')); - // } - }, [image]); + recallAllParameters(image); + }, [image, recallAllParameters]); useHotkeys( 'a', () => { - const type = image?.metadata?.invokeai?.node?.types; - if (isString(type) && ['txt2img', 'img2img'].includes(type)) { - handleClickUseAllParameters(); - toast({ - title: t('toast.parametersSet'), - status: 'success', - duration: 2500, - isClosable: true, - }); - } else { - toast({ - title: t('toast.parametersNotSet'), - description: t('toast.parametersNotSetDesc'), - status: 'error', - duration: 2500, - isClosable: true, - }); - } + handleClickUseAllParameters; }, - [image] + [image, recallAllParameters] ); const handleUseSeed = useCallback(() => { @@ -530,8 +507,8 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { tooltip={`${t('parameters.useAll')} (A)`} aria-label={`${t('parameters.useAll')} (A)`} isDisabled={ - !['txt2img', 'img2img'].includes( - image?.metadata?.sd_metadata?.type + !['txt2img', 'img2img', 'inpaint'].includes( + String(image?.metadata?.invokeai?.node?.type) ) } onClick={handleClickUseAllParameters} diff --git a/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx b/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx index 3c2dcdf818..d2fba22c3e 100644 --- a/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx @@ -105,7 +105,8 @@ const HoverableImage = memo((props: HoverableImageProps) => { const { t } = useTranslation(); const { isFeatureEnabled: isLightboxEnabled } = useFeatureStatus('lightbox'); - const { recallSeed, recallPrompt, recallInitialImage } = useParameters(); + const { recallSeed, recallPrompt, recallInitialImage, recallAllParameters } = + useParameters(); const handleMouseOver = () => setIsHovered(true); const handleMouseOut = () => setIsHovered(false); @@ -176,16 +177,9 @@ const HoverableImage = memo((props: HoverableImageProps) => { }); }; - const handleUseAllParameters = () => { - // metadata.invokeai?.node && - // dispatch(setAllParameters(metadata.invokeai?.node)); - // toast({ - // title: t('toast.parametersSet'), - // status: 'success', - // duration: 2500, - // isClosable: true, - // }); - }; + const handleUseAllParameters = useCallback(() => { + recallAllParameters(image); + }, [image, recallAllParameters]); const handleLightBox = () => { // dispatch(setCurrentImage(image)); @@ -239,7 +233,7 @@ const HoverableImage = memo((props: HoverableImageProps) => { icon={} onClickCapture={handleUseAllParameters} isDisabled={ - !['txt2img', 'img2img'].includes( + !['txt2img', 'img2img', 'inpaint'].includes( String(image?.metadata?.invokeai?.node?.type) ) } diff --git a/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts b/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts index 7b8dc455ac..a093010343 100644 --- a/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts +++ b/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts @@ -4,11 +4,12 @@ import { isFinite, isString } from 'lodash-es'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import useSetBothPrompts from './usePrompt'; -import { setSeed } from '../store/generationSlice'; +import { allParametersSet, setSeed } from '../store/generationSlice'; import { isImageField } from 'services/types/guards'; import { NUMPY_RAND_MAX } from 'app/constants'; import { initialImageSelected } from '../store/actions'; import { Image } from 'app/types/invokeai'; +import { setActiveTab } from 'features/ui/store/uiSlice'; export const useParameters = () => { const dispatch = useAppDispatch(); @@ -110,5 +111,42 @@ export const useParameters = () => { [dispatch] ); - return { recallPrompt, recallSeed, recallInitialImage, sendToImageToImage }; + const recallAllParameters = useCallback( + (image: Image | undefined) => { + const type = image?.metadata?.invokeai?.node?.type; + if (['txt2img', 'img2img', 'inpaint'].includes(String(type))) { + dispatch(allParametersSet(image)); + + if (image?.metadata?.invokeai?.node?.type === 'img2img') { + dispatch(setActiveTab('img2img')); + } else if (image?.metadata?.invokeai?.node?.type === 'txt2img') { + dispatch(setActiveTab('txt2img')); + } + + toast({ + title: t('toast.parametersSet'), + status: 'success', + duration: 2500, + isClosable: true, + }); + } else { + toast({ + title: t('toast.parametersNotSet'), + description: t('toast.parametersNotSetDesc'), + status: 'error', + duration: 2500, + isClosable: true, + }); + } + }, + [t, toast, dispatch] + ); + + return { + recallPrompt, + recallSeed, + recallInitialImage, + sendToImageToImage, + recallAllParameters, + }; }; diff --git a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts index 948ba4cc1e..e1bb20c1ab 100644 --- a/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/generationSlice.ts @@ -3,6 +3,7 @@ import { createSlice } from '@reduxjs/toolkit'; import * as InvokeAI from 'app/types/invokeai'; import promptToString from 'common/util/promptToString'; import { clamp } from 'lodash-es'; +import { setAllParametersReducer } from './setAllParametersReducer'; export interface GenerationState { cfgScale: number; @@ -187,131 +188,7 @@ export const generationSlice = createSlice({ state.shouldGenerateVariations = true; state.variationAmount = 0; }, - setAllTextToImageParameters: ( - state, - action: PayloadAction - ) => { - // const { - // sampler, - // prompt, - // seed, - // variations, - // steps, - // cfg_scale, - // threshold, - // perlin, - // seamless, - // _hires_fix, - // width, - // height, - // } = action.payload.image; - // if (variations && variations.length > 0) { - // state.seedWeights = seedWeightsToString(variations); - // state.shouldGenerateVariations = true; - // state.variationAmount = 0; - // } else { - // state.shouldGenerateVariations = false; - // } - // if (seed) { - // state.seed = seed; - // state.shouldRandomizeSeed = false; - // } - // if (prompt) state.prompt = promptToString(prompt); - // if (sampler) state.sampler = sampler; - // if (steps) state.steps = steps; - // if (cfg_scale) state.cfgScale = cfg_scale; - // if (typeof threshold === 'undefined') { - // state.threshold = 0; - // } else { - // state.threshold = threshold; - // } - // if (typeof perlin === 'undefined') { - // state.perlin = 0; - // } else { - // state.perlin = perlin; - // } - // if (typeof seamless === 'boolean') state.seamless = seamless; - // // if (typeof hires_fix === 'boolean') state.hiresFix = hires_fix; // TODO: Needs to be fixed after reorg - // if (width) state.width = width; - // if (height) state.height = height; - }, - setAllImageToImageParameters: ( - state, - action: PayloadAction - ) => { - // const { type, strength, fit, init_image_path, mask_image_path } = - // action.payload.image; - // if (type === 'img2img') { - // if (init_image_path) state.initialImage = init_image_path; - // if (mask_image_path) state.maskPath = mask_image_path; - // if (strength) state.img2imgStrength = strength; - // if (typeof fit === 'boolean') state.shouldFitToWidthHeight = fit; - // } - }, - setAllParameters: (state, action: PayloadAction) => { - // const { - // type, - // sampler, - // prompt, - // seed, - // variations, - // steps, - // cfg_scale, - // threshold, - // perlin, - // seamless, - // _hires_fix, - // width, - // height, - // strength, - // fit, - // init_image_path, - // mask_image_path, - // } = action.payload.image; - // if (type === 'img2img') { - // if (init_image_path) state.initialImage = init_image_path; - // if (mask_image_path) state.maskPath = mask_image_path; - // if (strength) state.img2imgStrength = strength; - // if (typeof fit === 'boolean') state.shouldFitToWidthHeight = fit; - // } - // if (variations && variations.length > 0) { - // state.seedWeights = seedWeightsToString(variations); - // state.shouldGenerateVariations = true; - // state.variationAmount = 0; - // } else { - // state.shouldGenerateVariations = false; - // } - // if (seed) { - // state.seed = seed; - // state.shouldRandomizeSeed = false; - // } - // if (prompt) { - // const [promptOnly, negativePrompt] = getPromptAndNegative(prompt); - // if (promptOnly) state.prompt = promptOnly; - // negativePrompt - // ? (state.negativePrompt = negativePrompt) - // : (state.negativePrompt = ''); - // } - // if (sampler) state.sampler = sampler; - // if (steps) state.steps = steps; - // if (cfg_scale) state.cfgScale = cfg_scale; - // if (typeof threshold === 'undefined') { - // state.threshold = 0; - // } else { - // state.threshold = threshold; - // } - // if (typeof perlin === 'undefined') { - // state.perlin = 0; - // } else { - // state.perlin = perlin; - // } - // if (typeof seamless === 'boolean') state.seamless = seamless; - // // if (typeof hires_fix === 'boolean') state.hiresFix = hires_fix; // TODO: Needs to be fixed after reorg - // if (width) state.width = width; - // if (height) state.height = height; - // // state.shouldRunESRGAN = false; // TODO: Needs to be fixed after reorg - // // state.shouldRunFacetool = false; // TODO: Needs to be fixed after reorg - }, + allParametersSet: setAllParametersReducer, resetParametersState: (state) => { return { ...state, @@ -321,12 +198,6 @@ export const generationSlice = createSlice({ setShouldRandomizeSeed: (state, action: PayloadAction) => { state.shouldRandomizeSeed = action.payload; }, - // setInitialImage: ( - // state, - // action: PayloadAction - // ) => { - // state.initialImage = action.payload; - // }, clearInitialImage: (state) => { state.initialImage = undefined; }, @@ -417,6 +288,7 @@ export const { setSeamless, setSeamlessXAxis, setSeamlessYAxis, + allParametersSet, } = generationSlice.actions; export default generationSlice.reducer; diff --git a/invokeai/frontend/web/src/features/parameters/store/setAllParametersReducer.ts b/invokeai/frontend/web/src/features/parameters/store/setAllParametersReducer.ts new file mode 100644 index 0000000000..7b02647ebc --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/store/setAllParametersReducer.ts @@ -0,0 +1,61 @@ +import { Draft, PayloadAction } from '@reduxjs/toolkit'; +import { Image } from 'app/types/invokeai'; +import { GenerationState } from './generationSlice'; +import { ImageToImageInvocation } from 'services/api'; + +export const setAllParametersReducer = ( + state: Draft, + action: PayloadAction +) => { + const node = action.payload?.metadata.invokeai?.node; + + if (!node) { + return; + } + + if ( + node.type === 'txt2img' || + node.type === 'img2img' || + node.type === 'inpaint' + ) { + const { cfg_scale, height, model, prompt, scheduler, seed, steps, width } = + node; + + if (cfg_scale !== undefined) { + state.cfgScale = Number(cfg_scale); + } + if (height !== undefined) { + state.height = Number(height); + } + if (model !== undefined) { + state.model = String(model); + } + if (prompt !== undefined) { + state.prompt = String(prompt); + } + if (scheduler !== undefined) { + state.sampler = String(scheduler); + } + if (seed !== undefined) { + state.seed = Number(seed); + state.shouldRandomizeSeed = false; + } + if (steps !== undefined) { + state.steps = Number(steps); + } + if (width !== undefined) { + state.width = Number(width); + } + } + + if (node.type === 'img2img') { + const { fit, image } = node as ImageToImageInvocation; + + if (fit !== undefined) { + state.shouldFitToWidthHeight = Boolean(fit); + } + // if (image !== undefined) { + // state.initialImage = image; + // } + } +};