diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 3300f7c7fa..e7eac057ef 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1691,6 +1691,27 @@ "missingUpscaleModel": "Missing upscale model", "missingTileControlNetModel": "No valid tile ControlNet models installed" }, + "stylePresets": { + "active": "Active", + "choosePromptTemplate": "Choose Prompt Template", + "createPromptTemplate": "Create Prompt Template", + "defaultTemplates": "Default Templates", + "deleteImage": "Delete Image", + "deleteTemplate": "Delete Template", + "deleteTemplate2": "Are you sure you want to delete this template? This cannot be undone.", + "editTemplate": "Edit Template", + "myTemplates": "My Templates", + "name": "Name", + "negativePrompt": "Negative Prompt", + "noMatchingTemplates": "No matching templates", + "placeholderDirections": "Use the { } button to specify where your manual prompt should be included in the template. If you do not provide one, the template will be appended to your prompt.", + "positivePrompt": "Positive Prompt", + "templateDeleted": "Prompt template deleted", + "unableToDeleteTemplate": "Unable to delete prompt template", + "updatePromptTemplate": "Update Prompt Template", + "uploadImage": "Upload Image", + "useForTemplate": "Use For Prompt Template" + }, "upsell": { "inviteTeammates": "Invite Teammates", "professional": "Professional", diff --git a/invokeai/frontend/web/src/app/store/store.ts b/invokeai/frontend/web/src/app/store/store.ts index 5cd97110a6..eba0ca4b15 100644 --- a/invokeai/frontend/web/src/app/store/store.ts +++ b/invokeai/frontend/web/src/app/store/store.ts @@ -72,7 +72,7 @@ const allReducers = { [api.reducerPath]: api.reducer, [upscaleSlice.name]: upscaleSlice.reducer, [stylePresetModalSlice.name]: stylePresetModalSlice.reducer, - [stylePresetSlice.name]: stylePresetSlice.reducer + [stylePresetSlice.name]: stylePresetSlice.reducer, }; const rootReducer = combineReducers(allReducers); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 6c24617086..1ae4b7b6bc 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -6,7 +6,6 @@ import { useCopyImageToClipboard } from 'common/hooks/useCopyImageToClipboard'; import { useDownloadImage } from 'common/hooks/useDownloadImage'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { imagesToChangeSelected, isModalOpenChanged } from 'features/changeBoardModal/store/slice'; -import { isModalOpenChanged as isStylePresetModalOpenChanged } from 'features/stylePresets/store/stylePresetModalSlice'; import { iiLayerAdded } from 'features/controlLayers/store/controlLayersSlice'; import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice'; import { useImageActions } from 'features/gallery/hooks/useImageActions'; @@ -41,8 +40,6 @@ import { } from 'react-icons/pi'; import { useStarImagesMutation, useUnstarImagesMutation } from 'services/api/endpoints/images'; import type { ImageDTO } from 'services/api/types'; -import { isMenuOpenChanged } from '../../../stylePresets/store/stylePresetSlice'; -import { createPresetFromImageChanged } from '../../../stylePresets/store/stylePresetModalSlice'; type SingleSelectionMenuItemsProps = { imageDTO: ImageDTO; @@ -200,7 +197,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { onClickCapture={createAsPreset} isDisabled={isLoadingMetadata || !hasPrompts} > - Create Preset + {t('stylePresets.useForTemplate')} } onClickCapture={handleSendToImageToImage} id="send-to-img2img"> diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useImageActions.ts b/invokeai/frontend/web/src/features/gallery/hooks/useImageActions.ts index c661f8b217..d29f417517 100644 --- a/invokeai/frontend/web/src/features/gallery/hooks/useImageActions.ts +++ b/invokeai/frontend/web/src/features/gallery/hooks/useImageActions.ts @@ -1,12 +1,12 @@ +import { skipToken } from '@reduxjs/toolkit/query'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { useImageUrlToBlob } from 'common/hooks/useImageUrlToBlob'; import { handlers, parseAndRecallAllMetadata, parseAndRecallPrompts } from 'features/metadata/util/handlers'; +import { isModalOpenChanged, prefilledFormDataChanged } from 'features/stylePresets/store/stylePresetModalSlice'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { useCallback, useEffect, useState } from 'react'; +import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata'; -import { useImageUrlToBlob } from '../../../common/hooks/useImageUrlToBlob'; -import { prefilledFormDataChanged, isModalOpenChanged } from '../../stylePresets/store/stylePresetModalSlice'; -import { useGetImageDTOQuery } from '../../../services/api/endpoints/images'; -import { skipToken } from '@reduxjs/toolkit/query'; export const useImageActions = (image_name?: string) => { const activeTabName = useAppSelector(activeTabNameSelector); @@ -15,8 +15,8 @@ export const useImageActions = (image_name?: string) => { const [hasSeed, setHasSeed] = useState(false); const [hasPrompts, setHasPrompts] = useState(false); const imageUrlToBlob = useImageUrlToBlob(); - const dispatch = useAppDispatch() - const { data: imageDTO } = useGetImageDTOQuery(image_name ?? skipToken) + const dispatch = useAppDispatch(); + const { data: imageDTO } = useGetImageDTOQuery(image_name ?? skipToken); useEffect(() => { const parseMetadata = async () => { @@ -70,15 +70,31 @@ export const useImageActions = (image_name?: string) => { const createAsPreset = useCallback(async () => { if (image_name && metadata && imageDTO) { - const positivePrompt = await handlers.positivePrompt.parse(metadata) - const negativePrompt = await handlers.negativePrompt.parse(metadata) - const imageBlob = await imageUrlToBlob(imageDTO.image_url, 100) + const positivePrompt = await handlers.positivePrompt.parse(metadata); + const negativePrompt = await handlers.negativePrompt.parse(metadata); + const imageBlob = await imageUrlToBlob(imageDTO.image_url, 100); - dispatch(prefilledFormDataChanged({ name: "", positivePrompt, negativePrompt, image: imageBlob ? new File([imageBlob], "stylePreset.png", { type: 'image/png', }) : null })) - dispatch(isModalOpenChanged(true)) + dispatch( + prefilledFormDataChanged({ + name: '', + positivePrompt, + negativePrompt, + image: imageBlob ? new File([imageBlob], 'stylePreset.png', { type: 'image/png' }) : null, + }) + ); + dispatch(isModalOpenChanged(true)); } + }, [image_name, metadata, dispatch, imageDTO, imageUrlToBlob]); - }, [image_name, metadata, dispatch, imageDTO]) - - return { recallAll, remix, recallSeed, recallPrompts, hasMetadata, hasSeed, hasPrompts, isLoadingMetadata, createAsPreset }; + return { + recallAll, + remix, + recallSeed, + recallPrompts, + hasMetadata, + hasSeed, + hasPrompts, + isLoadingMetadata, + createAsPreset, + }; }; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts index 646f97cf44..76f61598d4 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts @@ -98,7 +98,8 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise let modelNode; if (model.base === 'sdxl') { - const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = getPresetModifiedPrompts(state); + const { positivePrompt, negativePrompt, positiveStylePrompt, negativeStylePrompt } = + getPresetModifiedPrompts(state); posCondNode = g.addNode({ type: 'sdxl_compel_prompt', diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasImageToImageGraph.ts index 15db40bff4..3d17da9b4a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasImageToImageGraph.ts @@ -16,7 +16,11 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types'; import { isNonRefinerMainModelConfig } from 'services/api/types'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasInpaintGraph.ts index 5cdefb395e..39cdbb31cd 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasInpaintGraph.ts @@ -19,7 +19,11 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types'; import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasOutpaintGraph.ts index 00fc129edc..ce8f86223f 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasOutpaintGraph.ts @@ -23,7 +23,11 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types'; import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLImageToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLImageToImageGraph.ts index 49525d37bf..bcf2f8a93c 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLImageToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLImageToImageGraph.ts @@ -16,7 +16,11 @@ import { SDXL_REFINER_SEAMLESS, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types'; import { isNonRefinerMainModelConfig } from 'services/api/types'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLInpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLInpaintGraph.ts index e8c3af2e4d..e56e4d0ddb 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLInpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLInpaintGraph.ts @@ -19,7 +19,11 @@ import { SDXL_REFINER_SEAMLESS, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types'; import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLOutpaintGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLOutpaintGraph.ts index 98cb9ece96..095918ab71 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLOutpaintGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLOutpaintGraph.ts @@ -23,7 +23,11 @@ import { SDXL_REFINER_SEAMLESS, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import type { ImageDTO, Invocation, NonNullableGraph } from 'services/api/types'; import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLTextToImageGraph.ts index 14bc649c99..2b37255070 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasSDXLTextToImageGraph.ts @@ -14,7 +14,11 @@ import { SDXL_REFINER_SEAMLESS, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import { isNonRefinerMainModelConfig, type NonNullableGraph } from 'services/api/types'; import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasTextToImageGraph.ts index 57cb695a71..352dc0771d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/canvas/buildCanvasTextToImageGraph.ts @@ -14,7 +14,11 @@ import { POSITIVE_CONDITIONING, SEAMLESS, } from 'features/nodes/util/graph/constants'; -import { getBoardField, getIsIntermediate, getPresetModifiedPrompts } from 'features/nodes/util/graph/graphBuilderUtils'; +import { + getBoardField, + getIsIntermediate, + getPresetModifiedPrompts, +} from 'features/nodes/util/graph/graphBuilderUtils'; import { isNonRefinerMainModelConfig, type NonNullableGraph } from 'services/api/types'; import { addControlNetToLinearGraph } from './addControlNetToLinearGraph'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts index b681a3fc04..9f03f58a69 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabGraph.ts @@ -105,10 +105,10 @@ export const buildGenerationTabGraph = async (state: RootState): Promise | Invocation<'img_nsfw'> | Invocation<'img_watermark'> = l2i; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabSDXLGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabSDXLGraph.ts index a9a2d86a70..e05e3ee87a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabSDXLGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/buildGenerationTabSDXLGraph.ts @@ -93,10 +93,10 @@ export const buildGenerationTabSDXLGraph = async (state: RootState): Promise | Invocation<'img_nsfw'> | Invocation<'img_watermark'> = l2i; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts index e977c87f16..00bd213c62 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts @@ -17,22 +17,29 @@ export const getBoardField = (state: RootState): BoardField | undefined => { /** * Gets the prompts, modified for the active style preset. */ -export const getPresetModifiedPrompts = (state: RootState): { positivePrompt: string; negativePrompt: string, positiveStylePrompt?: string; negativeStylePrompt?: string } => { +export const getPresetModifiedPrompts = ( + state: RootState +): { positivePrompt: string; negativePrompt: string; positiveStylePrompt?: string; negativeStylePrompt?: string } => { const { positivePrompt, negativePrompt, positivePrompt2, negativePrompt2, shouldConcatPrompts } = state.controlLayers.present; - const { activeStylePreset } = state.stylePreset + const { activeStylePreset } = state.stylePreset; if (activeStylePreset) { - const presetModifiedPositivePrompt = buildPresetModifiedPrompt(activeStylePreset.preset_data.positive_prompt, positivePrompt) + const presetModifiedPositivePrompt = buildPresetModifiedPrompt( + activeStylePreset.preset_data.positive_prompt, + positivePrompt + ); - const presetModifiedNegativePrompt = buildPresetModifiedPrompt(activeStylePreset.preset_data.negative_prompt, negativePrompt) + const presetModifiedNegativePrompt = buildPresetModifiedPrompt( + activeStylePreset.preset_data.negative_prompt, + negativePrompt + ); return { positivePrompt: presetModifiedPositivePrompt, negativePrompt: presetModifiedNegativePrompt, positiveStylePrompt: shouldConcatPrompts ? presetModifiedPositivePrompt : positivePrompt2, negativeStylePrompt: shouldConcatPrompts ? presetModifiedNegativePrompt : negativePrompt2, - }; } diff --git a/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx b/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx index f06b468bf6..fcbcfa495c 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Core/ParamNegativePrompt.tsx @@ -2,12 +2,12 @@ import { Box, Textarea } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { negativePromptChanged } from 'features/controlLayers/store/controlLayersSlice'; import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper'; +import { ViewModePrompt } from 'features/parameters/components/Prompts/ViewModePrompt'; import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton'; import { PromptPopover } from 'features/prompt/PromptPopover'; import { usePrompt } from 'features/prompt/usePrompt'; import { memo, useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; -import { ViewModePrompt } from '../Prompts/ViewModePrompt'; const DEFAULT_HEIGHT = 20; @@ -42,7 +42,7 @@ export const ParamNegativePrompt = memo(() => { return ( - +