mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
refactor(ui): update components & logic to use new unified slice
This commit is contained in:
parent
bfa496e37f
commit
02ad7a0f93
@ -1,5 +1,5 @@
|
||||
import { PropsWithChildren, memo, useEffect } from 'react';
|
||||
import { modelChanged } from '../src/features/parameters/store/generationSlice';
|
||||
import { modelChanged } from '../src/features/controlLayers/store/canvasV2Slice';
|
||||
import { useAppDispatch } from '../src/app/store/storeHooks';
|
||||
import { useGlobalModifiersInit } from '@invoke-ai/ui-library';
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { setInfillMethod } from 'features/parameters/store/generationSlice';
|
||||
import { setInfillMethod } from 'features/canvas/store/canvasSlice';
|
||||
import { shouldUseNSFWCheckerChanged, shouldUseWatermarkerChanged } from 'features/system/store/systemSlice';
|
||||
import { appInfoApi } from 'services/api/endpoints/appInfo';
|
||||
|
||||
|
@ -13,7 +13,7 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening)
|
||||
effect: async (action, { getState, dispatch }) => {
|
||||
const state = getState();
|
||||
const { shouldShowProgressInViewer } = state.ui;
|
||||
const model = state.generation.model;
|
||||
const model = state.canvasV2.params.model;
|
||||
const { prepend } = action.payload;
|
||||
|
||||
let graph;
|
||||
|
@ -29,7 +29,7 @@ export const addEnqueueRequestedNodes = (startAppListening: AppStartListening) =
|
||||
batch: {
|
||||
graph,
|
||||
workflow: builtWorkflow,
|
||||
runs: state.generation.iterations,
|
||||
runs: state.canvasV2.params.iterations,
|
||||
},
|
||||
prepend: action.payload.prepend,
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { loraRemoved } from 'features/lora/store/loraSlice';
|
||||
import { modelSelected } from 'features/parameters/store/actions';
|
||||
import { modelChanged, vaeSelected } from 'features/parameters/store/generationSlice';
|
||||
import { modelChanged, vaeSelected } from 'features/canvas/store/canvasSlice';
|
||||
import { zParameterModel } from 'features/parameters/types/parameterSchemas';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { t } from 'i18next';
|
||||
@ -29,7 +29,7 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) =
|
||||
const newModel = result.data;
|
||||
|
||||
const newBaseModel = newModel.base;
|
||||
const didBaseModelChange = state.generation.model?.base !== newBaseModel;
|
||||
const didBaseModelChange = state.canvasV2.params.model?.base !== newBaseModel;
|
||||
|
||||
if (didBaseModelChange) {
|
||||
// we may need to reset some incompatible submodels
|
||||
@ -44,7 +44,7 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) =
|
||||
});
|
||||
|
||||
// handle incompatible vae
|
||||
const { vae } = state.generation;
|
||||
const { vae } = state.canvasV2.params;
|
||||
if (vae && vae.base !== newBaseModel) {
|
||||
dispatch(vaeSelected(null));
|
||||
modelsCleared += 1;
|
||||
@ -70,7 +70,7 @@ export const addModelSelectedListener = (startAppListening: AppStartListening) =
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(modelChanged(newModel, state.generation.model));
|
||||
dispatch(modelChanged(newModel, state.canvasV2.params.model));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -3,17 +3,18 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'
|
||||
import type { AppDispatch, RootState } from 'app/store/store';
|
||||
import type { JSONObject } from 'common/types';
|
||||
import {
|
||||
controlAdapterModelCleared,
|
||||
selectControlAdapterAll,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { heightChanged, widthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
caModelChanged,
|
||||
heightChanged,
|
||||
modelChanged,
|
||||
refinerModelChanged,
|
||||
vaeSelected,
|
||||
widthChanged,
|
||||
} from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { loraRemoved } from 'features/lora/store/loraSlice';
|
||||
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||
import { modelChanged, vaeSelected } from 'features/parameters/store/generationSlice';
|
||||
import { postProcessingModelChanged, upscaleModelChanged } from 'features/parameters/store/upscaleSlice';
|
||||
import { zParameterModel, zParameterVAEModel } from 'features/parameters/types/parameterSchemas';
|
||||
import { getIsSizeOptimal, getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||
import { refinerModelChanged } from 'features/sdxl/store/sdxlSlice';
|
||||
import { forEach } from 'lodash-es';
|
||||
import type { Logger } from 'roarr';
|
||||
import { modelConfigsAdapterSelectors, modelsApi } from 'services/api/endpoints/models';
|
||||
@ -55,11 +56,11 @@ type ModelHandler = (
|
||||
) => undefined;
|
||||
|
||||
const handleMainModels: ModelHandler = (models, state, dispatch, log) => {
|
||||
const currentModel = state.generation.model;
|
||||
const currentModel = state.canvasV2.params.model;
|
||||
const mainModels = models.filter(isNonRefinerMainModelConfig);
|
||||
if (mainModels.length === 0) {
|
||||
// No models loaded at all
|
||||
dispatch(modelChanged(null));
|
||||
dispatch(modelChanged({ model: null }));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -74,16 +75,10 @@ const handleMainModels: ModelHandler = (models, state, dispatch, log) => {
|
||||
if (defaultModelInList) {
|
||||
const result = zParameterModel.safeParse(defaultModelInList);
|
||||
if (result.success) {
|
||||
dispatch(modelChanged(defaultModelInList, currentModel));
|
||||
dispatch(modelChanged({ model: defaultModelInList, previousModel: currentModel ?? undefined }));
|
||||
|
||||
const optimalDimension = getOptimalDimension(defaultModelInList);
|
||||
if (
|
||||
getIsSizeOptimal(
|
||||
state.canvasV2.document.width,
|
||||
state.canvasV2.document.height,
|
||||
optimalDimension
|
||||
)
|
||||
) {
|
||||
if (getIsSizeOptimal(state.canvasV2.document.width, state.canvasV2.document.height, optimalDimension)) {
|
||||
return;
|
||||
}
|
||||
const { width, height } = calculateNewSize(
|
||||
@ -104,11 +99,11 @@ const handleMainModels: ModelHandler = (models, state, dispatch, log) => {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(modelChanged(result.data, currentModel));
|
||||
dispatch(modelChanged({ model: result.data, previousModel: currentModel ?? undefined }));
|
||||
};
|
||||
|
||||
const handleRefinerModels: ModelHandler = (models, state, dispatch, _log) => {
|
||||
const currentRefinerModel = state.sdxl.refinerModel;
|
||||
const currentRefinerModel = state.canvasV2.params.refinerModel;
|
||||
const refinerModels = models.filter(isRefinerMainModelModelConfig);
|
||||
if (models.length === 0) {
|
||||
// No models loaded at all
|
||||
@ -127,7 +122,7 @@ const handleRefinerModels: ModelHandler = (models, state, dispatch, _log) => {
|
||||
};
|
||||
|
||||
const handleVAEModels: ModelHandler = (models, state, dispatch, log) => {
|
||||
const currentVae = state.generation.vae;
|
||||
const currentVae = state.canvasV2.params.vae;
|
||||
|
||||
if (currentVae === null) {
|
||||
// null is a valid VAE! it means "use the default with the main model"
|
||||
@ -174,14 +169,14 @@ const handleLoRAModels: ModelHandler = (models, state, dispatch, _log) => {
|
||||
};
|
||||
|
||||
const handleControlAdapterModels: ModelHandler = (models, state, dispatch, _log) => {
|
||||
selectControlAdapterAll(state.controlAdapters).forEach((ca) => {
|
||||
state.canvasV2.controlAdapters.forEach((ca) => {
|
||||
const isModelAvailable = models.some((m) => m.key === ca.model?.key);
|
||||
|
||||
if (isModelAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(controlAdapterModelCleared({ id: ca.id }));
|
||||
dispatch(caModelChanged({ id: ca.id, modelConfig: null }));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
setSteps,
|
||||
vaePrecisionChanged,
|
||||
vaeSelected,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
import {
|
||||
isParameterCFGRescaleMultiplier,
|
||||
isParameterCFGScale,
|
||||
@ -30,7 +30,7 @@ export const addSetDefaultSettingsListener = (startAppListening: AppStartListeni
|
||||
effect: async (action, { dispatch, getState }) => {
|
||||
const state = getState();
|
||||
|
||||
const currentModel = state.generation.model;
|
||||
const currentModel = state.canvasV2.params.model;
|
||||
|
||||
if (!currentModel) {
|
||||
return;
|
||||
|
@ -32,7 +32,7 @@ export const useGroupedModelCombobox = <T extends AnyModelConfig>(
|
||||
arg: UseGroupedModelComboboxArg<T>
|
||||
): UseGroupedModelComboboxReturn => {
|
||||
const { t } = useTranslation();
|
||||
const base_model = useAppSelector((s) => s.generation.model?.base ?? 'sdxl');
|
||||
const base_model = useAppSelector((s) => s.canvasV2.params.model?.base ?? 'sdxl');
|
||||
const { modelConfigs, selectedModel, getIsDisabled, onChange, isLoading, groupByType = false } = arg;
|
||||
const options = useMemo<GroupBase<ComboboxOption>[]>(() => {
|
||||
if (!modelConfigs) {
|
||||
|
@ -9,7 +9,6 @@ import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import type { Templates } from 'features/nodes/store/types';
|
||||
import { selectWorkflowSettingsSlice } from 'features/nodes/store/workflowSettingsSlice';
|
||||
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';
|
||||
@ -30,7 +29,6 @@ const LAYER_TYPE_TO_TKEY: Record<CanvasEntity['type'], string> = {
|
||||
const createSelector = (templates: Templates) =>
|
||||
createMemoizedSelector(
|
||||
[
|
||||
selectGenerationSlice,
|
||||
selectSystemSlice,
|
||||
selectNodesSlice,
|
||||
selectWorkflowSettingsSlice,
|
||||
@ -40,9 +38,9 @@ const createSelector = (templates: Templates) =>
|
||||
selectConfigSlice,
|
||||
activeTabNameSelector,
|
||||
],
|
||||
(generation, system, nodes, workflowSettings, dynamicPrompts, canvasV2, upscale, config, activeTabName) => {
|
||||
const { model, positivePrompt } = generation;
|
||||
(system, nodes, workflowSettings, dynamicPrompts, canvasV2, upscale, config, activeTabName) => {
|
||||
const { bbox } = canvasV2;
|
||||
const { model, positivePrompt } = canvasV2.params;
|
||||
|
||||
const { isConnected } = system;
|
||||
|
||||
|
@ -17,8 +17,8 @@ import {
|
||||
setShouldSnapToGrid,
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
import { CANVAS_GRID_SIZE_COARSE, CANVAS_GRID_SIZE_FINE } from 'features/canvas/store/constants';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import type Konva from 'konva';
|
||||
import type { GroupConfig } from 'konva/lib/Group';
|
||||
import type { KonvaEventObject } from 'konva/lib/Node';
|
||||
|
@ -3,6 +3,7 @@ import { createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { roundDownToMultiple, roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||
import { modelChanged } from 'features/canvas/store/canvasSlice';
|
||||
import calculateCoordinates from 'features/canvas/util/calculateCoordinates';
|
||||
import calculateScale from 'features/canvas/util/calculateScale';
|
||||
import { STAGE_PADDING_PERCENTAGE } from 'features/canvas/util/constants';
|
||||
@ -11,7 +12,6 @@ import getScaledBoundingBoxDimensions from 'features/canvas/util/getScaledBoundi
|
||||
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||
import { initialAspectRatioState } from 'features/parameters/components/ImageSize/constants';
|
||||
import type { AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
||||
import { modelChanged } from 'features/parameters/store/generationSlice';
|
||||
import type { PayloadActionWithOptimalDimension } from 'features/parameters/store/types';
|
||||
import { getIsSizeOptimal, getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||
import type { IRect, Vector2d } from 'konva/lib/types';
|
||||
|
@ -4,10 +4,10 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||
import { heightChanged, widthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import type { ControlAdapterData } from 'features/controlLayers/store/types';
|
||||
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiArrowCounterClockwiseBold, PiFloppyDiskBold, PiRulerBold } from 'react-icons/pi';
|
||||
|
@ -13,7 +13,7 @@ type Props = {
|
||||
|
||||
export const CAModelCombobox = memo(({ modelKey, onChange: onChangeModel }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const currentBaseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const currentBaseModel = useAppSelector((s) => s.canvasV2.params.model?.base);
|
||||
const [modelConfigs, { isLoading }] = useControlNetAndT2IAdapterModels();
|
||||
const selectedModel = useMemo(() => modelConfigs.find((m) => m.key === modelKey), [modelConfigs, modelKey]);
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { heightChanged, widthChanged } from 'features/controlLayers/store/canvas
|
||||
import type { ImageWithDims } from 'features/controlLayers/store/types';
|
||||
import type { ImageDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { memo, useCallback, useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiArrowCounterClockwiseBold, PiRulerBold } from 'react-icons/pi';
|
||||
|
@ -24,7 +24,7 @@ type Props = {
|
||||
|
||||
export const IPAModelCombobox = memo(({ modelKey, onChangeModel, clipVisionModel, onChangeCLIPVisionModel }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const currentBaseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const currentBaseModel = useAppSelector((s) => s.canvasV2.params.model?.base);
|
||||
const [modelConfigs, { isLoading }] = useIPAdapterModels();
|
||||
const selectedModel = useMemo(() => modelConfigs.find((m) => m.key === modelKey), [modelConfigs, modelKey]);
|
||||
|
||||
|
@ -15,7 +15,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export const useAddCALayer = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const baseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const baseModel = useAppSelector((s) => s.canvasV2.params.model?.base);
|
||||
const [modelConfigs] = useControlNetAndT2IAdapterModels();
|
||||
const model: ControlNetModelConfig | T2IAdapterModelConfig | null = useMemo(() => {
|
||||
// prefer to use a model that matches the base model
|
||||
@ -48,7 +48,7 @@ export const useAddCALayer = () => {
|
||||
|
||||
export const useAddIPALayer = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const baseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const baseModel = useAppSelector((s) => s.canvasV2.params.model?.base);
|
||||
const [modelConfigs] = useIPAdapterModels();
|
||||
const model: IPAdapterModelConfig | null = useMemo(() => {
|
||||
// prefer to use a model that matches the base model
|
||||
@ -72,7 +72,7 @@ export const useAddIPALayer = () => {
|
||||
|
||||
export const useAddIPAdapterToRGLayer = (id: string) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const baseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const baseModel = useAppSelector((s) => s.canvasV2.params.model?.base);
|
||||
const [modelConfigs] = useIPAdapterModels();
|
||||
const model: IPAdapterModelConfig | null = useMemo(() => {
|
||||
// prefer to use a model that matches the base model
|
||||
|
@ -1,8 +1,13 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
|
||||
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||
|
||||
export const selectEntityCount = createSelector(selectCanvasSlice, (canvasV2) => {
|
||||
return (
|
||||
canvasV2.regions.length + canvasV2.controlAdapters.length + canvasV2.ipAdapters.length + canvasV2.layers.length
|
||||
);
|
||||
});
|
||||
|
||||
export const selectOptimalDimension = createSelector(selectCanvasSlice, (canvasV2) => {
|
||||
return getOptimalDimension(canvasV2.params.model);
|
||||
});
|
||||
|
@ -7,6 +7,7 @@ import { useDownloadImage } from 'common/hooks/useDownloadImage';
|
||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||
import { imagesToChangeSelected, isModalOpenChanged } from 'features/changeBoardModal/store/slice';
|
||||
import { iiLayerAdded } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice';
|
||||
import { useImageActions } from 'features/gallery/hooks/useImageActions';
|
||||
import { sentImageToCanvas, sentImageToImg2Img } from 'features/gallery/store/actions';
|
||||
|
@ -17,7 +17,7 @@ const LoRASelect = () => {
|
||||
const [modelConfigs, { isLoading }] = useLoRAModels();
|
||||
const { t } = useTranslation();
|
||||
const addedLoRAs = useAppSelector(selectAddedLoRAs);
|
||||
const currentBaseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const currentBaseModel = useAppSelector((s) => s.canvasV2.params.model?.base);
|
||||
|
||||
const getIsDisabled = (lora: LoRAModelConfig): boolean => {
|
||||
const isCompatible = currentBaseModel === lora.base;
|
||||
|
@ -40,7 +40,7 @@ import {
|
||||
setSeed,
|
||||
setSteps,
|
||||
vaeSelected,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
} from 'features/canvas/store/canvasSlice';
|
||||
import type {
|
||||
ParameterCFGRescaleMultiplier,
|
||||
ParameterCFGScale,
|
||||
|
@ -9,7 +9,7 @@ import { getHasMetadata, removeMetadata } from './canvas/metadata';
|
||||
import { CANVAS_COHERENCE_NOISE, METADATA, NOISE, POSITIVE_CONDITIONING } from './constants';
|
||||
|
||||
export const prepareLinearUIBatch = (state: RootState, graph: NonNullableGraph, prepend: boolean): BatchConfig => {
|
||||
const { iterations, model, shouldRandomizeSeed, seed } = state.generation;
|
||||
const { iterations, model, shouldRandomizeSeed, seed } = state.canvasV2.params;
|
||||
const { shouldConcatPrompts } = state.canvasV2;
|
||||
const { prompts, seedBehaviour } = state.dynamicPrompts;
|
||||
|
||||
|
@ -17,7 +17,7 @@ export const addControlNetToLinearGraph = async (
|
||||
const controlNets = selectValidControlNets(state.controlAdapters).filter(
|
||||
({ model, processedControlImage, processorType, controlImage, isEnabled }) => {
|
||||
const hasModel = Boolean(model);
|
||||
const doesBaseMatch = model?.base === state.generation.model?.base;
|
||||
const doesBaseMatch = model?.base === state.canvasV2.params.model?.base;
|
||||
const hasControlImage = (processedControlImage && processorType !== 'none') || controlImage;
|
||||
|
||||
return isEnabled && hasModel && doesBaseMatch && hasControlImage;
|
||||
|
@ -19,7 +19,7 @@ export const addIPAdapterToLinearGraph = async (
|
||||
|
||||
const ipAdapters = selectValidIPAdapters(state.controlAdapters).filter(({ model, controlImage, isEnabled }) => {
|
||||
const hasModel = Boolean(model);
|
||||
const doesBaseMatch = model?.base === state.generation.model?.base;
|
||||
const doesBaseMatch = model?.base === state.canvasV2.params.model?.base;
|
||||
const hasControlImage = controlImage;
|
||||
return isEnabled && hasModel && doesBaseMatch && hasControlImage;
|
||||
});
|
||||
|
@ -34,13 +34,13 @@ export const addSDXLRefinerToGraph = async (
|
||||
refinerScheduler,
|
||||
refinerCFGScale,
|
||||
refinerStart,
|
||||
} = state.sdxl;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
if (!refinerModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { seamlessXAxis, seamlessYAxis } = state.generation;
|
||||
const { seamlessXAxis, seamlessYAxis } = state.canvasV2.params;
|
||||
const { boundingBoxScaleMethod } = state.canvas;
|
||||
|
||||
const isUsingScaledDimensions = ['auto', 'manual'].includes(boundingBoxScaleMethod);
|
||||
|
@ -19,7 +19,7 @@ export const addSeamlessToLinearGraph = (
|
||||
modelLoaderNodeId: string
|
||||
): void => {
|
||||
// Remove Existing UNet Connections
|
||||
const { seamlessXAxis, seamlessYAxis, vae } = state.generation;
|
||||
const { seamlessXAxis, seamlessYAxis, vae } = state.canvasV2.params;
|
||||
const isAutoVae = !vae;
|
||||
|
||||
graph.nodes[SEAMLESS] = {
|
||||
|
@ -20,7 +20,7 @@ export const addT2IAdaptersToLinearGraph = async (
|
||||
const t2iAdapters = selectValidT2IAdapters(state.controlAdapters).filter(
|
||||
({ model, processedControlImage, processorType, controlImage, isEnabled }) => {
|
||||
const hasModel = Boolean(model);
|
||||
const doesBaseMatch = model?.base === state.generation.model?.base;
|
||||
const doesBaseMatch = model?.base === state.canvasV2.params.model?.base;
|
||||
const hasControlImage = (processedControlImage && processorType !== 'none') || controlImage;
|
||||
|
||||
return isEnabled && hasModel && doesBaseMatch && hasControlImage;
|
||||
|
@ -28,9 +28,9 @@ export const addVAEToGraph = async (
|
||||
graph: NonNullableGraph,
|
||||
modelLoaderNodeId: string = MAIN_MODEL_LOADER
|
||||
): Promise<void> => {
|
||||
const { vae, seamlessXAxis, seamlessYAxis } = state.generation;
|
||||
const { vae, seamlessXAxis, seamlessYAxis } = state.canvasV2.params;
|
||||
const { boundingBoxScaleMethod } = state.canvas;
|
||||
const { refinerModel } = state.sdxl;
|
||||
const { refinerModel } = state.canvasV2.params;
|
||||
|
||||
const isUsingScaledDimensions = ['auto', 'manual'].includes(boundingBoxScaleMethod);
|
||||
|
||||
|
@ -19,7 +19,7 @@ export const buildCanvasGraph = async (
|
||||
let graph: NonNullableGraph;
|
||||
|
||||
if (generationMode === 'txt2img') {
|
||||
if (state.generation.model && state.generation.model.base === 'sdxl') {
|
||||
if (state.canvasV2.params.model && state.canvasV2.params.model.base === 'sdxl') {
|
||||
graph = await buildCanvasSDXLTextToImageGraph(state);
|
||||
} else {
|
||||
graph = await buildCanvasTextToImageGraph(state);
|
||||
@ -28,7 +28,7 @@ export const buildCanvasGraph = async (
|
||||
if (!canvasInitImage) {
|
||||
throw new Error('Missing canvas init image');
|
||||
}
|
||||
if (state.generation.model && state.generation.model.base === 'sdxl') {
|
||||
if (state.canvasV2.params.model && state.canvasV2.params.model.base === 'sdxl') {
|
||||
graph = await buildCanvasSDXLImageToImageGraph(state, canvasInitImage);
|
||||
} else {
|
||||
graph = await buildCanvasImageToImageGraph(state, canvasInitImage);
|
||||
@ -37,7 +37,7 @@ export const buildCanvasGraph = async (
|
||||
if (!canvasInitImage || !canvasMaskImage) {
|
||||
throw new Error('Missing canvas init and mask images');
|
||||
}
|
||||
if (state.generation.model && state.generation.model.base === 'sdxl') {
|
||||
if (state.canvasV2.params.model && state.canvasV2.params.model.base === 'sdxl') {
|
||||
graph = await buildCanvasSDXLInpaintGraph(state, canvasInitImage, canvasMaskImage);
|
||||
} else {
|
||||
graph = await buildCanvasInpaintGraph(state, canvasInitImage, canvasMaskImage);
|
||||
@ -46,7 +46,7 @@ export const buildCanvasGraph = async (
|
||||
if (!canvasInitImage) {
|
||||
throw new Error('Missing canvas init image');
|
||||
}
|
||||
if (state.generation.model && state.generation.model.base === 'sdxl') {
|
||||
if (state.canvasV2.params.model && state.canvasV2.params.model.base === 'sdxl') {
|
||||
graph = await buildCanvasSDXLOutpaintGraph(state, canvasInitImage, canvasMaskImage);
|
||||
} else {
|
||||
graph = await buildCanvasOutpaintGraph(state, canvasInitImage, canvasMaskImage);
|
||||
|
@ -54,7 +54,7 @@ export const buildCanvasImageToImageGraph = async (
|
||||
shouldUseCpuNoise,
|
||||
seamlessXAxis,
|
||||
seamlessYAxis,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
// The bounding box determines width and height, not the width and height params
|
||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||
|
@ -61,7 +61,7 @@ export const buildCanvasInpaintGraph = async (
|
||||
canvasCoherenceMinDenoise,
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
if (!model) {
|
||||
log.error('No model found in state');
|
||||
|
@ -73,7 +73,7 @@ export const buildCanvasOutpaintGraph = async (
|
||||
canvasCoherenceMinDenoise,
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
if (!model) {
|
||||
log.error('No model found in state');
|
||||
|
@ -54,9 +54,9 @@ export const buildCanvasSDXLImageToImageGraph = async (
|
||||
seamlessXAxis,
|
||||
seamlessYAxis,
|
||||
img2imgStrength: strength,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
const { refinerModel, refinerStart } = state.canvasV2.params;
|
||||
|
||||
// The bounding box determines width and height, not the width and height params
|
||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||
|
@ -61,9 +61,9 @@ export const buildCanvasSDXLInpaintGraph = async (
|
||||
canvasCoherenceMinDenoise,
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
const { refinerModel, refinerStart } = state.canvasV2.params;
|
||||
|
||||
if (!model) {
|
||||
log.error('No model found in state');
|
||||
|
@ -73,9 +73,9 @@ export const buildCanvasSDXLOutpaintGraph = async (
|
||||
canvasCoherenceMinDenoise,
|
||||
canvasCoherenceEdgeSize,
|
||||
maskBlur,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
const { refinerModel, refinerStart } = state.canvasV2.params;
|
||||
|
||||
if (!model) {
|
||||
log.error('No model found in state');
|
||||
|
@ -47,7 +47,7 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
|
||||
shouldUseCpuNoise,
|
||||
seamlessXAxis,
|
||||
seamlessYAxis,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
// The bounding box determines width and height, not the width and height params
|
||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||
@ -58,7 +58,7 @@ export const buildCanvasSDXLTextToImageGraph = async (state: RootState): Promise
|
||||
const is_intermediate = true;
|
||||
const isUsingScaledDimensions = ['auto', 'manual'].includes(boundingBoxScaleMethod);
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
const { refinerModel, refinerStart } = state.canvasV2.params;
|
||||
|
||||
if (!model) {
|
||||
log.error('No model found in state');
|
||||
|
@ -47,7 +47,7 @@ export const buildCanvasTextToImageGraph = async (state: RootState): Promise<Non
|
||||
shouldUseCpuNoise,
|
||||
seamlessXAxis,
|
||||
seamlessYAxis,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
// The bounding box determines width and height, not the width and height params
|
||||
const { width, height } = state.canvas.boundingBoxDimensions;
|
||||
|
@ -419,8 +419,8 @@ const addInitialImageLayerToGraph = (
|
||||
| Invocation<'sdxl_model_loader'>,
|
||||
layer: InitialImageLayer
|
||||
) => {
|
||||
const { vaePrecision } = state.generation;
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
const { vaePrecision } = state.canvasV2.params;
|
||||
const { refinerModel, refinerStart } = state.canvasV2.params;
|
||||
const { width, height } = state.canvasV2.document;
|
||||
assert(layer.isEnabled, 'Initial image layer is not enabled');
|
||||
assert(layer.image, 'Initial image layer has no image');
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
} from 'features/nodes/util/graph/constants';
|
||||
import type { Graph } from 'features/nodes/util/graph/generation/Graph';
|
||||
import { getBoardField } from 'features/nodes/util/graph/graphBuilderUtils';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import type { Invocation } from 'services/api/types';
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,7 @@ export const addSDXLRefiner = async (
|
||||
refinerScheduler,
|
||||
refinerCFGScale,
|
||||
refinerStart,
|
||||
} = state.sdxl;
|
||||
} = state.canvasV2.params;
|
||||
|
||||
assert(refinerModel, 'No refiner model found in state');
|
||||
|
||||
|
@ -21,7 +21,7 @@ export const addSeamless = (
|
||||
modelLoader: Invocation<'main_model_loader'> | Invocation<'sdxl_model_loader'>,
|
||||
vaeLoader: Invocation<'vae_loader'> | null
|
||||
): Invocation<'seamless'> | null => {
|
||||
const { seamlessXAxis: seamless_x, seamlessYAxis: seamless_y } = state.generation;
|
||||
const { seamlessXAxis: seamless_x, seamlessYAxis: seamless_y } = state.canvasV2.params;
|
||||
|
||||
if (!seamless_x && !seamless_y) {
|
||||
return null;
|
||||
|
@ -39,7 +39,7 @@ export const buildGenerationTabGraph = async (state: RootState): Promise<GraphTy
|
||||
vaePrecision,
|
||||
seed,
|
||||
vae,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
const { width, height } = state.canvasV2.document;
|
||||
|
||||
assert(model, 'No model found in state');
|
||||
|
@ -35,10 +35,10 @@ export const buildGenerationTabSDXLGraph = async (state: RootState): Promise<Non
|
||||
shouldUseCpuNoise,
|
||||
vaePrecision,
|
||||
vae,
|
||||
} = state.generation;
|
||||
} = state.canvasV2.params;
|
||||
const { width, height } = state.canvasV2.document;
|
||||
|
||||
const { refinerModel, refinerStart } = state.sdxl;
|
||||
const { refinerModel, refinerStart } = state.canvasV2.params;
|
||||
|
||||
assert(model, 'No model found in state');
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCfgRescaleMultiplier } from 'features/parameters/store/generationSlice';
|
||||
import { setCfgRescaleMultiplier } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCFGRescaleMultiplier = () => {
|
||||
const cfgRescaleMultiplier = useAppSelector((s) => s.generation.cfgRescaleMultiplier);
|
||||
const cfgRescaleMultiplier = useAppSelector((s) => s.canvasV2.params.cfgRescaleMultiplier);
|
||||
const initial = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMax);
|
||||
|
@ -1,19 +1,19 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setClipSkip } from 'features/parameters/store/generationSlice';
|
||||
import { setClipSkip } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { CLIP_SKIP_MAP } from 'features/parameters/types/constants';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamClipSkip = () => {
|
||||
const clipSkip = useAppSelector((s) => s.generation.clipSkip);
|
||||
const clipSkip = useAppSelector((s) => s.canvasV2.params.clipSkip);
|
||||
const initial = useAppSelector((s) => s.config.sd.clipSkip.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.clipSkip.sliderMin);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.clipSkip.numberInputMin);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.clipSkip.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.clipSkip.fineStep);
|
||||
const { model } = useAppSelector((s) => s.generation);
|
||||
const model = useAppSelector((s) => s.canvasV2.params.model);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCanvasCoherenceEdgeSize } from 'features/parameters/store/generationSlice';
|
||||
import { setCanvasCoherenceEdgeSize } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCanvasCoherenceEdgeSize = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const canvasCoherenceEdgeSize = useAppSelector((s) => s.generation.canvasCoherenceEdgeSize);
|
||||
const canvasCoherenceEdgeSize = useAppSelector((s) => s.canvasV2.compositing.canvasCoherenceEdgeSize);
|
||||
const initial = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.sliderMax);
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCanvasCoherenceMinDenoise } from 'features/parameters/store/generationSlice';
|
||||
import { setCanvasCoherenceMinDenoise } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCanvasCoherenceMinDenoise = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const canvasCoherenceMinDenoise = useAppSelector((s) => s.generation.canvasCoherenceMinDenoise);
|
||||
const canvasCoherenceMinDenoise = useAppSelector((s) => s.canvasV2.compositing.canvasCoherenceMinDenoise);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChange = useCallback(
|
||||
|
@ -2,14 +2,14 @@ import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCanvasCoherenceMode } from 'features/parameters/store/generationSlice';
|
||||
import { setCanvasCoherenceMode } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { isParameterCanvasCoherenceMode } from 'features/parameters/types/parameterSchemas';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCanvasCoherenceMode = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const canvasCoherenceMode = useAppSelector((s) => s.generation.canvasCoherenceMode);
|
||||
const canvasCoherenceMode = useAppSelector((s) => s.canvasV2.compositing.canvasCoherenceMode);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const options = useMemo<ComboboxOption[]>(
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setMaskBlur } from 'features/parameters/store/generationSlice';
|
||||
import { setMaskBlur } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamMaskBlur = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const maskBlur = useAppSelector((s) => s.generation.maskBlur);
|
||||
const maskBlur = useAppSelector((s) => s.canvasV2.compositing.maskBlur);
|
||||
const initial = useAppSelector((s) => s.config.sd.maskBlur.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.maskBlur.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.maskBlur.sliderMax);
|
||||
|
@ -1,20 +1,16 @@
|
||||
import { Box, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIColorPicker from 'common/components/IAIColorPicker';
|
||||
import { selectGenerationSlice, setInfillColorValue } from 'features/parameters/store/generationSlice';
|
||||
import { setInfillColorValue } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import type { RgbaColor } from 'react-colorful';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selectInfillColor = createMemoizedSelector(selectGenerationSlice, (generation) => generation.infillColorValue);
|
||||
|
||||
const ParamInfillColorOptions = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const infillColor = useAppSelector(selectInfillColor);
|
||||
|
||||
const infillMethod = useAppSelector((s) => s.generation.infillMethod);
|
||||
const infillColor = useAppSelector((s) => s.canvasV2.compositing.infillColorValue);
|
||||
const infillMethod = useAppSelector((s) => s.canvasV2.compositing.infillMethod);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -2,7 +2,7 @@ import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setInfillMethod } from 'features/parameters/store/generationSlice';
|
||||
import { setInfillMethod } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useGetAppConfigQuery } from 'services/api/endpoints/appInfo';
|
||||
@ -10,7 +10,7 @@ import { useGetAppConfigQuery } from 'services/api/endpoints/appInfo';
|
||||
const ParamInfillMethod = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const infillMethod = useAppSelector((s) => s.generation.infillMethod);
|
||||
const infillMethod = useAppSelector((s) => s.canvasV2.compositing.infillMethod);
|
||||
const { data: appConfigData } = useGetAppConfigQuery();
|
||||
const options = useMemo<ComboboxOption[]>(
|
||||
() =>
|
||||
|
@ -1,115 +0,0 @@
|
||||
import { Box, CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIColorPicker from 'common/components/IAIColorPicker';
|
||||
import {
|
||||
setInfillMosaicMaxColor,
|
||||
setInfillMosaicMinColor,
|
||||
setInfillMosaicTileHeight,
|
||||
setInfillMosaicTileWidth,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import type { RgbaColor } from 'react-colorful';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamInfillMosaicTileSize = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const infillMosaicTileWidth = useAppSelector((s) => s.generation.infillMosaicTileWidth);
|
||||
const infillMosaicTileHeight = useAppSelector((s) => s.generation.infillMosaicTileHeight);
|
||||
const infillMosaicMinColor = useAppSelector((s) => s.generation.infillMosaicMinColor);
|
||||
const infillMosaicMaxColor = useAppSelector((s) => s.generation.infillMosaicMaxColor);
|
||||
const infillMethod = useAppSelector((s) => s.generation.infillMethod);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleInfillMosaicTileWidthChange = useCallback(
|
||||
(v: number) => {
|
||||
dispatch(setInfillMosaicTileWidth(v));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleInfillMosaicTileHeightChange = useCallback(
|
||||
(v: number) => {
|
||||
dispatch(setInfillMosaicTileHeight(v));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleInfillMosaicMinColor = useCallback(
|
||||
(v: RgbaColor) => {
|
||||
dispatch(setInfillMosaicMinColor(v));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleInfillMosaicMaxColor = useCallback(
|
||||
(v: RgbaColor) => {
|
||||
dispatch(setInfillMosaicMaxColor(v));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<FormControl isDisabled={infillMethod !== 'mosaic'}>
|
||||
<FormLabel>{t('parameters.infillMosaicTileWidth')}</FormLabel>
|
||||
<CompositeSlider
|
||||
min={8}
|
||||
max={256}
|
||||
value={infillMosaicTileWidth}
|
||||
defaultValue={64}
|
||||
onChange={handleInfillMosaicTileWidthChange}
|
||||
step={8}
|
||||
fineStep={8}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
min={8}
|
||||
max={1024}
|
||||
value={infillMosaicTileWidth}
|
||||
defaultValue={64}
|
||||
onChange={handleInfillMosaicTileWidthChange}
|
||||
step={8}
|
||||
fineStep={8}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={infillMethod !== 'mosaic'}>
|
||||
<FormLabel>{t('parameters.infillMosaicTileHeight')}</FormLabel>
|
||||
<CompositeSlider
|
||||
min={8}
|
||||
max={256}
|
||||
value={infillMosaicTileHeight}
|
||||
defaultValue={64}
|
||||
onChange={handleInfillMosaicTileHeightChange}
|
||||
step={8}
|
||||
fineStep={8}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
min={8}
|
||||
max={1024}
|
||||
value={infillMosaicTileHeight}
|
||||
defaultValue={64}
|
||||
onChange={handleInfillMosaicTileHeightChange}
|
||||
step={8}
|
||||
fineStep={8}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={infillMethod !== 'mosaic'}>
|
||||
<FormLabel>{t('parameters.infillMosaicMinColor')}</FormLabel>
|
||||
<Box w="full" pt={2} pb={2}>
|
||||
<IAIColorPicker color={infillMosaicMinColor} onChange={handleInfillMosaicMinColor} />
|
||||
</Box>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={infillMethod !== 'mosaic'}>
|
||||
<FormLabel>{t('parameters.infillMosaicMaxColor')}</FormLabel>
|
||||
<Box w="full" pt={2} pb={2}>
|
||||
<IAIColorPicker color={infillMosaicMaxColor} onChange={handleInfillMosaicMaxColor} />
|
||||
</Box>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamInfillMosaicTileSize);
|
@ -2,12 +2,11 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { memo } from 'react';
|
||||
|
||||
import ParamInfillColorOptions from './ParamInfillColorOptions';
|
||||
import ParamInfillMosaicOptions from './ParamInfillMosaicOptions';
|
||||
import ParamInfillPatchmatchDownscaleSize from './ParamInfillPatchmatchDownscaleSize';
|
||||
import ParamInfillTilesize from './ParamInfillTilesize';
|
||||
|
||||
const ParamInfillOptions = () => {
|
||||
const infillMethod = useAppSelector((s) => s.generation.infillMethod);
|
||||
const infillMethod = useAppSelector((s) => s.canvasV2.compositing.infillMethod);
|
||||
if (infillMethod === 'tile') {
|
||||
return <ParamInfillTilesize />;
|
||||
}
|
||||
@ -16,10 +15,6 @@ const ParamInfillOptions = () => {
|
||||
return <ParamInfillPatchmatchDownscaleSize />;
|
||||
}
|
||||
|
||||
if (infillMethod === 'mosaic') {
|
||||
return <ParamInfillMosaicOptions />;
|
||||
}
|
||||
|
||||
if (infillMethod === 'color') {
|
||||
return <ParamInfillColorOptions />;
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setInfillPatchmatchDownscaleSize } from 'features/parameters/store/generationSlice';
|
||||
import { setInfillPatchmatchDownscaleSize } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamInfillPatchmatchDownscaleSize = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const infillMethod = useAppSelector((s) => s.generation.infillMethod);
|
||||
const infillPatchmatchDownscaleSize = useAppSelector((s) => s.generation.infillPatchmatchDownscaleSize);
|
||||
const infillMethod = useAppSelector((s) => s.canvasV2.compositing.infillMethod);
|
||||
const infillPatchmatchDownscaleSize = useAppSelector((s) => s.canvasV2.compositing.infillPatchmatchDownscaleSize);
|
||||
const initial = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.sliderMax);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setInfillTileSize } from 'features/parameters/store/generationSlice';
|
||||
import { setInfillTileSize } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamInfillTileSize = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const infillTileSize = useAppSelector((s) => s.generation.infillTileSize);
|
||||
const infillTileSize = useAppSelector((s) => s.canvasV2.compositing.infillTileSize);
|
||||
const initial = useAppSelector((s) => s.config.sd.infillTileSize.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.infillTileSize.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.infillTileSize.sliderMax);
|
||||
@ -15,7 +15,7 @@ const ParamInfillTileSize = () => {
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.infillTileSize.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.infillTileSize.fineStep);
|
||||
|
||||
const infillMethod = useAppSelector((s) => s.generation.infillMethod);
|
||||
const infillMethod = useAppSelector((s) => s.canvasV2.compositing.infillMethod);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -4,14 +4,14 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setBoundingBoxScaleMethod } from 'features/canvas/store/canvasSlice';
|
||||
import { isBoundingBoxScaleMethod } from 'features/canvas/store/canvasTypes';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamScaleBeforeProcessing = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const boundingBoxScaleMethod = useAppSelector((s) => s.canvas.boundingBoxScaleMethod);
|
||||
const boundingBoxScaleMethod = useAppSelector((s) => s.canvasV2.scaledBbox.scaleMethod);
|
||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||
|
||||
const OPTIONS: ComboboxOption[] = useMemo(
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@ -9,8 +9,8 @@ const ParamScaledHeight = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||
const isManual = useAppSelector((s) => s.canvas.boundingBoxScaleMethod === 'manual');
|
||||
const height = useAppSelector((s) => s.canvas.scaledBoundingBoxDimensions.height);
|
||||
const isManual = useAppSelector((s) => s.canvasV2.scaledBbox.scaleMethod === 'manual');
|
||||
const height = useAppSelector((s) => s.canvasV2.scaledBbox.height);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxHeight.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.scaledBoundingBoxHeight.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxHeight.numberInputMin);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@ -9,8 +9,8 @@ const ParamScaledWidth = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||
const isManual = useAppSelector((s) => s.canvas.boundingBoxScaleMethod === 'manual');
|
||||
const width = useAppSelector((s) => s.canvas.scaledBoundingBoxDimensions.width);
|
||||
const isManual = useAppSelector((s) => s.canvasV2.scaledBbox.scaleMethod === 'manual');
|
||||
const width = useAppSelector((s) => s.canvasV2.scaledBbox.width);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.scaledBoundingBoxWidth.numberInputMin);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setImg2imgStrength } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import ImageToImageStrength from 'features/parameters/components/ImageToImage/ImageToImageStrength';
|
||||
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
const ParamImageToImageStrength = () => {
|
||||
const img2imgStrength = useAppSelector((s) => s.generation.img2imgStrength);
|
||||
const img2imgStrength = useAppSelector((s) => s.canvasV2.params.img2imgStrength);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onChange = useCallback(
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCfgScale } from 'features/parameters/store/generationSlice';
|
||||
import { setCfgScale } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCFGScale = () => {
|
||||
const cfgScale = useAppSelector((s) => s.generation.cfgScale);
|
||||
const cfgScale = useAppSelector((s) => s.canvasV2.params.cfgScale);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.guidance.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.guidance.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.guidance.numberInputMin);
|
||||
|
@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Box, Textarea } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { negativePromptChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
|
||||
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
|
||||
import { ViewModePrompt } from 'features/parameters/components/Prompts/ViewModePrompt';
|
||||
import { negativePromptChanged } from 'features/parameters/store/generationSlice';
|
||||
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
|
||||
import { PromptPopover } from 'features/prompt/PromptPopover';
|
||||
import { usePrompt } from 'features/prompt/usePrompt';
|
||||
@ -13,7 +13,7 @@ import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
export const ParamNegativePrompt = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const prompt = useAppSelector((s) => s.generation.negativePrompt);
|
||||
const prompt = useAppSelector((s) => s.canvasV2.params.negativePrompt);
|
||||
const viewMode = useAppSelector((s) => s.stylePreset.viewMode);
|
||||
const activeStylePresetId = useAppSelector((s) => s.stylePreset.activeStylePresetId);
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Box, Textarea } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { positivePromptChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { ShowDynamicPromptsPreviewButton } from 'features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton';
|
||||
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
|
||||
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
|
||||
import { ViewModePrompt } from 'features/parameters/components/Prompts/ViewModePrompt';
|
||||
import { positivePromptChanged } from 'features/parameters/store/generationSlice';
|
||||
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
|
||||
import { PromptPopover } from 'features/prompt/PromptPopover';
|
||||
import { usePrompt } from 'features/prompt/usePrompt';
|
||||
@ -17,8 +17,8 @@ import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
export const ParamPositivePrompt = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const prompt = useAppSelector((s) => s.generation.positivePrompt);
|
||||
const baseModel = useAppSelector((s) => s.generation.model)?.base;
|
||||
const prompt = useAppSelector((s) => s.canvasV2.params.positivePrompt);
|
||||
const baseModel = useAppSelector((s) => s.canvasV2.params.model)?.base;
|
||||
const viewMode = useAppSelector((s) => s.stylePreset.viewMode);
|
||||
const activeStylePresetId = useAppSelector((s) => s.stylePreset.activeStylePresetId);
|
||||
|
||||
|
@ -2,7 +2,7 @@ import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setScheduler } from 'features/parameters/store/generationSlice';
|
||||
import { setScheduler } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants';
|
||||
import { isParameterScheduler } from 'features/parameters/types/parameterSchemas';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
|
||||
const ParamScheduler = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const scheduler = useAppSelector((s) => s.generation.scheduler);
|
||||
const scheduler = useAppSelector((s) => s.canvasV2.params.scheduler);
|
||||
|
||||
const onChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setSteps } from 'features/parameters/store/generationSlice';
|
||||
import { setSteps } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamSteps = () => {
|
||||
const steps = useAppSelector((s) => s.generation.steps);
|
||||
const steps = useAppSelector((s) => s.canvasV2.params.steps);
|
||||
const initial = useAppSelector((s) => s.config.sd.steps.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
|
||||
|
@ -2,7 +2,7 @@ import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||
import { ASPECT_RATIO_MAP, initialAspectRatioState } from 'features/parameters/components/ImageSize/constants';
|
||||
import type { AspectRatioID, AspectRatioState } from 'features/parameters/components/ImageSize/types';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { createContext, useCallback, useContext, useMemo } from 'react';
|
||||
|
||||
export type ImageSizeContextInnerValue = {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { getIsSizeTooLarge, getIsSizeTooSmall } from 'features/parameters/util/optimalDimension';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -1,22 +1,18 @@
|
||||
import { Box, Combobox, FormControl, FormLabel, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox';
|
||||
import { zModelIdentifierField } from 'features/nodes/types/common';
|
||||
import { modelSelected } from 'features/parameters/store/actions';
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSDMainModels } from 'services/api/hooks/modelsByType';
|
||||
import type { MainModelConfig } from 'services/api/types';
|
||||
|
||||
const selectModel = createMemoizedSelector(selectGenerationSlice, (generation) => generation.model);
|
||||
|
||||
const ParamMainModelSelect = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const selectedModel = useAppSelector(selectModel);
|
||||
const selectedModel = useAppSelector((s) => s.canvasV2.params.model);
|
||||
const [modelConfigs, { isLoading }] = useSDMainModels();
|
||||
const tooltipLabel = useMemo(() => {
|
||||
if (!modelConfigs.length || !selectedModel) {
|
||||
|
@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { RiSparklingFill } from 'react-icons/ri';
|
||||
|
||||
export const UseDefaultSettingsButton = () => {
|
||||
const model = useAppSelector((s) => s.generation.model);
|
||||
const model = useAppSelector((s) => s.canvasV2.params.model);
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setSeamlessXAxis } from 'features/parameters/store/generationSlice';
|
||||
import { setSeamlessXAxis } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamSeamlessXAxis = () => {
|
||||
const { t } = useTranslation();
|
||||
const seamlessXAxis = useAppSelector((s) => s.generation.seamlessXAxis);
|
||||
const seamlessXAxis = useAppSelector((s) => s.canvasV2.params.seamlessXAxis);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setSeamlessYAxis } from 'features/parameters/store/generationSlice';
|
||||
import { setSeamlessYAxis } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamSeamlessYAxis = () => {
|
||||
const { t } = useTranslation();
|
||||
const seamlessYAxis = useAppSelector((s) => s.generation.seamlessYAxis);
|
||||
const seamlessYAxis = useAppSelector((s) => s.canvasV2.params.seamlessYAxis);
|
||||
const dispatch = useAppDispatch();
|
||||
const handleChange = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
|
@ -2,13 +2,13 @@ import { CompositeNumberInput, FormControl, FormLabel } from '@invoke-ai/ui-libr
|
||||
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setSeed } from 'features/parameters/store/generationSlice';
|
||||
import { setSeed } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const ParamSeedNumberInput = memo(() => {
|
||||
const seed = useAppSelector((s) => s.generation.seed);
|
||||
const shouldRandomizeSeed = useAppSelector((s) => s.generation.shouldRandomizeSeed);
|
||||
const seed = useAppSelector((s) => s.canvasV2.params.seed);
|
||||
const shouldRandomizeSeed = useAppSelector((s) => s.canvasV2.params.shouldRandomizeSeed);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setShouldRandomizeSeed } from 'features/parameters/store/generationSlice';
|
||||
import { setShouldRandomizeSeed } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -9,7 +9,7 @@ export const ParamSeedRandomize = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const shouldRandomizeSeed = useAppSelector((s) => s.generation.shouldRandomizeSeed);
|
||||
const shouldRandomizeSeed = useAppSelector((s) => s.canvasV2.params.shouldRandomizeSeed);
|
||||
|
||||
const handleChangeShouldRandomizeSeed = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => dispatch(setShouldRandomizeSeed(e.target.checked)),
|
||||
|
@ -2,14 +2,14 @@ import { Button } from '@invoke-ai/ui-library';
|
||||
import { NUMPY_RAND_MAX, NUMPY_RAND_MIN } from 'app/constants';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import randomInt from 'common/util/randomInt';
|
||||
import { setSeed } from 'features/parameters/store/generationSlice';
|
||||
import { setSeed } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiShuffleBold } from 'react-icons/pi';
|
||||
|
||||
export const ParamSeedShuffle = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const shouldRandomizeSeed = useAppSelector((s) => s.generation.shouldRandomizeSeed);
|
||||
const shouldRandomizeSeed = useAppSelector((s) => s.canvasV2.params.shouldRandomizeSeed);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleClickRandomizeSeed = useCallback(
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox';
|
||||
import { vaeSelected } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { zModelIdentifierField } from 'features/nodes/types/common';
|
||||
import { selectGenerationSlice, vaeSelected } from 'features/parameters/store/generationSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useVAEModels } from 'services/api/hooks/modelsByType';
|
||||
import type { VAEModelConfig } from 'services/api/types';
|
||||
|
||||
const selector = createMemoizedSelector(selectGenerationSlice, (generation) => {
|
||||
const { model, vae } = generation;
|
||||
return { model, vae };
|
||||
});
|
||||
|
||||
const ParamVAEModelSelect = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const { model, vae } = useAppSelector(selector);
|
||||
const model = useAppSelector((s) => s.canvasV2.params.model);
|
||||
const vae = useAppSelector((s) => s.canvasV2.params.vae);
|
||||
const [modelConfigs, { isLoading }] = useVAEModels();
|
||||
const getIsDisabled = useCallback(
|
||||
(vae: VAEModelConfig): boolean => {
|
||||
|
@ -2,7 +2,7 @@ import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { vaePrecisionChanged } from 'features/parameters/store/generationSlice';
|
||||
import { vaePrecisionChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { isParameterPrecision } from 'features/parameters/types/parameterSchemas';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -15,7 +15,7 @@ const options = [
|
||||
const ParamVAEModelSelect = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const vaePrecision = useAppSelector((s) => s.generation.vaePrecision);
|
||||
const vaePrecision = useAppSelector((s) => s.canvasV2.params.vaePrecision);
|
||||
|
||||
const onChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
|
@ -2,8 +2,8 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||
import { iiLayerAdded } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { selectOptimalDimension } from 'features/controlLayers/store/selectors';
|
||||
import { parseAndRecallAllMetadata } from 'features/metadata/util/handlers';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||
import { t } from 'i18next';
|
||||
|
@ -1,264 +0,0 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import { initialAspectRatioState } from 'features/parameters/components/ImageSize/constants';
|
||||
import { CLIP_SKIP_MAP } from 'features/parameters/types/constants';
|
||||
import type {
|
||||
ParameterCanvasCoherenceMode,
|
||||
ParameterCFGRescaleMultiplier,
|
||||
ParameterCFGScale,
|
||||
ParameterModel,
|
||||
ParameterPrecision,
|
||||
ParameterScheduler,
|
||||
ParameterVAEModel,
|
||||
} from 'features/parameters/types/parameterSchemas';
|
||||
import { getOptimalDimension } from 'features/parameters/util/optimalDimension';
|
||||
import { configChanged } from 'features/system/store/configSlice';
|
||||
import { clamp } from 'lodash-es';
|
||||
import type { RgbaColor } from 'react-colorful';
|
||||
|
||||
import type { GenerationState } from './types';
|
||||
|
||||
const initialGenerationState: GenerationState = {
|
||||
_version: 2,
|
||||
cfgScale: 7.5,
|
||||
cfgRescaleMultiplier: 0,
|
||||
img2imgStrength: 0.75,
|
||||
iterations: 1,
|
||||
scheduler: 'euler',
|
||||
seed: 0,
|
||||
shouldRandomizeSeed: true,
|
||||
steps: 50,
|
||||
model: null,
|
||||
vae: null,
|
||||
vaePrecision: 'fp32',
|
||||
seamlessXAxis: false,
|
||||
seamlessYAxis: false,
|
||||
clipSkip: 0,
|
||||
shouldUseCpuNoise: true,
|
||||
shouldShowAdvancedOptions: false,
|
||||
maskBlur: 16,
|
||||
maskBlurMethod: 'box',
|
||||
canvasCoherenceMode: 'Gaussian Blur',
|
||||
canvasCoherenceMinDenoise: 0,
|
||||
canvasCoherenceEdgeSize: 16,
|
||||
infillMethod: 'patchmatch',
|
||||
infillTileSize: 32,
|
||||
infillPatchmatchDownscaleSize: 1,
|
||||
infillMosaicTileWidth: 64,
|
||||
infillMosaicTileHeight: 64,
|
||||
infillMosaicMinColor: { r: 0, g: 0, b: 0, a: 1 },
|
||||
infillMosaicMaxColor: { r: 255, g: 255, b: 255, a: 1 },
|
||||
infillColorValue: { r: 0, g: 0, b: 0, a: 1 },
|
||||
positivePrompt: '',
|
||||
negativePrompt: '',
|
||||
positivePrompt2: '',
|
||||
negativePrompt2: '',
|
||||
shouldConcatPrompts: true,
|
||||
};
|
||||
|
||||
export const generationSlice = createSlice({
|
||||
name: 'generation',
|
||||
initialState: initialGenerationState,
|
||||
reducers: {
|
||||
setIterations: (state, action: PayloadAction<number>) => {
|
||||
state.iterations = action.payload;
|
||||
},
|
||||
setSteps: (state, action: PayloadAction<number>) => {
|
||||
state.steps = action.payload;
|
||||
},
|
||||
setCfgScale: (state, action: PayloadAction<ParameterCFGScale>) => {
|
||||
state.cfgScale = action.payload;
|
||||
},
|
||||
setCfgRescaleMultiplier: (state, action: PayloadAction<ParameterCFGRescaleMultiplier>) => {
|
||||
state.cfgRescaleMultiplier = action.payload;
|
||||
},
|
||||
setScheduler: (state, action: PayloadAction<ParameterScheduler>) => {
|
||||
state.scheduler = action.payload;
|
||||
},
|
||||
setSeed: (state, action: PayloadAction<number>) => {
|
||||
state.seed = action.payload;
|
||||
state.shouldRandomizeSeed = false;
|
||||
},
|
||||
setImg2imgStrength: (state, action: PayloadAction<number>) => {
|
||||
state.img2imgStrength = action.payload;
|
||||
},
|
||||
setSeamlessXAxis: (state, action: PayloadAction<boolean>) => {
|
||||
state.seamlessXAxis = action.payload;
|
||||
},
|
||||
setSeamlessYAxis: (state, action: PayloadAction<boolean>) => {
|
||||
state.seamlessYAxis = action.payload;
|
||||
},
|
||||
setShouldRandomizeSeed: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldRandomizeSeed = action.payload;
|
||||
},
|
||||
setMaskBlur: (state, action: PayloadAction<number>) => {
|
||||
state.maskBlur = action.payload;
|
||||
},
|
||||
setCanvasCoherenceMode: (state, action: PayloadAction<ParameterCanvasCoherenceMode>) => {
|
||||
state.canvasCoherenceMode = action.payload;
|
||||
},
|
||||
setCanvasCoherenceEdgeSize: (state, action: PayloadAction<number>) => {
|
||||
state.canvasCoherenceEdgeSize = action.payload;
|
||||
},
|
||||
setCanvasCoherenceMinDenoise: (state, action: PayloadAction<number>) => {
|
||||
state.canvasCoherenceMinDenoise = action.payload;
|
||||
},
|
||||
modelChanged: {
|
||||
reducer: (
|
||||
state,
|
||||
action: PayloadAction<ParameterModel | null, string, { previousModel?: ParameterModel | null }>
|
||||
) => {
|
||||
const newModel = action.payload;
|
||||
state.model = newModel;
|
||||
|
||||
if (newModel === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clamp ClipSkip Based On Selected Model
|
||||
// TODO(psyche): remove this special handling when https://github.com/invoke-ai/InvokeAI/issues/4583 is resolved
|
||||
// WIP PR here: https://github.com/invoke-ai/InvokeAI/pull/4624
|
||||
if (newModel.base === 'sdxl') {
|
||||
// We don't support clip skip for SDXL yet - it's not in the graphs
|
||||
state.clipSkip = 0;
|
||||
} else {
|
||||
const { maxClip } = CLIP_SKIP_MAP[newModel.base];
|
||||
state.clipSkip = clamp(state.clipSkip, 0, maxClip);
|
||||
}
|
||||
},
|
||||
prepare: (payload: ParameterModel | null, previousModel?: ParameterModel | null) => ({
|
||||
payload,
|
||||
meta: {
|
||||
previousModel,
|
||||
},
|
||||
}),
|
||||
},
|
||||
vaeSelected: (state, action: PayloadAction<ParameterVAEModel | null>) => {
|
||||
// null is a valid VAE!
|
||||
state.vae = action.payload;
|
||||
},
|
||||
vaePrecisionChanged: (state, action: PayloadAction<ParameterPrecision>) => {
|
||||
state.vaePrecision = action.payload;
|
||||
},
|
||||
setClipSkip: (state, action: PayloadAction<number>) => {
|
||||
state.clipSkip = action.payload;
|
||||
},
|
||||
shouldUseCpuNoiseChanged: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldUseCpuNoise = action.payload;
|
||||
},
|
||||
setInfillMethod: (state, action: PayloadAction<string>) => {
|
||||
state.infillMethod = action.payload;
|
||||
},
|
||||
setInfillTileSize: (state, action: PayloadAction<number>) => {
|
||||
state.infillTileSize = action.payload;
|
||||
},
|
||||
setInfillPatchmatchDownscaleSize: (state, action: PayloadAction<number>) => {
|
||||
state.infillPatchmatchDownscaleSize = action.payload;
|
||||
},
|
||||
setInfillMosaicTileWidth: (state, action: PayloadAction<number>) => {
|
||||
state.infillMosaicTileWidth = action.payload;
|
||||
},
|
||||
setInfillMosaicTileHeight: (state, action: PayloadAction<number>) => {
|
||||
state.infillMosaicTileHeight = action.payload;
|
||||
},
|
||||
setInfillMosaicMinColor: (state, action: PayloadAction<RgbaColor>) => {
|
||||
state.infillMosaicMinColor = action.payload;
|
||||
},
|
||||
setInfillMosaicMaxColor: (state, action: PayloadAction<RgbaColor>) => {
|
||||
state.infillMosaicMaxColor = action.payload;
|
||||
},
|
||||
setInfillColorValue: (state, action: PayloadAction<RgbaColor>) => {
|
||||
state.infillColorValue = action.payload;
|
||||
},
|
||||
positivePromptChanged: (state, action: PayloadAction<string>) => {
|
||||
state.positivePrompt = action.payload;
|
||||
},
|
||||
negativePromptChanged: (state, action: PayloadAction<string>) => {
|
||||
state.negativePrompt = action.payload;
|
||||
},
|
||||
positivePrompt2Changed: (state, action: PayloadAction<string>) => {
|
||||
state.positivePrompt2 = action.payload;
|
||||
},
|
||||
negativePrompt2Changed: (state, action: PayloadAction<string>) => {
|
||||
state.negativePrompt2 = action.payload;
|
||||
},
|
||||
shouldConcatPromptsChanged: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldConcatPrompts = action.payload;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(configChanged, (state, action) => {
|
||||
if (action.payload.sd?.scheduler) {
|
||||
state.scheduler = action.payload.sd.scheduler;
|
||||
}
|
||||
if (action.payload.sd?.vaePrecision) {
|
||||
state.vaePrecision = action.payload.sd.vaePrecision;
|
||||
}
|
||||
});
|
||||
},
|
||||
selectors: {
|
||||
selectOptimalDimension: (slice) => getOptimalDimension(slice.model),
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
setCfgScale,
|
||||
setCfgRescaleMultiplier,
|
||||
setImg2imgStrength,
|
||||
setInfillMethod,
|
||||
setIterations,
|
||||
setScheduler,
|
||||
setMaskBlur,
|
||||
setCanvasCoherenceMode,
|
||||
setCanvasCoherenceEdgeSize,
|
||||
setCanvasCoherenceMinDenoise,
|
||||
setSeed,
|
||||
setShouldRandomizeSeed,
|
||||
setSteps,
|
||||
modelChanged,
|
||||
vaeSelected,
|
||||
setSeamlessXAxis,
|
||||
setSeamlessYAxis,
|
||||
setClipSkip,
|
||||
shouldUseCpuNoiseChanged,
|
||||
vaePrecisionChanged,
|
||||
setInfillTileSize,
|
||||
setInfillPatchmatchDownscaleSize,
|
||||
setInfillMosaicTileWidth,
|
||||
setInfillMosaicTileHeight,
|
||||
setInfillMosaicMinColor,
|
||||
setInfillMosaicMaxColor,
|
||||
setInfillColorValue,
|
||||
positivePromptChanged,
|
||||
negativePromptChanged,
|
||||
positivePrompt2Changed,
|
||||
negativePrompt2Changed,
|
||||
shouldConcatPromptsChanged,
|
||||
} = generationSlice.actions;
|
||||
|
||||
export const { selectOptimalDimension } = generationSlice.selectors;
|
||||
|
||||
export const selectGenerationSlice = (state: RootState) => state.generation;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateGenerationState = (state: any): GenerationState => {
|
||||
if (!('_version' in state)) {
|
||||
state._version = 1;
|
||||
state.aspectRatio = initialAspectRatioState;
|
||||
}
|
||||
if (state._version === 1) {
|
||||
// The signature of the model has changed, so we need to reset it
|
||||
state._version = 2;
|
||||
state.model = null;
|
||||
state.canvasCoherenceMode = initialGenerationState.canvasCoherenceMode;
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const generationPersistConfig: PersistConfig<GenerationState> = {
|
||||
name: generationSlice.name,
|
||||
initialState: initialGenerationState,
|
||||
migrate: migrateGenerationState,
|
||||
persistDenylist: [],
|
||||
};
|
@ -1,59 +0,0 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import type {
|
||||
ParameterCanvasCoherenceMode,
|
||||
ParameterCFGRescaleMultiplier,
|
||||
ParameterCFGScale,
|
||||
ParameterMaskBlurMethod,
|
||||
ParameterModel,
|
||||
ParameterNegativePrompt,
|
||||
ParameterNegativeStylePromptSDXL,
|
||||
ParameterPositivePrompt,
|
||||
ParameterPositiveStylePromptSDXL,
|
||||
ParameterPrecision,
|
||||
ParameterScheduler,
|
||||
ParameterSeed,
|
||||
ParameterSteps,
|
||||
ParameterStrength,
|
||||
ParameterVAEModel,
|
||||
} from 'features/parameters/types/parameterSchemas';
|
||||
import type { RgbaColor } from 'react-colorful';
|
||||
|
||||
export interface GenerationState {
|
||||
_version: 2;
|
||||
cfgScale: ParameterCFGScale;
|
||||
cfgRescaleMultiplier: ParameterCFGRescaleMultiplier;
|
||||
img2imgStrength: ParameterStrength;
|
||||
infillMethod: string;
|
||||
iterations: number;
|
||||
scheduler: ParameterScheduler;
|
||||
maskBlur: number;
|
||||
maskBlurMethod: ParameterMaskBlurMethod;
|
||||
canvasCoherenceMode: ParameterCanvasCoherenceMode;
|
||||
canvasCoherenceMinDenoise: ParameterStrength;
|
||||
canvasCoherenceEdgeSize: number;
|
||||
seed: ParameterSeed;
|
||||
shouldRandomizeSeed: boolean;
|
||||
steps: ParameterSteps;
|
||||
model: ParameterModel | null;
|
||||
vae: ParameterVAEModel | null;
|
||||
vaePrecision: ParameterPrecision;
|
||||
seamlessXAxis: boolean;
|
||||
seamlessYAxis: boolean;
|
||||
clipSkip: number;
|
||||
shouldUseCpuNoise: boolean;
|
||||
shouldShowAdvancedOptions: boolean;
|
||||
infillTileSize: number;
|
||||
infillPatchmatchDownscaleSize: number;
|
||||
infillMosaicTileWidth: number;
|
||||
infillMosaicTileHeight: number;
|
||||
infillMosaicMinColor: RgbaColor;
|
||||
infillMosaicMaxColor: RgbaColor;
|
||||
infillColorValue: RgbaColor;
|
||||
positivePrompt: ParameterPositivePrompt;
|
||||
negativePrompt: ParameterNegativePrompt;
|
||||
positivePrompt2: ParameterPositiveStylePromptSDXL;
|
||||
negativePrompt2: ParameterNegativeStylePromptSDXL;
|
||||
shouldConcatPrompts: boolean;
|
||||
}
|
||||
|
||||
export type PayloadActionWithOptimalDimension<T = void> = PayloadAction<T, string, { optimalDimension: number }>;
|
@ -1,11 +1,8 @@
|
||||
import type { ChakraProps, ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl } from '@invoke-ai/ui-library';
|
||||
import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import type { GroupBase } from 'chakra-react-select';
|
||||
import { selectLoraSlice } from 'features/lora/store/loraSlice';
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import type { PromptTriggerSelectProps } from 'features/prompt/types';
|
||||
import { t } from 'i18next';
|
||||
import { flatten, map } from 'lodash-es';
|
||||
@ -17,14 +14,11 @@ import { isNonRefinerMainModelConfig } from 'services/api/types';
|
||||
|
||||
const noOptionsMessage = () => t('prompt.noMatchingTriggers');
|
||||
|
||||
const selectLoRAs = createMemoizedSelector(selectLoraSlice, (loras) => loras.loras);
|
||||
const selectMainModel = createMemoizedSelector(selectGenerationSlice, (generation) => generation.model);
|
||||
|
||||
export const PromptTriggerSelect = memo(({ onSelect, onClose }: PromptTriggerSelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const mainModel = useAppSelector(selectMainModel);
|
||||
const addedLoRAs = useAppSelector(selectLoRAs);
|
||||
const mainModel = useAppSelector((s) => s.canvasV2.params.model);
|
||||
const addedLoRAs = useAppSelector((s) => s.lora.loras);
|
||||
const { data: mainModelConfig, isLoading: isLoadingMainModelConfig } = useGetModelConfigQuery(
|
||||
mainModel?.key ?? skipToken
|
||||
);
|
||||
|
@ -35,7 +35,7 @@ const TooltipContent = memo(({ prepend = false }: Props) => {
|
||||
const { isReady, reasons } = useIsReadyToEnqueue();
|
||||
const isLoadingDynamicPrompts = useAppSelector((s) => s.dynamicPrompts.isLoading);
|
||||
const promptsCount = useAppSelector(selectPromptsCount);
|
||||
const iterationsCount = useAppSelector((s) => s.generation.iterations);
|
||||
const iterationsCount = useAppSelector((s) => s.canvasV2.params.iterations);
|
||||
const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId);
|
||||
const autoAddBoardName = useBoardName(autoAddBoardId);
|
||||
const [_, { isLoading }] = useEnqueueBatchMutation({
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { CompositeNumberInput } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setIterations } from 'features/parameters/store/generationSlice';
|
||||
import { setIterations } from 'features/canvas/store/canvasSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
export const QueueIterationsNumberInput = memo(() => {
|
||||
const iterations = useAppSelector((s) => s.generation.iterations);
|
||||
const iterations = useAppSelector((s) => s.canvasV2.params.iterations);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.iterations.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.iterations.fineStep);
|
||||
const dispatch = useAppDispatch();
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Box, Textarea } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { negativePrompt2Changed } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
|
||||
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
|
||||
import { negativePrompt2Changed } from 'features/parameters/store/generationSlice';
|
||||
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
|
||||
import { PromptPopover } from 'features/prompt/PromptPopover';
|
||||
import { usePrompt } from 'features/prompt/usePrompt';
|
||||
@ -12,7 +12,7 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const ParamSDXLNegativeStylePrompt = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const prompt = useAppSelector((s) => s.generation.negativePrompt2);
|
||||
const prompt = useAppSelector((s) => s.canvasV2.params.negativePrompt2);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const { t } = useTranslation();
|
||||
const handleChange = useCallback(
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Box, Textarea } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { positivePrompt2Changed } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
|
||||
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
|
||||
import { positivePrompt2Changed } from 'features/parameters/store/generationSlice';
|
||||
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
|
||||
import { PromptPopover } from 'features/prompt/PromptPopover';
|
||||
import { usePrompt } from 'features/prompt/usePrompt';
|
||||
@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const ParamSDXLPositiveStylePrompt = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const prompt = useAppSelector((s) => s.generation.positivePrompt2);
|
||||
const prompt = useAppSelector((s) => s.canvasV2.params.positivePrompt2);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const { t } = useTranslation();
|
||||
const handleChange = useCallback(
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { IconButton, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { shouldConcatPromptsChanged } from 'features/parameters/store/generationSlice';
|
||||
import { shouldConcatPromptsChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiLinkSimpleBold, PiLinkSimpleBreakBold } from 'react-icons/pi';
|
||||
|
||||
export const SDXLConcatButton = memo(() => {
|
||||
const shouldConcatPrompts = useAppSelector((s) => s.generation.shouldConcatPrompts);
|
||||
const shouldConcatPrompts = useAppSelector((s) => s.canvasV2.params.shouldConcatPrompts);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
||||
const ParamSDXLRefinerCFGScale = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const refinerCFGScale = useAppSelector((s) => s.sdxl.refinerCFGScale);
|
||||
const refinerCFGScale = useAppSelector((s) => s.canvasV2.params.refinerCFGScale);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.guidance.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.guidance.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.guidance.numberInputMin);
|
||||
|
@ -6,7 +6,7 @@ import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamSDXLRefinerNegativeAestheticScore = () => {
|
||||
const refinerNegativeAestheticScore = useAppSelector((s) => s.sdxl.refinerNegativeAestheticScore);
|
||||
const refinerNegativeAestheticScore = useAppSelector((s) => s.canvasV2.params.refinerNegativeAestheticScore);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
@ -6,7 +6,7 @@ import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamSDXLRefinerPositiveAestheticScore = () => {
|
||||
const refinerPositiveAestheticScore = useAppSelector((s) => s.sdxl.refinerPositiveAestheticScore);
|
||||
const refinerPositiveAestheticScore = useAppSelector((s) => s.canvasV2.params.refinerPositiveAestheticScore);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
|
||||
const ParamSDXLRefinerScheduler = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const refinerScheduler = useAppSelector((s) => s.sdxl.refinerScheduler);
|
||||
const refinerScheduler = useAppSelector((s) => s.canvasV2.params.refinerScheduler);
|
||||
|
||||
const onChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
|
@ -6,7 +6,7 @@ import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamSDXLRefinerStart = () => {
|
||||
const refinerStart = useAppSelector((s) => s.sdxl.refinerStart);
|
||||
const refinerStart = useAppSelector((s) => s.canvasV2.params.refinerStart);
|
||||
const dispatch = useAppDispatch();
|
||||
const handleChange = useCallback((v: number) => dispatch(setRefinerStart(v)), [dispatch]);
|
||||
const { t } = useTranslation();
|
||||
|
@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next';
|
||||
const ParamSDXLRefinerSteps = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const refinerSteps = useAppSelector((s) => s.sdxl.refinerSteps);
|
||||
const refinerSteps = useAppSelector((s) => s.canvasV2.params.refinerSteps);
|
||||
const initial = useAppSelector((s) => s.config.sd.steps.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
|
||||
|
@ -1,86 +0,0 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import type { ParameterScheduler, ParameterSDXLRefinerModel } from 'features/parameters/types/parameterSchemas';
|
||||
|
||||
type SDXLState = {
|
||||
_version: 2;
|
||||
refinerModel: ParameterSDXLRefinerModel | null;
|
||||
refinerSteps: number;
|
||||
refinerCFGScale: number;
|
||||
refinerScheduler: ParameterScheduler;
|
||||
refinerPositiveAestheticScore: number;
|
||||
refinerNegativeAestheticScore: number;
|
||||
refinerStart: number;
|
||||
};
|
||||
|
||||
const initialSDXLState: SDXLState = {
|
||||
_version: 2,
|
||||
refinerModel: null,
|
||||
refinerSteps: 20,
|
||||
refinerCFGScale: 7.5,
|
||||
refinerScheduler: 'euler',
|
||||
refinerPositiveAestheticScore: 6,
|
||||
refinerNegativeAestheticScore: 2.5,
|
||||
refinerStart: 0.8,
|
||||
};
|
||||
|
||||
export const sdxlSlice = createSlice({
|
||||
name: 'sdxl',
|
||||
initialState: initialSDXLState,
|
||||
reducers: {
|
||||
refinerModelChanged: (state, action: PayloadAction<ParameterSDXLRefinerModel | null>) => {
|
||||
state.refinerModel = action.payload;
|
||||
},
|
||||
setRefinerSteps: (state, action: PayloadAction<number>) => {
|
||||
state.refinerSteps = action.payload;
|
||||
},
|
||||
setRefinerCFGScale: (state, action: PayloadAction<number>) => {
|
||||
state.refinerCFGScale = action.payload;
|
||||
},
|
||||
setRefinerScheduler: (state, action: PayloadAction<ParameterScheduler>) => {
|
||||
state.refinerScheduler = action.payload;
|
||||
},
|
||||
setRefinerPositiveAestheticScore: (state, action: PayloadAction<number>) => {
|
||||
state.refinerPositiveAestheticScore = action.payload;
|
||||
},
|
||||
setRefinerNegativeAestheticScore: (state, action: PayloadAction<number>) => {
|
||||
state.refinerNegativeAestheticScore = action.payload;
|
||||
},
|
||||
setRefinerStart: (state, action: PayloadAction<number>) => {
|
||||
state.refinerStart = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
refinerModelChanged,
|
||||
setRefinerSteps,
|
||||
setRefinerCFGScale,
|
||||
setRefinerScheduler,
|
||||
setRefinerPositiveAestheticScore,
|
||||
setRefinerNegativeAestheticScore,
|
||||
setRefinerStart,
|
||||
} = sdxlSlice.actions;
|
||||
|
||||
export const selectSdxlSlice = (state: RootState) => state.sdxl;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateSDXLState = (state: any): any => {
|
||||
if (!('_version' in state)) {
|
||||
state._version = 1;
|
||||
}
|
||||
if (state._version === 1) {
|
||||
// Model type has changed, so we need to reset the state - too risky to migrate
|
||||
state._version = 2;
|
||||
state.refinerModel = null;
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const sdxlPersistConfig: PersistConfig<SDXLState> = {
|
||||
name: sdxlSlice.name,
|
||||
initialState: initialSDXLState,
|
||||
migrate: migrateSDXLState,
|
||||
persistDenylist: [],
|
||||
};
|
@ -12,7 +12,7 @@ import { ParamSeedRandomize } from 'features/parameters/components/Seed/ParamSee
|
||||
import { ParamSeedShuffle } from 'features/parameters/components/Seed/ParamSeedShuffle';
|
||||
import ParamVAEModelSelect from 'features/parameters/components/VAEModel/ParamVAEModelSelect';
|
||||
import ParamVAEPrecision from 'features/parameters/components/VAEModel/ParamVAEPrecision';
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import { selectGenerationSlice } from 'features/canvas/store/canvasSlice';
|
||||
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { memo, useMemo } from 'react';
|
||||
@ -28,7 +28,7 @@ const formLabelProps2: FormLabelProps = {
|
||||
};
|
||||
|
||||
export const AdvancedSettingsAccordion = memo(() => {
|
||||
const vaeKey = useAppSelector((state) => state.generation.vae?.key);
|
||||
const vaeKey = useAppSelector((state) => state.canvasV2.params.vae?.key);
|
||||
const { currentData: vaeConfig } = useGetModelConfigQuery(vaeKey ?? skipToken);
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
|
||||
|
@ -12,7 +12,7 @@ import ParamImageToImageStrength from 'features/parameters/components/Canvas/Par
|
||||
import { ParamSeedNumberInput } from 'features/parameters/components/Seed/ParamSeedNumberInput';
|
||||
import { ParamSeedRandomize } from 'features/parameters/components/Seed/ParamSeedRandomize';
|
||||
import { ParamSeedShuffle } from 'features/parameters/components/Seed/ParamSeedShuffle';
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import { selectGenerationSlice } from 'features/canvas/store/canvasSlice';
|
||||
import { useExpanderToggle } from 'features/settingsAccordions/hooks/useExpanderToggle';
|
||||
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
|
@ -58,7 +58,7 @@ const RefinerSettingsAccordionNoRefiner: React.FC = memo(() => {
|
||||
RefinerSettingsAccordionNoRefiner.displayName = 'RefinerSettingsAccordionNoRefiner';
|
||||
|
||||
const RefinerSettingsAccordionContent: React.FC = memo(() => {
|
||||
const isRefinerModelSelected = useAppSelector((state) => !isNil(state.sdxl.refinerModel));
|
||||
const isRefinerModelSelected = useAppSelector((state) => !isNil(state.canvasV2.params.refinerModel));
|
||||
|
||||
return (
|
||||
<FormControlGroup isDisabled={!isRefinerModelSelected}>
|
||||
|
@ -19,7 +19,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import { useClearStorage } from 'common/hooks/useClearStorage';
|
||||
import { shouldUseCpuNoiseChanged } from 'features/parameters/store/generationSlice';
|
||||
import { shouldUseCpuNoiseChanged } from 'features/canvas/store/canvasSlice';
|
||||
import { useClearIntermediates } from 'features/system/components/SettingsModal/useClearIntermediates';
|
||||
import { StickyScrollable } from 'features/system/components/StickyScrollable';
|
||||
import {
|
||||
@ -88,7 +88,7 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
||||
|
||||
const { isOpen: isRefreshModalOpen, onOpen: onRefreshModalOpen, onClose: onRefreshModalClose } = useDisclosure();
|
||||
|
||||
const shouldUseCpuNoise = useAppSelector((s) => s.generation.shouldUseCpuNoise);
|
||||
const shouldUseCpuNoise = useAppSelector((s) => s.canvasV2.params.shouldUseCpuNoise);
|
||||
const shouldConfirmOnDelete = useAppSelector((s) => s.system.shouldConfirmOnDelete);
|
||||
const enableImageDebugging = useAppSelector((s) => s.system.enableImageDebugging);
|
||||
const shouldShowProgressInViewer = useAppSelector((s) => s.ui.shouldShowProgressInViewer);
|
||||
|
@ -16,7 +16,6 @@ import { RefinerSettingsAccordion } from 'features/settingsAccordions/components
|
||||
import { StylePresetMenu } from 'features/stylePresets/components/StylePresetMenu';
|
||||
import { StylePresetMenuTrigger } from 'features/stylePresets/components/StylePresetMenuTrigger';
|
||||
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||
@ -42,15 +41,14 @@ const selectedStyles: ChakraProps['sx'] = {
|
||||
const ParametersPanelTextToImage = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
const controlLayersCount = useAppSelector((s) => s.layers.layers.length);
|
||||
const controlLayersCount = useAppSelector((s) => s.canvasV2.layers.length);
|
||||
const controlLayersTitle = useMemo(() => {
|
||||
if (controlLayersCount === 0) {
|
||||
return t('controlLayers.controlLayers');
|
||||
}
|
||||
return `${t('controlLayers.controlLayers')} (${controlLayersCount})`;
|
||||
}, [controlLayersCount, t]);
|
||||
const isSDXL = useAppSelector((s) => s.generation.model?.base === 'sdxl');
|
||||
const isSDXL = useAppSelector((s) => s.canvasV2.params.model?.base === 'sdxl');
|
||||
const onChangeTabs = useCallback(
|
||||
(i: number) => {
|
||||
if (i === 1) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import { selectGenerationSlice } from 'features/canvas/store/canvasSlice';
|
||||
import { useGetModelConfigQuery } from 'services/api/endpoints/models';
|
||||
|
||||
const selectModelKey = createSelector(selectGenerationSlice, (generation) => generation.model?.key);
|
||||
|
Loading…
Reference in New Issue
Block a user