refactor(ui): move positive and negative prompt to regional

This commit is contained in:
psychedelicious 2024-04-25 18:41:42 +10:00 committed by Kent Keirsey
parent c686625076
commit 1cf1e53a6c
22 changed files with 70 additions and 62 deletions

View File

@ -10,11 +10,17 @@ import {
promptsChanged, promptsChanged,
} from 'features/dynamicPrompts/store/dynamicPromptsSlice'; } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt'; import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt';
import { setPositivePrompt } from 'features/parameters/store/generationSlice'; import { positivePromptChanged } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { utilitiesApi } from 'services/api/endpoints/utilities'; import { utilitiesApi } from 'services/api/endpoints/utilities';
import { socketConnected } from 'services/events/actions'; import { socketConnected } from 'services/events/actions';
const matcher = isAnyOf(setPositivePrompt, combinatorialToggled, maxPromptsChanged, maxPromptsReset, socketConnected); const matcher = isAnyOf(
positivePromptChanged,
combinatorialToggled,
maxPromptsChanged,
maxPromptsReset,
socketConnected
);
export const addDynamicPromptsListener = (startAppListening: AppStartListening) => { export const addDynamicPromptsListener = (startAppListening: AppStartListening) => {
startAppListening({ startAppListening({
@ -22,7 +28,7 @@ export const addDynamicPromptsListener = (startAppListening: AppStartListening)
effect: async (action, { dispatch, getState, cancelActiveListeners, delay }) => { effect: async (action, { dispatch, getState, cancelActiveListeners, delay }) => {
cancelActiveListeners(); cancelActiveListeners();
const state = getState(); const state = getState();
const { positivePrompt } = state.generation; const { positivePrompt } = state.regionalPrompts.present.baseLayer;
const { maxPrompts } = state.dynamicPrompts; const { maxPrompts } = state.dynamicPrompts;
if (state.config.disabledFeatures.includes('dynamicPrompting')) { if (state.config.disabledFeatures.includes('dynamicPrompting')) {
@ -32,7 +38,7 @@ export const addDynamicPromptsListener = (startAppListening: AppStartListening)
const cachedPrompts = utilitiesApi.endpoints.dynamicPrompts.select({ const cachedPrompts = utilitiesApi.endpoints.dynamicPrompts.select({
prompt: positivePrompt, prompt: positivePrompt,
max_prompts: maxPrompts, max_prompts: maxPrompts,
})(getState()).data; })(state).data;
if (cachedPrompts) { if (cachedPrompts) {
dispatch(promptsChanged(cachedPrompts.prompts)); dispatch(promptsChanged(cachedPrompts.prompts));
@ -40,8 +46,8 @@ export const addDynamicPromptsListener = (startAppListening: AppStartListening)
return; return;
} }
if (!getShouldProcessPrompt(state.generation.positivePrompt)) { if (!getShouldProcessPrompt(positivePrompt)) {
dispatch(promptsChanged([state.generation.positivePrompt])); dispatch(promptsChanged([positivePrompt]));
dispatch(parsingErrorChanged(undefined)); dispatch(parsingErrorChanged(undefined));
dispatch(isErrorChanged(false)); dispatch(isErrorChanged(false));
return; return;

View File

@ -10,6 +10,7 @@ import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldPr
import { selectNodesSlice } from 'features/nodes/store/nodesSlice'; import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
import { isInvocationNode } from 'features/nodes/types/invocation'; import { isInvocationNode } from 'features/nodes/types/invocation';
import { selectGenerationSlice } from 'features/parameters/store/generationSlice'; import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
import { selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { selectSystemSlice } from 'features/system/store/systemSlice'; import { selectSystemSlice } from 'features/system/store/systemSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import i18n from 'i18next'; import i18n from 'i18next';
@ -23,10 +24,12 @@ const selector = createMemoizedSelector(
selectSystemSlice, selectSystemSlice,
selectNodesSlice, selectNodesSlice,
selectDynamicPromptsSlice, selectDynamicPromptsSlice,
selectRegionalPromptsSlice,
activeTabNameSelector, activeTabNameSelector,
], ],
(controlAdapters, generation, system, nodes, dynamicPrompts, activeTabName) => { (controlAdapters, generation, system, nodes, dynamicPrompts, regionalPrompts, activeTabName) => {
const { initialImage, model, positivePrompt } = generation; const { initialImage, model } = generation;
const { positivePrompt } = regionalPrompts.present.baseLayer;
const { isConnected } = system; const { isConnected } = system;

View File

@ -21,8 +21,6 @@ import {
setCfgRescaleMultiplier, setCfgRescaleMultiplier,
setCfgScale, setCfgScale,
setImg2imgStrength, setImg2imgStrength,
setNegativePrompt,
setPositivePrompt,
setScheduler, setScheduler,
setSeed, setSeed,
setSteps, setSteps,
@ -51,6 +49,7 @@ import type {
ParameterVAEModel, ParameterVAEModel,
ParameterWidth, ParameterWidth,
} from 'features/parameters/types/parameterSchemas'; } from 'features/parameters/types/parameterSchemas';
import { negativePromptChanged, positivePromptChanged } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { import {
refinerModelChanged, refinerModelChanged,
setNegativeStylePromptSDXL, setNegativeStylePromptSDXL,
@ -65,11 +64,11 @@ import {
import type { ImageDTO } from 'services/api/types'; import type { ImageDTO } from 'services/api/types';
const recallPositivePrompt: MetadataRecallFunc<ParameterPositivePrompt> = (positivePrompt) => { const recallPositivePrompt: MetadataRecallFunc<ParameterPositivePrompt> = (positivePrompt) => {
getStore().dispatch(setPositivePrompt(positivePrompt)); getStore().dispatch(positivePromptChanged(positivePrompt));
}; };
const recallNegativePrompt: MetadataRecallFunc<ParameterNegativePrompt> = (negativePrompt) => { const recallNegativePrompt: MetadataRecallFunc<ParameterNegativePrompt> = (negativePrompt) => {
getStore().dispatch(setNegativePrompt(negativePrompt)); getStore().dispatch(negativePromptChanged(negativePrompt));
}; };
const recallSDXLPositiveStylePrompt: MetadataRecallFunc<ParameterPositiveStylePromptSDXL> = (positiveStylePrompt) => { const recallSDXLPositiveStylePrompt: MetadataRecallFunc<ParameterPositiveStylePromptSDXL> = (positiveStylePrompt) => {

View File

@ -42,8 +42,6 @@ export const buildCanvasImageToImageGraph = async (
): Promise<NonNullableGraph> => { ): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -57,6 +55,7 @@ export const buildCanvasImageToImageGraph = async (
seamlessXAxis, seamlessXAxis,
seamlessYAxis, seamlessYAxis,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
// The bounding box determines width and height, not the width and height params // The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions; const { width, height } = state.canvas.boundingBoxDimensions;

View File

@ -47,8 +47,6 @@ export const buildCanvasInpaintGraph = async (
): Promise<NonNullableGraph> => { ): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -66,6 +64,7 @@ export const buildCanvasInpaintGraph = async (
canvasCoherenceEdgeSize, canvasCoherenceEdgeSize,
maskBlur, maskBlur,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
if (!model) { if (!model) {
log.error('No model found in state'); log.error('No model found in state');

View File

@ -51,8 +51,6 @@ export const buildCanvasOutpaintGraph = async (
): Promise<NonNullableGraph> => { ): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -78,6 +76,7 @@ export const buildCanvasOutpaintGraph = async (
canvasCoherenceEdgeSize, canvasCoherenceEdgeSize,
maskBlur, maskBlur,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
if (!model) { if (!model) {
log.error('No model found in state'); log.error('No model found in state');

View File

@ -43,8 +43,6 @@ export const buildCanvasSDXLImageToImageGraph = async (
): Promise<NonNullableGraph> => { ): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -57,6 +55,7 @@ export const buildCanvasSDXLImageToImageGraph = async (
seamlessYAxis, seamlessYAxis,
img2imgStrength: strength, img2imgStrength: strength,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { refinerModel, refinerStart } = state.sdxl; const { refinerModel, refinerStart } = state.sdxl;

View File

@ -48,8 +48,6 @@ export const buildCanvasSDXLInpaintGraph = async (
): Promise<NonNullableGraph> => { ): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -66,6 +64,7 @@ export const buildCanvasSDXLInpaintGraph = async (
canvasCoherenceEdgeSize, canvasCoherenceEdgeSize,
maskBlur, maskBlur,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { refinerModel, refinerStart } = state.sdxl; const { refinerModel, refinerStart } = state.sdxl;

View File

@ -52,8 +52,6 @@ export const buildCanvasSDXLOutpaintGraph = async (
): Promise<NonNullableGraph> => { ): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -78,6 +76,7 @@ export const buildCanvasSDXLOutpaintGraph = async (
canvasCoherenceEdgeSize, canvasCoherenceEdgeSize,
maskBlur, maskBlur,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { refinerModel, refinerStart } = state.sdxl; const { refinerModel, refinerStart } = state.sdxl;

View File

@ -33,8 +33,6 @@ import { addCoreMetadataNode, getModelMetadataField } from './metadata';
export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => { export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -46,6 +44,7 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
seamlessXAxis, seamlessXAxis,
seamlessYAxis, seamlessYAxis,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
// The bounding box determines width and height, not the width and height params // The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions; const { width, height } = state.canvas.boundingBoxDimensions;

View File

@ -32,8 +32,6 @@ import { addCoreMetadataNode, getModelMetadataField } from './metadata';
export const buildCanvasTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => { export const buildCanvasTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -46,6 +44,7 @@ export const buildCanvasTextToImageGraph = async (state: RootState): Promise<Non
seamlessXAxis, seamlessXAxis,
seamlessYAxis, seamlessYAxis,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
// The bounding box determines width and height, not the width and height params // The bounding box determines width and height, not the width and height params
const { width, height } = state.canvas.boundingBoxDimensions; const { width, height } = state.canvas.boundingBoxDimensions;

View File

@ -38,8 +38,6 @@ import { addCoreMetadataNode, getModelMetadataField } from './metadata';
export const buildLinearImageToImageGraph = async (state: RootState): Promise<NonNullableGraph> => { export const buildLinearImageToImageGraph = async (state: RootState): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -57,6 +55,7 @@ export const buildLinearImageToImageGraph = async (state: RootState): Promise<No
seamlessXAxis, seamlessXAxis,
seamlessYAxis, seamlessYAxis,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
/** /**
* The easiest way to build linear graphs is to do it in the node editor, then copy and paste the * The easiest way to build linear graphs is to do it in the node editor, then copy and paste the

View File

@ -39,8 +39,6 @@ import { addCoreMetadataNode, getModelMetadataField } from './metadata';
export const buildLinearSDXLImageToImageGraph = async (state: RootState): Promise<NonNullableGraph> => { export const buildLinearSDXLImageToImageGraph = async (state: RootState): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -57,6 +55,7 @@ export const buildLinearSDXLImageToImageGraph = async (state: RootState): Promis
seamlessYAxis, seamlessYAxis,
img2imgStrength: strength, img2imgStrength: strength,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { refinerModel, refinerStart } = state.sdxl; const { refinerModel, refinerStart } = state.sdxl;

View File

@ -30,8 +30,6 @@ import { addCoreMetadataNode, getModelMetadataField } from './metadata';
export const buildLinearSDXLTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => { export const buildLinearSDXLTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -45,6 +43,7 @@ export const buildLinearSDXLTextToImageGraph = async (state: RootState): Promise
seamlessXAxis, seamlessXAxis,
seamlessYAxis, seamlessYAxis,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { refinerModel, refinerStart } = state.sdxl; const { refinerModel, refinerStart } = state.sdxl;

View File

@ -30,8 +30,6 @@ import { addCoreMetadataNode, getModelMetadataField } from './metadata';
export const buildLinearTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => { export const buildLinearTextToImageGraph = async (state: RootState): Promise<NonNullableGraph> => {
const log = logger('nodes'); const log = logger('nodes');
const { const {
positivePrompt,
negativePrompt,
model, model,
cfgScale: cfg_scale, cfgScale: cfg_scale,
cfgRescaleMultiplier: cfg_rescale_multiplier, cfgRescaleMultiplier: cfg_rescale_multiplier,
@ -46,6 +44,7 @@ export const buildLinearTextToImageGraph = async (state: RootState): Promise<Non
seamlessYAxis, seamlessYAxis,
seed, seed,
} = state.generation; } = state.generation;
const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const use_cpu = shouldUseCpuNoise; const use_cpu = shouldUseCpuNoise;

View File

@ -17,7 +17,7 @@ export const getBoardField = (state: RootState): BoardField | undefined => {
* Gets the SDXL style prompts, based on the concat setting. * Gets the SDXL style prompts, based on the concat setting.
*/ */
export const getSDXLStylePrompts = (state: RootState): { positiveStylePrompt: string; negativeStylePrompt: string } => { export const getSDXLStylePrompts = (state: RootState): { positiveStylePrompt: string; negativeStylePrompt: string } => {
const { positivePrompt, negativePrompt } = state.generation; const { positivePrompt, negativePrompt } = state.regionalPrompts.present.baseLayer;
const { positiveStylePrompt, negativeStylePrompt, shouldConcatSDXLStylePrompt } = state.sdxl; const { positiveStylePrompt, negativeStylePrompt, shouldConcatSDXLStylePrompt } = state.sdxl;
return { return {

View File

@ -1,21 +1,21 @@
import { Box, Textarea } from '@invoke-ai/ui-library'; import { Box, Textarea } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper'; import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
import { setNegativePrompt } from 'features/parameters/store/generationSlice';
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton'; import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
import { PromptPopover } from 'features/prompt/PromptPopover'; import { PromptPopover } from 'features/prompt/PromptPopover';
import { usePrompt } from 'features/prompt/usePrompt'; import { usePrompt } from 'features/prompt/usePrompt';
import { negativePromptChanged } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { memo, useCallback, useRef } from 'react'; import { memo, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
export const ParamNegativePrompt = memo(() => { export const ParamNegativePrompt = memo(() => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const prompt = useAppSelector((s) => s.generation.negativePrompt); const prompt = useAppSelector((s) => s.regionalPrompts.present.baseLayer.negativePrompt);
const textareaRef = useRef<HTMLTextAreaElement>(null); const textareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation(); const { t } = useTranslation();
const _onChange = useCallback( const _onChange = useCallback(
(v: string) => { (v: string) => {
dispatch(setNegativePrompt(v)); dispatch(negativePromptChanged(v));
}, },
[dispatch] [dispatch]
); );

View File

@ -2,10 +2,10 @@ import { Box, Textarea } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { ShowDynamicPromptsPreviewButton } from 'features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton'; import { ShowDynamicPromptsPreviewButton } from 'features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton';
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper'; import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
import { setPositivePrompt } from 'features/parameters/store/generationSlice';
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton'; import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
import { PromptPopover } from 'features/prompt/PromptPopover'; import { PromptPopover } from 'features/prompt/PromptPopover';
import { usePrompt } from 'features/prompt/usePrompt'; import { usePrompt } from 'features/prompt/usePrompt';
import { positivePromptChanged } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { SDXLConcatButton } from 'features/sdxl/components/SDXLPrompts/SDXLConcatButton'; import { SDXLConcatButton } from 'features/sdxl/components/SDXLPrompts/SDXLConcatButton';
import { memo, useCallback, useRef } from 'react'; import { memo, useCallback, useRef } from 'react';
import type { HotkeyCallback } from 'react-hotkeys-hook'; import type { HotkeyCallback } from 'react-hotkeys-hook';
@ -14,14 +14,14 @@ import { useTranslation } from 'react-i18next';
export const ParamPositivePrompt = memo(() => { export const ParamPositivePrompt = memo(() => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const prompt = useAppSelector((s) => s.generation.positivePrompt); const prompt = useAppSelector((s) => s.regionalPrompts.present.baseLayer.positivePrompt);
const baseModel = useAppSelector((s) => s.generation.model)?.base; const baseModel = useAppSelector((s) => s.generation.model)?.base;
const textareaRef = useRef<HTMLTextAreaElement>(null); const textareaRef = useRef<HTMLTextAreaElement>(null);
const { t } = useTranslation(); const { t } = useTranslation();
const handleChange = useCallback( const handleChange = useCallback(
(v: string) => { (v: string) => {
dispatch(setPositivePrompt(v)); dispatch(positivePromptChanged(v));
}, },
[dispatch] [dispatch]
); );

View File

@ -32,8 +32,6 @@ const initialGenerationState: GenerationState = {
img2imgStrength: 0.75, img2imgStrength: 0.75,
infillMethod: 'patchmatch', infillMethod: 'patchmatch',
iterations: 1, iterations: 1,
positivePrompt: '',
negativePrompt: '',
scheduler: 'euler', scheduler: 'euler',
maskBlur: 16, maskBlur: 16,
maskBlurMethod: 'box', maskBlurMethod: 'box',
@ -67,12 +65,6 @@ export const generationSlice = createSlice({
name: 'generation', name: 'generation',
initialState: initialGenerationState, initialState: initialGenerationState,
reducers: { reducers: {
setPositivePrompt: (state, action: PayloadAction<string>) => {
state.positivePrompt = action.payload;
},
setNegativePrompt: (state, action: PayloadAction<string>) => {
state.negativePrompt = action.payload;
},
setIterations: (state, action: PayloadAction<number>) => { setIterations: (state, action: PayloadAction<number>) => {
state.iterations = action.payload; state.iterations = action.payload;
}, },
@ -259,8 +251,6 @@ export const {
setImg2imgStrength, setImg2imgStrength,
setInfillMethod, setInfillMethod,
setIterations, setIterations,
setPositivePrompt,
setNegativePrompt,
setScheduler, setScheduler,
setMaskBlur, setMaskBlur,
setCanvasCoherenceMode, setCanvasCoherenceMode,

View File

@ -7,8 +7,6 @@ import type {
ParameterHeight, ParameterHeight,
ParameterMaskBlurMethod, ParameterMaskBlurMethod,
ParameterModel, ParameterModel,
ParameterNegativePrompt,
ParameterPositivePrompt,
ParameterPrecision, ParameterPrecision,
ParameterScheduler, ParameterScheduler,
ParameterSeed, ParameterSeed,
@ -28,8 +26,6 @@ export interface GenerationState {
infillMethod: string; infillMethod: string;
initialImage?: { imageName: string; width: number; height: number }; initialImage?: { imageName: string; width: number; height: number };
iterations: number; iterations: number;
positivePrompt: ParameterPositivePrompt;
negativePrompt: ParameterNegativePrompt;
scheduler: ParameterScheduler; scheduler: ParameterScheduler;
maskBlur: number; maskBlur: number;
maskBlurMethod: ParameterMaskBlurMethod; maskBlurMethod: ParameterMaskBlurMethod;

View File

@ -4,17 +4,17 @@ import { useAppSelector } from 'app/store/storeHooks';
import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue'; import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt'; import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt';
import { selectGenerationSlice } from 'features/parameters/store/generationSlice'; import { selectRegionalPromptsSlice } from 'features/regionalPrompts/store/regionalPromptsSlice';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useEnqueueBatchMutation } from 'services/api/endpoints/queue'; import { useEnqueueBatchMutation } from 'services/api/endpoints/queue';
import { useBoardName } from 'services/api/hooks/useBoardName'; import { useBoardName } from 'services/api/hooks/useBoardName';
const selectPromptsCount = createSelector( const selectPromptsCount = createSelector(
selectGenerationSlice, selectRegionalPromptsSlice,
selectDynamicPromptsSlice, selectDynamicPromptsSlice,
(generation, dynamicPrompts) => (regionalPrompts, dynamicPrompts) =>
getShouldProcessPrompt(generation.positivePrompt) ? dynamicPrompts.prompts.length : 1 getShouldProcessPrompt(regionalPrompts.present.baseLayer.positivePrompt) ? dynamicPrompts.prompts.length : 1
); );
type Props = { type Props = {

View File

@ -4,7 +4,11 @@ import type { PersistConfig, RootState } from 'app/store/store';
import { moveBackward, moveForward, moveToBack, moveToFront } from 'common/util/arrayUtils'; import { moveBackward, moveForward, moveToBack, moveToFront } from 'common/util/arrayUtils';
import { controlAdapterRemoved } from 'features/controlAdapters/store/controlAdaptersSlice'; import { controlAdapterRemoved } from 'features/controlAdapters/store/controlAdaptersSlice';
import type { ControlAdapterConfig } from 'features/controlAdapters/store/types'; import type { ControlAdapterConfig } from 'features/controlAdapters/store/types';
import type { ParameterAutoNegative } from 'features/parameters/types/parameterSchemas'; import type {
ParameterAutoNegative,
ParameterNegativePrompt,
ParameterPositivePrompt,
} from 'features/parameters/types/parameterSchemas';
import type { IRect, Vector2d } from 'konva/lib/types'; import type { IRect, Vector2d } from 'konva/lib/types';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { atom } from 'nanostores'; import { atom } from 'nanostores';
@ -64,6 +68,11 @@ export type VectorMaskLayer = MaskLayerBase & {
export type Layer = VectorMaskLayer | ControlLayer; export type Layer = VectorMaskLayer | ControlLayer;
type BaseLayerState = {
positivePrompt: ParameterPositivePrompt;
negativePrompt: ParameterNegativePrompt;
};
type RegionalPromptsState = { type RegionalPromptsState = {
_version: 1; _version: 1;
selectedLayerId: string | null; selectedLayerId: string | null;
@ -71,6 +80,7 @@ type RegionalPromptsState = {
brushSize: number; brushSize: number;
globalMaskLayerOpacity: number; globalMaskLayerOpacity: number;
isEnabled: boolean; isEnabled: boolean;
baseLayer: BaseLayerState;
}; };
export const initialRegionalPromptsState: RegionalPromptsState = { export const initialRegionalPromptsState: RegionalPromptsState = {
@ -80,6 +90,10 @@ export const initialRegionalPromptsState: RegionalPromptsState = {
layers: [], layers: [],
globalMaskLayerOpacity: 0.5, // this globally changes all mask layers' opacity globalMaskLayerOpacity: 0.5, // this globally changes all mask layers' opacity
isEnabled: true, isEnabled: true,
baseLayer: {
positivePrompt: '',
negativePrompt: '',
},
}; };
const isLine = (obj: VectorMaskLine | VectorMaskRect): obj is VectorMaskLine => obj.type === 'vector_mask_line'; const isLine = (obj: VectorMaskLine | VectorMaskRect): obj is VectorMaskLine => obj.type === 'vector_mask_line';
@ -326,6 +340,15 @@ export const regionalPromptsSlice = createSlice({
}, },
//#endregion //#endregion
//#region Base Layer
positivePromptChanged: (state, action: PayloadAction<string>) => {
state.baseLayer.positivePrompt = action.payload;
},
negativePromptChanged: (state, action: PayloadAction<string>) => {
state.baseLayer.negativePrompt = action.payload;
},
//#endregion
//#region General //#region General
brushSizeChanged: (state, action: PayloadAction<number>) => { brushSizeChanged: (state, action: PayloadAction<number>) => {
state.brushSize = action.payload; state.brushSize = action.payload;
@ -415,6 +438,9 @@ export const {
maskLayerIPAdapterAdded, maskLayerIPAdapterAdded,
maskLayerAutoNegativeChanged, maskLayerAutoNegativeChanged,
maskLayerPreviewColorChanged, maskLayerPreviewColorChanged,
// Base layer actions
positivePromptChanged,
negativePromptChanged,
// General actions // General actions
brushSizeChanged, brushSizeChanged,
globalMaskLayerOpacityChanged, globalMaskLayerOpacityChanged,